LangChain 学习笔记(七):智能体 Agent
本文基于《尚硅谷 LangChain 1.2》第7章整理,并结合实际开发经验进行补充。
本章是 LangChain 最重要的章节,介绍了从 v0.x 碎片化 Agent 到 v1.x 统一 create_agent() 的架构变迁,以及 Agent 的完整使用方法。
一、本章学习目标
学习完本章,你应该能够:
- 理解 Agent 的核心概念和五大组件(LLM + Planning + Tools + Memory + Action)
- 掌握 v0.x 旧时代与 v1.x 新时代的架构差异
- 会使用
create_agent()一步创建 Agent - 理解 Agent 底层是 LangGraph 的
CompiledStateGraph - 掌握模型传入的两种方式(字符串 vs 模型对象)
- 掌握
agent.invoke()的调用方式和消息格式 - 理解工具绑定的完整流程
- 掌握工具调用的完整 Function Calling 执行链路
- 会设置系统提示词和 Agent 名称
- 掌握结构化输出的四种策略
- 掌握流式输出的七种模式
- 理解重试机制和常见问题
- 能够构建完整的多功能智能助手
二、什么是 Agent?
通用人工智能(AGI)将是 AI 的终极形态,几乎已成为业界共识。
同样,构建智能体(Agent)则是 AI 工程应用当下的"终极形态"。
Agent 是大模型应用开发的核心。
1、Agent 的定义
在大模型应用开发中,智能体通常指一种:
以大语言模型为推理与决策核心,结合记忆、工具调用与环境交互能力,能够进行规划决策并执行复杂任务以达成目标的软件系统。
┌──────────────────────┐
│ Agent │
│ │
│ ┌──────────────┐ │
│ │ LLM (大脑) │ │
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ Planning │ │
│ │ (规划决策) │ │
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ Tools │ │
│ │ (工具调用) │ │
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ Memory │ │
│ │ (记忆) │ │
│ └──────┬───────┘ │
│ │ │
│ ┌──────┴───────┐ │
│ │ Action │ │
│ │ (行动) │ │
│ └──────────────┘ │
└──────────────────────┘
2、Agent 的关键能力
Agent 必须具备以下五种核心能力:
| 能力 | 说明 |
|---|---|
| 理解用户问题 | 准确理解用户的意图和需求 |
| 拆解任务 | 将复杂任务分解为可执行的子步骤 |
| 判断是否需要工具 | 分析当前任务是否需要借助外部工具 |
| 选择调用哪些工具 | 从可用工具中选择最合适的工具 |
| 利用工具结果 | 综合工具返回的结果,生成回答或推进任务 |
3、Agent 的核心组件
现代 AI Agent 的架构包含以下要素:
| 组件 | 必要性 | 说明 |
|---|---|---|
| Action | 必须的 | 行动能力,Agent 必须能执行操作 |
| Tool | 几乎总是存在 | 工具,扩展 Agent 的能力边界 |
| Planning | 有条件存在 | 规划决策,复杂任务需要,简单任务可省略 |
| Memory | 最容易被省略 | 记忆,简单 Agent 可能不需要持久记忆 |
实际开发中几个要素并不需要同时出现。
一句话总结:
- 必须的:行动(Action)
- 几乎总是存在的:工具(Tool)
- 有条件存在的:规划决策(Planning)
- 最容易被省略的:记忆(Memory)
三、Agent 创建与调用的历史变迁
这是本章最重要的内容,也是理解 LangChain Agent 设计思想的关键。
1、v0.x 旧时代:碎片化的 Agent 创建
在 LangChain 0.x 时代,框架内的 Agent 系统经历了"碎片化"阶段。
当时的设计理念是"针对场景设计特定 Agent":
-
如果要实现思维链推理(ReAct),就用
create_react_agent -
如果需要结构化输出,就用
create_structured_chat_agent -
要工具调用,则用
create_tool_calling_agentv0.x 时代:每种 Agent 都需要单独记忆 API
create_react_agent → ReAct 推理 create_structured_chat_agent → 结构化输出 create_tool_calling_agent → 工具调用 create_json_agent → JSON 输出 ...
v0.x 的复杂方式:
python
# 需要多个步骤
from langchain_openai import ChatOpenAI
from langchain.agents import AgentExecutor, create_react_agent
from langchain_core.prompts import PromptTemplate
# 1. 模型初始化
model = ChatOpenAI(model="gpt-4o-mini")
# 2. 创建提示词模板
prompt = PromptTemplate.from_template("""
You are a helpful assistant.
Tools: {tools}
Tool Names: {tool_names}
{agent_scratchpad}
""")
# 3. 创建 agent
agent = create_react_agent(
llm=model,
tools=tools,
prompt=prompt
)
# 4. 创建 executor
executor = AgentExecutor(
agent=agent,
tools=tools,
verbose=True
)
# 5. 调用
result = executor.invoke({"input": "问题"})
这种方式带来了三个明显问题:
| 问题 | 说明 |
|---|---|
| 心智负担高 | 每种 Agent 都要单独记忆 API 与参数 |
| 可组合性差 | 多个 Agent 之间无法统一调度 |
| 生态碎片化 | 不同模块难以复用或协同演化 |
2、v1.x 新时代:统一的 create_agent()
LangChain 在 1.0 版本后,团队做出了彻底重构:
将所有 Agent 的创建方式统一为一个入口:
create_agent()
它取代了旧版本中的 create_react_agent、create_json_agent、create_tool_calling_agent 等多种分支函数。
真正让开发者用一行代码即可创建任何类型的智能体。
同时在底层通过"中间件机制(Middleware)"和"标准模型接口(invoke/stream)"实现全局统一。
这让框架更轻、更稳,也更易于被集成到其他 Agent 平台中。
v1.x 时代:一个函数,所有场景
create_agent(model, tools, system_prompt)
│
│ 统一入口
│
┌──────────┼──────────┐
│ │ │
ReAct 工具调用 结构化输出
v1.x 的简洁方式:
python
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
# 1. 初始化模型
model = init_chat_model("gpt-4o-mini", model_provider="openai")
# 2. 创建 agent(一步完成)
agent = create_agent(
model=model,
tools=[tool1, tool2],
system_prompt="Agent 的行为指令" # 可选
)
# 3. 调用
result = agent.invoke({
"messages": [{"role": "user", "content": "问题"}]
})
v0.x 与 v1.x 对比:
| 维度 | v0.x (旧时代) | v1.x (新时代) |
|---|---|---|
| 创建方式 | 多个函数,每种 Agent 不同 | 一个 create_agent() 统一入口 |
| 需要步骤 | 5 步(模型 + 提示词 + Agent + Executor + 调用) | 3 步(模型 + Agent + 调用) |
| 底层实现 | AgentExecutor 包装 | 直接基于 LangGraph |
| 可组合性 | 差,Agent 之间难协同 | 好,可作为子图或工具嵌套 |
| 流式输出 | 支持有限 | 原生支持多种模式 |
| 中间件 | 不支持 | 支持 Middleware 机制 |
| 人机协作 | 不支持 | 原生支持 interrupt_before/after |
四、create_agent() 完整参数列表
python
from langchain.agents import create_agent
agent = create_agent(
model: str | BaseChatModel, # 必需:聊天模型
tools: List[BaseTool], # 必需:工具列表
*,
system_prompt: str = "", # 系统提示词
middleware: Sequence[AgentMiddleware[StateT_co, ContextT]] = (), # 中间件
interrupt_before: List[str] = None, # 在某些工具前暂停(人机协作)
interrupt_after: List[str] = None, # 在某些工具后暂停
debug: bool = False, # 调试模式
name: str | None = None, # 设置模型名称
response_format: Union[ # 结构化输出
ToolStrategy[StructuredResponseT],
ProviderStrategy[StructuredResponseT],
type[StructuredResponseT],
None,
] = None
)
| 参数 | 类型 | 必需 | 说明 |
|---|---|---|---|
| model | str 或 BaseChatModel | 是 | 聊天模型,Agent 的"大脑" |
| tools | ListBaseTool | 是 | 工具列表,Agent 可调用的工具 |
| system_prompt | str | 否 | 系统提示词,定义 Agent 行为 |
| middleware | SequenceAgentMiddleware | 否 | 中间件,动态修改工具和提示词 |
| interrupt_before | Liststr | 否 | 在指定工具执行前暂停,用于人机协作 |
| interrupt_after | Liststr | 否 | 在指定工具执行后暂停,用于人机协作 |
| debug | bool | 否 | 调试模式,输出详细执行日志 |
| name | str | 否 | Agent 名称,用于标识和归因 |
| response_format | Union | 否 | 结构化输出格式,支持四种策略 |
更多参数参考:https://reference.langchain.com/python/langchain/agents/factory/create_agent
五、Agent 就是 LangGraph 的 CompiledStateGraph
1、核心本质
创建 Agent 后,检查其类型:
python
from langchain.agents import create_agent
agent = create_agent("deepseek-v4-flash")
print(type(agent))
输出:
<class 'langgraph.graph.state.CompiledStateGraph'>
Agent 本质上就是 LangGraph 的 CompiledStateGraph 实例。
底层实现是一个图结构。
Agent 底层图结构(ReAct 模式)
┌─────────────────────┐
│ 用户输入 │
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ 模型推理 (Agent) │◄──────────────┐
└─────────┬───────────┘ │
│ │
▼ │
┌─────────────────────┐ │
│ 是否调用工具? │ │
└────┬───────────┬────┘ │
│ │ │
是 │ │ 否 │
│ │ │
▼ ▼ │
┌──────────────┐ ┌──────────────┐ │
│ 调用工具 │ │ 生成最终答案 │ │
└──────┬───────┘ └──────────────┘ │
│ │
▼ │
┌──────────────┐ │
│ 工具返回结果 │─────────────────────────┘
└──────────────┘
2、可视化 Agent 图结构
python
from langchain.agents import create_agent
from IPython.display import Image, display
agent = create_agent(model)
display(Image(agent.get_graph().draw_mermaid_png()))
通过 agent.get_graph().draw_mermaid_png() 可以可视化 Agent 内部的图结构。
这是一个经典的 ReAct 结构:一个具备"思考-行动-观察"不断循环的自主工作者。
六、模型的传入方式
模型是 Agent 的"大脑",负责决策和推理。根据模型传入方式的不同,分为两种方式。
1、传入模型字符串(快捷方式)
python
from langchain.agents import create_agent
agent = create_agent("deepseek-v4-flash")
Agent 根据传入的模型字符串,自主创建模型对象。
这种方式最简洁,适合快速原型开发。
2、传入模型对象(推荐方式)
python
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
# 以 init_chat_model 为例
model = init_chat_model(
model="gpt-5.4-mini",
model_provider="openai",
api_key=os.getenv("CLOSEAI_API_KEY"),
base_url=os.getenv("CLOSEAI_BASE_URL")
)
agent = create_agent(model)
也可以直接使用具体模型类:
python
from langchain_deepseek import ChatDeepSeek
model = ChatDeepSeek(model="deepseek-v4-flash")
agent = create_agent(model)
3、两种方式对比
| 方式 | 优点 | 缺点 | 推荐场景 |
|---|---|---|---|
| 传入字符串 | 简洁,一行代码 | 无法自定义 API Key、URL 等 | 快速测试、Demo |
| 传入对象 | 可完全控制模型参数 | 代码稍多 | 生产环境 ★★★★★ |
七、Agent 的基本用法:invoke() 调用
agent.invoke() 是 Agent 最基本的同步调用方法,它会阻塞程序执行直到返回最终结果。
1、输入格式
输入参数为字典类型,字典内通过 messages 字段传递消息列表。
python
response = agent.invoke({
"messages": [{"role": "user", "content": "你好"}]
})
也可以直接传字符串列表(默认自动识别为 HumanMessage):
python
agent.invoke({"messages": ["你好"]}) # 默认是 HumanMessage
2、输出格式
通过 invoke 调用 Agent,底层可能会经历多轮交互,返回的是完整的消息列表,被封装在字典中。
python
response = agent.invoke({"messages": [...]})
# response 是字典类型
{
"messages": [
HumanMessage(...), # 用户问题
AIMessage(...), # AI 工具调用
ToolMessage(...), # 工具返回结果
AIMessage(...) # 最终回答 ← 通常取这个
]
}
# 获取最终回答
final_answer = response['messages'][-1].content
3、完整调用示例
python
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
model = init_chat_model(
model="gpt-5.4-mini",
model_provider="openai",
api_key=os.getenv("CLOSEAI_API_KEY"),
base_url=os.getenv("CLOSEAI_BASE_URL")
)
agent = create_agent(model=model)
response = agent.invoke({"messages": ["你好"]})
print(type(response)) # <class 'dict'>
# 获取最终答案
print(response['messages'][-1].content)
4、带 System Message 的调用
可以在 message 列表的开头加入 "system" 角色的消息来定义 Agent 的行为:
python
resp = agent.invoke({
"messages": [
{"role": "system", "content": "你是一个小学数学老师,耐心,幽默,讲解深入浅出"},
{"role": "user", "content": "100加上50等于多少?"}
]
})
八、绑定工具
只有接入了一些工具,create_agent 完成 Agent 创建才算完整。
Agent 支持静态和动态绑定工具,后者需要用到中间件。
1、工具来源
工具可以是 LangChain 内置的,也可以是自定义的。
LangChain 生态中已经内置集成了非常多的实用工具。
LangChain 内置工具列表:https://docs.langchain.com/oss/python/integrations/tools
典型内置工具:
| 工具 | 功能 |
|---|---|
| TavilySearch | 网络搜索 |
| WikipediaQueryRun | 维基百科查询 |
| PythonREPL | Python 代码执行 |
| Calculator | 数学计算 |
| ArxivQueryRun | 学术论文搜索 |
2、绑定一个工具
python
from langchain.agents import create_agent
from langchain.tools import tool
@tool(parse_docstring=True)
def get_weather(city: str) -> str:
"""
天气查询工具
Args:
city: 城市名称
"""
return f"{city}的天气为晴朗,25°C。"
agent = create_agent(
model=model,
tools=[get_weather]
)
resp = agent.invoke({
"messages": [
{"role": "system", "content": "你是一个天气查询助手,只回答天气相关的问题。"},
{"role": "user", "content": "北京的天气怎么样?"}
]
})
3、绑定内置工具(TavilySearch)
python
from langchain_tavily import TavilySearch
web_search = TavilySearch(
tavily_api_key=os.getenv("TAVILY_API_KEY"),
max_results=2
)
agent = create_agent(
model=model,
tools=[web_search],
system_prompt="你是一名多才多艺的智能助手,可以调用工具帮助用户解决问题。"
)
result = agent.invoke({
"messages": [{"role": "user", "content": "请帮我查询2024年诺贝尔物理学奖得主是谁?"}]
})
print(result['messages'][-1].content)
4、绑定多个工具
python
agent = create_agent(
model,
tools=[get_weather, get_news]
)
response = agent.invoke({
"messages": ["你好,杭州今天的天气如何?今天有哪些新闻?"]
})
5、工具数量建议
注意:只给 Agent 需要的工具,工具太多会混淆。
一般 2-5 个工具最佳。
python
# ✅ 好:只给需要的工具
agent = create_agent(
model=model,
tools=[get_weather, calculator] # 2-5 个工具最佳
)
# ❌ 不好:工具太多
agent = create_agent(
model=model,
tools=[tool1, tool2, ..., tool20] # 会混淆
)
九、工具调用流程分析
1、完整流程
LangChain 的 Agent 会将模型与工具结合起来,在实现上由一个基于 LangGraph 的图结构来编排执行流程。
当用户提出一个复杂需求时,Agent 会像人类一样:
先理解任务 -> 规划步骤 -> 使用合适的工具获取信息 -> 反复调用直到不再需要工具 -> 综合所有信息给出最终答案。
用户问题
│
▼
AI 思考
│
▼
调用工具
│
▼
观察结果
│
▼
继续思考 ──→ 需要更多工具?──→ 是 ──→ 调用工具 ──→ 观察结果
│ │
│ 否 │
▼ │
最终答案 ←─────────────────────────────────────┘
2、完整 Function Calling 执行流程
一次完整的 Function Calling 执行流程包含 4 条消息:
① HumanMessage ← 用户首次发起消息
② AIMessage ← 涉及 function call message
③ ToolMessage ← 涉及 function response message
④ AIMessage ← 涉及 final response
具体示例:用户问题"找出当前最流行的无线耳机并检查库存"
步骤 1:输入解析与初始推理
LLM 分析任务:"要找出'最流行'的产品,需要最新的市场信息,
我应该先使用搜索工具。"
步骤 2:第一次行动 (action) 与观察 (observation)
行动:Agent 调用 search_products 工具,参数为 "wireless headphones"
观察:工具返回结果:"找到 5 款匹配产品。Top 结果:WH-1000XM5, ..."
步骤 3:迭代推理
LLM 根据搜索结果分析:"WH-1000XM5 是排名第一的型号。
现在需要确认其库存状态才能回答用户问题。"
步骤 4:第二次行动 (action) 与观察 (observation)
行动:Agent 调用 check_inventory 工具,参数为 "WH-1000XM5"
观察:工具返回:"产品 WH-1000XM5:库存 10 件。"
步骤 5:最终输出
LLM 综合所有信息:"已获得所需信息,可以生成最终答案。"
模型生成最终答案,不再调用工具。
十、重试机制
Agent 可以在工具调用结果不满足要求时,自主重试。
python
from langchain.agents import create_agent
from langchain.tools import tool
from langchain.messages import SystemMessage, HumanMessage
flag = 0
@tool
def get_weather(city: str):
"""
天气查询工具
Args:
city: 城市名称
"""
global flag
flag += 1
if flag < 3:
return "TEMP_UNAVAILABLE: 天气服务暂时不可用,请稍后重试"
return f"{city}今天天气挺好"
messages = [
SystemMessage("""
你是一个天气助手。
当工具返回以 'TEMP_UNAVAILABLE:' 开头的结果时,
说明是临时故障,不要立即放弃;
你应再次调用同一个工具,最多重试 3 次。
如果 3 次后仍失败,再向用户说明服务暂时不可用。
"""),
HumanMessage("你好,杭州今天的天气如何?")
]
agent = create_agent(model, tools=[get_weather])
response = agent.invoke({"messages": messages})
模型会三次调用 get_weather,最终获得满意的结果。
十一、常见问题
问题 1:Agent 如何选择工具?
依据:工具的 docstring。
AI 会根据:
- 问题内容
- 每个工具的描述
- 自动选择最匹配的工具
python
@tool
def get_weather(city: str) -> str:
"""获取指定城市的天气信息""" # ← AI Agent 读这个!
...
@tool
def calculator(operation: str, a: float, b: float) -> str:
"""执行基本的数学计算""" # ← AI Agent 也读这个!
...
问题 2:Agent 为什么没有调用工具?
原因:
- 工具的 docstring 不清晰
- 问题表述不明确
- 模型认为不需要工具
解决:
- 写清楚 docstring
python
# ❌ 不好
@tool
def tool1(x: str) -> str:
"""做一些事情""" # 太模糊
# ✅ 好
@tool
def get_weather(city: str) -> str:
"""
获取指定城市的实时天气信息
Args:
city: 城市名称,如 "北京"、"上海"
"""
问题 3:Agent 选错工具?
原因:
- 多个工具的功能描述相似
- 工具太多导致混淆
解决:
- 只给必要的工具
- 工具描述要有明确区分
- 在 system_prompt 中说明工具使用场景
问题 4:如何知道 Agent 何时完成?
当 AIMessage 不包含 tool_calls 时:
python
for msg in response['messages']:
if isinstance(msg, AIMessage):
if hasattr(msg, 'tool_calls') and msg.tool_calls:
print("还在调用工具...")
else:
print("完成!最终答案:", msg.content)
问题 5:Agent 可以调用多少次工具?
默认没有限制,直到得到最终答案。
但可能会:
- 超时
- 达到 token 限制
- 模型决定停止
问题 6:如何限制工具调用次数?
LangChain 1.0 的 create_agent 默认使用 LangGraph,可以通过配置限制:
python
config = {
"recursion_limit": 5 # 最多 5 步
}
response = agent.invoke(input, config=config)
十二、设置 Agent 名称
创建 Agent 时,LangChain 允许用户指定其名称。
1、基本用法
python
agent = create_agent(
model=model,
name="chat_assistant"
)
response = agent.invoke({"messages": ["你好"]})
输出的 AI Message 带有 Name 信息:
================================== Ai Message ==================================
Name: chat_assistant
你好!有什么我可以帮你的吗?
2、经典使用场景
| 使用场景 | 说明 |
|---|---|
| 流式输出归因 | 在启用流式输出时,name 可用于标识当前输出内容来自哪个 Agent |
| 消息身份标记 | Agent 产生的 AIMessage 会携带对应的 name 信息 |
| 调试与 trace 可读性 | name 可以作为 Agent 的稳定标识,帮助快速判断执行的 Agent |
| 组件化封装 | 有助于在模块注册、运行监控、日志归档和能力复用时保持身份标识 |
| 前端展示 | name 可直接作为运行时展示标识使用 |
| 运行时身份标识 | 作为 Agent 在系统中的"运行时身份 ID" |
十三、系统提示词
使用 create_agent 创建 Agent 时,需传入模型和工具、可选地传入系统提示词。
提示词为 Agent 提供了任务背景、行为准则和操作指南。
1、设置方式
系统指令,即 SystemMessage,通过 system_prompt 设置,定义 Agent 行为。
这个参数可以是 str 或者 SystemMessage 类型。
方式一:传入字符串
python
agent = create_agent(
model=model,
tools=[get_weather],
system_prompt="你是天气助手。可以调用 get_weather 获取天气信息。"
)
方式二:传入 SystemMessage 对象
python
from langchain_core.messages import SystemMessage
agent = create_agent(
model=model,
tools=[add_numbers],
system_prompt=SystemMessage(content="你是一个数学助手,解决日常的算术问题")
)
2、使用建议
- 明确说明 Agent 的角色
- 定义输出格式
- 说明何时使用工具
python
agent = create_agent(
model=model,
tools=[get_weather],
system_prompt="""
你是天气助手。
工作流程:
1. 理解用户的城市查询
2. 使用 get_weather 工具获取数据
3. 简洁清晰地回答
输出格式:
- 天气状况
- 温度
- 注意事项(如有)
"""
)
十四、结构化输出
结构化输出是 Agent 的核心功能之一,它允许 Agent 以特定、可预测的格式返回数据。
1、模型 vs Agent 的结构化输出对比
| 维度 | 模型的结构化输出 | Agent 结构化输出 |
|---|---|---|
| 操作对象 | 作用于大模型对象 | 作用于 Agent |
| 解析时机 | 每次模型调用生成 AIMessage 时进行解析 | 仅在 Agent 决定"任务结束"并输出最终答案时解析 |
| 数据流转 | 模型 -> 结构化对象 | 模型 -> 工具 -> 反思 -> ... -> 结构化对象 |
| 绑定方式 | 使用 with_structured_output | 使用 response_format 参数 |
| 适用场景 | 单次、确定性的任务(如提取字段、翻译、分类) | 多步、复杂推理的任务(如查文档后汇总报表) |
2、结构化输出的 4 种策略
create_agent 函数中的 response_format 参数支持四种不同的策略:
python
def create_agent(
...
response_format: Union[
ToolStrategy[StructuredResponseT],
ProviderStrategy[StructuredResponseT],
type[StructuredResponseT],
None,
]
)
(1)ProviderStrategy
使用模型提供商的原生结构化输出功能实现结构化输出。
适用于支持原生结构化输出的模型,比如 OpenAI、Anthropic Claude 或 xAI Grok 等。
python
from pydantic import BaseModel, Field
from langchain.agents.structured_output import ProviderStrategy
class ContactInfo(BaseModel):
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
agent = create_agent(
model=model,
response_format=ProviderStrategy(ContactInfo)
)
(2)ToolStrategy(★★★★★ 推荐)
对于不支持原生结构化输出的模型,LangChain 采用工具调用的方式实现结构化输出。
此策略兼容绝大多数支持工具调用的现代模型。
核心原理:动态创建一个"虚拟工具",该工具的输入参数对应着期望的数据结构。
当模型需要生成最终答案时,系统会引导模型"调用"这个虚拟工具,从而间接产生符合要求的结构化数据。
python
from langchain.agents.structured_output import ToolStrategy
agent = create_agent(
model=model,
response_format=ToolStrategy(ContactInfo)
)
ToolStrategy 的配置包含三个主要参数:
| 参数 | 说明 |
|---|---|
| schema (必需) | 支持 Pydantic 模型、TypedDict、JSON Schema、@dataclass、Union |
| tool_message_content (可选) | 自定义生成结构化输出时的提示信息 |
| handle_errors (可选) | 数据校验失败时的重试策略,默认值为 True |
(3)type / AutoStrategy
直接传入一个定义类型时,LangChain 会自动包装为 AutoStrategy,触发自动选择策略:
- 如果模型支持原生结构化输出(如 OpenAI、Anthropic Claude 或 xAI Grok),则优先使用 ProviderStrategy
- 否则使用 ToolStrategy
python
agent = create_agent(
model=model,
response_format=ContactInfo # 自动选择 ProviderStrategy 或 ToolStrategy
)
(4)None
默认配置,表示不以结构化输出,以自然语言响应用户问题。
3、四种输出模式(Schema 类型)
ToolStrategy 支持四种 Schema 定义方式:
输出模式 1:Pydantic 类型(★★★★★ 推荐)
Pydantic 类型的 Schema 支持数据验证,是优先推荐使用的方式。
python
from pydantic import BaseModel, Field
from langchain.agents.structured_output import ToolStrategy
class ContactInfo(BaseModel):
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
agent = create_agent(
model=model,
response_format=ToolStrategy(ContactInfo)
)
输出模式 2:TypedDict 类型
python
from typing import TypedDict, Annotated
class ContactInfo(TypedDict):
"""用户的联系方式"""
name: Annotated[str, ..., "用户姓名"]
email: Annotated[str, ..., "用户邮箱地址"]
phone: Annotated[str, ..., "用户的手机号"]
agent = create_agent(
model=model,
response_format=ToolStrategy(ContactInfo)
)
TypedDict 字段定义采用 Annotated[类型, 默认值, "描述"] 格式,不支持运行时验证。
输出模式 3:JsonSchema 类型
python
json_schema = {
"title": "ContactInfo",
"description": "用户的联系方式",
"type": "object",
"properties": {
"name": {"description": "用户姓名", "type": "string"},
"email": {"description": "用户邮箱地址", "type": "string"},
"phone": {"description": "用户的手机号", "type": "string"}
},
"required": ["name", "email", "phone"]
}
agent = create_agent(
model=model,
response_format=ToolStrategy(json_schema)
)
输出模式 4:@dataclass 类型
python
from dataclasses import dataclass
@dataclass
class ContactInfo:
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
agent = create_agent(
model=model,
response_format=ToolStrategy(ContactInfo)
)
4、多 Schema 联合模式
ToolStrategy 允许指定多个类型 Union[类型1, 类型2],LLM 能够根据输入文本的内容智能选择最合适的一个数据模型。
python
from typing import Union
class ContactInfo(BaseModel):
"""用户的联系方式"""
name: str = Field(description="用户姓名")
email: str = Field(description="用户邮箱地址")
phone: str = Field(description="用户的手机号")
class EventInfo(BaseModel):
"""事件详情"""
event_name: str = Field(description="事件名称")
date: str = Field(description="事件发生日期")
agent = create_agent(
model=model,
response_format=ToolStrategy(
Union[ContactInfo, EventInfo]
)
)
5、获取结构化输出结果
python
result = agent.invoke({"messages": [...]})
if "structured_response" in result:
analysis = result["structured_response"]
print(analysis)
6、自定义工具消息:tool_message_content
当不设置 tool_message_content 时,模型收到的 ToolMessage 里包含具体数据。
当设置了 tool_message_content 时,模型收到的 ToolMessage 只是一个预定义的确认信息,节省上下文窗口的 token 消耗。
python
agent = create_agent(
model=model,
response_format=ToolStrategy(
ContactInfo,
tool_message_content="已成功抽取信息"
)
)
7、错误处理:handle_errors
| handle_errors 值 | 说明 |
|---|---|
| True (默认) | 捕获所有异常,使用内置错误消息模板提示模型重试 |
| False | 关闭自动重试机制,任何异常都会直接抛出 |
| "自定义字符串" | 捕获所有异常,使用预设固定字符串作为错误消息 |
| ExceptionType | 仅捕获指定类型的异常并进行重试,其他异常直接抛出 |
| callable | 使用自定义函数处理异常,可根据不同异常类型返回差异化的提示信息 |
python
def custom_error_handler(error: Exception) -> str:
"""自定义错误处理器"""
error_str = str(error)
if isinstance(error, StructuredOutputValidationError):
return "数据格式有误,请检查字段是否符合要求。"
elif isinstance(error, MultipleStructuredOutputsError):
return "检测到多个响应,请选择最相关的一个进行返回。"
else:
return f"Error: {error_str}"
agent = create_agent(
model=model,
response_format=ToolStrategy(
Union[ContactInfo, EventDetails],
tool_message_content="提取完成!",
handle_errors=custom_error_handler
)
)
两类常见异常:
| 异常类型 | 说明 |
|---|---|
| MultipleStructuredOutputsError | 多结构化输出错误,工具调用请求数量大于 1 时抛出 |
| StructuredOutputValidationError | 输出结构化验证错误,格式不符合要求时抛出 |
十五、流式输出及模式
1、为什么需要流式输出?
通过 invoke 调用 Agent 时,内部可能经历多次调用,长时间看不到调用情况,用户体验不好。
流式输出好处:
- 大型语言模型生成完整响应通常需要几秒钟,流式传输让等待过程更加可控
- 可以立即显示文字逐渐出现的效果,大幅降低用户的等待焦虑
2、设置方式
通过 agent.stream(stream_mode=指定模式) 来指定。
python
for chunk in agent.stream(
{"messages": [{"role": "user", "content": "..."}]},
stream_mode="values"
):
# 处理 chunk
3、七种输出模式详解
(1)values 模式
每个步骤执行后,都会输出完整的状态信息。
适用于每一步都要获取完整状态、状态持久化场景。
python
for chunk in agent.stream(
{"messages": [...]},
stream_mode="values"
):
rprint(chunk)
(2)updates 模式(默认)
每个步骤执行后,只增量更新状态中发生变化的内容。
用于监控 Agent 执行进度,例如观察 Agent 决定调用工具、工具执行结果等步骤。
python
for chunk in agent.stream(
{"messages": [...]},
stream_mode="updates"
):
rprint(chunk)
(3)messages 模式(★★★★★ 推荐用于聊天)
输出流式返回的 Token 以及相关的元数据(如:来自哪个节点 model/tool)。
实现类似 ChatGPT 的打字机效果,为聊天机器人等交互式应用提供最佳的实时体验。
python
for chunk in agent.stream(
{"messages": [...]},
stream_mode="messages"
):
print(chunk[0].content, end="", flush=True)
(4)tasks 模式
输出当前 task 任务开始和结束的时间,包含任务的结果和错误信息。
用于监控任务的生命周期。
python
for chunk in agent.stream(
{"messages": [...]},
stream_mode="tasks"
):
print(chunk)
(5)debug 模式
与 tasks 模式类似,比 task 模式多输出任务步骤、时间戳、task 类型(task/task_result)。
用于调试、监控 task 任务的生命周期。
python
for chunk in agent.stream(
{"messages": [...]},
stream_mode="debug"
):
print(chunk)
(6)checkpoints 模式
每当检查点(checkpoint)被创建时会触发输出,输出包含检查点中的状态。
用于需要状态持久化、工作流恢复或分布式执行跟踪的高级场景。
python
from langgraph.checkpoint.memory import InMemorySaver
checkpointer = InMemorySaver()
agent = create_agent(
model=model,
tools=[...],
checkpointer=checkpointer # 启用检查点
)
config = {"configurable": {"thread_id": "session01"}}
for chunk in agent.stream(
{"messages": [...]},
config=config,
stream_mode="checkpoints"
):
print(chunk)
(7)custom 模式
开发者通过 get_stream_writer 在工具或节点内部自定义发送的数据。
用于输出业务逻辑相关的进度信息(如"已处理 10/100 条记录")、自定义日志或指标。
python
from langgraph.config import get_stream_writer
@tool
def generate_sales_report() -> str:
"""生成销售报告"""
writer = get_stream_writer()
writer({"type": "生成销售报告", "message": "开始生成销售报告"})
# 模拟数据处理
for i in range(1, 4):
time.sleep(0.5)
writer({"type": "生成销售报告", "message": f"生成销售报告进度百分比:{i * 25}%"})
writer({"type": "生成销售报告", "message": "报告生成完成"})
return f"销售报告:总收入 150 万元,同比增长 12%"
4、流式输出模式总结
| 模式 | 输出内容 | 使用场景 |
|---|---|---|
| values | 每个步骤执行后,都会输出完整的状态信息 | 获取完整状态、状态持久化 |
| updates | 每个步骤执行后,只增量更新状态中发生变化的内容 | 监控 Agent 执行进度(默认模式) |
| messages | 输出流式返回的 Token 以及相关的元数据 | 实现打字机效果,聊天机器人 ★★★★★ |
| tasks | 输出当前 task 任务开始和结束的时间,包含结果和错误信息 | 监控任务的生命周期 |
| debug | 比 tasks 多输出任务步骤、时间戳、task 类型 | 调试、监控 task 任务 |
| checkpoints | 检查点被创建时触发输出,输出包含检查点中的状态 | 状态持久化、工作流恢复 |
| custom | 通过 get_stream_writer 在工具或节点内部自定义发送的数据 | 输出业务逻辑相关的进度信息、自定义日志 |
选择建议:
- 实现实时对话交互 ,优先选择
messages模式 - 观察 Agent 的思考与执行步骤 ,优先选择
updates模式 - 需要查看每一步状态 优先选择
values/tasks/debug模式 - 在工具执行时输出自定义业务日志 优先选择
custom模式
5、多模式组合
可以同时指定多个模式:
python
for stream_mode, chunk in agent.stream(
{"messages": [...]},
stream_mode=["tasks", "updates"]
):
print(f"当前流模式: {stream_mode}, 当前数据: {chunk}")
十六、人机协作(Human-in-the-Loop)
通过 interrupt_before 和 interrupt_after 参数实现。
python
agent = create_agent(
model=model,
tools=[...],
interrupt_before=["get_weather"], # 在调用 get_weather 前暂停
interrupt_after=["send_email"], # 在 send_email 执行后暂停
)
这在需要人工审批敏感操作(如发送邮件、执行数据库写入)时非常有用。
十七、Agent 状态管理
Agent 支持通过 checkpointer 进行状态管理。
python
from langgraph.checkpoint.memory import InMemorySaver
# 创建内存检查点存储
checkpointer = InMemorySaver()
# 创建 Agent
agent = create_agent(
model=model,
tools=[...],
checkpointer=checkpointer # 启用检查点
)
# 创建唯一的会话 ID
config = {"configurable": {"thread_id": "session01"}}
# 调用 Agent
result = agent.invoke(
{"messages": [...]},
config=config
)
通过 thread_id,可以在后续调用中恢复之前的对话状态。
十八、多 Agent 协作概念
虽然本章没有深入展开多 Agent 编排,但 Agent 的 name 参数为多 Agent 协作奠定了基础。
在 Multi-Agent 场景中:
name用于区分不同的 Agent- 每个 Agent 可以作为独立的节点
- Agent 之间可以通过消息传递进行协作
- Agent 可以包装为工具供其他 Agent 调用
十九、Agent vs Chain vs 简单 LLM 调用对比
| 维度 | 简单 LLM 调用 | Chain | Agent |
|---|---|---|---|
| 决策能力 | 无 | 固定流程 | 自主决策 |
| 工具使用 | 不支持 | 预定义工具 | 动态选择工具 |
| 任务分解 | 不支持 | 硬编码分解 | 自主规划分解 |
| 执行流程 | 一次调用,一个回答 | 线性流程 | 循环迭代,直到完成 |
| 适用场景 | 翻译、总结、分类 | 固定的多步骤流水线 | 复杂的、开放式的任务 |
| 灵活性 | 低 | 中 | 高 |
| 可控性 | 高 | 高 | 需要精心设计系统提示词 |
| 成本 | 低 | 中 | 可能较高(多次模型调用) |
二十、最佳实践和注意事项
1、工具设计
- 每个工具的 docstring 必须清晰描述功能和参数
- 工具数量控制在 2-5 个最佳
- 工具功能要互相有明确区分
2、系统提示词设计
- 明确 Agent 的角色和职责
- 说明什么情况下使用什么工具
- 定义输出格式和风格
- 设定边界(什么能做,什么不能做)
3、模型选择
- 确保模型支持工具调用(Function Calling)
- 简单任务用小模型,复杂任务用大模型
- 优先选择支持原生结构化输出的模型
4、成本控制
- 设置
recursion_limit限制工具调用次数 - 注意每次工具调用都会消耗 token
- 合理使用
tool_message_content减少 token 消耗
5、生产环境建议
- 使用
checkpointer实现状态持久化 - 使用
interrupt_before/interrupt_after实现敏感操作审批 - 为 Agent 设置明确的
name用于日志和监控 - 使用
stream_mode="messages"提供良好的用户体验
二十一、实战:多功能智能助手
项目需求:开发一个多功能智能助手,支持:
- 天气查询:查询城市天气
- 数学计算:复杂数学运算
- 时间查询:获取当前时间、日期计算
- 货币转换:多种货币之间转换
- 信息搜索:搜索产品、新闻等信息
完整代码
python
import os
import math
from datetime import datetime, timedelta
from dotenv import load_dotenv
from langchain.chat_models import init_chat_model
from langchain.agents import create_agent
from langchain_core.tools import tool
load_dotenv(override=True)
# ==================== 模型的初始化 ====================
model = init_chat_model(
model="gpt-5.4-mini",
model_provider="openai",
api_key=os.getenv("CLOSEAI_API_KEY"),
base_url=os.getenv("CLOSEAI_BASE_URL")
)
# ==================== 工具定义 ====================
@tool
def get_weather(city: str) -> str:
"""获取指定城市的实时天气信息
支持中国主要城市的天气查询
Args:
city: 城市名称,如 "北京"、"上海"、"深圳" 等
Returns:
包含温度、天气状况、空气质量的详细信息
"""
weather_db = {
"北京": "多云,15-22℃,空气质量良,湿度 45%",
"上海": "晴天,18-25℃,空气质量优,湿度 60%",
"深圳": "小雨,22-28℃,空气质量优,湿度 75%",
"成都": "阴天,16-23℃,空气质量良,湿度 70%",
"杭州": "晴天,17-24℃,空气质量优,湿度 55%",
"广州": "多云,21-29℃,空气质量良,湿度 72%"
}
result = weather_db.get(city)
if result:
return f"{city}:{result}"
else:
return f"抱歉,暂不支持查询 {city} 的天气信息。当前支持:北京、上海、深圳、成都、杭州、广州"
@tool
def calculator(expression: str) -> str:
"""执行数学计算
支持基本运算符(+、-、*、/、**)和常用数学函数
Args:
expression: 数学表达式
Returns:
计算结果或错误信息
"""
try:
safe_functions = {
"sqrt": math.sqrt, "pow": pow, "abs": abs, "round": round,
"sin": math.sin, "cos": math.cos, "tan": math.tan,
"log": math.log, "pi": math.pi, "e": math.e
}
result = eval(expression, {"__builtins__": {}}, safe_functions)
return f"{expression} = {result}"
except Exception as e:
return f"计算出错:{str(e)}"
@tool
def get_time_info(query_type: str = "current") -> str:
"""获取时间相关信息
Args:
query_type: 查询类型 ("current"/"date"/"tomorrow"/"yesterday"/"weekday")
Returns:
时间信息字符串
"""
now = datetime.now()
if query_type == "current":
return now.strftime("当前时间:%Y年%m月%d日 %H:%M:%S")
elif query_type == "date":
return now.strftime("今天是:%Y年%m月%d日")
elif query_type == "tomorrow":
tomorrow = now + timedelta(days=1)
return tomorrow.strftime("明天是:%Y年%m月%d日")
elif query_type == "yesterday":
yesterday = now - timedelta(days=1)
return yesterday.strftime("昨天是:%Y年%m月%d日")
elif query_type == "weekday":
weekdays = ["星期一", "星期二", "星期三", "星期四", "星期五", "星期六", "星期日"]
return f"今天是{weekdays[now.weekday()]}"
else:
return f"不支持的查询类型:{query_type}。支持:current, date, tomorrow, yesterday, weekday"
@tool
def convert_currency(amount: float, from_curr: str, to_curr: str) -> str:
"""货币转换工具,支持主要货币之间的实时汇率转换
Args:
amount: 金额数值
from_curr: 源货币代码(CNY/USD/EUR/GBP/JPY/HKD)
to_curr: 目标货币代码(CNY/USD/EUR/GBP/JPY/HKD)
Returns:
转换结果
"""
exchange_rates = {
"CNY": 1.0, "USD": 0.14, "EUR": 0.13,
"GBP": 0.11, "JPY": 20.8, "HKD": 1.09
}
currency_names = {
"CNY": "人民币", "USD": "美元", "EUR": "欧元",
"GBP": "英镑", "JPY": "日元", "HKD": "港币"
}
from_curr = from_curr.upper()
to_curr = to_curr.upper()
if from_curr not in exchange_rates:
return f"不支持的源货币:{from_curr}。支持的货币:CNY, USD, EUR, GBP, JPY, HKD"
if to_curr not in exchange_rates:
return f"不支持的目标货币:{to_curr}。支持的货币:CNY, USD, EUR, GBP, JPY, HKD"
cny_amount = amount / exchange_rates[from_curr]
result_amount = cny_amount * exchange_rates[to_curr]
return f"{amount} {currency_names[from_curr]}({from_curr})= {result_amount:.2f} {currency_names[to_curr]}({to_curr})"
@tool
def search_info(keyword: str, category: str = "all") -> str:
"""搜索各类信息
Args:
keyword: 搜索关键词
category: 搜索分类 ("product"/"news"/"all")
Returns:
搜索结果
"""
products = {
"手机": "iPhone 15 (¥5999), 小米 14 (¥3999), 华为 Mate60 (¥6999)",
"笔记本": "MacBook Pro (¥12999), ThinkPad X1 (¥9999), 华为 MateBook (¥7999)",
"耳机": "AirPods Pro (¥1999), Sony WH-1000XM5 (¥2499)"
}
news = {
"AI": "1. GPT-5 即将发布 2. AI 芯片市场增长 30% 3. 新 AI 法规出台",
"科技": "1. 量子计算新突破 2. 6G 技术测试 3. 新能源汽车销量创新高"
}
results = []
if category in ["product", "all"]:
for key, value in products.items():
if keyword in key:
results.append(f"【产品】{key}:{value}")
if category in ["news", "all"]:
for key, value in news.items():
if keyword in key or keyword in value:
results.append(f"【新闻】{key}相关:{value}")
if results:
return "\n".join(results)
else:
return f"未找到关于 '{keyword}' 的 {category} 信息"
# ==================== Agent 创建 ====================
class SmartAssistant:
"""多功能智能助手"""
def __init__(self):
self.model = model
self.tools = [
get_weather,
calculator,
get_time_info,
convert_currency,
search_info
]
system_prompt = """你是一个多功能智能助手,可以帮助用户:
🌤 查询天气:使用 get_weather 工具
🔢 数学计算:使用 calculator 工具
⏰ 时间查询:使用 get_time_info 工具
💱 货币转换:使用 convert_currency 工具
🔍 信息搜索:使用 search_info 工具
重要提示:
1. 仔细阅读用户问题,确定需要使用哪个工具
2. 如果需要多个工具,按顺序调用
3. 总是用友好、专业的语气回答
4. 如果工具返回了数据,要用通俗易懂的语言解释给用户
5. 如果无法完成任务,诚实地告诉用户原因
请始终使用中文回答。"""
self.agent = create_agent(
model=self.model,
tools=self.tools,
system_prompt=system_prompt
)
self.messages = []
def chat(self, user_input: str) -> str:
"""对话接口"""
self.messages.append({"role": "user", "content": user_input})
result = self.agent.invoke({"messages": self.messages})
self.messages = result["messages"]
for msg in reversed(self.messages):
if msg.type == "ai" and msg.content:
return msg.content
return "抱歉,我无法处理这个请求。"
def reset(self):
"""重置对话历史"""
self.messages = []
# ==================== 主程序 ====================
def main():
assistant = SmartAssistant()
print("=" * 40)
print(" 🤖 多功能智能助手(LangChain 1.2)")
print("=" * 40)
print("\n我可以帮你:")
print(" 🌤 查询天气")
print(" 🔢 数学计算")
print(" ⏰ 时间查询")
print(" 💱 货币转换")
print(" 🔍 信息搜索")
print("\n输入 'quit' 退出,输入 'reset' 重置对话\n")
# 演示示例
demos = [
"北京今天天气怎么样?",
"帮我算一下 (25 + 17) * 3",
"现在几点了?",
"100 美元等于多少人民币?"
]
for demo in demos:
print(f" 👤 {demo}")
response = assistant.chat(demo)
print(f" 🤖 {response}\n")
assistant.reset()
# 交互模式
print("=" * 40)
print(" 💬 进入交互模式")
print("=" * 40)
while True:
user_input = input("\n 👤 你: ")
if user_input.lower() == 'quit':
print("再见!👋")
break
if user_input.lower() == 'reset':
assistant.reset()
print(" ✅ 对话已重置")
continue
if not user_input.strip():
continue
response = assistant.chat(user_input)
print(f" 🤖 助手: {response}")
if __name__ == "__main__":
main()
二十二、本章总结
| 主题 | 核心要点 |
|---|---|
| Agent 定义 | LLM + Planning + Tools + Memory + Action,五大组件协作 |
| v0.x vs v1.x | v0.x 碎片化(create_react_agent 等),v1.x 统一为 create_agent() |
| create_agent() | 一站式创建,底层基于 LangGraph 的 CompiledStateGraph |
| Agent 本质 | 本质是 LangGraph 图结构,经典 ReAct 模式:"思考-行动-观察" 循环 |
| 模型传入 | 字符串(快捷)和模型对象(推荐),两种方式各有适用场景 |
| invoke() 调用 | 输入为 {"messages": ...} 字典,输出包含完整消息列表 |
| 工具绑定 | 支持自定义工具和内置工具,建议 2-5 个工具最佳 |
| 工具调用流程 | Function Calling 流程:HumanMessage -> AIMessage -> ToolMessage -> AIMessage |
| 重试机制 | Agent 可在工具调用失败时自主重试,通过 system_prompt 控制 |
| Agent 名称 | 用于流式归因、消息身份标记、调试追踪、组件化封装等场景 |
| 系统提示词 | 定义 Agent 角色、输出格式、工具使用时机,支持 str 和 SystemMessage |
| 结构化输出 | 支持 4 种策略(ProviderStrategy/ToolStrategy/AutoStrategy/None)+ 4 种 Schema 类型 |
| ToolStrategy | 通过虚拟工具实现结构化输出,推荐方式,兼容所有支持工具调用的模型 |
| 流式输出 | 支持 7 种模式(values/updates/messages/tasks/debug/checkpoints/custom) |
| 人机协作 | interrupt_before/interrupt_after 实现敏感操作审批 |
| 状态管理 | checkpointer 实现状态持久化和会话恢复 |
| 最佳实践 | 清晰 docstring、合理工具数量、精心设计 system_prompt、限制递归次数 |
二十三、面试常见问题
Q1:Agent 的核心组件有哪些?
Agent 包含五个核心组件:
- LLM(大脑):负责推理和决策
- Planning(规划):将任务分解为子步骤
- Tools(工具):扩展 Agent 的能力边界
- Memory(记忆):保存上下文和历史信息
- Action(行动):执行操作
其中 Action 是必须的,Planning 和 Memory 是可选的。
Q2:LangChain v0.x 和 v1.x 的 Agent 有什么区别?
v0.x 时代有多个创建函数(create_react_agent、create_tool_calling_agent 等),需要 5 步创建(模型 + 提示词 + Agent + Executor + 调用),心智负担高、可组合性差、生态碎片化。
v1.x 统一为 create_agent() 一个函数,3 步完成(模型 + Agent + 调用),底层直接基于 LangGraph,支持中间件、流式输出、人机协作等高级功能。
Q3:Agent 的底层实现是什么?
Agent 本质上是 LangGraph 的 CompiledStateGraph 实例,底层是一个图结构,采用经典的 ReAct 模式:一个"思考-行动-观察"不断循环的自主工作者。
Q4:Agent 如何选择工具?
Agent 根据工具的 docstring(描述文档)来选择工具。AI 会阅读每个工具的 docstring,结合用户的问题内容,自动选择最匹配的工具。
Q5:如何控制 Agent 的工具调用次数?
可以通过 LangGraph 的配置来限制:
python
config = {"recursion_limit": 5}
response = agent.invoke(input, config=config)
Q6:Agent 什么时候停止调用工具?
当 AIMessage 不包含 tool_calls 时,说明 Agent 认为任务已完成,开始生成最终答案。
Q7:结构化输出有哪些策略?推荐哪种?
有四种策略:
- ProviderStrategy:使用模型原生结构化输出
- ToolStrategy:通过虚拟工具实现(★★★★★ 推荐)
- AutoStrategy:自动选择 ProviderStrategy 或 ToolStrategy
- None:不启用结构化输出
推荐使用 ToolStrategy,因为它兼容所有支持工具调用的现代模型。
Q8:Agent 的流式输出有哪些模式?如何选择?
有七种模式:
- values:获取完整状态
- updates:监控执行进度(默认)
- messages:实现打字机效果(推荐用于聊天)
- tasks:监控任务生命周期
- debug:调试模式
- checkpoints:状态持久化
- custom:自定义业务日志
聊天机器人推荐 messages 模式,调试推荐 updates 或 debug 模式。
Q9:Agent 和 Chain 有什么区别?
Chain 是固定流程的线性执行,Agent 是自主决策的循环执行。
Agent 可以动态选择工具、自主分解任务、在循环中迭代直到完成,而 Chain 的流程是硬编码的。
Q10:如何优化 Agent 的性能?
- 控制工具数量在 2-5 个
- 写清晰的工具 docstring
- 精心设计 system_prompt
- 设置 recursion_limit 限制递归次数
- 使用合适的模型(大模型用于复杂任务,小模型用于简单任务)
- 使用 checkpointer 避免重复计算
本章是 LangChain 最核心的章节。Agent 是 LLM 应用开发的"终极形态",理解 Agent 的设计思想和使用方法,是成为一名合格的 AI 应用开发者的关键一步。