构建一个 Agent
LangChain 支持创建Agents,也就是利用LLMs 作为推理引擎来决定采取何种行动以及执行该行动所需的输入的系统。 在执行行动后,其结果可以反馈给 LLM,以确定是否需要采取更多行动,或者是否可以结束。这通常通过工具调用来实现。
在本教程中,我们将构建一个可以与搜索引擎交互的 Agent。你可以向该 Agent 提问,观察它调用搜索工具,并与之进行对话。
端到端 Agent
下面的代码片段代表了一个使用 LLM 来决定使用哪些工具的完整功能的 Agent。它配备了一个通用的搜索工具。它具有会话记忆——这意味着它可以作为一个多轮对话的聊天机器人使用。
在本指南的其余部分,我们将逐一介绍各个组件及其作用——但如果你只想获取一些代码然后开始,随时可以使用这段代码!
# Import relevant functionality
from langchain.chat_models import init_chat_model
from langchain_tavily import TavilySearch
from langgraph.checkpoint.memory import MemorySaver
from langgraph.prebuilt import create_react_agent
# Create the agent
memory = MemorySaver()
model = init_chat_model("anthropic:claude-3-5-sonnet-latest")
search = TavilySearch(max_results=2)
tools = [search]
agent_executor = create_react_agent(model, tools, checkpointer=memory)
# Use the agent
config = {"configurable": {"thread_id": "abc123"}}
input_message = {
"role": "user",
"content": "Hi, I'm Bob and I live in SF.",
}
for step in agent_executor.stream(
{"messages": [input_message]}, config, stream_mode="values"
):
step["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
Hi, I'm Bob and I live in SF.
==================================[1m Ai Message [0m==================================
Hello Bob! I notice you've introduced yourself and mentioned you live in SF (San Francisco), but you haven't asked a specific question or made a request that requires the use of any tools. Is there something specific you'd like to know about San Francisco or any other topic? I'd be happy to help you find information using the available search tools.
input_message = {
"role": "user",
"content": "What's the weather where I live?",
}
for step in agent_executor.stream(
{"messages": [input_message]}, config, stream_mode="values"
):
step["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
What's the weather where I live?
==================================[1m Ai Message [0m==================================
[{'text': 'Let me search for current weather information in San Francisco.', 'type': 'text'}, {'id': 'toolu_011kSdheoJp8THURoLmeLtZo', 'input': {'query': 'current weather San Francisco CA'}, 'name': 'tavily_search', 'type': 'tool_use'}]
Tool Calls:
tavily_search (toolu_011kSdheoJp8THURoLmeLtZo)
Call ID: toolu_011kSdheoJp8THURoLmeLtZo
Args:
query: current weather San Francisco CA
=================================[1m Tool Message [0m=================================
Name: tavily_search
{"query": "current weather San Francisco CA", "follow_up_questions": null, "answer": null, "images": [], "results": [{"title": "Weather in San Francisco, CA", "url": "https://www.weatherapi.com/", "content": "{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.775, 'lon': -122.4183, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1750168606, 'localtime': '2025-06-17 06:56'}, 'current': {'last_updated_epoch': 1750167900, 'last_updated': '2025-06-17 06:45', 'temp_c': 11.7, 'temp_f': 53.1, 'is_day': 1, 'condition': {'text': 'Fog', 'icon': '//cdn.weatherapi.com/weather/64x64/day/248.png', 'code': 1135}, 'wind_mph': 4.0, 'wind_kph': 6.5, 'wind_degree': 215, 'wind_dir': 'SW', 'pressure_mb': 1017.0, 'pressure_in': 30.02, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 86, 'cloud': 0, 'feelslike_c': 11.3, 'feelslike_f': 52.4, 'windchill_c': 8.7, 'windchill_f': 47.7, 'heatindex_c': 9.8, 'heatindex_f': 49.7, 'dewpoint_c': 9.6, 'dewpoint_f': 49.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 0.0, 'gust_mph': 6.3, 'gust_kph': 10.2}}", "score": 0.944705, "raw_content": null}, {"title": "Weather in San Francisco in June 2025", "url": "https://world-weather.info/forecast/usa/san_francisco/june-2025/", "content": "Detailed ⚡ San Francisco Weather Forecast for June 2025 - day/night 🌡️ temperatures, precipitations - World-Weather.info. Add the current city. Search. Weather; Archive; Weather Widget °F. World; United States; California; Weather in San Francisco; ... 17 +64° +54° 18 +61° +54° 19", "score": 0.86441374, "raw_content": null}], "response_time": 2.34}
==================================[1m Ai Message [0m==================================
Based on the search results, here's the current weather in San Francisco:
- Temperature: 53.1°F (11.7°C)
- Condition: Foggy
- Wind: 4.0 mph from the Southwest
- Humidity: 86%
- Visibility: 9 miles
This is quite typical weather for San Francisco, with the characteristic fog that the city is known for. Would you like to know anything else about the weather or San Francisco in general?
设置
Jupyter Notebook
本指南(以及文档中的大部分其他指南)使用了 Jupyter notebooks,并假设读者也在使用。Jupyter notebooks 是学习如何使用 LLM 系统的绝佳互动环境,因为事情常常会出错(意外输出、API 宕机等),观察这些情况是深入了解 LLM 构建的绝佳方式。
在 Jupyter notebook 中运行本教程和其他教程可能最为方便。请参阅此处了解安装说明。
安装
要安装 LangChain,请运行:
%pip install -U langgraph langchain-tavily langgraph-checkpoint-sqlite
更多详情,请参阅我们的 安装指南。
LangSmith
您使用 LangChain 构建的许多应用程序将包含多个步骤和多次 LLM 调用。 随着这些应用程序日益复杂,能够检查链或代理内部确切发生的事情变得至关重要。 做到这一点最好的方法是使用 LangSmith。
在上面的链接注册后,请确保设置您的环境变量以开始记录追踪:
export LANGSMITH_TRACING="true"
export LANGSMITH_API_KEY="..."
或者,如果您在笔记本中,可以使用以下方式设置:
import getpass
import os
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_API_KEY"] = getpass.getpass()
Tavily
我们将使用 Tavily(一个搜索引擎)作为工具。 为了使用它,您需要获取并设置一个 API 密钥:
export TAVILY_API_KEY="..."
或者,如果您在笔记本中,可以使用以下方式设置:
import getpass
import os
os.environ["TAVILY_API_KEY"] = getpass.getpass()
定义工具
我们首先需要创建想要使用的工具。我们选择的主要工具是 Tavily - 一个搜索引擎。我们可以使用专用的 langchain-tavily 集成包 来轻松地将 Tavily 搜索引擎用作 LangChain 的工具。
from langchain_tavily import TavilySearch
search = TavilySearch(max_results=2)
search_results = search.invoke("What is the weather in SF")
print(search_results)
# If we want, we can create other tools.
# Once we have all the tools we want, we can put them in a list that we will reference later.
tools = [search]
{'query': 'What is the weather in SF', 'follow_up_questions': None, 'answer': None, 'images': [], 'results': [{'title': 'Weather in San Francisco, CA', 'url': 'https://www.weatherapi.com/', 'content': "{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.775, 'lon': -122.4183, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1750168606, 'localtime': '2025-06-17 06:56'}, 'current': {'last_updated_epoch': 1750167900, 'last_updated': '2025-06-17 06:45', 'temp_c': 11.7, 'temp_f': 53.1, 'is_day': 1, 'condition': {'text': 'Fog', 'icon': '//cdn.weatherapi.com/weather/64x64/day/248.png', 'code': 1135}, 'wind_mph': 4.0, 'wind_kph': 6.5, 'wind_degree': 215, 'wind_dir': 'SW', 'pressure_mb': 1017.0, 'pressure_in': 30.02, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 86, 'cloud': 0, 'feelslike_c': 11.3, 'feelslike_f': 52.4, 'windchill_c': 8.7, 'windchill_f': 47.7, 'heatindex_c': 9.8, 'heatindex_f': 49.7, 'dewpoint_c': 9.6, 'dewpoint_f': 49.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 0.0, 'gust_mph': 6.3, 'gust_kph': 10.2}}", 'score': 0.9185379, 'raw_content': None}, {'title': 'Weather in San Francisco in June 2025', 'url': 'https://world-weather.info/forecast/usa/san_francisco/june-2025/', 'content': "Weather in San Francisco in June 2025 (California) - Detailed Weather Forecast for a Month * Weather in San Francisco Weather in San Francisco in June 2025 * 1 +63° +55° * 2 +66° +54° * 3 +66° +55° * 4 +66° +54° * 5 +66° +55° * 6 +66° +57° * 7 +64° +55° * 8 +63° +55° * 9 +63° +54° * 10 +59° +54° * 11 +59° +54° * 12 +61° +54° Weather in Washington, D.C.**+68°** Sacramento**+81°** Pleasanton**+72°** Redwood City**+68°** San Leandro**+61°** San Mateo**+64°** San Rafael**+70°** San Ramon**+64°** South San Francisco**+61°** Daly City**+59°** Wilder**+66°** Woodacre**+70°** world's temperature today Colchani day+50°F night+16°F Az Zubayr day+124°F night+93°F Weather forecast on your site Install _San Francisco_ +61° Temperature units", 'score': 0.7978881, 'raw_content': None}], 'response_time': 2.62}
在许多应用程序中,您可能想要定义自定义工具。LangChain 支持通过 Python 函数等方式创建自定义工具。有关详细信息,请参阅 如何创建工具 指南。
使用语言模型
接下来,我们将学习如何使用语言模型来调用工具。LangChain 支持许多不同的语言模型,您可以根据需要进行切换使用——请在下方选择您想使用的 模型!
pip install -qU "langchain[google-genai]"
import getpass
import os
if not os.environ.get("GOOGLE_API_KEY"):
os.environ["GOOGLE_API_KEY"] = getpass.getpass("Enter API key for Google Gemini: ")
from langchain.chat_models import init_chat_model
model = init_chat_model("gemini-2.0-flash", model_provider="google_genai")
您可以将消息列表传递给语言模型来调用它。默认情况下,响应是 content 字符串。
query = "Hi!"
response = model.invoke([{"role": "user", "content": query}])
response.text()
'Hello! How can I help you today?'
现在我们可以看到启用此模型进行工具调用的情况了。为了实现这一点,我们使用 .bind_tools 来让语言模型了解这些工具。
model_with_tools = model.bind_tools(tools)
现在我们可以调用模型了。让我们先用一个普通消息调用它,看看它的响应。我们可以同时查看 content 字段和 tool_calls 字段。
query = "Hi!"
response = model_with_tools.invoke([{"role": "user", "content": query}])
print(f"Message content: {response.text()}\n")
print(f"Tool calls: {response.tool_calls}")
Message content: Hello! I'm here to help you. I have access to a powerful search tool that can help answer questions and find information about various topics. What would you like to know about?
Feel free to ask any question or request information, and I'll do my best to assist you using the available tools.
Tool calls: []
现在,让我们尝试使用一些会调用工具的输入来调用它。
query = "Search for the weather in SF"
response = model_with_tools.invoke([{"role": "user", "content": query}])
print(f"Message content: {response.text()}\n")
print(f"Tool calls: {response.tool_calls}")
Message content: I'll help you search for information about the weather in San Francisco.
Tool calls: [{'name': 'tavily_search', 'args': {'query': 'current weather San Francisco'}, 'id': 'toolu_015gdPn1jbB2Z21DmN2RAnti', 'type': 'tool_call'}]
我们可以看到现在没有文本内容,但是有一个工具调用!它要求我们调用 Tavily Search 工具。
这并不是在调用该工具——它只是在告诉我们去调用它。为了真 正调用它,我们需要创建我们的代理。
创建代理
既然我们已经定义了工具和 LLM,就可以创建代理了。我们将使用 LangGraph 来构建代理。 目前,我们使用了一个高层接口来构建代理,但 LangGraph 的优点在于,这个高层接口背后有一个底层且高度可控的 API,以防你想修改代理逻辑。
现在,我们可以使用 LLM 和工具来初始化代理。
请注意,我们传入的是 model 而不是 model_with_tools。这是因为 create_react_agent 会在后台为我们调用 .bind_tools。
from langgraph.prebuilt import create_react_agent
agent_executor = create_react_agent(model, tools)
运行代理
现在我们可以用几个查询来运行代理了!请注意,目前这些都是无状态查询(它不会记住之前的交互)。请注意,代理将在交互结束时返回最终状态(包括任何输入,我们稍后将看到如何只获取输出)。
首先,让我们看看当不需要调用工具时它是如何响应的:
input_message = {"role": "user", "content": "Hi!"}
response = agent_executor.invoke({"messages": [input_message]})
for message in response["messages"]:
message.pretty_print()
================================[1m Human Message [0m=================================
Hi!
==================================[1m Ai Message [0m==================================
Hello! I'm here to help you with your questions using the available search tools. Please feel free to ask any question, and I'll do my best to find relevant and accurate information for you.
为了确切地了解幕后发生的情况(并确保它没有调用工具),我们可以查看一下 LangSmith 跟踪
现在让我们在一个应该调用该工具的示例上尝试一下
input_message = {"role": "user", "content": "Search for the weather in SF"}
response = agent_executor.invoke({"messages": [input_message]})
for message in response["messages"]:
message.pretty_print()
================================[1m Human Message [0m=================================
Search for the weather in SF
==================================[1m Ai Message [0m==================================
[{'text': "I'll help you search for weather information in San Francisco. Let me use the search engine to find current weather conditions.", 'type': 'text'}, {'id': 'toolu_01WWcXGnArosybujpKzdmARZ', 'input': {'query': 'current weather San Francisco SF'}, 'name': 'tavily_search', 'type': 'tool_use'}]
Tool Calls:
tavily_search (toolu_01WWcXGnArosybujpKzdmARZ)
Call ID: toolu_01WWcXGnArosybujpKzdmARZ
Args:
query: current weather San Francisco SF
=================================[1m Tool Message [0m=================================
Name: tavily_search
{"query": "current weather San Francisco SF", "follow_up_questions": null, "answer": null, "images": [], "results": [{"title": "Weather in San Francisco, CA", "url": "https://www.weatherapi.com/", "content": "{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.775, 'lon': -122.4183, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1750168606, 'localtime': '2025-06-17 06:56'}, 'current': {'last_updated_epoch': 1750167900, 'last_updated': '2025-06-17 06:45', 'temp_c': 11.7, 'temp_f': 53.1, 'is_day': 1, 'condition': {'text': 'Fog', 'icon': '//cdn.weatherapi.com/weather/64x64/day/248.png', 'code': 1135}, 'wind_mph': 4.0, 'wind_kph': 6.5, 'wind_degree': 215, 'wind_dir': 'SW', 'pressure_mb': 1017.0, 'pressure_in': 30.02, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 86, 'cloud': 0, 'feelslike_c': 11.3, 'feelslike_f': 52.4, 'windchill_c': 8.7, 'windchill_f': 47.7, 'heatindex_c': 9.8, 'heatindex_f': 49.7, 'dewpoint_c': 9.6, 'dewpoint_f': 49.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 0.0, 'gust_mph': 6.3, 'gust_kph': 10.2}}", "score": 0.885373, "raw_content": null}, {"title": "Weather in San Francisco in June 2025", "url": "https://world-weather.info/forecast/usa/san_francisco/june-2025/", "content": "Detailed ⚡ San Francisco Weather Forecast for June 2025 - day/night 🌡️ temperatures, precipitations - World-Weather.info. Add the current city. Search. Weather; Archive; Weather Widget °F. World; United States; California; Weather in San Francisco; ... 17 +64° +54° 18 +61° +54° 19", "score": 0.8830044, "raw_content": null}], "response_time": 2.6}
==================================[1m Ai Message [0m==================================
Based on the search results, here's the current weather in San Francisco:
- Temperature: 53.1°F (11.7°C)
- Conditions: Foggy
- Wind: 4.0 mph from the SW
- Humidity: 86%
- Visibility: 9.0 miles
The weather appears to be typical for San Francisco, with morning fog and mild temperatures. The "feels like" temperature is 52.4°F (11.3°C).
我们可以 查看 LangSmith trace 来确保它正在有效地调用搜索工具。
流式传输消息
我们已经看到了如何使用 .invoke 调用代理来获得最终响应。如果代理执行多个步骤,这可能需要一些时间。为了显示中间进度,我们可以将消息在发生时流式传输回来。
for step in agent_executor.stream({"messages": [input_message]}, stream_mode="values"):
step["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
Search for the weather in SF
==================================[1m Ai Message [0m==================================
[{'text': "I'll help you search for information about the weather in San Francisco.", 'type': 'text'}, {'id': 'toolu_01DCPnJES53Fcr7YWnZ47kDG', 'input': {'query': 'current weather San Francisco'}, 'name': 'tavily_search', 'type': 'tool_use'}]
Tool Calls:
tavily_search (toolu_01DCPnJES53Fcr7YWnZ47kDG)
Call ID: toolu_01DCPnJES53Fcr7YWnZ47kDG
Args:
query: current weather San Francisco
=================================[1m Tool Message [0m=================================
Name: tavily_search
{"query": "current weather San Francisco", "follow_up_questions": null, "answer": null, "images": [], "results": [{"title": "Weather in San Francisco", "url": "https://www.weatherapi.com/", "content": "{'location': {'name': 'San Francisco', 'region': 'California', 'country': 'United States of America', 'lat': 37.775, 'lon': -122.4183, 'tz_id': 'America/Los_Angeles', 'localtime_epoch': 1750168506, 'localtime': '2025-06-17 06:55'}, 'current': {'last_updated_epoch': 1750167900, 'last_updated': '2025-06-17 06:45', 'temp_c': 11.7, 'temp_f': 53.1, 'is_day': 1, 'condition': {'text': 'Fog', 'icon': '//cdn.weatherapi.com/weather/64x64/day/248.png', 'code': 1135}, 'wind_mph': 4.0, 'wind_kph': 6.5, 'wind_degree': 215, 'wind_dir': 'SW', 'pressure_mb': 1017.0, 'pressure_in': 30.02, 'precip_mm': 0.0, 'precip_in': 0.0, 'humidity': 86, 'cloud': 0, 'feelslike_c': 11.3, 'feelslike_f': 52.4, 'windchill_c': 8.7, 'windchill_f': 47.7, 'heatindex_c': 9.8, 'heatindex_f': 49.7, 'dewpoint_c': 9.6, 'dewpoint_f': 49.2, 'vis_km': 16.0, 'vis_miles': 9.0, 'uv': 0.0, 'gust_mph': 6.3, 'gust_kph': 10.2}}", "score": 0.9542825, "raw_content": null}, {"title": "Weather in San Francisco in June 2025", "url": "https://world-weather.info/forecast/usa/san_francisco/june-2025/", "content": "Detailed ⚡ San Francisco Weather Forecast for June 2025 - day/night 🌡️ temperatures, precipitations - World-Weather.info. Add the current city. Search. Weather; Archive; Weather Widget °F. World; United States; California; Weather in San Francisco; ... 17 +64° +54° 18 +61° +54° 19", "score": 0.8638634, "raw_content": null}], "response_time": 2.57}
==================================[1m Ai Message [0m==================================
Based on the search results, here's the current weather in San Francisco:
- Temperature: 53.1°F (11.7°C)
- Condition: Foggy
- Wind: 4.0 mph from the Southwest
- Humidity: 86%
- Visibility: 9.0 miles
- Feels like: 52.4°F (11.3°C)
This is quite typical weather for San Francisco, which is known for its fog, especially during the morning hours. The city's proximity to the ocean and unique geographical features often result in mild temperatures and foggy conditions.
流式传输 tokens
除了流式传输消息之外,流式传输 tokens 也很有用。
我们可以通过指定 stream_mode="messages" 来实现这一点。
::: note
下面我们使用 message.text(),这需要 langchain-core>=0.3.37。
:::
for step, metadata in agent_executor.stream(
{"messages": [input_message]}, stream_mode="messages"
):
if metadata["langgraph_node"] == "agent" and (text := step.text()):
print(text, end="|")
I|'ll help you search for information| about the weather in San Francisco.|Base|d on the search results, here|'s the current weather in| San Francisco:
-| Temperature: 53.1°F (|11.7°C)
-| Condition: Foggy
- Wind:| 4.0 mph from| the Southwest
- Humidity|: 86%|
- Visibility: 9|.0 miles
- Pressure: |30.02 in|Hg
The weather| is characteristic of San Francisco, with| foggy conditions and mild temperatures|. The "feels like" temperature is slightly| lower at 52.4|°F (11.|3°C)| due to the wind chill effect|.|
添加内存
如前所述,此代理是无状态的。这意味着它不记得先前的交互。为了给它提供内存,我们需要传入一个检查点(checkpointer)。在传入检查点时,我们还必 须在调用代理时传入一个 thread_id(以便它知道要恢复哪个线程/对话)。
from langgraph.checkpoint.memory import MemorySaver
memory = MemorySaver()
agent_executor = create_react_agent(model, tools, checkpointer=memory)
config = {"configurable": {"thread_id": "abc123"}}
input_message = {"role": "user", "content": "Hi, I'm Bob!"}
for step in agent_executor.stream(
{"messages": [input_message]}, config, stream_mode="values"
):
step["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
Hi, I'm Bob!
==================================[1m Ai Message [0m==================================
Hello Bob! I'm an AI assistant who can help you search for information using specialized search tools. Is there anything specific you'd like to know about or search for? I'm happy to help you find accurate and up-to-date information on various topics.
input_message = {"role": "user", "content": "What's my name?"}
for step in agent_executor.stream(
{"messages": [input_message]}, config, stream_mode="values"
):
step["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
What's my name?
==================================[1m Ai Message [0m==================================
Your name is Bob, as you introduced yourself earlier. I can remember information shared within our conversation without needing to search for it.
示例 LangSmith 追踪
यदि आप एक नई बातचीत शुरू करना चाहते हैं, तो आपको केवल thread_id का उपयोग करना है
config = {"configurable": {"thread_id": "xyz123"}}
input_message = {"role": "user", "content": "What's my name?"}
for step in agent_executor.stream(
{"messages": [input_message]}, config, stream_mode="values"
):
step["messages"][-1].pretty_print()
================================[1m Human Message [0m=================================
What's my name?
==================================[1m Ai Message [0m==================================
I apologize, but I don't have access to any tools that would tell me your name. I can only assist you with searching for publicly available information using the tavily_search function. I don't have access to personal information about users. If you'd like to tell me your name, I'll be happy to address you by it.
结论
本次快速入门介绍了一个简单的代理的创建方法。 我们展示了如何流式传输响应——不仅包括中间步骤,还包括 token! 我们还加入了内存功能,方便您与代理进行对话。 代理是一个复杂的话题,有很多内容需要学习!
有关代理的更多信息,请查看 LangGraph 文档。其中包含了一系列概念、教程和操作指南。