LangChain Agent 高级玩法:命名、结构化输出与流式模式

让你的 Agent 不止于"聊天",还能精准提取数据、实时反馈进度

LangChain 的 create_agent 让我们能轻松构建具备工具调用能力的智能体。但很多同学只停留在"一问一答"的层面,对于 Agent 的身份标识、结构化输出、流式控制 这些高级特性却了解甚少。

本文将带你深入 Agent 的三大高级用法:

  1. 名称与系统提示词 ------ 多智能体场景的身份标记
  2. 结构化输出(response_format ------ 让 Agent 返回类型安全的数据
  3. 流式输出(stream_mode ------ 实现打字机效果与进度监控

每个部分都会配合完整代码示例,并揭示底层原理,助你写出更健壮、更可控的 Agent 应用。


环境准备

我们仍使用 OpenRouter 托管的 DeepSeek 模型,你可以替换成任意支持 create_agent 的模型。

python 复制代码
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from dotenv import load_dotenv
import os

load_dotenv(override=True)
model = init_chat_model(
    model="deepseek-v4-flash",
    model_provider="openai",
    api_key=os.getenv("OPENROUTER_API_KEY"),
    base_url=os.getenv("OPENROUTER_BASE_URL")
)

1. 命名你的 Agent:多智能体场景的身份标识

当系统中有多个 Agent 协作时,给每个 Agent 起个名字能极大提升日志可读性和调试效率。

create_agentname 参数就是干这个的:

python 复制代码
agent = create_agent(
    model=model,
    name="OpenAI Gym",  # 自定义名称
)
messages = [{"role": "user", "content": "你好"}]
response = agent.invoke({"messages": messages})

for msg in response["messages"]:
    msg.pretty_print()

输出中会看到 AI 消息带上了 Name: OpenAI Gym,在多 Agent 系统中一眼就能区分消息来源。


2. 系统提示词:定制 Agent 的"人设"

通过 system_prompt 参数,你可以为 Agent 设置系统级指令,既可以是字符串,也可以是 SystemMessage 对象。

python 复制代码
agent = create_agent(
    model=model,
    name="江西文旅助手",
    system_prompt="你是一个热心的江西文旅推介系统的客服助手"
)
messages = [{"role": "user", "content": "帮我推荐南昌一日游路线"}]
response = agent.invoke({"messages": messages})

结合工具使用时,系统提示词还能指导 Agent 的调用流程,例如"如果是 VIP 客户则发送感谢邮件"。


3. 结构化输出:让 Agent 返回类型安全的对象

这是 Agent 高级用法中最关键的功能。create_agent 提供了 response_format 参数,让我们可以要求 Agent 最终输出一个符合特定 Schema 的结构化数据。

3.1 ProviderStrategy ------ 原生结构化支持

对于本身就支持结构化输出(如 OpenAI 的 response_format 参数)的模型,使用 ProviderStrategy 最为高效。

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,
    name="信息提取助手",
    response_format=ProviderStrategy(ContactInfo)
)

response = agent.invoke({
    "messages": [
        {"role": "user", "content": "小明的电话是12874384973,邮箱是12347923@qq.com"}
    ]
})

# 直接取结构化结果
print(response["structured_response"])  # ContactInfo(name='小明', email='...', phone='...')

返回结果中会多出一个 structured_response 字段,里面就是解析好的 Pydantic 实例(或其他类型,取决于你的 Schema)。

3.2 ToolStrategy ------ 通用回退方案

如果模型本身不支持原生的结构化输出(例如某些开源模型),LangChain 会采用 ToolStrategy,将你的 Schema 伪装成一个"工具",让模型通过调用这个工具来"传递"结构化数据。

python 复制代码
from langchain.agents.structured_output import ToolStrategy

agent = create_agent(
    model=model,
    response_format=ToolStrategy(ContactInfo)
)

底层流程

  • Agent 运行过程中,模型会生成一个 tool_calls,其 name 就是你的 Schema 名称(如 ContactInfo),args 里就是提取到的字段值。
  • LangChain 拦截这个调用,并不实际执行工具,而是将 args 转为 structured_response,同时向消息历史中添加一条 ToolMessage(伪工具消息),告诉模型"结构化输出成功"。
  • 最终,structured_response 就是你想要的对象。

关键点ToolStrategy 适用于所有模型,是兜底方案。如果你的模型支持原生结构化,优先用 ProviderStrategy,更省 token。

3.3 支持哪些 Schema 类型?

ToolStrategyschema 参数支持多种定义方式,满足不同场景:

Schema 类型 示例 特点
Pydantic BaseModel class ContactInfo(BaseModel): ... 运行时校验,推荐
TypedDict class ContactInfo(TypedDict): ... 轻量,无校验
JSON Schema 字典 {"type":"object","properties":...} 动态定义
@dataclass @dataclass class ContactInfo: ... 标准库,无校验

TypedDict 示例

python 复制代码
from typing import TypedDict, Annotated, Optional

class ContactInfo(TypedDict):
    name: Annotated[Optional[str], None, "姓名"]
    email: str
    phone: str

JSON Schema 示例

python 复制代码
json_schema = {
    "type": "object",
    "properties": {
        "name": {"type": "string", "description": "姓名"},
        "email": {"type": "string"},
        "phone": {"type": "string"}
    },
    "required": ["name", "email", "phone"]
}

@dataclass 示例 (需配合 Pydantic 的 Field):

python 复制代码
from dataclasses import dataclass
from pydantic import Field

@dataclass
class ContactInfo:
    name: str = Field(description="姓名")
    email: str = Field(description="邮箱")
    phone: str = Field(description="电话")

联合类型(Union) :当输出可能是多种结构时,可使用 Union[Schema1, Schema2],Agent 会根据上下文选择最合适的一个。

3.4 自定义 Tool 消息内容(tool_message_content

默认情况下,ToolStrategy 会在 ToolMessage 中返回完整的结构化数据(如 "Returning structured response: name='张三' ...")。如果你不想让这段冗长数据进入对话上下文(节省 token),可以自定义消息内容:

python 复制代码
agent = create_agent(
    model=model,
    response_format=ToolStrategy(ContactInfo, tool_message_content="提取成功")
)

这样模型收到的 ToolMessage 仅含"提取成功",而 structured_response 依然正常返回,不影响最终结果。

3.5 错误处理(handle_errors

模型有时会生成不符合 Schema 的数据。ToolStrategyhandle_errors 参数提供了多重策略:

参数值 行为
True(默认) 捕获所有异常,用 LangChain 内置错误提示让模型重试,直到成功
False 直接抛出异常,中断执行
"自定义字符串" 用你指定的字符串作为错误消息喂给模型重试
ExceptionType(如 ValueError 只捕获指定类型异常重试,其余抛出
callable 函数 自定义异常处理逻辑,根据不同异常返回不同提示
python 复制代码
# 自定义错误消息
agent = create_agent(
    model=model,
    response_format=ToolStrategy(ContactInfo, handle_errors="请严格按照格式返回姓名、邮箱和电话")
)

4. 流式输出:实时掌控 Agent 执行过程

create_agent 提供了 .stream() 方法,通过 stream_mode 参数你可以获得不同粒度的输出,适应不同场景。

4.1 messages 模式 ------ 打字机效果(聊天机器人最爱)

python 复制代码
for chunk in agent.stream(
    {"messages": [{"role": "user", "content": "查询客户 CUST123456 的信息"}]},
    stream_mode="messages"
):
    # chunk 是一个元组 (AIMessageChunk, metadata)
    print(chunk[0].content, end="", flush=True)

输出会以 token 流的形式逐字打印,非常适合需要实时交互的聊天应用。

4.2 updates 模式 ------ 观察 Agent 的"思考"步骤(默认)

updates 是默认模式,每次节点(模型、工具)执行完毕,都会增量返回该节点产生的新消息。你可以看到 Agent 调用了哪些工具、拿到了什么结果。

python 复制代码
for chunk in agent.stream(..., stream_mode="updates"):
    # chunk 形如 {"model": {"messages": [...]}} 或 {"tools": {"messages": [...]}}
    print(chunk)

适合做执行监控或调试。

4.3 values 模式 ------ 获取每一步的完整状态

每次迭代都会输出整个状态字典(包含所有消息),适合需要状态持久化或快照的场景。

4.4 tasks / debug 模式 ------ 任务生命周期监控

tasks 模式会在每个任务(task)开始和结束时输出信息;debug 模式更详细,包含时间戳和任务类型。适合分布式追踪。

4.5 checkpoints 模式 ------ 状态检查点

当 LangGraph 检查点被创建时触发,适合工作流恢复。

4.6 custom 模式 ------ 工具内部自定义进度

这是最灵活的模式。在工具函数内部,通过 get_stream_writer() 获取 writer,可以发送任意自定义数据(如进度百分比),然后在外层以 stream_mode="custom" 接收。

python 复制代码
from langgraph.config import get_stream_writer
from langchain.tools import tool
import time

@tool
def generate_sales_report():
    writer = get_stream_writer()
    writer({"type": "进度", "message": "开始生成销售报告"})
    for i in range(1, 4):
        time.sleep(0.5)
        writer({"type": "进度", "message": f"进度:{i*25}%"})
    return "报告完成"

agent = create_agent(model=model, tools=[generate_sales_report])
for chunk in agent.stream(
    {"messages": [{"role": "user", "content": "生成销售报告"}]},
    stream_mode="custom"
):
    print(chunk)

这在长耗时工具(如批量数据处理、爬虫)中尤其有用,能给用户实时反馈。


5. 组合使用多种模式

你还可以传入列表,同时启用多种模式,例如:

python 复制代码
for chunk in agent.stream(..., stream_mode=["messages", "updates"]):
    # 根据 chunk 类型分别处理

这样既能看到 token 流,又能知道执行到哪个步骤了。


📊 模式对比一览

模式 输出内容 适用场景
messages 增量 token + 元数据 聊天打字机效果
updates(默认) 每个节点(model/tools)产生的增量消息 监控 Agent 执行步骤
values 每一步的完整状态 状态持久化、快照
tasks 任务开始/结束事件 任务生命周期监控
debug tasks 基础上加时间戳和类型 深度调试
checkpoints 检查点创建时触发 工作流恢复、分布式
custom 工具内 writer 自定义数据 进度反馈、自定义日志

🧠 进阶技巧与避坑指南

  1. 结构化输出与工具调用的顺序:在系统提示词中,如果先要求结构化输出,Agent 可能提前结束,导致后续工具不再调用。建议把"生成结构化报告"放在最后一步。
  2. ToolStrategy 的伪工具消息 :即使你没有真正定义那个工具,LangChain 也会在消息历史中插入一条 ToolMessage。如果你不在意历史记录里的细节,可以通过 tool_message_content 精简它。
  3. 错误重试的代价 :开启 handle_errors=True 会消耗额外 token,如果对数据质量要求极高且不介意成本,可以保持;否则可关闭并自己捕获异常。
  4. ProviderStrategy vs ToolStrategyProviderStrategy 更高效(少一轮工具调用),但要求模型支持原生 response_format;不确定时直接用 ToolStrategy 最稳妥。

总结

LangChain Agent 的高级用法远不止"调用工具"。通过:

  • 命名系统提示词管理身份与行为
  • 结构化输出response_format)获取类型安全的结果
  • 流式模式stream_mode)实现实时交互与进度监控

你能让 Agent 从"黑盒"变成"可观测、可控制"的可靠组件。希望这篇文章能帮你在实际项目中灵活运用这些特性,构建更强大的 AI 应用。

如果觉得有用,欢迎点赞收藏,也欢迎在评论区聊聊你的 Agent 实战经验! 🚀


扩展阅读LangChain Agents API 官方文档

相关推荐
武子康2 小时前
Ask/Allow 不是安全边界:企业 Coding Agent 必须建立四层治理(Policy / Scoped Credential / Sandbox / Provenance)
人工智能·后端·agent
wWYy.2 小时前
如何设计多Agent的协作与动态切换机制?
人工智能·agent
怕浪猫3 小时前
第7章 多智能体协作:从单兵作战到群体智能
openai·agent·ai编程
神奇霸王龙3 小时前
Claude Code 三层架构Subagent并发优化实战
人工智能·ai·架构·agent·ai编程·并发·claude
phltxy3 小时前
LangGraph智能租房助手实践
大数据·人工智能·python·深度学习·语言模型·langchain
枫叶丹43 小时前
Codex Hooks 实战:给 AI 工作流增加确定性门禁
人工智能·chatgpt·agent·codex
安逸sgr3 小时前
Agent经典面试题:Agent 安全问题有哪些?如何防止工具误调用和 Prompt Injection?
人工智能·ai·agent·智能体
AINative软件工程3 小时前
LLM 生产环境的 Prompt 注入防御工程实践:5 层防护体系与真实攻防案例
llm·ai编程
Esaka_Forever3 小时前
LangChain RunnableSequence 获取中间输出的几种方案(替代SequentialChain获取中间结果)
langchain