第07章:Agent 开发实战
版本:LangChain v1.3.7 | 讲师:汤姆小白
1. Agent 概述
1.1 什么是 Agent
Agent(智能体)是具有自主决策能力的 AI 应用。与简单的"一问一答"不同,Agent 会自己思考、选择工具、多步推理,直到完成目标任务。
Chain:固定流程,A → B → C
Agent:自主决策,根据情况动态选择下一步做什么
1.2 Agent 的核心循环
用户输入 → 模型思考 → 需要工具? → 是 → 执行工具 → 回到思考
↓
否 → 输出最终答案
这个"思考-行动-观察"的循环是 Agent 的本质。每次循环,LLM 都会决定:给出最终答案,还是调用工具获取更多信息。
2. create_agent:统一入口
2.1 最简 Agent
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain_core.tools import tool
# 1. 定义工具
@tool
def get_weather(city: str) -> str:
"""查询指定城市的天气"""
weather_data = {
"北京": "晴,28°C",
"上海": "多云,32°C",
"深圳": "阵雨,26°C",
}
return weather_data.get(city, f"未找到 {city} 的天气数据")
# 2. 创建 Agent
model = init_chat_model("openai:gpt-4o-mini")
agent = create_agent(
model=model,
tools=[get_weather],
system_prompt="你是一个有用的天气助手,帮助用户查询天气信息。",
)
# 3. 使用 Agent
result = agent.invoke({
"messages": [{"role": "user", "content": "北京今天天气怎么样?"}]
})
print(result["messages"][-1].content)
2.2 create_agent 参数
| 参数 | 类型 | 说明 |
|---|---|---|
model | BaseChatModel | 模型实例或字符串(自动用 init_chat_model 初始化) |
tools | List[BaseTool] | 工具列表 |
system_prompt | str | 系统提示词,定义 Agent 角色 |
middleware | List | 中间件列表(见第3节) |
checkpointer | Checkpointer | 持久化检查点(见第06章 LangGraph) |
2.3 完整工具调用示例
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain_core.tools import tool
import math
@tool
def calculator(expression: str) -> str:
"""执行数学计算,支持 + - * / ** sqrt() 等运算"""
try:
result = eval(expression, {"__builtins__": {}}, {"sqrt": math.sqrt})
return f"计算结果: {result}"
except Exception as e:
return f"计算出错: {e}"
@tool
def word_count(text: str) -> str:
"""统计文本的字数"""
return f"共 {len(text)} 个字符"
# 创建 Agent
model = init_chat_model("openai:gpt-4o-mini")
agent = create_agent(
model=model,
tools=[calculator, word_count],
system_prompt="你是数学和文字助手,能计算和统计。",
)
# 测试
result = agent.invoke({
"messages": [{"role": "user", "content": "计算 2 的 10 次方是多少?"}]
})
print(result["messages"][-1].content)
3. Middleware 中间件体系
3.1 什么是 Middleware
Middleware 是 Agent 的"切面拦截器",在 Agent 执行的各个阶段插入自定义逻辑。
Agent 执行 = 内置逻辑 + Middleware 拦截层
类似 Web 框架的中间件——在请求处理链中插入鉴权、日志、限流等逻辑。
3.2 六大拦截点
| 拦截点 | 装饰器 | 触发时机 | 适用场景 |
|---|---|---|---|
| Agent 执行前 | @before_agent | 收到用户请求,Agent 启动前 | 日志记录、权限校验 |
| 模型调用前 | @before_model | 每次调用模型之前 | 修改系统提示词、注入上下文 |
| 包装模型调用 | @wrap_model_call | 模型调用过程 | 修改请求/响应、动态选模型 |
| 模型调用后 | @after_model | 每次模型调用完成 | 日志收集、输出校验 |
| 包装工具调用 | @wrap_tool_call | 工具调用过程 | 监控工具调用、权限控制 |
| Agent 结束后 | @after_agent | Agent 执行完成 | 统计信息、清理资源 |
3.3 代码示例
from langchain.agents import create_agent
from langchain.agents.middleware import (
before_agent, after_agent,
before_model, after_model,
wrap_model_call, wrap_tool_call,
)
# before_model:动态修改系统提示词
@before_model
def inject_user_context(state, runtime):
"""在每次模型调用前注入用户上下文"""
system_msg = state["messages"][0]
system_msg.content += "\n当前时间:2026年6月12日"
return None
# wrap_model_call:记录模型调用耗时
@wrap_model_call
def log_model_call(request, handler):
import time
start = time.time()
result = handler(request)
elapsed = time.time() - start
print(f"[模型调用] 耗时: {elapsed:.2f}s")
return result
# wrap_tool_call:监控工具调用
@wrap_tool_call
def monitor_tools(request, handler):
print(f"[工具调用] {request.tool_call['name']}")
print(f"[参数] {request.tool_call['args']}")
result = handler(request)
print(f"[结果] {result}")
return result
# 注册中间件
agent = create_agent(
model="openai:gpt-4o-mini",
tools=[...],
system_prompt="你是智能助手",
middleware=[
inject_user_context,
log_model_call,
monitor_tools,
],
)
3.4 中间件执行顺序(洋葱模型)
before_agent → before_model → wrap_model_call(模型) → after_model
↓
wrap_tool_call(工具)
↓
before_model → ...循环...
↓
after_agent
多个同类型中间件按注册顺序依次执行,wrap_* 类型的"后置"部分按反向顺序执行。
4. Context Engineering(上下文工程)
4.1 核心理念
"上下文工程是以正确的格式提供正确的信息和工具,以便 LLM 能完成任务。这是 AI 工程师的首要工作。"
上下文工程解决 Agent 三大实际问题:
- 上下文过长:历史消息越多,推理越慢、越容易出错
- 信息杂乱:无关信息干扰 LLM 判断
- 超出 Token 限制:对话太长时需要裁剪
4.2 上下文管理策略
策略1:滑动窗口
@before_model
def sliding_window(state, runtime, max_messages=20):
"""只保留最近 N 条消息"""
state["messages"] = state["messages"][-max_messages:]
策略2:动态摘要
@before_model
def dynamic_summary(state, runtime):
"""当消息超过阈值时,自动摘要早期对话"""
if len(state["messages"]) > 30:
# 保留前10条(系统提示+初始上下文)
# 摘要中间部分
# 保留最后10条(最近的对话)
early = state["messages"][:10]
middle = state["messages"][10:-10]
recent = state["messages"][-10:]
# 用模型做摘要
summary = model.invoke([
{"role": "system", "content": "请用一段话总结以下对话"},
*middle,
])
state["messages"] = [
*early,
{"role": "system", "content": f"对话历史摘要: {summary.content}"},
*recent,
]
策略3:工具输出截断
@wrap_tool_call
def truncate_tool_output(request, handler, max_chars=2000):
"""截断过长的工具输出"""
result = handler(request)
if isinstance(result, str) and len(result) > max_chars:
result = result[:max_chars] + f"\n... (已截断,原长{len(result)}字符)"
return result
5. Agent 流式输出
# 逐条消息流式输出
for chunk in agent.stream(
{"messages": [{"role": "user", "content": "用Python写一个快速排序"}]},
stream_mode="values",
):
if "messages" in chunk and chunk["messages"]:
last_msg = chunk["messages"][-1]
role = last_msg.get("role", "unknown")
content = last_msg.get("content", "")
if isinstance(content, str) and content:
print(f"[{role}] {content}")
6. Agent 类型速览
| 类型 | 适用场景 | LangGraph 节点数 |
|---|---|---|
| ReAct | 通用任务(create_agent 默认) | model + tools |
| Tool Calling | 多工具选择调用 | model + tools |
| Multi-Agent | 多 Agent 协作 | 多个 agent 节点 |
| Human-in-the-Loop | 需要人工审批 | model + tools + interrupt |
7. Agent vs Chain 对比
| 维度 | Chain | Agent |
|---|---|---|
| 执行方式 | 固定流程 | 自主决策 |
| 工具调用 | 预设 | 动态选择 |
| 循环能力 | 无 | 多轮思考-行动 |
| 灵活性 | 低 | 高 |
| 复杂度 | 简单 | 复杂 |
| 适用场景 | 明确的任务流水线 | 开放式任务 |
本章小结
| 概念 | 作用 |
|---|---|
| create_agent | 一行代码创建 Agent |
| Middleware | 6 大拦截点,切面编程 |
| Context Engineering | 管理上下文窗口、自动摘要 |
| 流式输出 | 实时监控 Agent 思考过程 |
Agent 的本质:让 LLM 在"思考→行动→观察"中自主循环,直到完成任务。
create_agent是最高效的入口,Middleware 是实现定制化最灵活的武器。