Skip to main content
Alpha 版本提示: 本文档涵盖的是 v1-alpha 版本。内容尚不完整,且可能随时变更。如需查阅最新稳定版本,请参阅 v0 版本的 LangChain Python 文档LangChain JavaScript 文档

概述

代理将语言模型与工具相结合,创建能够对任务进行推理、决定使用哪些工具并迭代推进解决方案的系统。 create_agent() 提供了一个基于论文《ReAct: Synergizing Reasoning and Acting in Language Models》(https://arxiv.org/abs/2210.03629)的生产级 ReAct(推理 + 行动)代理实现。

ReAct 将代理的行为框架化为交替进行的 思考 -> 行动 -> 观察 步骤,其中模型会写出其推理过程,选择一个工具,查看工具的结果,然后重复此过程。ReAct 减少了幻觉现象,并使决策过程可审计:代理可以形成假设(思考),用工具进行测试(行动),并根据反馈更新其计划(观察)。ReAct 循环会一直运行,直到达到停止条件——即模型输出最终答案或达到最大迭代次数限制。

在底层,create_agent() 使用 LangGraph 构建了一个基于图的代理运行时。图由节点(步骤)和边(连接)组成,定义了代理如何处理信息。代理在图中移动,执行诸如模型节点(调用模型)、工具节点(执行工具)或模型前后钩子节点等节点。了解更多关于 图 API 的内容。

核心组件

模型

模型 是代理的推理引擎。它可以通过多种方式指定,支持静态和动态模型选择。

静态模型

静态模型在创建代理时配置一次,并在执行过程中保持不变。这是最常见且最直接的方法。要从模型标识符字符串初始化静态模型:
from langchain.agents import create_agent

agent = create_agent(
    "openai:gpt-5",
    tools=tools
)
模型标识符字符串使用 provider:model 格式(例如 "openai:gpt-5"),并支持自动推断(例如 "gpt-5" 将被推断为 "openai:gpt-5")。您可能希望对模型配置拥有更多控制权,此时可以直接使用提供商包初始化模型实例:
from langchain.agents import create_agent
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model="gpt-5",
    temperature=0.1,
    max_tokens=1000,
    timeout=30
)
agent = create_agent(model, tools=tools)
模型实例让您完全控制配置。当您需要设置特定参数(如温度、最大令牌数、超时时间)或配置 API 密钥、基础 URL 和其他提供商特定设置时,请使用它们。请参阅 API 参考 以查看模型上可用的参数和方法。

动态模型

runtime:代理的执行环境,包含在代理执行期间保持不变的配置和上下文数据(例如用户 ID、会话详细信息或应用程序特定配置)。
state:在代理执行过程中流动的数据,包括消息、自定义字段以及在处理过程中需要跟踪和可能修改的任何信息(例如用户偏好或工具使用统计)。
动态模型在运行时根据当前状态和上下文进行选择。这实现了复杂的路由逻辑和成本优化。 要使用动态模型,您需要提供一个函数,该函数接收图状态和运行时,并返回一个使用 .bind_tools(tools) 绑定工具的 BaseChatModel 实例,其中 toolstools 参数的一个子集。
from langchain_openai import ChatOpenAI
from langchain.agents import create_agent, AgentState
from langgraph.runtime import Runtime

def select_model(state: AgentState, runtime: Runtime) -> ChatOpenAI:
    """根据对话复杂性选择模型。"""
    messages = state["messages"]
    message_count = len(messages)

    if message_count < 10:
        return ChatOpenAI(model="gpt-4.1-mini").bind_tools(tools)
    else:
        return ChatOpenAI(model="gpt-5").bind_tools(tools) # 适用于更长对话的更好模型

agent = create_agent(select_model, tools=tools)
有关模型配置的详细信息,请参阅 模型

工具

工具赋予代理采取行动的能力。代理超越了简单的仅模型工具绑定,能够实现:
  • 由单个提示触发的多个工具调用序列
  • 在适当情况下并行调用工具
  • 根据结果动态选择工具
  • 工具重试逻辑和错误处理
  • 工具调用之间的状态持久化
工具可以以下列形式提供给代理:
  1. 工具列表(LangChain @tool、可调用对象或表示内置提供商工具的 dict
  2. 配置好的 ToolNode

传递工具列表

将工具列表传递给代理将在底层创建一个 ToolNode。这是设置工具调用代理的最简单方法:
from langchain_core.tools import tool
from langchain.agents import create_agent

@tool
def search(query: str) -> str:
    """搜索信息。"""
    return f"结果为:{query}"

@tool
def calculate(expression: str) -> str:
    """执行计算。"""
    return str(eval(expression))

agent = create_agent(model, tools=[search, calculate])
如果提供空的工具列表,代理将仅由一个没有工具调用的 LLM 节点组成。

传递配置好的 ToolNode

或者,您可以直接创建一个 ToolNode 并将其传递给代理。这允许您自定义工具节点的行为,例如处理工具错误:
tool_node = ToolNode(
    tools=[search, calculate],
    handle_tool_errors="请检查您的输入并重试。"
)
agent = create_agent(model, tools=tool_node)
result = agent.invoke({"messages": [...]})
如果在 ToolNode 中发生错误,代理将向模型返回一个带有自定义错误消息的 ToolMessage
# result["messages"]
[
    ...
    ToolMessage(content="请检查您的输入并重试。", tool_call_id="..."),
    ...
]

要了解有关 ToolNode 中错误处理的更多信息,请参阅 ToolNode

ReAct 循环中的工具使用

代理遵循 ReAct(推理 + 行动)模式,在简短的推理步骤与有针对性的工具调用之间交替进行,并将结果观察反馈到后续决策中,直到能够提供最终答案。 跟随代理应用 ReAct 回答用户问题的过程:

提示:识别当前最受欢迎的无线耳机并验证库存。

================================ 人类消息 =================================

找出目前最受欢迎的无线耳机并检查是否有库存
推理:“流行度是随时间变化的,我需要使用提供的搜索工具。”行动:调用 search_products("wireless headphones")
================================== AI 消息 ==================================
工具调用:
  search_products (call_abc123)
 调用 ID: call_abc123
  参数:
    query: wireless headphones
================================= 工具消息 =================================

找到 5 个匹配“无线耳机”的产品。前 5 个结果:WH-1000XM5, ...
推理:“在回答之前,我需要确认排名第一的产品的库存情况。”行动:调用 check_inventory("WH-1000XM5")
================================== AI 消息 ==================================
工具调用:
  check_inventory (call_def456)
 调用 ID: call_def456
  参数:
    product_id: WH-1000XM5
================================= 工具消息 =================================

产品 WH-1000XM5:库存 10 件
推理:“我已获得最受欢迎的型号及其库存状态。现在可以回答用户的问题了。”行动:生成最终答案
================================== AI 消息 ==================================

我找到了无线耳机(型号 WH-1000XM5),库存 10 件...
要了解有关工具的更多信息,请参阅 工具

提示

您可以通过提供提示来塑造代理处理任务的方式。prompt 参数可以以多种形式提供。

字符串

agent = create_agent(
    model,
    tools,
    prompt="您是一个乐于助人的助手。请简洁准确。"
)

SystemMessage

agent = create_agent(
    model,
    tools,
    prompt=SystemMessage(content="您是一个研究助理。请引用您的来源。")
)

可调用对象

def dynamic_prompt(state):
    user_type = state.get("user_type", "standard")
    system_msg = SystemMessage(
        content="提供详细的技术响应。"
        if user_type == "expert"
        else "提供简单清晰的解释。"
    )
    return [system_msg] + state["messages"]
agent = create_agent(model, tools, prompt=dynamic_prompt)
当未提供 prompt 时,代理将直接从消息中推断其任务。
有关消息类型和格式的更多详细信息,请参阅 消息

高级配置

结构化输出

在某些情况下,您可能希望代理以特定格式返回输出。LangChain 通过 response_format 参数提供了一种简单通用的方法。
from pydantic import BaseModel
from langchain.agents import create_agent

class ContactInfo(BaseModel):
    name: str
    email: str
    phone: str

agent = create_agent(
    model,
    tools=[search_tool],
    response_format=ContactInfo
)

result = agent.invoke({
    "messages": [{"role": "user", "content": "从以下内容中提取联系信息:John Doe, [email protected], (555) 123-4567"}]
})

result["structured_response"]
# ContactInfo(name='John Doe', email='[email protected]', phone='(555) 123-4567')
要了解有关结构化输出的更多信息,请参阅 结构化输出

内存

代理通过消息状态自动维护对话历史。您还可以配置代理使用自定义状态模式在对话期间记住额外信息。 存储在状态中的信息可以被视为代理的“短期记忆”:
from typing import TypedDict
from typing_extensions import Annotated
from langgraph.graph.message import add_messages
from langchain.agents import create_agent
from langchain.agents import AgentState

class CustomAgentState(AgentState):
    messages: Annotated[list, add_messages]
    user_preferences: dict

agent = create_agent(
    model,
    tools=tools,
    state_schema=CustomAgentState
)

# 代理现在可以跟踪除消息之外的额外状态。此自定义状态可以在整个对话过程中访问和更新。
result = agent.invoke({
    "messages": [{"role": "user", "content": "我更喜欢技术性解释"}],
    "user_preferences": {"style": "technical", "verbosity": "detailed"},
})
要了解有关内存的更多信息,包括如何实现跨会话持久化的长期记忆,请参阅 内存

模型前钩子

模型前钩子是一个可选节点,可以在调用模型之前处理状态。用例包括消息修剪、摘要和上下文注入。 它必须是一个可调用对象或可运行对象,接收当前图状态并以以下形式返回状态更新:
{
    # 将更新状态中的 `messages`
    "messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES), ...],
    # 需要传播的其他状态键
    ...
}
模型前钩子示例,用于修剪消息以适应上下文窗口:
from langchain_core.messages import RemoveMessage
from langgraph.graph.message import REMOVE_ALL_MESSAGES
from langchain.agents import create_agent

def trim_messages(state):
    """仅保留最后几条消息以适应上下文窗口。"""
    messages = state["messages"]

    if len(messages) <= 3:
        return {"messages": messages}

    first_msg = messages[0]
    recent_messages = messages[-3:] if len(messages) % 2 == 0 else messages[-4:]
    new_messages = [first_msg] + recent_messages

    return {
        "messages": [
            RemoveMessage(id=REMOVE_ALL_MESSAGES),
            *new_messages
        ]
    }

agent = create_agent(
    model,
    tools=tools,
    pre_model_hook=trim_messages
)
必须提供 messages,并将其用作 agent 节点(即调用 LLM 的节点)的输入。其余键将添加到图状态中。
如果您在模型前钩子中返回 messages,应通过以下方式覆盖 messages 键:
{
"messages": [RemoveMessage(id=REMOVE_ALL_MESSAGES), *new_messages]
...
}

模型后钩子

模型后钩子是一个可选节点,可以在工具执行之前处理模型的响应。用例包括验证、防护措施或其他后处理。 它必须是一个可调用对象或可运行对象,接收当前图状态并返回状态更新。 模型后钩子示例,用于过滤机密信息:
from langchain_core.messages import AIMessage, RemoveMessage
from langgraph.graph.message import REMOVE_ALL_MESSAGES

def validate_response(state):
    """检查模型响应是否存在策略违规。"""
    messages = state["messages"]
    last_message = messages[-1]

    if "confidential" in last_message.content.lower():
        return {
            "messages": [
                RemoveMessage(id=REMOVE_ALL_MESSAGES),
                *messages[:-1],
                AIMessage(content="我无法分享机密信息。")
            ]
        }

    return {}

agent = create_agent(
    model,
    tools=tools,
    post_model_hook=validate_response
)

流式传输

我们已经看到如何使用 .invoke 调用代理以获得最终响应。如果代理执行多个步骤,这可能需要一段时间。为了显示中间进度,我们可以流式传输回发生的消息。
for chunk in agent.stream({
    "messages": [{"role": "user", "content": "搜索 AI 新闻并总结发现"}]
}, stream_mode="values"):
    # 每个块包含此时的完整状态
    latest_message = chunk["messages"][-1]
    if latest_message.content:
        print(f"代理:{latest_message.content}")
    elif latest_message.tool_calls:
        print(f"调用工具:{[tc['name'] for tc in latest_message.tool_calls]}")
有关流式传输的更多详细信息,请参阅 流式传输