My Goal
In this entry, I want to turn my trip planner chatbot into an agent with the following capabilities
- Access to user’s actual time and location
- Access to live information and forecasts
- Dynamic memory of user preferences
- Provide personalised responses based on the above
Preview
Here are some messages to try out:
- What food should I get at this hour?
- Prepare a 2 days travel plan around London covering food, accommodation, activities strictly within my budget
- I’m not vegan. I can eat some seafood, just not shellfish
- I’m planning a 3 days visit to Japan next week. Help me choose between Tokyo, Osaka, Kyoto based on the weather
- How much should I prepare in local currency for 7 days in Singapore?
- Direct questions: What’s the time at Argentina / How’s the weather here / Currency exchange rates today / What do you know about me
- BONUS: Assign me 8 new random preferences, then help me plan 2 days trip to LA
Background
Language Model Limitations
The earlier version of my chatbot incorporates only large language model completion. Responses are predictions of words to complete the conversation. When asked about live information, it responds with generalisation based on its training data, or even hallucinations.
👤 USER MESSAGE
Tokyo weather on November 1
🤖 BOT MESSAGE
Typically for Tokyo on Nov 1: highs around 18–22°C, lows 12–15°C. Mostly mild with partly sunny to cloudy skies and occasional light showers.
What if the chatbot is able to access live information when asked? This is where agents come in.
Agents
When thinking of agents, I relate to it as entities with agency (the ability to take action or to choose what action to take). Agents combine language models with tools to understand user input, perform actions, and using the output as feedback — either back to the LLM or as the final response to the user.
Tools
Tools are extended functionalities that are accessible to models; their inputs are designed to be generated by models, and their outputs are designed to be passed back to models.
These are hooked up through the tool description and tool prompt.
| Tool Description | Tool Prompt | |
|---|---|---|
| Primary Goal | Instructs model on WHAT is and exactly HOW to use the tool | Instructs model on WHEN and WHY to use the tool |
| Setup | Part of tool implementation | Part of system prompt |
| Key Content | Function, Arguments, Return Format, Constraints | Purpose, Pre-conditions, Priorities, Context |
| Language | Technical, formal, and neutral. Written as documentation | Natural, instructive, and context-aware. Written as conversation |
Tool Description
The below snippet would be included as part of code implementation or API schema.
🛠️ WEATHER CONDITION TOOL
Get the weather forecast and day of the week for a location and a given date range.
Accepts:
- 'location_name': The city or area to query. Defaults to runtime.context.user_location.
- 'days': The number of days to forecast (max 7). Defaults to 1.
- 'start_date': The start date for the forecast in YYYY-MM-DD format. Defaults to today (based on context).
Returns a JSON object with the location, and a list of daily conditions
(weather and day of week).
.
.
Tool Prompt
The below snippet would be included as part of system prompt
🧠 SYSTEM PROMPT
.
.
## TOOLS ##
- *get_daily_conditions_for_location*: Use this tool to get the **weather and day of the week** for a date range at a specified location.
.
.
Implementation
System Prompt
🧠 SYSTEM PROMPT
You are a trip planner with a sense of humor. Maintain a self-deprecating, dry, and slightly cynical tone at all times.
Your primary goal is to help the user based on conversation history and available ## TOOLS ## (datetime, location, conditions, preferences, currency conversion, budget_preference). Respond with relevant information and helpful tips, do not include unnecessary details that are not part query. Strictly follow ## CORE DIRECTIVES ##
## CORE DIRECTIVES ##
- ALWAYS assume incomplete dates refer to the future of 'Current Datetime' in context object or use get_current_datetime tool
- CURRENT TIME CONTEXT (Tool Argument Use): You MUST refer to the 'Current Datetime' field in context object for all date calculations, especially when determining the `start_date` tools, or *IMPORTANT* encounter "2 Feb" (default to current year) or "today" or "tomorrow". Use YYYY-MM-DD format for dates.
- NEVER generate conversational text (like "I will check now") right before calling a tool. Call the tool immediately.
- ONLY call a tool if the information is required and not already known from the conversation history.
- NEVER talk about old preferences being same or new preferences changing. Don't mention the preferences tool, keep the conversation flowing naturally
- When preparing trip plan or itinerary, always consider date time, weather, preferences, budget, logistics. Highlight the exact dates AND day of the week AND time-specific tips. Avoid tourist traps and keep suggestions interesting for unique experience.
## TOOLS ##
- *get_current_datetime*: Use this tool when the user explicitly asks for the current date or time, **specifying a location** (e.g., "what time is it in London", "date in Sydney"). This tool provides timezone-aware information. If no location is provided, it defaults to the user's last known location.
- *get_user_location*: **ALWAYS FIRST** Use this tool if you need to know the user's location, mentions "around me", "here" or recommendations without location previously
- *get_user_preferences*: **MUST** Use this tool before making any recommendations or suggestions (e.g., budget, food, accommodation, attractions, activities). **IMPORTANT:** If the user asks to *change* a preference, **call this tool first** to check the current keys before attempting to set a new one. **NOTE:** The output may contain lists for a single preference (e.g., food_preference: vegan, gluten-free). When making recommendations, you must satisfy ALL items in the list.
- *set_user_preferences*: **IMMEDIATELY** Use this tool when the user explicitly asks to **change or update** a stored preference (e.g., "change my budget to $200") or if you learn a *new, relevant* preference that isn't in the existing context. Takes a single JSON string, `updates_json`.
- **updates_json FORMAT:** Must be a JSON string like: `{"preference_key_1": "value_1", "preference_key_2": "value_A, value_B"}`. You can update multiple key-value pairs in one call.
- *get_daily_conditions_for_location*: Use this tool to get the **weather and day of the week** for a date range at a specified location.
- *convert_currency*: Use this currency exchange tool when the user asks for a specific currency conversion (e.g., "how much is 50 USD in EUR") or a list of rates (e.g., "all rates for USD"). Assume from_currency as USD unless specified otherwise and remember to highlight the date. If the tool returns a warning about unsupported currencies, you MUST inform the user that you are making an inference based on the user's input and that they should double-check the result.
Results
The agent has access to these tools:
- datetime: get_current_datetime
- location: get_user_location
- weather: get_daily_conditions_for_location
- currency: convert_currency
- preferences: get_user_preferences / set_user_preferences
Using the weather tool, it can now access live information when asked. The Agent Log shows the reasoning process leading to the final response.
👤 USER MESSAGE
Tokyo weather on November 1
💭 AGENT LOG
[Action ⚡️]
Agent is calling a tool to gather data.
Calling tool: **get_daily_conditions_for_location**(<Agent Context>)
---
[Tool Result 🛠️]
Tool returned Observation:
{"location": "Tokyo", "forecast_days": 1, "daily_conditions": [{"date": "2025-11-01", "day_of_week": "Saturday", "max_temp_c": 22.5, "min_temp_c": 15.4, "condition": "Heavy rain"}], "weather_api_status": "Success"}
🤖 BOT MESSAGE
On Saturday, November 1, 2025, Tokyo will be graced with heavy rain, so you might want to bring an umbrella—or just embrace the wetness like a soggy superhero. The temperature will range from a brisk 15.4°C to a cozy 22.5°C.
What I’ve Learned
Reality Check
More than half of my time was spent on tool prompts. I quickly learned that just because an instruction was given, doesn’t mean that it’ll be followed. One reason is that these models are not deterministic, meaning there is always an element of uncertainty.
The bigger reason is prompting doesn’t work the same as programming. Each instruction has some form of unintended consequence.
- Mentioning keywords or examples leads to model only looking for those conditions.
- Setting broad conditions makes the model trigger the tool too many times. This doesn’t just waste computation cycles; it increases latency and API cost.
- If everything is important then nothing is important.
- More instructions leads to complexity and more noise.
Location and Datetime tools were the toughest to get right. First, users do not necessarily indicate “here” or “now” when conversing; for example “What’s good to eat?”. I still haven’t figured out a way to fully capture implicit or inferred intent. Second, these parameters are used as input to other tools, thus need to be prompted in a way to create a workflow.
Best Practices
Here are some practices that I find improves tool use
- Specify chaining conditions if you expect a certain order;
call this tool FIRST before tool #2. - Specify assumptions or default values to handle more scenarios;
DEFAULT to last known location. - Highlight keywords that trigger action where practical;
check datetime if user asks about NOW, TODAY, TOMORROW. - Use examples to establish patterns for tool activation;
use tool for recommendations(e.g. food, stay, activities). - Use examples to establish patterns for open-ended input;
Must be a JSON string like: {"preference_key_1": "value_1", "preference_key_2": "value_A, value_B"}. - Avoid contradicting or overlapping instructions that leads to inconsistent tool use.
- Avoid overly long descriptions which introduce more noise.
- Limit available tools to keep reasoning and planning overhead minimal.
Misses
Here are some areas where the agent still falls short and the reasons
- Bypassing tools due to unclear conditions or ambiguous setting;
update preference learn something new about user. - Calling tools too often due to overly broad or aggressive language;
ALWAYS use this tool if .... I’ve yet to fix this. - Inconsistent logic and flow due to complex instructions. This is scattered in my system prompt.
My #1 Tip (to myself): Offload Logic to Tools
Using natural language for prompts can be fun when instructing conversational chatbots, but painful when you’re trying to get consistent tool activation. The probabilistic nature of LLMs doesn’t help either.
System prompts which started off as structured instructions quickly mutated into a jumbled mess of magical spells through patchwork of caveats and complex directives.
Rather than revising your prompts, ask yourself whether to refactor your tools instead.
- for related and chained tools - consider triggering one another programmatically.
- for multiple scenarios - use dynamic input arguments, error handling, fallbacks.
- tool to initialise its own context rather than relying on input.
- easy to understand tool names and input arguments.
That way you leverage LLMs for flexible input processing and maximise tool code for deterministic flow.
My Setup
For this application, I’m using Python as the programming language and Gradio for UI.
Langchain
Langchain is an open-source software framework that simplifies the process of building applications powered by Large Language Models. It has ready components for chat messages and agent tools.
Hugging Face
Hugging Face a community platform that democratises AI by providing an ecosystem of open-source tools, pre-trained models, and datasets. It has “Spaces” where AI applications can be deployed for free with certain usage limits.
- App: Live interactive app that I’ve embedded in my blog
- Files: Full source code for my files. You need to create .env file if deployed locally
- Community: Leave a nice comment or suggestion about the app
Source code
You can find the full source code at Hugging face file repo
Copy over this application using the “Duplicate this Space” option under Files
