1.3 Hands-on Experience: Implementing Your First Agent in 5 Minutes
In the previous sections, we learned about the agent's task environment, core operating mechanism, and the Thought-Action-Observation interaction paradigm. While theoretical knowledge is important, the best way to learn is through hands-on practice. In this section, we will guide you to build a working intelligent travel assistant from scratch using a few simple lines of Python code. This process will follow the theoretical loop we just learned, allowing you to intuitively experience how an agent "thinks" and interacts with external "tools." Let's get started!
In this case, our goal is to build an intelligent travel assistant that can handle step-by-step tasks. The user task to be solved is defined as: "Hello, please help me check today's weather in Beijing, and then recommend a suitable tourist attraction based on the weather." To complete this task, the agent must demonstrate clear logical planning capabilities. It needs to first call the weather query tool and use the obtained observation results as the basis for the next step. In the next round of the loop, it then calls the attraction recommendation tool to arrive at the final suggestion.
1.3.1 Preparation
To access web APIs from a Python program, we need an HTTP library. requests is the most popular and easy-to-use choice in the Python community. tavily-python is a powerful AI search API client for obtaining real-time web search results, which can be obtained by registering on the official website. openai is the official Python SDK provided by OpenAI for calling large language model services such as GPT. Please install them first with the following command:
pip install requests tavily-python openai(1) Instruction Template
The key to driving a real LLM lies in Prompt Engineering. We need to design an "instruction template" that tells the LLM what role it should play, what tools it has, and how to format its thinking and actions. This is the "manual" for our agent, which will be passed to the LLM as system_prompt.
AGENT_SYSTEM_PROMPT = """
You are an intelligent travel assistant. Your task is to analyze user requests and use available tools to solve problems step by step.
# Available Tools:
- `get_weather(city: str)`: Query real-time weather for a specified city.
- `get_attraction(city: str, weather: str)`: Search for recommended tourist attractions based on city and weather.
# Output Format Requirements:
Each response must strictly follow this format, containing one Thought-Action pair:
Thought: [Your thinking process and next step plan]
Action: [The specific action you want to execute]
Action format must be one of the following:
1. Call a tool: function_name(arg_name="arg_value")
2. Finish task: Finish[final answer]
# Important Notes:
- Output only one Thought-Action pair each time
- Action must be on the same line, do not break lines
- When you have collected enough information to answer the user's question, you must use Action: Finish[final answer] format to end
Let's begin!
"""(2) Tool 1: Query Real Weather
We will use the free weather query service wttr.in, which can return weather data for a specified city in JSON format. Here is the code to implement this tool:
import requests
def get_weather(city: str) -> str:
"""
Query real weather information by calling the wttr.in API.
"""
# API endpoint, we request data in JSON format
url = f"https://wttr.in/{city}?format=j1"
try:
# Make network request
response = requests.get(url)
# Check if response status code is 200 (success)
response.raise_for_status()
# Parse returned JSON data
data = response.json()
# Extract current weather conditions
current_condition = data['current_condition'][0]
weather_desc = current_condition['weatherDesc'][0]['value']
temp_c = current_condition['temp_C']
# Format as natural language return
return f"{city} current weather: {weather_desc}, temperature {temp_c} degrees Celsius"
except requests.exceptions.RequestException as e:
# Handle network errors
return f"Error: Network problem encountered when querying weather - {e}"
except (KeyError, IndexError) as e:
# Handle data parsing errors
return f"Error: Failed to parse weather data, city name may be invalid - {e}"(3) Tool 2: Search and Recommend Tourist Attractions
We will define a new tool get_attraction that searches the internet for suitable attractions based on city and weather conditions:
import os
from tavily import TavilyClient
def get_attraction(city: str, weather: str) -> str:
"""
Based on city and weather, use Tavily Search API to search and return optimized attraction recommendations.
"""
# 1. Read API key from environment variable
api_key = os.environ.get("TAVILY_API_KEY")
if not api_key:
return "Error: TAVILY_API_KEY environment variable not configured."
# 2. Initialize Tavily client
tavily = TavilyClient(api_key=api_key)
# 3. Construct a precise query
query = f"'{city}' most worthwhile tourist attractions and reasons in '{weather}' weather"
try:
# 4. Call API, include_answer=True will return a comprehensive answer
response = tavily.search(query=query, search_depth="basic", include_answer=True)
# 5. Tavily's returned results are already very clean and can be used directly
# response['answer'] is a summary answer based on all search results
if response.get("answer"):
return response["answer"]
# If there's no comprehensive answer, format raw results
formatted_results = []
for result in response.get("results", []):
formatted_results.append(f"- {result['title']}: {result['content']}")
if not formatted_results:
return "Sorry, no relevant tourist attraction recommendations found."
return "Based on search, found the following information for you:\n" + "\n".join(formatted_results)
except Exception as e:
return f"Error: Problem occurred when executing Tavily search - {e}"Finally, we put all tool functions into a dictionary for the main loop to call:
# Put all tool functions into a dictionary for easy subsequent calling
available_tools = {
"get_weather": get_weather,
"get_attraction": get_attraction,
}1.3.2 Connecting to Large Language Models
Currently, many LLM service providers (including OpenAI, Azure, and numerous open-source model service frameworks such as Ollama, vLLM, etc.) follow interface specifications similar to the OpenAI API. This standardization brings great convenience to developers. The agent's autonomous decision-making capability comes from the LLM. We will implement a universal client OpenAICompatibleClient that can connect to any LLM service compatible with the OpenAI interface specification.
from openai import OpenAI
class OpenAICompatibleClient:
"""
A client for calling any LLM service compatible with the OpenAI interface.
"""
def __init__(self, model: str, api_key: str, base_url: str):
self.model = model
self.client = OpenAI(api_key=api_key, base_url=base_url)
def generate(self, prompt: str, system_prompt: str) -> str:
"""Call LLM API to generate response."""
print("Calling large language model...")
try:
messages = [
{'role': 'system', 'content': system_prompt},
{'role': 'user', 'content': prompt}
]
response = self.client.chat.completions.create(
model=self.model,
messages=messages,
stream=False
)
answer = response.choices[0].message.content
print("Large language model responded successfully.")
return answer
except Exception as e:
print(f"Error occurred when calling LLM API: {e}")
return "Error: Error occurred when calling language model service."To instantiate this class, you need to provide three pieces of information: API_KEY, BASE_URL, and MODEL_ID. The specific values depend on the service provider you use (such as OpenAI official, Azure, or local models like Ollama). If you don't have access to these yet, you can refer to Environment Configuration.
1.3.3 Executing the Action Loop
The main loop below will integrate all components and drive the LLM to make decisions through formatted prompts.
import re
# --- 1. Configure LLM client ---
# Please replace this with the corresponding credentials and address for the service you use
API_KEY = "YOUR_API_KEY"
BASE_URL = "YOUR_BASE_URL"
MODEL_ID = "YOUR_MODEL_ID"
TAVILY_API_KEY="YOUR_Tavily_KEY"
os.environ['TAVILY_API_KEY'] = "YOUR_TAVILY_API_KEY"
llm = OpenAICompatibleClient(
model=MODEL_ID,
api_key=API_KEY,
base_url=BASE_URL
)
# --- 2. Initialize ---
user_prompt = "Hello, please help me check today's weather in Beijing, and then recommend a suitable tourist attraction based on the weather."
prompt_history = [f"User request: {user_prompt}"]
print(f"User input: {user_prompt}\n" + "="*40)
# --- 3. Run main loop ---
for i in range(5): # Set maximum number of loops
print(f"--- Loop {i+1} ---\n")
# 3.1. Build Prompt
full_prompt = "\n".join(prompt_history)
# 3.2. Call LLM for thinking
llm_output = llm.generate(full_prompt, system_prompt=AGENT_SYSTEM_PROMPT)
# Truncate extra Thought-Action pairs that the model may generate
match = re.search(r'(Thought:.*?Action:.*?)(?=\n\s*(?:Thought:|Action:|Observation:)|\Z)',
llm_output, re.DOTALL)
if match:
truncated = match.group(1).strip()
if truncated != llm_output.strip():
llm_output = truncated
print("Truncated extra Thought-Action pairs")
print(f"Model output:\n{llm_output}\n")
prompt_history.append(llm_output)
# 3.3. Parse and execute action
action_match = re.search(r"Action: (.*)", llm_output, re.DOTALL)
if not action_match:
observation = "Error: No action found. Please explicitly use Action: finish(...) or other actions."
observation_str = f"Observation: {observation}"
print(f"{observation_str}\n" + "="*40)
prompt_history.append(observation_str)
continue
action_str = action_match.group(1).strip()
if action_str.startswith("Finish"):
final_answer = re.match(r"Finish\[(.*)\]", action_str).group(1)
print(f"Task completed, final answer: {final_answer}")
break
tool_name = re.search(r"(\w+)\(", action_str).group(1)
args_str = re.search(r"\((.*)\)", action_str).group(1)
kwargs = dict(re.findall(r'(\w+)="([^"]*)"', args_str))
if tool_name in available_tools:
observation = available_tools[tool_name](**kwargs)
else:
observation = f"Error: Undefined tool '{tool_name}'"
# 3.4. Record observation results
observation_str = f"Observation: {observation}"
print(f"{observation_str}\n" + "="*40)
prompt_history.append(observation_str)Through the above steps, we have built a complete agent driven by a real LLM. Its core lies in the combination of "tools" and "prompt engineering," which is precisely the design essence of current mainstream agent frameworks (such as LangChain, LlamaIndex, etc.).
1.3.4 Running Case Analysis
The following output fully demonstrates a successful agent execution process. Through analysis of this three-round loop, we can clearly see the core capabilities of the agent in solving problems.
User input: Hello, please help me check today's weather in Beijing, and then recommend a suitable tourist attraction based on the weather.
========================================
--- Loop 1 ---
Calling large language model...
Large language model responded successfully.
Model output:
Thought: First need to get Beijing's weather today, then recommend tourist attractions based on the weather.
Action: get_weather(city="Beijing")
Observation: Beijing current weather: Sunny, temperature 26 degrees Celsius
========================================
--- Loop 2 ---
Calling large language model...
Large language model responded successfully.
Model output:
Thought: Now I know Beijing's weather today is sunny with moderate temperature, I can recommend a suitable tourist attraction based on this information.
Action: get_attraction(city="Beijing", weather="Sunny")
Observation: The most worthwhile tourist attractions in Beijing on sunny days are the Summer Palace for its beautiful lake views and ancient architecture. Another recommendation is the Great Wall for its spectacular scenery and historical significance.
========================================
--- Loop 3 ---
Calling large language model...
Large language model responded successfully.
Model output:
Thought: I have obtained two attraction suggestions suitable for sunny days, now I can provide a satisfactory response to the user based on this information.
Action: Finish[Today's weather in Beijing is sunny with a temperature of 26 degrees Celsius, very suitable for outdoor activities. I recommend you visit the Summer Palace to enjoy the beautiful lake views and ancient architecture, or go to the Great Wall to experience its spectacular scenery and profound historical significance. Hope you have a pleasant trip!]
Task completed, final answer: Today's weather in Beijing is sunny with a temperature of 26 degrees Celsius, very suitable for outdoor activities. I recommend you visit the Summer Palace to enjoy the beautiful lake views and ancient architecture, or go to the Great Wall to experience its spectacular scenery and profound historical significance. Hope you have a pleasant trip!This simple travel assistant case concentrates on demonstrating the four basic capabilities of an agent based on the Thought-Action-Observation paradigm: task decomposition, tool invocation, context understanding, and result synthesis. It is through the continuous iteration of this loop that the agent can transform a vague user intent into a series of specific, executable steps and ultimately achieve the goal.