欢迎加入我的【ima知识库】从零开始学LangChain,第一时间收到更新!
Agents将大模型与工具结合起来,创建能够进行任务推理、决定使用哪种工具并迭代解决方案的系统。
create_agent 提供了一种适用于生产的Agent的实现方式。

Core components(核心组件)
Model(模型)
模型是Agent的推理引擎。可以通过多种方式指定,支持静态和动态模型选择。
Static model(静态模型)
静态模型在创建代理时配置一次,并在整个执行过程中保持不变。这是最常见和最直接的方法。
python
from langchain.agents import create_agent
agent = create_agent(
"gpt-5",
tools=tools
)
模型标识符字符串支持自动推理(例如,"gpt-5"将被推断为"openai:gpt-5")。参考查看模型标识符字符串映射的完整列表。
要对模型配置进行更多的控制,请使用供应商提供的工具包进行初始化模型实例。本次以 ChatDeepSeek 为例进行演示。其他可用的聊天模型,请参阅聊天模型。
python
from langchain.agents import create_agent
from langchain_deepseek import ChatDeepSeek
from dotenv import load_dotenv
load_dotenv()
model = ChatDeepSeek(
model="deepseek-chat",
api_base="https://api.deepseek.com/v1",
temperature=0.1,
max_tokens=1000,
timeout=30
# ... (other params)
)
agent = create_agent(model)
在使用ChatDeepSeek时,需使用api_base参数(而非api_url)
模型实例使你能够完全控制配置。当你需要设置特定的参数时,比如 temperature,max_tokens,timeouts,base_url 和其他特定于提供程序的设置。请参考查看模型上可用的参数和方法。
Dynamic model(动态模型)
动态模型是在运行时根据当前状态和上下文选择的。这样能够适配复杂的路由逻辑,还能优化成本。
要使用动态模型,请使用 @wrap_model_call 装饰器,在发起请求的过程中修改模型参数。
python
from langchain_deepseek import ChatDeepSeek
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from dotenv import load_dotenv
load_dotenv()
basic_model = ChatDeepSeek(model="deepseek-chat")
advanced_model = ChatDeepSeek(model="deepseek-reasoner")
@wrap_model_call
def dynamic_model_selection(request: ModelRequest, handler) -> ModelResponse:
"""根据对话的复杂度选择模型"""
message_count = len(request.state["messages"])
if message_count > 5:
# 在长对话的时候使用高级模型
model = advanced_model
else:
model = basic_model
return handler(request.override(model=model))
agent = create_agent(
model=basic_model, # 默认使用基础模型
middleware=[dynamic_model_selection]
)
result1 = agent.invoke({
"messages": [{"role": "user", "content": "你叫什么名字?"}]
})
print(f"✅: {result1['messages'][-1].content}")
result2 = agent.invoke({
"messages": [
{"role": "user", "content": "\n1+1等于多少?"},
{"role": "user", "content": "\n1+2等于多少?"},
{"role": "user", "content": "\n1+3等于多少?"},
{"role": "user", "content": "\n1+4等于多少?"},
{"role": "user", "content": "\n1+5等于多少?"},
{"role": "user", "content": "\n1+6等于多少?"}
]
})
print(f"✅: {result2['messages'][-1].content}")
⚠️ 使用结构化输出时不支持预绑定模型(通过bind_tools进行绑定的模型)。如果您需要具有结构化输出的动态模型选择,请确保传递给中间件的模型没有预绑定。
💡 更多模型配置的详细信息,参考Models。关于动态模型选择,参考Dynamic model in middleware,。
Tools(工具)
工具赋予agents采取行动的能力。agents通过以下方式超越了简单的纯模型工具绑定:
- 有次序地调用多个工具(通过prompt触发)
- 在适当的时候异步调用工具
- 基于之前的结果的进行动态工具选择
- 加入工具调用的重试逻辑和异常处理
- 在跨工具调用时保持Agent状态的持久性
想要了解更多关于工具的信息,请查看工具
Defining Tools(定义工具)
将工具列表传递给Agent。
💡 工具可以被指定为普通的Python函数或协程。 tool decorator可用来自定义工具名称、描述、参数模型和其他属性。
python
from langchain.tools import tool
from langchain.agents import create_agent
from langchain_deepseek import ChatDeepSeek
from dotenv import load_dotenv
load_dotenv()
model = ChatDeepSeek(model="deepseek-chat")
@tool
def search(query: str) -> str:
"""查询信息"""
return f"Results for: {query}"
@tool
def get_weather(location: str) -> str:
"""根据地点查询天气"""
return f"{location}天气: 晴, 25℃"
agent = create_agent(model, tools=[search, get_weather])
result = agent.invoke({
"messages": [{"role": "user", "content": "武汉的天气怎么样?"}]
})
print(f"✅: {result['messages'][-1].content}")
如果提供了一个空的工具列表,代理将由一个没有工具调用能力的LLM节点组成。
Tool error handling(工具的异常处理)
如果要自定义工具的异常处理,请使用@wrap_tool_call装饰器来创建中间件:
python
from langchain.tools import tool
from langchain.agents import create_agent
from langchain.agents.middleware import wrap_tool_call
from langchain.messages import ToolMessage
from langchain_deepseek import ChatDeepSeek
from dotenv import load_dotenv
load_dotenv()
model = ChatDeepSeek(model="deepseek-chat", max_retries=0)
@tool
def query_airindex(city: str) -> str:
"""计算空气指数"""
pm25 = 1000
airindex = pm25 / 0
return airindex
@wrap_tool_call
def handle_tool_errors(request, handler):
"""自定义工具执行过程中的异常消息"""
try:
return handler(request)
except Exception as e:
print(f"❌: {str(e)}")
return ToolMessage(
content=f"Tool error: 请检查输入并重试。 ({str(e)})",
tool_call_id=request.tool_call["id"]
)
agent = create_agent(
model=model,
tools = [query_airindex],
middleware=[handle_tool_errors]
)
result = agent.invoke({
"messages": [{"role": "user", "content": "查询一下武汉的空气指数"}]
})
print(f"✅: {result['messages'][-2].content}")
当工具执行失败时,Agent将返回带有自定义异常消息的ToolMessage:
python
[
...
ToolMessage(
content="Tool error: 请检查输入并重试。 (division by zero)",
tool_call_id="..."
),
...
]
Tool use in the ReAct loop
Agent遵循ReAct(" Reasoning(推理)+ Acting(执行)")规则,在简短的推理步骤与目标工具调用之间交替进行,并将结果观察结果提供给后续决策,直到它们能够提供最终答案。
ReaAct loop示例:
Prompt: 找到当前最流行的无线耳机并验证可用性。
ini
================================ Human Message =================================
找到现在最流行的无线耳机,看看是否有货
- Reasoning(推理):"流行度是时间敏感的,我需要使用已经提供的搜索工具。"
- Acting(执行): 调用
search_products("无线耳机")
yaml
================================== Ai Message ==================================
Tool Calls:
search_products (call_abc123)
Call ID: call_abc123
Args:
query: wireless headphones
ini
================================= Tool Message =================================
Found 5 products matching "wireless headphones". Top 5 results: WH-1000XM5, ...
后面还会继续重复上述Reasoning和Acting步骤,直到Agent得到最终答案(这里不继续演示)。
💡 更多关于工具信息,请参考 Tools
System prompt(系统提示词)
你可以通过提供提示词来塑造Agent处理任务的方式。系统提示词通常是以字符串的形式提供:
python
agent = create_agent(
model,
tools,
system_prompt="你是一个有用的助手。回答要简洁准确。"
)
如果没有提供系统提示词,Agent将直接从消息中推断其任务。
系统提示词参数可以是 str 或 SystemMessage。使用 SystemMessage 可以让你更好地控制提示词的结构,这对于特定大模型供应商的功能很有用,比如Anthropic的提示词缓存:
python
from langchain.agents import create_agent
from langchain.messages import SystemMessage, HumanMessage
literary_agent = create_agent(
model="anthropic:claude-sonnet-4-5",
system_prompt=SystemMessage(
content=[
{
"type": "text",
"text": "You are an AI assistant tasked with analyzing literary works.",
},
{
"type": "text",
"text": "<the entire contents of 'Pride and Prejudice'>",
"cache_control": {"type": "ephemeral"}
}
]
)
)
result = literary_agent.invoke(
{"messages": [HumanMessage("Analyze the major themes in 'Pride and Prejudice'.")]}
)
cache_control 字段的 {"type": "ephemeral"} 告诉Anthropic缓存内容块,减少重复使用相同系统提示词的请求的延迟和成本。
Dynamic system prompt(动态系统提示词)
对于需要根据运行时上下文或Agent状态修改系统提示词这种更高级的用法,可以使用middleware(中间件)。
通过 @dynamic_prompt 装饰器创建中间件,实现根据模型请求生成系统提示词:
python
from typing import TypedDict
from langchain.agents import create_agent
from langchain.agents.middleware import dynamic_prompt, ModelRequest
from langchain_deepseek import ChatDeepSeek
from dotenv import load_dotenv
load_dotenv()
class Context(TypedDict):
user_role: str
@dynamic_prompt
def user_role_prompt(request: ModelRequest) -> str:
"""根据用户角色来生成系统提示词"""
user_role = request.runtime.context.get("user_role", "user")
base_prompt = "你是一个有用的助手。"
if user_role == "专家":
return f"{base_prompt} 给出详细的专业解释。"
elif user_role == "小白":
return f"{base_prompt} 简单地解释概念,避免术语。"
return base_prompt
model = ChatDeepSeek(model="deepseek-chat")
agent = create_agent(
model=model,
middleware=[user_role_prompt],
context_schema=Context
)
# 系统提示词会根据上下文动态产生
result1 = agent.invoke(
{"messages": [{"role": "user", "content": "解释一下机器学习"}]},
context={"user_role": "专家"}
)
print(f"✅ 专家: {result1['messages'][-1].content}")
result2 = agent.invoke(
{"messages": [{"role": "user", "content": "解释一下机器学习"}]},
context={"user_role": "小白"}
)
print(f"✅ 小白: {result2['messages'][-1].content}")
Invocation(调用)
您可以通过更新Agent的 State 状态来调用它。所有agents在其状态中都包含一个 sequence of messages (消息序列),发送一条消息来调用Agent:
python
result = agent.invoke(
{"messages": [{"role": "user", "content": "武汉的天气怎么样?"}]}
)
有关Agent的streaming steps或tokens,请参考 streaming
另外,Agent遵循LangGraph Graph API,并支持所有相关的方法,如 stream 和 invoke 。
Advanced concepts(高级概念)
Structured output(结构化输出)
在某些情况下,你可能希望Agent以特定格式返回输出。LangChain通过 response_format (响应格式)提供了结构化输出的策略。
ToolStrategy(工具策略)
ToolStrategy 使用人为调用工具来生成结构化的输出。这适用于任何支持工具调用的模型:
python
from pydantic import BaseModel
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy
from langchain_deepseek import ChatDeepSeek
from dotenv import load_dotenv
load_dotenv()
# 结构化输出模型(必须定义):
# 方法1:Pydantic BaseModel - 官方推荐
class ContactInfo(BaseModel):
name: str
email: str
phone: str
# 方法2:dataclass - 极致性能,简单场景
# from dataclasses import dataclass
# @dataclass
# class ContactInfo:
# name: str
# email: str
# phone: str | None = None
# 方法3:TypedDict - 纯字典场景,无验证需求
# from typing import TypedDict, NotRequired
# class ContactInfo(TypedDict):
# name: str
# email: str
# phone: NotRequired[str]
model = ChatDeepSeek(model="deepseek-chat")
agent = create_agent(
model=model,
response_format=ToolStrategy(ContactInfo)
)
result = agent.invoke({
"messages": [{"role": "user", "content": "提取联系人信息: John Doe, john@example.com, (555) 123-4567"}]
})
print(result["structured_response"])
# ContactInfo(name='John Doe', email='john@example.com', phone='(555) 123-4567')
ProviderStrategy(供应商策略)
ProviderStrategy 使用模型供应商提供的native(原生)结构化输出。这更可靠,但只适用于支持原生结构化输出的供应商(例如:OpenAI,DeepSeek等国内大模型暂时不支持ProviderStrategy):
python
from pydantic import BaseModel
from langchain.agents import create_agent
from langchain.agents.structured_output import ProviderStrategy
from langchain_deepseek import ChatDeepSeek
from dotenv import load_dotenv
load_dotenv()
# 结构化输出模型(必须定义):
class ContactInfo(BaseModel):
name: str
email: str
phone: str
model = ChatDeepSeek(model="deepseek-chat")
try:
agent = create_agent(
model=model,
response_format=ProviderStrategy(ContactInfo)
)
result = agent.invoke({
"messages": [{"role": "user", "content": "提取联系人信息: John Doe, john@example.com, (555) 123-4567"}]
})
print(result["structured_response"])
except Exception as e:
print(f" ❌ ProviderStrategy 失败: {type(e).__name__}: {str(e)[:100]}...")
# ❌ ProviderStrategy 失败: BadRequestError: Error code: 400
🚨 从
langchain 1.0开始,必须显式地使用ToolStrategy或ProviderStrategy。
Memory
Agents通过消息state(状态)自动维护会话历史。还可以对agent进行配置,使用自定义状态模型,以便在会话期间记住额外的信息。
存储在状态中的信息可以看作是agent的 short-term memory 短期记忆:
自定义state(状态)模型必须将 AgentState 扩展为 TypedDict。
自定义state(状态)的方式有两种:
- 通过
middleware(首选) - 通过
state_schemaoncreate_agent
Defining state via middleware(通过中间件定义状态)
当你的自定义state(状态)需要被特定的中间件hooks(钩子)和附加到该中间件上的tools(工具)访问时,使用中间件来定义自定义state(状态)。
python
from langchain.agents import AgentState
from langchain.agents.middleware import AgentMiddleware
from typing import Any
from langchain.agents import create_agent
from langchain_core.tools import tool
from langchain_deepseek import ChatDeepSeek
from dotenv import load_dotenv
load_dotenv()
model = ChatDeepSeek(model="deepseek-chat")
@tool
def get_weather(city: str) -> str:
"""获取指定城市的天气信息"""
return f"{city} 当前天气:晴天,25°C"
class CustomState(AgentState):
"""支持用户偏好的自定义状态"""
user_preferences: dict[str, str]
class CustomMiddleware(AgentMiddleware):
"""根据用户偏好动态调整提示词和工具访问的自定义中间件"""
state_schema = CustomState
def before_model(self, state: CustomState, runtime) -> dict[str, Any] | None:
print("============= before_model ==================")
print(state.get("user_preferences"))
agent = create_agent(
model=model,
tools=[get_weather],
middleware=[CustomMiddleware()]
)
print("======== 🤖 开始调用... ==================")
result = agent.invoke({
"messages": [{"role": "user", "content": "武汉的天气怎么样,有哪些地方值得游玩?"}],
"user_preferences": {"style": "technical", "verbosity": "detailed"},
})
print(f"✅ 回答: {result['messages'][-1].content}")
Defining state via state_schema (通过 state_schema 定义状态)
使用 state_schema 这个参数作为定义状态的快捷键,这种方式只有在使用的tools(工具)的时候才能使用。
python
from langchain.agents import AgentState
from langchain.agents import create_agent
from langchain_core.tools import tool
from dotenv import load_dotenv
load_dotenv()
@tool
def get_weather(city: str) -> str:
"""获取指定城市的天气信息"""
return f"{city} 当前天气:晴天,25°C"
class CustomState(AgentState):
user_preferences: dict
agent = create_agent(
model="deepseek-chat",
tools=[get_weather],
state_schema=CustomState
)
print("======== 🤖 开始调用... ==================")
result = agent.invoke({
"messages": [{"role": "user", "content": "武汉的天气怎么样,有哪些地方值得游玩?"}],
"user_preferences": {"style": "technical", "verbosity": "detailed"},
})
print(f"✅ 回答: {result['messages'][-1].content}")
⚠️ 从
langchain 1.0开始,自定义状态模式模型是TypedDict类型。不再支持Pydantic models和dataclasses。详情请参考 v1 migration guide
⚠️ 定义自定义state(状态),使用middleware优于state_schema,这让你在概念上将状态扩展限定在相关中间件和工具的范围内。
state_schema在create_agent时仍然向后兼容。
💡 更多关于memory的信息,参考 Memory 。关于实现跨会话long-term memory的信息,参考 Long-term memory 。
Streaming(流)
我们已经看到了如何使用 invoke 调用Agent得到最终响应。如果Agent执行多个步骤,这可能需要一段时间。为了显示中间进程,我们可以在消息生成时将其流化。
python
from langchain.agents import create_agent
from langchain_core.tools import tool
from dotenv import load_dotenv
load_dotenv()
@tool
def get_weather(city: str) -> str:
"""获取指定城市的天气信息"""
return f"{city} 当前天气:晴天,25°C"
agent = create_agent(model="deepseek-chat", tools=[get_weather])
for chunk in agent.stream({
"messages": [{"role": "user", "content": "武汉的天气怎么样,给我一个穿衣建议"}]
}, stream_mode="values"):
# Each chunk contains the full state at that point
latest_message = chunk["messages"][-1]
if latest_message.content:
print(f"Agent: {latest_message.content}")
elif latest_message.tool_calls:
print(f"Calling tools: {[tc['name'] for tc in latest_message.tool_calls]}")
💡 更多关于streaming的细节,参考Streaming。
Middleware(中间件)
Middleware 中间件为在不同的执行阶段定制Agent的行为提供了强大的扩展能力。你可以这样使用中间件:
- 调用模型之前的处理Agent的状态。(例如:message trimming,context injection)
- 修改或验证模型的响应(例如:guardrails,content filtering)
- 使用自定义逻辑处理工具执行产生的异常
- 实现基于状态或上下文的动态模型选择
- 添加自定义日志、监控或分析
中间件无缝地集成到Agent的执行中,你可以在关键节点拦截和修改数据流,而无需更改核心Agent逻辑。
💡 关于中间件的完整文档(包括
@before_model,@after_model,@wrap_tool_call),请参考 Middleware