Langchain教程四:OutputParser解析与实战

2026-06-20阅读 0热度 0
ai 人工智能

LangChain 的 OutputParser 组件能够高效地将大模型返回的自然语言解析为结构化数据,显著提升开发效率。本文围绕以下核心内容展开:

  • OutputParser 的核心作用与主流类型详解
  • StrOutputParser 的实际操作与代码演示
  • 不同 OutputParser 的选型策略与业务适配建议

Langchain 教程四(OutputParser)

开发者在构建 LLM 应用时,常遇到一个棘手问题:模型输出的是自然语言字符串,但业务系统需要 JSON、字典、列表或 Python 数据类对象。LangChain 提供的 OutputParser 正是解决这一痛点的刚需组件。

OutputParser 是什么?

其实在前面的学习中我们已经接触过 OutputParser,它是 LangChain 专用于将 LLM 返回结果解析为结构化数据的模块。它能将模型输出的纯文本转换为特定数据结构(如 JSON、Dict、Pydantic 模型等),便于后续业务逻辑直接调用。

LangChain 内置了多种常用 OutputParser,以下列出主要类型:

名称是否支持流式是否有格式要求输出类型
StrOutputParserString(纯文本)
JsonOutputParserJSON Object
XMLOutputParserdict
ListOutputParserList[str]
PydanticOutputParserPydantic.BaseModel 对象
YamlOutputParserPydantic.BaseModel 对象

此前我们仅接触过 StrOutputParser,但 LangChain 提供的其他 Parser 各有特色:有的支持流式输出,有的对格式要求严格,有的能直接生成 Python 对象或模型实例。

StrOutputParser

StrOutputParser 用于直接提取纯文本输出。沿用之前的代码示例即可快速理解:


from langchain.prompts import PromptTemplate
from langchain_core.output_parsers import StrOutputParser
from langchain_openai import ChatOpenAI

template = "请将以下内容翻译成{language}:{input}"
prompt = PromptTemplate.from_template(template)

llm = ChatOpenAI(
    model="Qwen/Qwen3-32B",
    openai_api_key="your_key",
    base_url="https://api.siliconflow.cn/v1",
    temperature=0
)

parser = StrOutputParser()

chain = prompt | llm | parser

result = chain.invoke({
    "language": "日文",
    "input": "我是一个中国人"
})

print(result)

JsonOutputParser

JSON 格式是对开发者最为友好的结构化形式之一,以下展示其具体用法:


from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个中文翻译助手,请根据用户的要求翻译内容,请将内容的信息以 JSON 格式返回:original:xxx,translation:xxx"),
    ("user", "请翻译以下内容为英文:{text}")
])

llm = ChatOpenAI(
    model="Qwen/Qwen3-32B",
    openai_api_key="your_key",
    base_url="https://api.siliconflow.cn/v1",
    temperature=0
)

parser = JsonOutputParser()

chain = prompt | llm | parser

result = chain.invoke({
    "text": "我是一名中国人"
})

print(result)

输出结果是一个标准的 dict


{
'original': '我是一名中国人', 
'translation': 'I am a Chinese person.'
}

看起来不错。细心的读者可能已经发现,上面的 prompt 中特意添加了 请将内容的信息以 JSON 格式返回:original:xxx,translation:xxx。那么,能否省去这句指令呢?

直接给出结论:上方示例中不可省略

原因是 JsonOutputParser 的底层实现相当直接——它仅对 LLM 的完整输出执行 json.loads() 调用。因此只要输出符合 JSON 语法:


{
  "original": "你好",
  "translation": "Hello"
}

就能顺利解析。但如果不对模型明确指定格式,它很可能会输出自然语言风格的内容,比如 I am a Chinese,此时 json.loads() 必然报错。

Pydantic

每次在 prompt 中手动编写“请按 JSON 格式返回”显得冗余且扩展性差。有没有更优雅的方案?

当然有。在深入具体操作之前,先介绍 Pydantic

Pydantic = TypeScript + Yup + 自动校验 + 智能提示 + 更高级的 Python 数据模型系统。

对于前端开发者而言,可能熟悉 TypeScript(用类型约束结构)和 Yup/Zod(用 schema 做数据校验)。而 Pydantic 在 Python 中整合了这些功能,且能力更强。

编写 React / Vue 组件时,我们通常定义 props 类型:


type User = {
  name: string;
  age: number;
}

在 Python 中,使用 Pydantic 则类似这样:


from pydantic import BaseModel

class User(BaseModel):
    name: str
    age: int

随后可以这样使用:


user = User(name="张三", age="18")  # 自动将字符串 "18" 转换为整数

user = User(name="张三", age="abc")  # ❌ 抛出异常:age 不是数字

在 LangChain 中,Pydantic 最常见的三种应用场景是:

  1. 描述结构化输出数据的格式
  2. 配合 OutputParser 将 LLM 返回的数据解析为 Python 对象
  3. 在 FastAPI/Backend 中定义请求/响应的 schema

例如上述翻译演示,若希望 LLM 返回翻译对象:


{
  "original": "你好",
  "translation": "Hello"
}

便可借助 Pydantic 预先定义数据结构:


class Translation(BaseModel):
    original: str
    translation: str

完整代码如下:



from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel, Field

# 核心调整 START
class Translation(BaseModel):
    original: str = Field(description="用户输入的原文")
    translation: str = Field(description="翻译后的译文")

parser = JsonOutputParser(pydantic_object=Translation)
format_instructions = parser.get_format_instructions()

# 核心调整 END

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个中文翻译助手,请将用户提供的中文翻译成英文。n {format_instructions}"),
    ("user", "请翻译以下内容为英文:{text}")
])

llm = ChatOpenAI(
    model="Qwen/Qwen3-32B",
    openai_api_key="your_key",
    base_url="https://api.siliconflow.cn/v1",
    temperature=0
)

chain = prompt | llm | parser

result = chain.invoke({
    "text": "我是一名中国人",
    "format_instructions": format_instructions
})

print(result, result.get("translation"))

通过这种方式,我们能更精确地指定输出格式。那么 format_instructions 具体注入了什么内容?打印查看:


The output should be formatted as a JSON instance that conforms to the JSON schema below.

As an example, for the schema {"properties": {"foo": {"title": "Foo", "description": "a list of strings", "type": "array", "items": {"type": "string"}}}, "required": ["foo"]}
the object {"foo": ["bar", "baz"]} is a well-formatted instance of the schema. The object {"properties": {"foo": ["bar", "baz"]}} is not well-formatted.

Here is the output schema:

{"properties": {
"original": {"description": "用户输入的原文", "title": "Original", "type": "string"}, 
"translation": {"description": "翻译后的译文", "title": "Translation", "type": "string"}
}, "required": ["original", "translation"]}

可见,它自动生成了关于返回内容格式的详细提示词,并注入了 schema 结构。这使大模型能更精准地理解我们期望的格式。

JSON 格式的流式输出

在这种场景下,是否仍支持流式返回?答案是支持


result = chain.stream({
    "text": "我是一名中国人",
    "format_instructions": format_instructions
})

for s in result:
    print(s)
    

只需将上述 demo 的调用方式改为上述代码即可。来看实际输出:


{}
{'original': ''}
{'original': '我'}
{'original': '我是一名'}
{'original': '我是一名中国人'}
{'original': '我是一名中国人', 'translation': ''}
{'original': '我是一名中国人', 'translation': 'I'}
{'original': '我是一名中国人', 'translation': 'I am'}
{'original': '我是一名中国人', 'translation': 'I am a'}
{'original': '我是一名中国人', 'translation': 'I am a Chinese'}
{'original': '我是一名中国人', 'translation': 'I am a Chinese person'}
{'original': '我是一名中国人', 'translation': 'I am a Chinese person.'}

可见 LangChain 在保证格式规范的同时,成功实现了流式输出。

重试和修复

当要求大模型“请返回 JSON 格式”时,99 次可能都正确,但总有某一次它可能输出怪异内容,例如:


这是翻译结果:
{
  "original": "你好",
  "translation": "Hello"
}

或者:


{ "original": "你好", "translation": Hello }  # 缺少双引号,非合法 JSON

这些异常都会导致后续 JsonOutputParserPydanticOutputParser 解析失败,抛出 JSONDecodeErrorValidationError

为此,LangChain 提供了 RetryOutputParserOutputFixingParser 来自动处理此类问题。这两个输出容错解析器非常实用,下面逐一介绍。

RetryOutputParser

若解析失败,它会自动让 LLM 重新执行一次,提示模型“你刚才的输出格式有误,请按此格式重新输出”。

适用场景:

  • 要求模型输出严谨格式(JSON、CSV、Pydantic)
  • 在格式偶尔不一致时提供兜底重试机制

使用方式:


from langchain.output_parsers import RetryOutputParser, PydanticOutputParser
from langchain.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import BaseModel

class Translation(BaseModel):
    original: str
    translation: str

# 原始的解析器
base_parser = PydanticOutputParser(pydantic_object=Translation)

# 包裹 RetryOutputParser:失败时自动再执行一轮 LLM + parser
parser = RetryOutputParser.from_llm(parser=base_parser, llm=ChatOpenAI())

OutputFixingParser

若解析失败,它会尝试让另一个 LLM 来“修正”输出,而不是重新运行整个流程。

它的提示词大致为:“这是用户需要的格式,这是刚才输出的错误结果,请修复它。”

适用场景:

  • 不希望主模型重新执行 prompt,仅想修复输出
  • 尤其适合慢模型或成本敏感的环境

使用方式:


from langchain.output_parsers import OutputFixingParser, PydanticOutputParser
from langchain_openai import ChatOpenAI
from pydantic import BaseModel

class Translation(BaseModel):
    original: str
    translation: str

base_parser = PydanticOutputParser(pydantic_object=Translation)

# 用另一个 LLM 尝试修复格式错误
parser = OutputFixingParser.from_llm(parser=base_parser, llm=ChatOpenAI())

区别对比

项目RetryOutputParserOutputFixingParser
处理方式❗重新让主 LLM 完整运行一遍 prompt? 让另一个 LLM 修复输出,不重跑主模型
调用 LLM 次数1次失败 + 1次重试(最多两次)出错时调用 1 次小模型修复
成本 / 速度成本略高、速度略慢更快更便宜,适合优化部署
使用场景格式错误率低,但偶尔出现异常格式经常出错,希望仅修复而不重跑 prompt
推荐 LLM 模型同一个 ChatOpenAI(主模型)修复可用小模型,例如 Claude Haiku、Qwen-Mini

简而言之:

RetryOutputParser 是“原 prompt 再跑一遍”,OutputFixingParser 是“找个助手帮忙修复”。

当然也可组合使用:


parser = RetryOutputParser.from_llm(
    parser=OutputFixingParser.from_llm(base_parser, repair_llm),
    llm=main_llm
)

含义为:若主解析器失败 → 先尝试修复 → 如果修复不了 → 再全量重跑 prompt。

总结

OutputParser 是 LangChain 中构建高质量、可控输出不可或缺的工具。它能够从模型自然语言输出中提取出机器可理解的数据结构,充当 LLM 与业务逻辑之间的关键桥梁,确保输出结果可靠且易于集成。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策