当前位置:首页 > 文章列表 > 科技周边 > 人工智能 > LangChain structured output 怎样固定工具返回 schema

LangChain structured output 怎样固定工具返回 schema

来源:17golang原创 2026-11-01 03:29:24 0浏览 收藏

如果 agent 调用工具后仍然返回一段不稳定的自然语言,问题通常不在“提示词写得不够长”,而在 schema 绑定错了位置。LangChain 里至少有两个边界:工具的输入参数 schema,以及 agent 最终交给业务代码的结构化响应。要固定后者,应把 Pydantic 模型交给 response_format,需要明确走工具调用时使用 ToolStrategy,再从结果的 structured_response 读取。

官方地址:https://docs.langchain.com/

下面用一个订单查询工具作为例子。示例中的指标是用于设计验收的基线,不代表 LangChain 官方性能承诺。

先把两个 schema 边界分开

工具参数描述“模型怎样调用工具”,例如订单号是什么类型;结构化响应描述“agent 最终交给应用的结果”,例如订单状态、是否需要人工处理和解释。只给工具函数写返回类型,并不会自动把整个 agent 的最终输出固定成这个类型。

边界绑定位置业务代码读取
工具输入类型注解或 args_schema工具函数参数
agent 最终结果response_format + Pydanticstate["structured_response"]
LangChain 工具输入 schema 与 agent 结构化响应的边界关系图
图1:结构说明图,展示工具输入 schema 与 agent 最终响应 schema 的两条边界,不是运行截图。

用 Pydantic 把业务结果写成可校验结构

先定义一个足够小的结果模型。字段描述会进入模型可见的 schema,枚举和范围约束则让错误结果有明确的修正方向。

from typing import Literal

from pydantic import BaseModel, Field


class OrderDecision(BaseModel):
    """订单查询后交给业务层的固定结果。"""

    order_id: str = Field(description="用户提供的订单号")
    status: Literal["pending", "paid", "shipped", "cancelled"]
    needs_human: bool = Field(description="是否需要人工跟进")
    reason: str = Field(description="给业务人员看的简短原因")


# 约束写在模型中,后续的 agent 不必依赖字符串解析。
print(OrderDecision.model_json_schema()["properties"].keys())

这里的 Literal 限制状态集合,needs_human 明确为布尔值。不要为了“兼容模型”把所有字段都改成字符串,否则结构看似固定,业务层仍要二次猜测。

用 ToolStrategy 固定 agent 的最终响应

当模型支持工具调用、但不一定支持 provider-native structured output 时,显式使用 ToolStrategy 最直观。工具只负责查数据,response_format 负责把 agent 的最终结果收口。

from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy


def lookup_order(order_id: str) -> str:
    """按订单号查询脱敏后的订单状态。"""
    # 示例返回固定文本;真实项目应在这里访问订单服务并处理超时。
    return f"订单 {order_id} 已发货,物流单号为 SF123456"


agent = create_agent(
    model="openai:gpt-5.5",
    tools=[lookup_order],
    response_format=ToolStrategy(OrderDecision),
    system_prompt=(
        "你是订单助手。只能根据工具返回的信息填写 schema,"
        "不能补造订单号、状态或物流事实。"
    ),
)

result = agent.invoke({
    "messages": [{
        "role": "user",
        "content": "查询订单 A-1007 的状态,并告诉我是否需要人工处理。"
    }]
})

# 业务层读取结构化对象,而不是解析最后一条自然语言消息。
decision = result["structured_response"]
print(decision.order_id, decision.status, decision.needs_human)

这个组合形成两步约束:模型先按工具定义生成调用参数,工具执行后再按 OrderDecision 生成唯一的结构化响应。若模型或 provider 不支持原生结构化输出,LangChain 会用工具调用策略完成这一步。

让校验失败反馈给模型,而不是静默吞掉

ToolStrategy 默认会处理结构化输出错误。生产代码可以把提示改成业务语言,让重试针对字段约束,而不是无限重复同一个请求。

from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy


agent = create_agent(
    model="openai:gpt-5.5",
    tools=[lookup_order],
    response_format=ToolStrategy(
        schema=OrderDecision,
        # 只说明如何修正格式,不把业务事实写死在错误提示里。
        handle_errors="请重新输出单个 OrderDecision:status 必须是允许的四个值,needs_human 必须是布尔值。",
        tool_message_content="订单结果已按固定 schema 整理。",
    ),
)

# 真实项目应记录重试次数,避免把模型错误变成无上限成本。
result = agent.invoke({
    "messages": [{"role": "user", "content": "查询订单 A-1007"}]
})
print(result["structured_response"].model_dump())

如果应用希望所有异常直接抛出,可以把 handle_errors 设为 False;如果只想捕获某一类异常,也可以传入异常类型或自定义处理函数。注意:重试只能修正结构,不会替你验证订单服务返回的事实。

LangChain structured output schema 校验失败后反馈并重试的流程图
图2:结果说明图,展示 schema 校验失败、错误反馈与重新生成结构化结果的静态链路,不是运行截图。

用一组小指标判断 schema 是否真的稳定

可以把验收拆成三项,而不是只看“这次返回成功”。例如对一组包含已发货、待付款和信息不足的固定样例,记录结构通过率、人工兜底率和平均重试次数:

指标基线写法目标判断
结构通过率自然语言 + 手写解析应接近全部样例都能通过模型校验
人工兜底率字段缺失时靠业务猜测只在事实缺失或规则冲突时触发
平均重试次数默认提示不记录按模型、字段约束和输入类型分组观察

不要把“结构通过率提高”直接等同于“答案正确”。schema 只能保证形状、类型和部分范围;订单状态是否真实,仍要由工具服务、权限和业务规则负责。

工具多、模型能力不同的时候怎么选

如果模型供应商原生支持结构化输出,可以直接传 schema 类型,让 LangChain 自动选择 provider strategy;需要兼容更多支持 tool calling 的模型时,显式使用 ToolStrategy。当 agent 同时绑定普通工具和结构化响应时,模型还必须支持两者并用。

最后记住三个边界:

  • 工具的返回字符串不是最终 schema;要固定 agent 结果,就配置 response_format。
  • structured_response 是结果读取入口,不能再从自然语言消息中二次正则解析。
  • 多个结构化结果、字段校验失败和真实业务事实错误是三类问题,应分别记录和处理。

常见问题

只给工具函数加返回类型可以吗? 可以帮助阅读和静态检查,但不能替代 agent 的 response_format。

为什么用了 Pydantic 仍然会重试? Pydantic 负责校验结果;模型第一次生成的字段仍可能越界或缺失,handle_errors 会把错误反馈给模型。

工具本身也需要输入 schema 怎么办? 给工具参数添加类型注解,或使用 args_schema 绑定一个独立的 Pydantic 输入模型;它和最终响应模型可以不同。

版本声明
本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
vLLM continuous batching 的请求调度观察点vLLM continuous batching 的请求调度观察点
上一篇
vLLM continuous batching 的请求调度观察点
OpenAI Responses API 的 tool call 状态怎样串联
下一篇
OpenAI Responses API 的 tool call 状态怎样串联
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • PubMedQA数据集详解:生物医学问答基准、功能与应用指南
    PubMedQA
    深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
    820次使用
  • H2O EvalGPT:开源LLM大模型评估与排行榜工具
    H2O EvalGPT
    H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
    811次使用
  • LMArena是什么?伯克利AI模型评估平台使用指南与功能解析
    LMArena
    LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
    903次使用
  • 斯坦福HELM:大语言模型Holistic Evaluation整体评估框架详解
    HELM
    深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
    873次使用
  • MMBench详解:多模态大模型基准测试、功能特点与使用指南
    MMBench
    MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
    695次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议 和 隐私政策
返回登录
  • 重置密码