在这里插入图片描述

精读 LangChain 官方文档(六)Agent 篇:把模型调用升级为可治理的运行结构

本文基于 LangChain Python 官方文档整理:
Agents:https://docs.langchain.com/oss/python/langchain/agents
Markdown 版本:https://docs.langchain.com/oss/python/langchain/agents.md
对应开源文档源码:
https://github.com/langchain-ai/docs/blob/main/src/oss/langchain/agents.mdx

学习智能体时,都是从从一个非常小的代码片段开始:给模型一段 prompt,然后拿到一段回答。这与真实得智能体开发还是有很大差距得得。

真实 Agent 场景里,问题很快会变成另一组工程问题:模型什么时候该调用工具?工具返回结果怎么重新进入上下文?同一用户的连续对话怎么恢复?结构化结果怎么校验?流式进度怎么展示?模型失败、工具超时、敏感信息和人工审批又应该放在哪里治理?

如果所有能力都塞进一段大 prompt,系统会很快失控。prompt 会越来越长,工具调用边界会越来越模糊,排查问题时也很难知道到底是模型、工具、状态还是上下文出了问题。

LangChain 的 Agents 文档要解决的正是这个抽象边界问题:不要只把 Agent 理解成“会调用工具的模型”,而要把它理解成一个围绕模型循环构建出来的可配置运行结构。

这篇文档的核心主线可以概括成一句话:

Agent = Model + Harness。模型负责推理与决策,Harness 负责在正确时间把正确上下文、工具、状态和治理能力交给模型。

也就是说,create_agent 不是一个简单的模型包装函数,而是把“模型调用工具直到任务完成”的循环,提升为一个可以配置、扩展、观测和治理的 Agent runtime structure。

先把这条主线拆开看:

  • model:决定 Agent 使用哪个推理核心。
  • tools:决定 Agent 能采取哪些行动。
  • system_prompt:决定 Agent 的角色、风格和边界。
  • response_format:决定最终输出能否变成可校验结构。
  • messagesthread_idcheckpointer:决定对话状态如何进入运行时。
  • context_schemacontext:决定每次运行的业务上下文如何传入工具和中间件。
  • middleware:决定执行环境、上下文治理、委派、重试、安全和人工介入如何组合进 Agent loop。

下面这张图先把 Agent = Model + Harness 的主线放在一起:

Agent运行主线图

理解这条主线后,create_agentmodeltoolssystem_promptresponse_formatthread_idcontextmiddleware 就不再是散落参数,而是同一个 Agent 工程结构里的不同控制面。



1. Agent(智能体):从单次模型调用到任务循环

它解决的问题:
Agent 解决的是“模型如何在一个任务里持续观察、决策、行动和收敛”,而不是只解决“一次模型调用怎么返回文本”。

官方文档对 Agent 的定义很简洁:Agent 是一个模型不断调用工具,直到任务完成的循环。这个定义里有三个关键词:

  • model:负责判断下一步该说什么、查什么、调什么工具。
  • tools:让模型不只生成文本,还可以检索、查询、计算、写入或触发外部能力。
  • loop:说明 Agent 不是单次调用,而是多轮状态推进。

示例:

import os

from langchain.agents import create_agent
from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model="qwen3.7-max",
    api_key=os.environ["QWEN_API_KEY"],
    base_url=os.environ["QWEN_BASE_URL"],
)

agent = create_agent(
    model=model,
    tools=[],
    system_prompt="你是一名中文技术助手,需要用简洁语言解释复杂概念。",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "请解释什么是 LangChain Agent"}]}
)

这里:

  • create_agent:创建 Agent 的入口函数。它把模型、工具、提示词和可选中间件组织成一个可运行结构。
  • model:可以是模型标识字符串,也可以是已经初始化好的模型对象。这里用 ChatOpenAI 通过 OpenAI-compatible 协议调用 qwen3.7-max
  • tools:工具列表。空列表表示这个 Agent 暂时只能回答,不能采取外部行动。
  • system_prompt:系统提示词,负责给 Agent 设定长期稳定的行为边界。
  • agent.invoke(...):执行一次 Agent 调用,输入更新到 Agent state 后,再由运行时推进。

业务场景:
在客服系统里,普通模型调用只能回答“订单状态可能在哪里查”。Agent 则可以先识别用户意图,再调用订单查询工具,拿到结果后继续判断是否需要退款、补发或人工介入。

最简记法:

普通模型调用回答一句话,Agent 在任务循环里不断决定下一步。


2. Harness(运行外壳):让模型在正确时间拿到正确上下文

它解决的问题:
Harness 解决的是“模型周围那一整套运行支撑应该如何组织”。

如果只看模型本身,Agent 很容易被误解成“更长的 prompt”。但官方文档强调,Agent 的关键不是把所有说明写进 prompt,而是给模型一个 harness。

Harness 可以理解为模型外面的运行外壳,它包含:

  • 模型本身。
  • 系统提示词。
  • 可调用工具。
  • 消息和状态。
  • 中间件。
  • 检查点、上下文压缩、重试、安全、人工审批等运行能力。

核心组件关系图

示例:

agent = create_agent(
    model=model,
    tools=[],
    system_prompt="你负责把用户问题拆解成可执行步骤,再给出中文回答。",
)

这里:

  • Agent = Model + Harness:模型不是全部,模型周围的工具、上下文和治理能力同样是 Agent 的一部分。
  • Harness:不是一个必须显式实例化的类,而是官方文档用来解释 create_agent 所构建运行结构的心智模型。
  • system_prompttoolsmiddleware:都是 harness 的组成部分。

业务场景:
做企业知识库问答时,模型只负责理解问题和生成答案;harness 负责接入检索工具、控制上下文长度、加载用户权限、记录运行轨迹,并在高风险答案前触发人工确认。

最简记法:

Model 负责想,Harness 负责把能想、能查、能做、能管串起来。


3. create_agent(创建智能体):最小入口不是最小系统

它解决的问题:
create_agent 解决的是“如何用一个统一入口创建可扩展 Agent”,而不是让你手写一套工具循环。

官方文档展示的最小形式非常短:

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

但这行代码背后的意义并不小。它不是简单把 modeltools 存起来,而是创建了一个可以接受 state 更新、驱动模型调用、处理工具调用、返回结果并接入中间件的运行结构。

create_agent入口图

示例:

from langchain.agents import create_agent
from langchain.tools import tool


# 定义一个搜索工具,用于根据用户问题返回模拟检索结果
@tool
def search(query: str) -> str:
    """根据查询词搜索信息。"""
    return f"查询词:{query};结果:这里是模拟搜索结果。"


agent = create_agent(
    model=model,
    tools=[search],
    system_prompt="你是一名企业知识库助手,需要先查资料,再用中文回答。",
)

这里:

  • @tool:把普通 Python 函数声明成 LangChain 工具,使模型可以在需要时调用它。
  • query:工具参数名,表示搜索关键词。参数名会进入工具 schema,模型会参考它生成工具调用参数。
  • tools=[search]:把工具注册到 Agent harness 中。
  • system_prompt:说明工具使用习惯,例如“先查资料,再回答”。

业务场景:
做售后助手时,可以把 search_orderquery_refund_policycreate_ticket 这些函数都注册为工具。Agent 不再只回答“你可以联系客服”,而是能沿着业务流程推进。

最简记法:

create_agent 是 Agent 工程入口,不只是 model + tools 的字典拼装。


4. Model(模型):推理核心可以是字符串,也可以是实例

它解决的问题:
model 解决的是“Agent 由哪个模型来进行推理和决策”。

官方文档里,model 可以传模型标识字符串,例如 "provider:model",也可以传已经初始化好的模型实例。为了便于在国内项目里落地,这里统一采用 OpenAI-compatible 的 ChatOpenAI 初始化方式。

示例:

import os

from langchain_openai import ChatOpenAI

model = ChatOpenAI(
    model="qwen3.7-max",
    api_key=os.environ["QWEN_API_KEY"],
    base_url=os.environ["QWEN_BASE_URL"],
    temperature=0,
)

agent = create_agent(
    model=model,
    tools=[],
    system_prompt="你是一名严谨的中文业务分析助手。",
)

这里:

  • ChatOpenAI:LangChain 的 OpenAI-compatible 聊天模型封装。
  • model="qwen3.7-max":模型名称。这里用的是业务侧期望的模型名,而不是官方示例里的其他 provider 名称。
  • api_key:API key,来自环境变量 QWEN_API_KEY,不要写死在代码里。
  • base_url:OpenAI-compatible 服务地址,来自环境变量 QWEN_BASE_URL
  • temperature=0:降低随机性,适合业务分析、结构化输出和需要稳定复现的场景。

业务场景:
如果做财务、审批、合同问答这类系统,模型选择不只是“谁回答更聪明”,还要考虑输出稳定性、成本、延迟、上下文长度和内部合规要求。

最简记法:

model 是 Agent 的推理引擎,Harness 决定这个引擎怎么接入业务系统。


5. Tools(工具):让 Agent 从回答问题变成采取行动

它解决的问题:
tools 解决的是“模型如何使用外部能力”,比如搜索、查库、算数、发起工单、读取文件或调用企业 API。

没有工具的 Agent 更像一个聊天模型;有工具的 Agent 才开始接近真实业务助手。

示例:

from langchain.tools import tool


# 查询订单状态,供 Agent 在用户询问订单进度时调用
@tool
def query_order_status(order_id: str) -> str:
    """根据订单号查询订单状态。"""
    return f"订单 {order_id} 当前状态:已发货,预计明天送达。"


agent = create_agent(
    model=model,
    tools=[query_order_status],
    system_prompt="你是一名售后客服助手。需要查询订单时,先调用工具,再回答用户。",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "帮我查一下订单 A10086 到哪了"}]}
)

这里:

  • query_order_status:工具函数名。函数名会影响模型理解工具用途,应该清晰、具体。
  • order_id:工具参数名,表示订单号。真实系统里它通常会映射到数据库字段或接口参数。
  • """根据订单号查询订单状态。""":工具说明文本,模型会读它来判断何时调用工具。
  • tools=[query_order_status]:把工具加入 Agent 可行动作集合。

业务场景:
在积分商城里,工具可以包括 query_points_balancelist_available_couponscreate_exchange_order。Agent 先查积分,再判断能否兑换,再生成下一步动作。

最简记法:

Tools 是 Agent 的手脚;没有工具,它多数时候只是在解释世界。


6. System prompt(系统提示词):不是堆规则,而是设定稳定边界

它解决的问题:
system_prompt 解决的是“Agent 应该以什么身份、风格和原则完成任务”。

系统提示词适合放稳定规则,例如角色、语气、回答格式、工具使用原则和安全边界。不适合把每次调用才知道的用户 ID、订单号、权限、功能开关都写死进去;这些更适合通过 context 传入。

示例:

agent = create_agent(
    model=model,
    tools=[query_order_status],
    system_prompt=(
        "你是一名中文售后客服助手。"
        "回答前先判断是否需要查询订单。"
        "如果需要查询订单,必须先调用订单工具。"
        "回答要简洁、准确,并说明下一步建议。"
    ),
)

这里:

  • system_prompt:系统提示词参数,负责控制 Agent 的长期行为。
  • “必须先调用订单工具”:这是工具使用策略,适合放在系统提示词里。
  • “回答要简洁、准确”:这是输出风格约束。

业务场景:
客服 Agent、财务 Agent、代码助手和数据分析 Agent 的工具可能相似,但 system_prompt 会让它们呈现不同的职责边界。客服重视服务口径,财务重视审计准确性,代码助手重视可执行改动和测试。

最简记法:

system_prompt 定性格和边界,context 传当次运行的数据。


7. Structured output(结构化输出):让 Agent 结果进入业务系统

它解决的问题:
response_format 解决的是“Agent 最终输出如何变成可校验、可入库、可被下游系统消费的数据”。

如果只返回自然语言,前端展示很方便,但业务系统很难稳定解析。结构化输出让 Agent 的最终结果符合一个 schema。

示例:

from pydantic import BaseModel, Field


class ServiceDecision(BaseModel):
    summary: str = Field(description="给用户展示的中文结论")
    needs_human: bool = Field(description="是否需要人工客服介入")
    confidence: float = Field(description="判断置信度,范围从 0 到 1")


agent = create_agent(
    model=model,
    tools=[query_order_status],
    response_format=ServiceDecision,
    system_prompt="你是一名售后客服助手,需要给出可落库的处理结论。",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "订单 A10086 延迟了,我需要人工处理吗?"}]}
)

decision = result["structured_response"]

这里:

  • ServiceDecision:结构化输出 schema,用 Pydantic 描述返回字段。
  • summary:给用户看的中文摘要。
  • needs_human:布尔字段,表示是否需要人工介入。
  • confidence:数值字段,表示模型判断的置信度。
  • response_format=ServiceDecision:告诉 Agent 最终结果要符合这个 schema。
  • structured_response:结果字典里的结构化返回键。下游可以直接读取它,而不是从一段文本里猜。

业务场景:
在工单系统里,Agent 可以返回 categorypriorityneeds_humansummary 等字段。这样自动分派、统计报表和人工复核都能基于稳定字段运行。

最简记法:

response_format 把“模型回答”变成“业务系统能接的结果”。


8. Invocation 与 thread_id(调用与会话):Agent 运行的是 State 更新

它解决的问题:
Invocation 解决的是“如何把一次用户输入推进到 Agent state 里”,而 thread_id 解决的是“如何让多轮对话属于同一个会话”。

官方文档强调,调用 Agent 时传入的是对 state 的更新。所有 Agent state 里都包含一组消息,调用时把新的消息交给 Agent,再由运行时推进。

调用与状态图

示例:

from langchain_core.utils.uuid import uuid7
from langgraph.checkpoint.memory import InMemorySaver

agent = create_agent(
    model=model,
    tools=[],
    checkpointer=InMemorySaver(),
    system_prompt="你是一名中文对话助手,需要记住同一会话里的上下文。",
)

config = {"configurable": {"thread_id": str(uuid7())}}

result = agent.invoke(
    {"messages": [{"role": "user", "content": "我正在比较两个智能客服方案"}]},
    config=config,
)

follow_up = agent.invoke(
    {"messages": [{"role": "user", "content": "刚才提到的第二个方案适合小团队吗?"}]},
    config=config,
)

这里:

  • messages:Agent state 里的消息序列。每次调用通常追加新的用户消息。
  • role:消息角色,例如 user 表示用户消息。
  • content:消息内容。
  • thread_id:会话标识,用来区分不同对话线程。
  • configurable:运行配置中的可配置字段容器,thread_id 放在这里。
  • checkpointer=InMemorySaver():本地内存检查点,用来保存和恢复同一个 thread_id 下的对话状态。

业务场景:
用户在客服窗口里先问物流,再问“那可以改地址吗?”第二句话依赖第一轮上下文。没有 thread_id 和检查点,Agent 很难知道“那”指的是哪笔订单或哪段对话。

最简记法:

thread_id 管会话连续性,checkpointer 管状态能否被保存和恢复。


9. context_schema 与 context(运行上下文):把业务数据传给工具和中间件

它解决的问题:
context 解决的是“每次运行才知道的业务数据如何进入 Agent”,例如用户 ID、租户 ID、权限、功能开关、渠道来源和 API 凭据引用。

这类数据不应该硬塞进 system_prompt。它们更适合作为结构化运行上下文传入,并通过 context_schema 描述形状。

运行上下文图

示例:

from dataclasses import dataclass

from langchain.tools import ToolRuntime, tool


@dataclass
class RuntimeContext:
    user_id: str
    tenant_id: str
    channel: str


# 根据运行上下文读取当前用户的积分余额
@tool
def query_points(runtime: ToolRuntime[RuntimeContext]) -> str:
    """查询当前用户的积分余额。"""
    user_id = runtime.context.user_id
    tenant_id = runtime.context.tenant_id
    return f"租户 {tenant_id} 下,用户 {user_id} 当前积分余额为 1200。"


agent = create_agent(
    model=model,
    tools=[query_points],
    context_schema=RuntimeContext,
    system_prompt="你是一名积分商城助手,需要根据用户上下文回答问题。",
)

result = agent.invoke(
    {"messages": [{"role": "user", "content": "我现在有多少积分?"}]},
    context=RuntimeContext(
        user_id="user-123",
        tenant_id="mall-a",
        channel="mobile-app",
    ),
)

这里:

  • RuntimeContext:运行上下文的数据结构,描述本次运行可用的业务字段。
  • user_id:用户标识。
  • tenant_id:租户或组织标识,多租户系统里很常见。
  • channel:请求来源渠道,例如小程序、App、Web 或企业微信。
  • context_schema=RuntimeContext:告诉 Agent 运行上下文的类型。
  • context=RuntimeContext(...):本次调用真实传入的上下文数据。
  • runtime.context:工具或中间件读取运行上下文的位置。

业务场景:
做 SaaS 客服 Agent 时,同一句“帮我查订单”,不同租户、不同用户、不同渠道对应的权限和数据范围都不同。context 让这些业务条件以结构化方式进入运行时。

最简记法:

thread_id 是会话身份,context 是本次运行的业务身份。


10. Streaming(流式反馈):让长任务不再像黑箱

它解决的问题:
Streaming 解决的是“Agent 多步执行时,用户和系统如何看到中间进度”。

如果 Agent 要查资料、调用工具、分析结果、再生成答案,只等最终结果会让用户觉得系统卡住了。流式反馈可以让前端展示中间消息、工具调用和状态变化。

流式反馈图

示例:

from langchain.messages import AIMessage, HumanMessage

stream = agent.stream_events(
    {"messages": [{"role": "user", "content": "请搜索 AI 新闻并总结重点"}]},
    version="v3",
)

for snapshot in stream.values:
    latest_message = snapshot["messages"][-1]

    if latest_message.content:
        if isinstance(latest_message, HumanMessage):
            print(f"用户:{latest_message.content}")
        elif isinstance(latest_message, AIMessage):
            print(f"智能体:{latest_message.content}")
    elif latest_message.tool_calls:
        tool_names = [tool_call["name"] for tool_call in latest_message.tool_calls]
        print(f"正在调用工具:{tool_names}")

这里:

  • agent.stream_events(...):启动事件流。
  • version="v3":使用新版事件流协议。
  • stream.values:观察每一步 state 快照。
  • snapshot["messages"]:当前状态里的消息列表。
  • latest_message.tool_calls:模型准备调用的工具列表。

业务场景:
数据分析 Agent 可能要读取文件、清洗数据、跑统计、生成图表。前端可以用 streaming 展示“正在读取数据”“正在分析字段”“正在生成报告”,而不是让用户盯着一个转圈动画。

最简记法:

invoke 适合拿最终结果,streaming 适合看运行过程。


11. Middleware(中间件):Agent loop 的可组合治理层

它解决的问题:
middleware 解决的是“如何在不重写 Agent loop 的情况下,给 Agent 加上额外运行能力”。

官方文档强调,create_agent 是高度可扩展的,扩展原语就是 middleware。每个 middleware 处理一个关注点,并在 Agent loop 的合适位置介入。

中间件能力图

可以把 middleware 理解成 Agent runtime 的插件层。常见类别包括:

类别 中文理解 典型能力
Execution environment 执行环境 文件系统、沙箱、代码执行、工具工作区
Context management 上下文管理 摘要压缩、记忆、技能、prompt caching
Planning and delegation 规划与委派 待办列表、子智能体、并行任务
Fault tolerance 容错 模型重试、工具重试、fallback、调用限制
Guardrails 安全护栏 PII 检测、内容策略、输入输出治理
Steering 人工引导 高风险动作前暂停、审批、编辑、拒绝

示例:

from langchain.agents.middleware import ModelRetryMiddleware, ToolRetryMiddleware

agent = create_agent(
    model=model,
    tools=[query_order_status],
    middleware=[
        ModelRetryMiddleware(max_retries=3),
        ToolRetryMiddleware(max_retries=2),
    ],
    system_prompt="你是一名售后客服助手,需要稳定处理订单问题。",
)

这里:

  • middleware:中间件列表,按配置组合进 Agent harness。
  • ModelRetryMiddleware:模型调用失败时的重试中间件。
  • ToolRetryMiddleware:工具调用失败时的重试中间件。
  • max_retries:最大重试次数,属于运行可靠性参数。

业务场景:
生产环境里,模型 API 可能限流,订单查询 API 可能超时,用户输入可能包含敏感信息。把这些治理能力放进 middleware,比把所有异常处理写散在工具函数里更清楚。

最简记法:

middleware 是 Agent loop 的治理插槽,每个插槽只处理一个关注点。


12. Execution environment 与 Context management(执行环境与上下文治理)

它解决的问题:
执行环境解决“Agent 能在哪里工作”,上下文治理解决“Agent 如何在有限上下文窗口里保持任务连续性”。

官方文档把 execution environment 描述为工具、文件系统、沙箱和代码执行。它让 Agent 不只在聊天窗口里回答,而是有一个可以读写、执行和迭代的工作区。

同时,Agent 运行越久,上下文窗口越容易被消息、工具结果和中间步骤填满。上下文治理需要摘要压缩、长期记忆、技能按需加载等能力。

示例:

from deepagents.backends import StateBackend
from deepagents.middleware import (
    FilesystemMiddleware,
    MemoryMiddleware,
    SkillsMiddleware,
    SummarizationMiddleware,
)

backend = StateBackend()

agent = create_agent(
    model=model,
    tools=[query_order_status],
    middleware=[
        FilesystemMiddleware(backend=backend),
        SummarizationMiddleware(model=model, backend=backend),
        MemoryMiddleware(backend=backend, sources=["./AGENTS.md"]),
        SkillsMiddleware(backend=backend, sources=["./skills/"]),
    ],
    system_prompt="你是一名能处理长任务的中文业务助手。",
)

这里:

  • StateBackend:状态后端,用于给部分 deepagents middleware 提供共享存储。
  • FilesystemMiddleware:提供文件系统能力,让 Agent 可以围绕文件工作。
  • SummarizationMiddleware:在上下文膨胀时压缩历史。
  • MemoryMiddleware:加载持久记忆或项目规则。
  • SkillsMiddleware:按需加载技能,避免一开始把所有领域知识塞进上下文。
  • sources:资源来源路径,例如 ./AGENTS.md./skills/

业务场景:
一个投标方案生成 Agent 可能要读取客户资料、生成多版方案、对比报价、保存中间文件、复用公司写作规范。执行环境负责“能工作”,上下文治理负责“长任务不失忆”。

最简记法:

执行环境给 Agent 工作台,上下文治理让 Agent 长时间工作不散架。


13. Planning and delegation(规划与委派):让复杂任务从单脑袋变成可分工

它解决的问题:
Planning and delegation 解决的是“复杂任务如何拆分、跟踪和交给子智能体处理”。

当任务超过一个上下文窗口,或者需要多个专业视角时,让一个 Agent 从头扛到尾会很吃力。官方文档把待办列表和子智能体归到这个能力区:主 Agent 负责任务协调,子 Agent 在隔离上下文里完成专门工作。

示例:

from deepagents.backends import StateBackend
from deepagents.middleware import FilesystemMiddleware
from deepagents.middleware.subagents import SubAgentMiddleware
from langchain.agents.middleware import TodoListMiddleware

backend = StateBackend()

agent = create_agent(
    model=model,
    tools=[search],
    name="research_coordinator",
    middleware=[
        FilesystemMiddleware(backend=backend),
        TodoListMiddleware(),
        SubAgentMiddleware(
            backend=backend,
            subagents=[
                {
                    "name": "researcher",
                    "description": "搜索资料并返回结构化中文摘要。",
                    "system_prompt": "请使用搜索工具调研问题,并用中文总结关键证据。",
                    "tools": [search],
                    "model": model,
                    "middleware": [],
                }
            ],
        ),
    ],
)

这里:

  • TodoListMiddleware:让 Agent 维护任务待办列表,适合长任务。
  • SubAgentMiddleware:配置子智能体。
  • subagents:子智能体配置列表。
  • name:Agent 名称。在多智能体或子图场景里,它可以作为节点标识。
  • description:子智能体能力描述,帮助主 Agent 判断什么时候委派给它。
  • system_prompt:子智能体自己的系统提示词。

业务场景:
做行业研究报告时,主 Agent 可以负责框架和质量控制;子 Agent 分别调研竞品、政策、技术架构和成本测算。这样主 Agent 的上下文更干净,也更容易追踪各部分来源。

最简记法:

TodoList 管任务拆解,SubAgent 管专业分工,name 管多 Agent 里的身份。


14. Fault tolerance、Guardrails 与 Steering(可靠性、安全与人工介入)

它解决的问题:
这三个能力解决的是“Agent 进入生产环境后,如何在失败、安全和高风险动作面前可控”。

生产系统里的 Agent 不可能只面对理想输入。它会遇到模型超时、工具报错、接口限流、敏感信息、高影响操作和用户越权请求。官方文档把这些能力放在 harness 配置里,就是提醒我们:Agent 的核心不只是会做事,还要能被治理。

生产治理图

示例:

from langchain.agents.middleware import (
    HumanInTheLoopMiddleware,
    ModelRetryMiddleware,
    PIIMiddleware,
    ToolRetryMiddleware,
)

agent = create_agent(
    model=model,
    tools=[query_order_status],
    middleware=[
        ModelRetryMiddleware(max_retries=3),
        ToolRetryMiddleware(max_retries=2),
        PIIMiddleware("email"),
        HumanInTheLoopMiddleware(interrupt_on={"create_refund": True}),
    ],
    system_prompt="你是一名售后客服助手,高风险操作必须等待人工确认。",
)

这里:

  • ModelRetryMiddleware:模型调用失败时重试。
  • ToolRetryMiddleware:工具调用失败时重试。
  • PIIMiddleware("email"):对邮箱等个人信息进行治理。"email" 表示要处理的 PII 类型。
  • HumanInTheLoopMiddleware:在高风险工具调用前暂停,让人工审批、编辑或拒绝。
  • interrupt_on:指定哪些工具或动作需要中断等待人工处理。
  • create_refund:示例中的退款工具名。真实系统里它通常对应会产生资金或订单状态变化的动作。

业务场景:
普通查询可以自动完成,但退款、改地址、发券、删除数据、写入合同这类动作要进入人工审批。这样 Agent 既能提升效率,也不会把高风险动作完全交给模型自由执行。

最简记法:

可靠性靠 retry,合规靠 guardrails,高风险动作靠 human-in-the-loop。


15. 工程落地:读 Agent 文档时最该抓住的边界

它解决的问题:
这一节解决的是“读完 Agents 文档后,如何把它转成工程设计判断”。

不要把 create_agent 当成一个魔法函数,也不要把 Agent 当成一段超级 prompt。更稳的理解方式是:先确认 Agent loop 需要哪些控制面,再逐个选择参数和 middleware。

可以按下面这张表落到工程设计:

工程问题 对应能力 关键字段或函数
用哪个模型推理 Model modelChatOpenAIQWEN_API_KEYQWEN_BASE_URL
能调用哪些外部能力 Tools tools@tool、函数名、参数名、工具说明
行为边界是什么 System prompt system_prompt
输出能否入库 Structured output response_formatstructured_response
多轮对话如何恢复 Invocation messagesthread_idcheckpointer
本次运行有哪些业务变量 Runtime context context_schemacontextruntime.context
长任务如何显示进度 Streaming stream_eventsversion="v3"stream.values
生产治理怎么接入 Middleware middleware、retry、PII、human-in-the-loop
复杂任务如何拆分 Delegation TodoListMiddlewareSubAgentMiddlewarename

业务场景:
如果你在做企业智能客服,Agent 方案不应该只写“使用 LangChain + 大模型”。更准确的方案应该写清楚:模型选型、工具清单、订单/积分/工单 API、会话状态、用户上下文、结构化输出、流式进度、审计日志、敏感信息治理和人工审批边界。

最简记法:

Agent 不是模型增强版,而是围绕模型循环搭起来的运行时工程结构。


最后总结:从“会调工具”到“可运行、可治理、可扩展”

Agents 这篇官方文档真正重要的地方,不是告诉我们多写几个参数,而是给了一个更清晰的抽象层次:

Model -> Agent loop -> Harness -> Middleware ecosystem -> Production governance

最底层,模型负责理解和生成。
往上一层,Agent loop 让模型可以调用工具并持续推进任务。
再往上一层,Harness 把提示词、工具、状态、上下文和中间件组织起来。
到了生产层,middleware 让可靠性、安全、人工审批、上下文治理和任务委派成为可组合能力,而不是散落在业务代码里的临时补丁。

所以读 create_agent 时,不要只问“怎么创建一个 Agent”。更好的问题是:

我这个业务 Agent 需要哪些运行能力?

如果只是简单问答,model + system_prompt 可能够用。
如果要查业务数据,就要设计 tools
如果要多轮对话,就要设计 thread_idcheckpointer
如果要读取用户身份和租户权限,就要设计 context_schema
如果要进入生产环境,就要设计 streaming、retry、guardrails、human-in-the-loop 和审计。

理解这一层后,再读后续的 MessagesRuntimeToolsMiddlewareHuman-in-the-loop 文档时,它们就不再是分散 API,而是同一个 Agent harness 里的不同工程组件。

最简记法:

create_agent 把模型调用提升为可配置的 Agent harness;
middleware 再把 Agent harness 推向可治理的生产运行结构。
Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐