在 LangChain 的世界里,代理(Agent)就像一个会思考的执行者 —— 它能决定何时调用工具、如何处理工具返回,并最终整合成人类能理解的答案。今天我们就以「构建可调用 Tavily 搜索引擎的天气查询代理」为例,一步步拆解这个「思考 - 行动 - 反馈」的智能闭环,确保不遗漏任何关键技术细节。

一、核心组件准备:让模型与工具对话

1. 选择「思考引擎」:DeepSeek 大语言模型

我们首先需要一个具备推理能力的大脑。这里选用 DeepSeek 的聊天模型,通过langchain_deepseek库轻松集成:

python

from langchain_deepseek import ChatDeepSeek

llm = ChatDeepSeek(
    model="deepseek-chat",       # 使用深度求索的聊天模型
    temperature=0,              # 禁用随机性,确保回答确定性
    max_retries=2,              # 自动重试2次应对网络波动
    api_key="sk-xxxxxxxx"       # 记得替换为你的真实API密钥(已脱敏处理)
)

2. 接入「信息雷达」:Tavily 搜索引擎工具

LangChain 社区已经为我们封装好了 Tavily 搜索工具,只需简单两步即可启用实时搜索能力:

python

from langchain_community.tools.tavily_search import TavilySearchResults

# 初始化工具:最多返回2条搜索结果(可根据需求调整)
search = TavilySearchResults(max_results=2)

# 测试调用:获取旧金山实时天气(返回结构化的列表数据)
raw_results = search.invoke("what is the weather in SF")
print(f"首次搜索结果:{raw_results[:50]}...")  # 输出前50个字符预览

返回的raw_results是列表形式的字典,每个元素包含url(网页链接)和content(原始内容),既包含 JSON 格式的天气数据,也有人类可读的文本描述,为后续解析提供丰富信息。

二、关键步骤:从「单独调用」到「代理协作」

1. 让模型「认识」工具:绑定工具库

直接调用llm.invoke()只会得到纯文本回答,而我们需要模型学会主动调用工具。通过bind_tools方法建立模型与工具的关联:

python

model_with_tools = llm.bind_tools([search])  # 绑定搜索工具到模型

# 发送提问:观察模型的「工具调用意图」
response = model_with_tools.invoke([HumanMessage(content="What's the weather in SF?")])
print(f"工具调用指令:{response.tool_calls}")  # 输出包含工具名称和参数的调用指令

此时模型返回的不再是直接回答,而是一个tool_calls字段,说明它已经意识到「需要实时数据,应该调用 Tavily 搜索」。这是代理能自主决策的关键一步。

2. 构建完整代理:基于 REACT 模式的智能闭环

REACT 模式(推理→行动→观察→工具)是 LangChain 代理的核心逻辑。我们通过create_react_agent快速创建具备完整闭环的代理:

python

from langgraph.prebuilt import create_react_agent

# 初始化代理:传入模型和工具列表(内部自动完成工具绑定)
agent_executor = create_react_agent(llm, [search])

# 执行完整交互:代理会自动完成「调用工具→处理结果→生成回答」
full_response = agent_executor.invoke({"messages": [HumanMessage(content="whats the weather in sf?")]})

这个过程中,代理会经历两次 LLM 调用

  • 第一次:生成工具调用指令(解决「如何获取信息」)
  • 第二次:解析工具返回数据并生成自然语言回答(解决「如何整合信息」)

三、深度解析:代理的三次关键「对话阶段」

当用户提问「whats the weather in sf?」时,代理的对话历史会呈现清晰的三阶段演进:

1. 第一阶段:工具调用决策(Reasoning→Action)

LLM 分析问题后生成的 AIMessage 包含关键信息:

python

{
  "tool_calls": [
    {
      "name": "tavily_search_results_json",  # 工具名称与注册的工具匹配
      "args": {"query": "weather in san francisco"}  # 自动优化后的搜索关键词
    }
  ],
  "response_metadata": {"stop_reason": "tool_use"}  # 明确告知需要暂停以调用工具
}

这表明模型已具备「自我认知」—— 知道自己没有实时数据,需要借助外部工具。

2. 第二阶段:工具执行与数据获取(Observation)

代理框架自动捕获工具返回的ToolMessage,内容是结构化的搜索结果:

python

[
  {
    "content": '{"temp_c": 13.3, "condition": "Light rain"...}',  # 天气API返回的JSON数据
    "url": "https://www.weatherapi.com/"
  },
  {
    "content": "San Francisco... Night 43°",  # 另一个来源的文本描述
    "url": "https://weathershogun.com/"
  }
]

这些多源数据为后续回答提供了丰富的事实依据。

3. 第三阶段:结果整合与回答生成(再次 Reasoning)

LLM 基于工具返回数据二次处理,生成最终回答:

plaintext

Based on the search results, the current weather in San Francisco is light rain... 
(整合了温度、天气状况、风速等关键信息,并用自然语言呈现)

此时response_metadata中的stop_reason变为end_turn,标志对话闭环完成。

四、进阶能力:让代理更智能的两个技巧

1. 实时反馈:两种流式输出模式对比

模式一:调试友好的「阶段式输出」(stream_mode="values")

适合开发者观察代理决策流程,每个step包含完整对话历史:

python

for step in agent_executor.stream(
    {"messages": [HumanMessage(content="提问")]}, 
    stream_mode="values"
):
    print(f"当前阶段消息:{step['messages'][-1].type}")  # 输出当前是工具调用还是回答生成阶段
模式二:用户友好的「逐字流式」(stream_mode="messages")

模拟人类思考过程,逐令牌实时显示回答生成,提升交互体验:

python

for step, metadata in agent_executor.stream(
    {"messages": [HumanMessage(content="提问")]}, 
    stream_mode="messages"
):
    if metadata["langgraph_node"] == "agent":
        print(step.text(), end="")  # 实时拼接生成的文本

2. 对话记忆:让代理记住历史交互

通过MemorySaver组件添加状态记忆,解决无状态代理的局限:

python

from langgraph.checkpoint.memory import MemorySaver

# 初始化记忆组件
memory = MemorySaver()

# 创建带记忆的代理
agent_with_memory = create_react_agent(llm, [search], checkpointer=memory)

# 调用时传入thread_id标识对话线程
response = agent_with_memory.invoke(
    {"messages": [HumanMessage(content="hi")]}, 
    config={"configurable": {"thread_id": "unique_id"}}
)

这样代理就能记住之前的对话内容,实现上下文相关的连续交互。

五、避坑指南:开发中需要注意的细节

  1. 工具参数调优TavilySearchResultsmax_results决定返回结果数量,过多可能增加解析负担,过少可能导致信息不足,需根据任务调整(示例中设为 2 是平衡选择)。
  2. 模型配置temperature=0确保回答确定性,适合需要精确数据的场景;如果是创意类任务,可适当调高温度增加多样性。
  3. 错误处理max_retries=2能自动重试工具调用,避免偶发网络问题导致的失败。

六、总结:从代码到能力的本质提升

通过这个案例,我们不仅实现了「天气查询代理」,更掌握了 LangChain 代理的核心设计思想:

  1. 工具集成:将外部能力(如搜索引擎)转化为模型可调用的「动作」
  2. 闭环决策:让模型学会判断「何时需要工具」「如何使用工具」「如何处理结果」
  3. 用户体验:通过流式输出和记忆管理,让代理更像一个有交互感的智能体

现在,你可以尝试将 Tavily 搜索替换为其他工具(如股票查询、新闻检索),或者扩展多个工具让代理具备更强能力。如果在实践中遇到问题,欢迎在评论区留言,我们一起探讨解决方案。觉得有帮助的话,别忘了点赞收藏,关注我们获取更多 LangChain 实战技巧!

Logo

欢迎加入DeepSeek 技术社区。在这里,你可以找到志同道合的朋友,共同探索AI技术的奥秘。

更多推荐