LangChain 实战:Agent 4类结构化输出方式

一、Model vs Agent结构化输出

二、结构化输出的 4 种策略

LangChain 的 create_agent 会自动处理结构化输出。

用户设置所需的结构化输出模式,当模型生成结构化数据时,系统会将其捕获、验证,并返回到Agent 状态中的 'structured_response'

Python 复制代码
def create_agent(
    ...
    response_format: Union[
        ToolStrategy[StructuredResponseT],
        ProviderStrategy[StructuredResponseT],
        type[StructuredResponseT],
        None,
    ]
)

三、Response format

当直接传入一个 Schema 类型时,LangChain 会自动选择:

  • 如果选用的模型与模型服务商支持原生结构化输出 ,则使用 ProviderStrategy(例如 OpenAI、Anthropic、xAI,)
  • 其余所有模型,一律使用 ToolStrategy****(推荐)

JSON Schema 字典必须显式包裹在策略对象(****ProviderStrategy 或 **ToolStrategy****)内,**如果直接传给 response_format,不会被自动识别

四、Provider strategy

一些模型提供商通过其API原生支持结构化输出(例如OpenAI、xAI(Grok)、Gemini、Anthropic(Claude))

Python 复制代码
class ProviderStrategy(Generic[SchemaT]):
    schema: type[SchemaT]
    strict: bool | None = None

The strict param requires langchain>=1.2.

参数schema:必选

schema支持一下四种结构化输出定义:

  • Pydantic models :继承自 BaseModel 的子类,自带字段校验。返回经过校验的 Pydantic 实例对象
  • Dataclasses:带类型注解的 Python 数据类。返回字典(dict)
  • TypedDict:类型化字典类。返回字典(dict)
  • JSON Schema :遵循 JSON Schema 规范的字典。顶层必须包含 title 和 description 两个键。返回字典(dict)

例如:

Python 复制代码
class ContactInfo(BaseModel):
    """用户的联系方式"""
    name: str = Field(description="用户姓名")
    email: str = Field(description="用户邮箱地址")
    phone: str = Field(description="用户的手机号")

# 3.agent初始化
agent = create_agent(
    model=model,
    #response_format=ContactInfo  # 自动选择 ProviderStrategy
    response_format=ProviderStrategy(ContactInfo)
)
# 4.调用
response = agent.invoke({
    "messages": [HumanMessage("从这段话中抽取结构化信息:吴老狗的邮箱地址为:wu-old-dog@qq.com,手机号:19999999999")]
    })

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

五、Tool calling strategy

5.1 定义

对于不支持原生结构化输出的模型,LangChain 通过调用工具来实现相同的效果。

该方法适用于所有支持工具调用的模型(大多数现代模型)。

要使用此策略,配置一个 ToolStrategy即可

Python 复制代码
class ToolStrategy(Generic[SchemaT]):
    schema: type[SchemaT]
    tool_message_content: str | None
    handle_errors: Union[
        bool,
        str,
        type[Exception],
        tuple[type[Exception], ...],
        Callable[[Exception], str],
    ]

5.2 参数

(1)参数schema:必选

schema支持一下五种结构化输出定义:

  • Pydantic models :继承自 BaseModel 的子类,自带字段校验。返回经过校验的 Pydantic 实例对象。
  • Dataclasses:带有类型注解的 Python 数据类。返回字典(dict)
  • TypedDict:类型化字典类。返回字典(dict)
  • JSON Schema :遵循 JSON Schema 规范的字典。顶层必须包含 title 和 description 键。返回字典(dict)
  • Union types:联合类型,支持多种 Schema 选项。模型会根据上下文选择最合适的 Schema。

(2)参数handle_errors

结构化输出校验失败时的错误处理策略。默认值为 True。

  • True:捕获全部异常,使用内置默认错误提示模板
  • str:捕获全部异常,使用该自定义字符串作为错误提示
  • type[Exception]:仅捕获指定这一类异常,使用默认错误提示
  • tuple[type[Exception], ...]:仅捕获元组内列举的多种异常,使用默认错误提示
  • Callable[[Exception], str]:自定义回调函数,入参为异常对象,返回错误提示字符串
  • False:不进行重试,直接向上抛出异常

5.3 案例

5.3.1 Pydantic models

Python 复制代码
from pydantic import BaseModel, Field
from typing import Literal
from langchain.agents import create_agent
from langchain.agents.structured_output import ToolStrategy


class ProductReview(BaseModel):
    """Analysis of a product review."""
    rating: int | None = Field(description="The rating of the product", ge=1, le=5)
    sentiment: Literal["positive", "negative"] = Field(description="The sentiment of the review")
    key_points: list[str] = Field(description="The key points of the review. Lowercase, 1-3 words each.")

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

result = agent.invoke({
    "messages": [{"role": "user", "content": "Analyze this review: 'Great product: 5 out of 5 stars. Fast shipping, but expensive'"}]
})
rprint(result["structured_response"])

5.3.2 dataclass

5.3.3 TypedDict

5.3.4 JSON Schema

JSON 复制代码
product_review_schema = {
    "title": "ProductReview",
    "type": "object",
    "description": "Analysis of a product review.",
    "properties": {
        "rating": {
            "type": ["integer", "null"],
            "description": "The rating of the product (1-5)",
            "minimum": 1,
            "maximum": 5
        },
        "sentiment": {
            "type": "string",
            "enum": ["positive", "negative"],
            "description": "The sentiment of the review"
        },
        "key_points": {
            "type": "array",
            "items": {"type": "string"},
            "description": "The key points of the review"
        }
    },
    "required": ["sentiment", "key_points"]
}

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

5.3.5 Union Types

Python 复制代码
class ProductReview(BaseModel):
    """商品评论分析结果。"""
    rating: int | None = Field(description="商品的评分,取值范围1‑5分", ge=1, le=5)
    sentiment: Literal["positive", "negative"] = Field(description="评论的情感倾向")
    key_points: list[str] = Field(description="评论的核心要点。全部小写,每条1‑3个单词。")


class CustomerComplaint(BaseModel):
    """客户针对产品或服务提出的投诉。"""
    issue_type: Literal["product", "service", "shipping", "billing"] = Field(description="问题类型")
    severity: Literal["low", "medium", "high"] = Field(description="投诉严重等级")
    description: str = Field(description="对投诉内容的简短描述")


agent = create_agent(
    model=model,
    response_format=ToolStrategy(Union[ProductReview, CustomerComplaint])
)

5.4 自定义工具的返回值

5.5 错误处理

5.5.1 多结构化输出错误处理

当model错误地调用多个结构化输出工具时,agent 会通过 ToolMessage 提供错误反馈,并提示模型重试:

Python 复制代码
class ContactInfo(BaseModel):
    name: str = Field(description="人名")
    email: str = Field(description="邮箱地址")

class EventDetails(BaseModel):
    event_name: str = Field(description="事件名")
    date: str = Field(description="事件时间")

agent = create_agent(
    model=model,
    # Default: handle_errors=True
    response_format=ToolStrategy(Union[ContactInfo, EventDetails])
    # 两种同等效果
    response_format=ToolStrategy(Union[ContactInfo, EventDetails],
                             handle_errors = MultipleStructuredOutputsError
)

result = agent.invoke({
    "messages": [{"role": "user", "content": "提取信息:吴老狗(dog@email.com)将于 3 月 15 日 在杭州举办养狗大会"}]
})

handle_errors=False,直接报错

5.5.2 处理多种异常类型

如果 handle_errors 是一个异常元组,代理仅在抛出的异常属于指定类型时才会重试(使用默认错误消息)。

在所有其他情况下,异常将被正常抛出。

Python 复制代码
class ProductRating(BaseModel):
    """商品评论分析结果。"""
    rating: str | None = Field(description="评分范围 1 到 5 分", ge=1, le=5)
    comment: int = Field(description="评审意见")

agent= create_agent(
    model=model,
    # Default: handle_errors=True
    response_format = ToolStrategy(ProductRating,handle_errors = (ValueError, TypeError)
                                   ),
    system_prompt="你是一个用于解析产品评论的实用助手。**不得编造任何字段和数值。**"
)

result= agent.invoke({
    "messages": [{"role": "user", "content": "解析这个:很棒的产品,满分 10 分!"}]
})

六、小结

  • 核心机制 :create_agent 通过 response_format 参数接管结构化输出,最终结果统一存放在状态的 structured_response 字段中。
  • 四种策略 :
    • 直接传 Schema(懒人包):LangChain 自动根据模型能力在 Provider 和 Tool 之间二选一,日常开发首选。
    • ProviderStrategy(原生效能):调用模型厂商的原生 API 能力(如 OpenAI/Claude),性能和准确率最高。
    • ToolStrategy(万金油):把 Schema 伪装成工具调用,兼容所有支持 Function Call 的模型。
    • None(摆烂模式):不强制要求结构化,模型爱咋输出咋输出。
  • Schema 定义 :支持 Pydantic、Dataclass、TypedDict、JSON Schema,甚至 Union 联合类型(让模型自己判断该用哪个)。

搞懂了结构化输出,你的 Agent 才算真正"能干活"。

如果这篇干货帮你少踩了几个坑,欢迎点赞、在看、转发 三连!关于结构化输出,你还有哪些想深挖的实战场景?欢迎在评论区留言交流~

相关推荐
m4Rk_1 小时前
【论文阅读】Agent 记忆机制(83):Inside Out——用可演化 PersonaTree 构建 Agent 的核心长期记忆
论文阅读·人工智能·学习·开源·github
运行时异常1 小时前
【WMS 仓储系统集成 AI Agent 实战】第 8 讲(终篇):生产部署与并发安全——Semaphore 放进 Flux.defer 的坑,压测抓了一晚上
人工智能·安全
杨杨杨大侠1 小时前
Jev、Kev、Laya:决策模型怎么选,什么时候需要微调?
人工智能·python·agent
代码方舟1 小时前
零信任架构实战:基于天远人企关联构建自动化供应链金融网关
运维·人工智能·架构·自动化
虹科网络安全2 小时前
“顶会”看安全(十八):超越越狱:揭示由能力边界模糊引发的 LLM 应用安全风险
人工智能·安全
Maiko Star2 小时前
* LangChain 提示词模板详解:ChatPromptTemplate 的使用与高级特性
java·人工智能·langchain
鬓戈2 小时前
Rust 语言与 AI 应用生态调研及学习路径
人工智能·学习·rust
天远API2 小时前
零信任架构实战:基于天远人企关联构建自动化图谱网关
网络·人工智能·架构·自动化
爱吃提升2 小时前
文生视频模型发展趋势(2026)
人工智能·音视频
AIGS0012 小时前
什么是本体语义平台?和知识图谱、传统数据中台的区别在哪
人工智能·知识图谱·数据中台·ai问数·本体语义平台·智能数据中台