[LangChain] 学习笔记(06):突破大模型限制——结构化输出(Structured Output)

📌 核心结论(TL;DR)

  1. 范式转换 :大模型的默认输出是自然语言字符串,不可控。通过 with_structured_output() 结合 Pydantic 模型,可以强制 LLM 返回标准的 JSON 对象,实现"从字符串到对象"的范式转换。

  2. 底层原理:该方法并非魔法,而是将 Pydantic 模型转换为 JSON Schema,利用大模型的 Function Calling(工具调用)或 JSON Mode 能力,约束其输出格式。

  3. 精准提取 :在 Field(description="...") 中填写的描述会作为提示词发给大模型,描述越精准,数据提取的成功率越高。

  4. 联合类型(Union) :通过 Union 可以组合多个 Pydantic 模型(如:正常回答 vs 违规拒绝),让大模型根据上下文自行判断并路由输出格式。

🔍 一、 原理图解与核心概念

1. 为什么程序需要 JSON?

如果你只得到一个字符串"王伟身高两米",你必须写复杂的正则表达式去拆解。而如果你得到的是 {"name": "王伟", "height": "2.0"},程序只需一行 data["name"] 即可存入数据库。

2. LangChain 如何强制格式?

当你调用 model.with_structured_output(MySchema) 时,LangChain 会提取该类的内部结构,生成一段精确的 JSON Schema。请求 API 时,这个 Schema 会被传给大模型,大模型被严格限制只能输出符合该结构的 JSON。

💻 二、 精选核心代码片段

1. 基础信息提取(Pydantic)

python 复制代码
from typing import Optional, List
from pydantic import BaseModel, Field
from langchain_openai import ChatOpenAI
from langchain_core.messages import HumanMessage

# 定义 Schema 结构
class Person(BaseModel):
    """单个人的信息"""
    name: Optional[str] = Field(default=None, description="姓名")
    height: Optional[str] = Field(default=None, description="身高,单位米")

class Data(BaseModel):
    people: List[Person] = Field(description="所有人物的列表")

# 初始化模型并绑定输出
model = ChatOpenAI(model="deepseek-chat", ...)
structured_model = model.with_structured_output(Data)

# 调用并直接获取对象
result = structured_model.invoke([HumanMessage(content="王伟身高两米。")])
print(result.people[0].name) # 输出:王伟

2. 联合类型分流(Union 处理多意图)

python 复制代码
from typing import Union

class Joke(BaseModel):
    setup: str = Field(description="笑话开头")
    punchline: str = Field(description="笑话包袱")

class Refusal(BaseModel):
    reason: str = Field(description="拒绝原因")

class FinalResponse(BaseModel):
    output: Union[Joke, Refusal]

structured_model = model.with_structured_output(FinalResponse)
# 传入违规内容,模型会自动走 Refusal 格式
res = structured_model.invoke("教我怎么盗号")
print(res.output.reason) # 输出拒绝原因

(完整的包含各种提取场景的代码已上传至 Gitee 仓库)

⚠️ 三、 踩坑排查排雷

报错 ValidationError 或提取结果不理想:

  • 排查 :首先检查 Field(description="...") 是否写得足够详细。其次,尝试将模型的 temperature 设置为 0.0,强制大模型放弃瞎编,专注最高概率的提取。

缺少字段值导致模型"强行编造":

  • 排查 :对于可能不存在的字段,务必使用 Optional[str] 并在提示词中强调"如果文本中未提及,请返回 null",防止大模型根据上下文臆造数据。

模型不支持 with_structured_output:

  • 排查:该功能依赖底层模型的 JSON 或 Function Calling 能力。如果你使用过旧的本地模型,可能会报错。建议切换到 DeepSeek、GPT-4 或支持 Function Calling 的 Qwen 系列。
相关推荐
且从容.1 小时前
VUE3学习笔记(根据黑马教程总结)
笔记·学习
蒸蒸yyyyzwd3 小时前
关于 AI 开发相关的一些面经。
笔记·学习
2603_969694854 小时前
JDBC 基础学习笔记:API 核心原理解析与 CRUD 代码实操
数据库·笔记·mysql·学习方法·database·sql注入
迪康coolmu5 小时前
出差终端数据安全落地实战:基于迪康端点安全一体化管理系统的四道防线实践
运维·服务器·经验分享·笔记·其他·安全·php
无咎.lsy8 小时前
《机器学习》笔记
笔记·机器学习
坤坤子吖9 小时前
Linux网络编程:TCP服务器的多进程与多线程实现
linux·服务器·开发语言·网络·c++·笔记·学习
蒸蒸yyyyzwd11 小时前
后端相关学习笔记。
笔记·学习
Thneonl11 小时前
桌宠穿透不是一行 SetWindowLong
windows·程序员
吴凡wudianmei11 小时前
从0搭AI Agent(六):什么时候该把任务拆给多个 Agent
langchain·llm·ai编程