Structured output | 产品经理学Langchian

内容纲要

概述

LangChain 的结构化输出功能允许智能体(Agent)以特定、可预测的格式返回数据,无需解析自然语言响应,直接生成 JSON 对象、Pydantic 模型或数据类(dataclasses)等可被应用直接使用的结构化数据。其核心通过 <code>create_agent</code> 函数自动处理,用户仅需设置期望的结构化输出 schema,模型生成数据后会被捕获、验证,并最终存储在智能体状态的 structured_response键中。

本质是告诉智能体 “以什么格式返回结构化数据”。在 LangChain 中,智能体默认可能返回自然语言文本(需手动解析),而通过参数配置后,智能体可直接生成符合预设格式的结构化数据(如 Pydantic 模型实例、JSON 对象),并自动完成验证,最终存储在智能体状态的 <code>structured_response</code> 键中,供应用直接调用(无需解析自然语言)。

响应格式

在 LangChain 结构化输出(Structured Output)体系中,“响应格式” 是核心配置项,用于定义智能体(Agent)如何生成、组织和返回结构化数据,直接决定了输出是否符合应用需求(如能否被直接解析为 JSON、Pydantic 模型等)。

响应格式(<code>response_format</code>)是 <code>create_agent</code> 函数的关键参数,其本质是为智能体提供 “结构化输出的规则手册”

  • 替代 “自然语言响应”:避免后续手动解析非结构化文本(如从句子中提取字段),直接生成可机器读取的格式(JSON、模型实例等);
  • 统一输出标准:通过预设规则确保每次输出的字段、类型、约束(如数值范围)一致;
  • 衔接策略逻辑:不同格式类型对应不同的实现方案(原生功能 / 工具调用),适配不同能力的模型。

响应格式控制智能体返回结构化数据的方式,共支持四种类型,且会根据模型能力自动选择最优策略:

格式类型 完整表达式 核心逻辑 适用场景
工具调用策略 <code>ToolStrategy[StructuredResponseT]</code> 借助模型的 “工具调用能力” 模拟结构化输出:智能体通过调用预设工具,将结构化数据封装为工具调用结果返回 模型不支持原生结构化输出,但支持工具调用(如大部分开源模型 Llama 3、Mistral,或部分闭源模型)
提供商原生策略 <code>ProviderStrategy[StructuredResponseT]</code> 利用模型厂商 API 自带的结构化输出功能(如 OpenAI 的 <code>response_format</code> 参数、Anthropic 的结构化生成能力),由厂商直接保证格式正确性 模型支持原生结构化输出(如 OpenAI GPT-4/5、Anthropic Claude 3、Grok、Gemini)
Schema 类型直传 <code>type[StructuredResponseT]</code> 直接传入结构化数据的 “格式模板”(如 Pydantic 模型类、dataclass 类),LangChain 自动判断模型能力并选择最优策略(原生 / 工具) 所有场景,推荐优先使用(简化配置,无需手动判断模型能力)
无结构化输出 <code>None</code> 不启用结构化输出,智能体返回常规自然语言文本,无 <code>structured_response</code> 键 无需机器解析输出,仅需人类可读文本的场景(如闲聊、通用问答)

Provider strategy 提供商策略

在上面提到的几种类型中,若大模型本身支持结构化输出,则可以使用“Provider strategy 提供商策略”。代码层面需要使用进行声明,如下:

class ProviderStrategy(Generic[SchemaT]):
    schema: type[SchemaT]

在声明中,提到了Scheme的概念;下面将介绍schema及其类型。

什么是schema

<code>schema</code> 本质是一份 “结构化输出的规则说明书”,它告诉智能体两件关键事:

  1. “输出什么”:必须包含哪些字段(如 “联系人信息” 需包含 <code>name</code>、<code>email</code>、<code>phone</code>);
  2. “怎么输出才对”:字段的类型(如 <code>name</code> 是字符串、<code>rating</code> 是整数)、约束规则(如 <code>rating</code> 必须在 1-5 之间、<code>email</code> 需符合邮箱格式)。

有了 <code>schema</code>,智能体生成的结构化数据就会 “有章可循”,避免出现 “字段缺失”“类型错误”“数值超出范围” 等问题,最终输出能被应用直接使用的规范数据(无需额外解析或修正)。

4 种支持的 schema类型

LangChain 支持 4 种主流的 <code>schema</code> 定义方式,覆盖不同开发习惯(如 “追求强验证”“追求简洁”“需兼容 JSON 生态”),具体如下:

Pydantic models(Pydantic 模型):强验证、最推荐

from pydantic import BaseModel, Field, EmailStr  # 导入Pydantic核心类

# 定义“联系人信息”的schema(Pydantic模型)
class ContactInfo(BaseModel):
  &quot;&quot;&quot;联系人信息的结构化输出格式&quot;&quot;&quot;  # 模型描述(可选,提升可读性)
  name: str = Field(description=&quot;联系人姓名,必填&quot;, min_length=1)  # 字符串,至少1个字符
  email: EmailStr = Field(description=&quot;联系人邮箱,需符合邮箱格式(如xxx@xxx.com)&quot;)  # 邮箱格式验证
  phone: str | None = Field(description=&quot;联系人电话,可选(如无则为None)&quot;, default=None)  # 可选字段,默认None
  age: int = Field(description=&quot;联系人年龄,18-60岁之间&quot;, ge=18, le=60)  # 整数,18≤age≤60

其通过 <code>Field</code> 对字段进行类型声明 + 详细验证规则(如数值范围、格式校验、必填 / 可选),是 LangChain 中最推荐的 <code>schema</code> 类型。适用于需要严格验证字段规则的场景(如用户信息提取、产品评分解析、表单数据生成),是 LangChain 结构化输出的 “首选方案”。

支持几十种内置验证规则(如数值范围 <code>ge=1, le=5</code>、邮箱格式 <code>EmailStr</code>、字符串长度 <code>min_length=3</code>),能从源头过滤无效数据;可通过字段描述(<code>description</code>)明确字段含义,帮助模型更准确理解需求。

Dataclasses(Python 数据类):简洁、轻量

from dataclasses import dataclass  # 导入Python内置的dataclass

# 定义“产品信息”的schema(数据类)
@dataclass
class ProductInfo:
    &quot;&quot;&quot;产品信息的结构化输出格式&quot;&quot;&quot;
    product_name: str  # 字符串类型(仅声明类型,无额外验证)
    price: float       # 浮点型(如19.99)
    in_stock: bool     # 布尔型(True=有货,False=缺货)
    category: str | None = None  # 可选字段,默认None

通过类型注解声明字段类型,不支持复杂验证(仅基础类型检查,如 “是否为整数”),特点是 “简洁、无需额外安装依赖”。

TypedDict(类型字典):兼容字典、强类型

from typing import TypedDict, Optional  # 导入Python内置的TypedDict

# 定义“订单信息”的schema(类型字典)
class OrderInfo(TypedDict):
    &quot;&quot;&quot;订单信息的结构化输出格式&quot;&quot;&quot;
    order_id: str                # 订单ID(字符串,必填)
    total_amount: float          # 订单总金额(浮点型,必填)
    is_paid: bool                # 是否支付(布尔型,必填)
    shipping_address: Optional[str]  # 收货地址(可选,值为字符串或None)

基于 Python 标准库 <code>typing.TypedDict</code> 的类,本质是 “带类型注解的字典”—— 既保留字典的灵活性(可通过键值对访问),又通过类型注解约束 “键的名称” 和 “值的类型”,不支持字段验证(仅类型检查)。

JSON Schema(JSON 模式):跨语言、通用

# 定义“文章信息”的schema(JSON Schema字典)
ArticleSchema = {
    &quot;$schema&quot;: &quot;http://json-schema.org/draft-07/schema#&quot;,  # 声明遵循的JSON Schema版本
    &quot;type&quot;: &quot;object&quot;,  # 整体是一个对象(对应Python的字典)
    &quot;title&quot;: &quot;文章信息的结构化输出格式&quot;,
    &quot;properties&quot;: {  # 定义字段(键)及其规则
        &quot;title&quot;: {
            &quot;type&quot;: &quot;string&quot;,  # 字段类型:字符串
            &quot;description&quot;: &quot;文章标题,必填&quot;,
            &quot;minLength&quot;: 5  # 字符串至少5个字符
        },
        &quot;author&quot;: {
            &quot;type&quot;: &quot;string&quot;,
            &quot;description&quot;: &quot;文章作者,必填&quot;
        },
        &quot;word_count&quot;: {
            &quot;type&quot;: &quot;integer&quot;,
            &quot;description&quot;: &quot;文章字数,必填,且≥100&quot;,
            &quot;minimum&quot;: 100  # 数值最小为100
        },
        &quot;tags&quot;: {
            &quot;type&quot;: &quot;array&quot;,  # 字段类型:数组
            &quot;description&quot;: &quot;文章标签,可选,每个标签是字符串&quot;,
            &quot;items&quot;: {&quot;type&quot;: &quot;string&quot;}  # 数组元素必须是字符串
        }
    },
    &quot;required&quot;: [&quot;title&quot;, &quot;author&quot;, &quot;word_count&quot;],  # 声明必填字段
    &quot;additionalProperties&quot;: False  # 不允许出现schema中未定义的额外字段
}

基于 JSON 格式的 “模式描述字典”,遵循 JSON Schema 规范,通过键(如 <code>type</code>、<code>properties</code>、<code>required</code>、<code>minimum</code>)定义字段的类型、约束和结构,是跨语言通用的 schema 格式(不仅 Python,Java、JavaScript 等都支持)。

Tool calling strategy 工具调用策略

“工具调用策略” 是针对不支持原生结构化输出的模型设计的核心方案,让模型生成符合预设格式的结构化数据。当模型不支持厂商原生结构化输出(如大部分开源模型 Llama 3、Mistral,或部分闭源模型),但支持 “工具调用” 功能时,LangChain 会将 “结构化输出” 包装成一个 “虚拟工具”—— 模型通过调用这个 “工具”,将结构化数据以 “工具参数” 的形式返回,再由 LangChain 解析、验证后,转化为最终的结构化结果(如 Pydantic 模型实例)。

简单来说:工具调用策略 = 用 “工具调用” 的通用能力,模拟 “结构化输出” 的专属效果,实现 “让更多模型具备结构化输出能力” 的兼容性目标。

代码层面,要使用此策略,请配置一个<code>ToolStrategy</code>:

class ToolStrategy(Generic[SchemaT]):
    schema: type[SchemaT]  # 必需:结构化输出的格式规则(schema)
    tool_message_content: str | None  # 可选:生成结构化输出后的自定义反馈消息
    handle_errors: Union[bool, str, type[Exception], tuple[type[Exception], ...], Callable[[Exception], str]]  # 可选:错误处理策略

在代码中,可以看见三个重要参数:schema、tool_message_content、handle_errors。

schema 模式

schema<code> 的作用与 Provider Strategy 中的 </code>schema<code> 完全一致 —— 定义结构化输出的 “字段、类型、约束”,是智能体判断 “输出是否正确” 的核心依据。支持的 </code>schema` 类型与 Provider Strategy 相同,覆盖主流格式需求:

  • Pydantic 模型(<code>BaseModel</code> 子类,带字段验证,如 <code>rating: int = Field(ge=1, le=5)</code>);
  • Python 数据类(<code>@dataclass</code> 装饰,带类型注解,如 <code>product_name: str</code>);
  • TypedDict(类型化字典,如 <code>class OrderInfo(TypedDict): order_id: str</code>);
  • JSON Schema(字典格式的 JSON 规范,如 <code>{"type": "object", "properties": {"name": {"type": "string"}}}</code>);
  • Union 类型(工具调用策略独有的灵活能力):允许指定多个 <code>schema</code> 选项(如 <code>Union[ContactInfo, EventDetails]</code>),模型会根据用户输入的上下文,自动选择最匹配的 <code>schema</code> 生成输出。

tool_message_content自定义工具反馈消息

该参数用于自定义 “模型生成结构化输出后” 的反馈内容,默认情况下,反馈消息会显示原始结构化数据(如 <code>Returning structured response: {'name': 'John', 'email': 'john@xxx.com'}</code>);通过该参数可替换为更友好、更贴合业务场景的提示。

核心价值:让工具调用的 “反馈过程” 更符合业务逻辑(如 “行动项已记录到会议笔记”“用户信息已存入数据库”),而非暴露技术细节。示例代码如下:

strategy = ToolStrategy(
    schema=MeetingAction,  # MeetingAction是定义“会议行动项”的Pydantic模型
    tool_message_content=&quot;✅ 会议行动项已捕获并添加到待办列表!&quot;  # 自定义反馈
)

# 调用智能体后,工具反馈消息会显示:
# &quot;✅ 会议行动项已捕获并添加到待办列表!&quot;
# 而非默认的“Returning structured response: {...}”

当然,这一步如果不是在Agent体系内,也可以用工程方法基于大模型返回进行特殊提示文案的处理。

handle_errors错误处理

该参数定义了 “当模型生成的结构化数据不符合 <code>schema</code> 时,如何处理”,是提升结构化输出可靠性的关键配置。支持 5 种配置方式,覆盖不同错误处理需求:

配置类型 具体含义 示例
<code>True</code>(默认) 捕获所有错误,使用 LangChain 内置的默认错误模板提示模型重试 <code>handle_errors=True</code>
字符串(str) 捕获所有错误,使用自定义的固定文本提示模型重试 <code>handle_errors="请确保评分在1-5分,且包含评论!"</code>
异常类型 仅捕获指定类型的错误(其他错误直接抛出),用默认模板提示重试 <code>handle_errors=ValueError</code>(仅处理值错误)
异常元组 仅捕获元组中指定的多种错误,用默认模板提示重试 <code>handle_errors=(ValueError, TypeError)</code>
自定义函数 捕获所有错误,按函数逻辑返回自定义提示(支持根据错误类型差异化处理) 见下文示例
from langchain.agents.structured_output import StructuredOutputValidationError, MultipleStructuredOutputsError

# 自定义错误处理函数:根据错误类型返回不同提示
def custom_error_handler(error: Exception) -&gt; str:
    if isinstance(error, StructuredOutputValidationError):
        return &quot;❌ 格式错误!请检查字段是否完整(如评分需1-5分),重新生成。&quot;
    elif isinstance(error, MultipleStructuredOutputsError):
        return &quot;❌ 仅允许返回1个结构化结果,请删除多余内容后重试。&quot;
    else:
        return f&quot;❌ 未知错误:{str(error)},请重新生成。&quot;

# 配置策略时指定自定义函数
strategy = ToolStrategy(
    schema=ProductRating,
    handle_errors=custom_error_handler
)

代码示例

下面的代码示例将串联起上方提到的参数,还是用代码例子来理解实现细节吧:

from pydantic import BaseModel, Field, EmailStr
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy

# 1. 定义Pydantic模型(强验证schema)
class UserInfo(BaseModel):
    &quot;&quot;&quot;用户信息的结构化输出格式&quot;&quot;&quot;
    username: str = Field(description=&quot;用户名,3-20个字符&quot;, min_length=3, max_length=20)
    email: EmailStr = Field(description=&quot;用户邮箱,需符合格式(如xxx@xxx.com)&quot;)
    age: int | None = Field(description=&quot;用户年龄,18-60岁(可选,无则为None)&quot;, ge=18, le=60)

# 2. 自定义错误处理函数
def error_handler(e: Exception) -&gt; str:
    if isinstance(e, StructuredOutputValidationError):
        return f&quot;格式错!请检查:1. 用户名3-20字符;2. 邮箱格式正确;3. 年龄18-60。详情:{e}&quot;
    return f&quot;未知错:{e},请重新生成!&quot;

# 3. 创建ToolStrategy(配置所有参数)
strategy = ToolStrategy[UserInfo](  # 显式声明泛型,提升可读性
    schema=UserInfo,
    tool_message_content=&quot;✅ 用户信息已验证通过,可用于账号注册!&quot;,
    handle_errors=error_handler
)

# 4. 创建智能体并调用
agent = create_agent(
    model=&quot;llama-3-70b&quot;,  # 不支持原生结构化输出,用ToolStrategy
    tools=[],  # 无真实工具,仅用工具策略实现结构化输出
    response_format=strategy
)

# 5. 调用智能体提取用户信息
result = agent.invoke({
    &quot;messages&quot;: [{&quot;role&quot;: &quot;user&quot;, &quot;content&quot;: &quot;提取用户信息:小明(username: xiaoming123),邮箱xiaoming@test.com,年龄25岁&quot;}]
})

# 6. 输出结果(结构化数据)
print(result[&quot;structured_response&quot;])
# 输出:UserInfo(username=&#039;xiaoming123&#039;, email=&#039;xiaoming@test.com&#039;, age=25)

知识点拆解

模块 关键信息 产品关注
Response Format 参数 <code>response_format=ContactInfo</code>、<code>ToolStrategy(schema=...)</code> PRD 中必须定义输出 schema,明确字段含义、必填程度
ProviderStrategy 模型原生 structured output;自动校验、可靠性高 选择支持度较好的模型,减少二次解析
ToolStrategy 利用 tool calling 返回结构化数据,几乎所有现代模型可用 需考虑 tool message 内容、错误提示语、重试策略
Schema 类型 支持 Pydantic、Dataclass、TypedDict、JSON Schema、Union 输出 schema 可直接复用业务数据模型,便于研发对接
结果获取 <code>result["structured_response"]</code> 即为校验完的对象 需求设计中说明后续系统直接消费该字段
Tool Message <code>tool_message_content</code> 自定义提示,默认展示 structured data 适合低代码场景,让用户看到友好的提示语
Error Handling Default 自动重试;可自定义捕获异常类型或自定义函数 PRD 中说明错误文案、重试次数、容错场景
多结构输出 Union schema 允许在多个结构间选择(如联系人 vs 事件) 需设计判定逻辑及错误反馈,避免多 schema 同时返回
Provider 能力探测 <code>response_format=Schema</code> 时 LangChain 自动判断;也可自定义 profile 明确 fallback 机制,以免切换模型后失效

适用场景(问题 → 方案 → 价值)

  1. 合同要素抽取
    • 问题:法务工具需从自然语言合同中提取签约主体、金额、有效期。
    • 方案:定义 <code>ContractInfo</code> Pydantic 模型并设置为 <code>response_format</code>;模型输出直接进入 <code>structured_response</code>,无须再写解析器。
    • 价值:减少手写解析逻辑,字段缺失能即时通过 schema 校验捕获。
  2. 会议纪要行动项
    • 问题:运维会议需要自动生成任务列表(task/assignee/priority)。
    • 方案:使用 ToolStrategy + 自定义 <code>tool_message_content</code>,确保 UI 展示“Action item captured”而非原始 JSON。
    • 价值:输出结果更友好,可直接同步至任务系统,提升闭环效率。

常见问题(FAQ)

  1. ProviderStrategy 与 ToolStrategy 何时选?→ 模型支持原生 structured output 时优先 Provider;否则使用 ToolStrategy。
  2. 可以同时使用工具和 structured output 吗?→ 可以,但需确认模型支持“Tool + Structured Output”组合。
  3. Schema 更新后如何兼容?→ 版本化 schema,并在 PRD 中记录字段变化;若字段必填需同步调整验证逻辑。
  4. Union schema 如何避免多输出?→ LangChain检测到多 schema 同时返回会报错并提示模型重试;错误文案可自定义。
  5. JSON Schema vs Pydantic 选择?→ Pydantic 便于 Python 项目直接使用;JSON Schema 对跨语言友好。
  6. 能否自定义错误提示?→ <code>handle_errors</code> 支持字符串或函数,覆盖默认提示。
  7. Structured response 与普通 <code>messages</code> 冲突吗?→ 不冲突;结构化数据存在 state 中,同时仍可查看自然语言回答。
  8. 如何调试 schema 校验?→ 在日志中打印 <code>ToolMessage</code> 内容,或暂时关闭 <code>handle_errors</code> 直接抛异常。
  9. 大模型会“编造字段”吗?→ Schema 会强制校验类型/必填;必要时在系统提示强调“禁止杜撰”。
  10. 输出需要国际化吗?→ schema 字段通常英文,若需中文可在后处理阶段转换;关键是保证字段名稳定。

扩展信息

滚动至顶部