神经中枢:输出解析器,搭建文本与数据的桥梁
经过前面几篇文章我们已经把提示词模板玩出了花——静态的、动态的、带少样本的、能自动挑例子的。模型在我们的指挥下输出质量越来越高。但有一个环节始终卡在我们的指尖模型的输出还是字符串。哪怕模型返回的是一个长得像 JSON 的字符串你的代码也得再跑一遍json.loads()还得祈祷它没在前面加一句“好的这是结果”。一旦格式稍有偏差你的解析代码就报错整个链断开。我们需要一个能自动把模型原始输出转成 Python 数据结构字典、列表、甚至 Pydantic 对象的中间层。这个中间层就是今天的主角——输出解析器Output Parser。它像整个系统的“神经中枢”一头接着模型这个“大脑”另一头连着你的业务代码把生物电信号翻译成身体动作。一、从文本到数据一座必须跨越的桥1.1 字符串是给人类看的数据是给程序吃的回忆一下我们在第 10 篇《结构化返回》中学了with_structured_output那是让模型直接在内部按照 Pydantic Schema 生成 JSON输出就是一个解析好的对象。但这种方法有两个局限并非所有模型都原生支持结构化输出。有时我们需要更灵活的输出格式比如逗号分隔的列表、自定义分隔符甚至是多步骤推理的中间产物。输出解析器就是处理这种“模型说人话我们得数据”的万能胶水。它的核心任务接收模型的原始文本自动提取我们需要的数据结构并且在失败时尝试修复。1.2 一个熟悉的痛点假设你让模型返回一个 JSON 数组但它是这样回的好的以下是你需要的三个要点 [ 要点1, 要点2, 要点3 ] 希望对你有所帮助直接json.loads会失败因为前后有废话。你得写正则去头去尾还要处理单引号、换行。每次写这种胶水代码都像在重复造轮子。二、输出解析器怎么工作一种自带“纠错”的翻译官LangChain 把输出解析器抽象成了BaseOutputParser。所有解析器都是 Runnable这意味着你可以把它们直接串在链的末端提示词 → 模型 → 解析器 → 结构化数据解析器内部通常做了两件事解析Parse从模型输出中提取目标数据。这可能包括去除 markdown 标记、寻找 JSON 块、按分隔符切割等。重试Retry如果解析失败解析器会抛出一个OutputParserException。你可以选择捕获它然后把错误信息返回给模型让模型自我纠正并重新生成。LangChain 甚至提供了OutputFixingParser来自动完成这个循环。更妙的是解析器可以向提示词注入格式指令。每个解析器都有一个get_format_instructions()方法返回一段文本告诉模型应该怎样输出。你把这段文本嵌入提示词模板模型就会按规矩说话。三、解析器全景从简单到复杂的四件套LangChain 提供了多种开箱即用的解析器。我们按复杂度递进快速过一遍然后重点学习最强大的PydanticOutputParser。3.1StrOutputParser最朴素的搬运工这是我们从第 7 篇就开始用的老朋友。它做的事情极其简单把AIMessage的content字符串取出来去掉首尾空白。适用于只需要纯文本的任务。fromlangchain_core.output_parsersimportStrOutputParser parserStrOutputParser()3.2CommaSeparatedListOutputParser列表就绪当你需要模型返回一个列表如关键词提取、标签生成时这个解析器很有用。它会告诉模型“请用逗号分隔每一项”然后把输出按逗号切分成 Python 列表。fromlangchain_core.output_parsersimportCommaSeparatedListOutputParser parserCommaSeparatedListOutputParser()print(parser.get_format_instructions())# 输出Your response should be a list of comma separated values, eg: foo, bar, baz使用方法fromlangchain_core.promptsimportChatPromptTemplate promptChatPromptTemplate.from_messages([(system,你是一个关键词提取器。parser.get_format_instructions()),(user,{input})])chainprompt|model|parser resultchain.invoke({input:这篇文章讲了 Python 的装饰器和上下文管理器。})# result 是 [装饰器, 上下文管理器, Python]3.3JsonOutputParser返回标准 JSON 字典对于任意 JSON 输出你可以用JsonOutputParser。它会自动在模型输出的文本中定位到完整的 JSON 块即使被 markdown 包裹然后解析为 dict。fromlangchain_core.output_parsersimportJsonOutputParser parserJsonOutputParser()parser.get_format_instructions()# 返回一段指示要求模型输出纯 JSON由于没有预先定义 Schema它只能给你一个 dict你需要自己在代码里校验字段。但它的容错能力很强能处理前后追加的文本。如果你需要强类型校验Pydantic 解析器是更好的选择。3.4PydanticOutputParser强类型、带校验的终极形态这是我个人最常用的解析器。它结合了 Pydantic 的数据校验能力和 LangChain 的自动重试机制让你直接拿到一个验证完成的 Pydantic 实例。和第 10 篇的with_structured_output不同PydanticOutputParser不依赖模型的内置结构化输出能力——它通过纯提示词工程告诉模型“请按这个 JSON Schema 输出”然后用 Pydantic 在应用层解析和校验。这就意味着几乎所有模型都能用包括一些不支持函数调用的老模型或本地模型。四、实战用 PydanticOutputParser 打造一个影评提取器我们来完整走一遍 Pydantic 解析器的使用流程定义 Schema → 创建解析器 → 注入格式指令 → 构建链 → 调用并拿到对象。4.1 定义 Pydantic 模型frompydanticimportBaseModel,FieldfromtypingimportListclassMovieReview(BaseModel):电影评论提取结果title:strField(description电影的中文名称)year:intField(description上映年份)rating:floatField(description用户给出的评分范围 0-10)pros:List[str]Field(description优点列表)cons:List[str]Field(description缺点列表)summary:strField(description一句话总结评价)4.2 创建解析器并获取格式指令fromlangchain_core.output_parsersimportPydanticOutputParser parserPydanticOutputParser(pydantic_objectMovieReview)format_instructionsparser.get_format_instructions()print(format_instructions)打印出来的格式指令大概是这样的部分The output should be formatted as a JSON instance that conforms to the JSON schema below. Here is the output schema:{“properties”: {“title”: {“description”: “电影的中文名称”, …}}, …}这段指令会直接嵌入提示词模型看后就知道必须返回符合特定结构的 JSON。 ### 4.3 构建提示词模板并注入指令 python from langchain_core.prompts import ChatPromptTemplate prompt ChatPromptTemplate.from_messages([ (system, 你是一个专业的影评提取助手。请根据用户的观后感提取关键信息。\n{format_instructions}), (user, {input}) ]) # 注意format_instructions 是作为变量传入的4.4 组建链并测试fromlangchain_deepseekimportChatDeepSeek modelChatDeepSeek(modeldeepseek-chat,temperature0)chainprompt|model|parser# 一段模拟的用户观后感user_text 昨天看了《流浪地球2》2023年的片子。我给9分。 优点特效震撼剧情有深度吴京演技在线。 缺点时长太长中间节奏有点慢。 总的来说这是一部让人重新审视中国科幻的佳作。 resultchain.invoke({format_instructions:format_instructions,input:user_text})print(type(result))# class __main__.MovieReviewprint(result.title)# 流浪地球2print(result.rating)# 9.0print(result.pros)# [特效震撼, 剧情有深度, 吴京演技在线]你拿到的不再是字符串而是一个字段类型正确、可以直接传给数据库或前端的 Python 对象。任何不符合 Schema 的输出解析器都会抛出异常你可以在外层捕获并设计降级逻辑。五、解析器的自我修复当模型“说错话”时有时模型会返回不合规的 JSON——漏了一个引号、字段名打错、或干脆没输出 JSON 块。PydanticOutputParser默认会抛出OutputParserException。但 LangChain 提供了一个更聪明的包装器OutputFixingParser。它接收一个普通解析器和一个“修复模型”当解析失败时会自动把错误信息和原始输出提交给修复模型让它重新生成符合格式的输出fromlangchain_core.output_parsersimportOutputFixingParser# 创建一个修复解析器fixing_parserOutputFixingParser.from_llm(parserparser,# 原始的 PydanticOutputParserllmChatDeepSeek(modeldeepseek-chat,temperature0)# 修复用的模型)# 即使模型第一次输出格式错误fixing_parser 也会尝试修复chainprompt|model|fixing_parser内部流程解析失败 → 捕获异常 → 将错误信息和原输出作为提示词发给修复模型 → 修复模型返回合规 JSON → 解析成功。这个机制极大提高了鲁棒性尤其适合生产环境。六、解析器 vswith_structured_output怎么选你可能困惑第 10 篇的with_structured_output和今天的PydanticOutputParser都能拿到 Pydantic 对象该用哪个特性with_structured_outputPydanticOutputParser依赖模型能力需要模型原生支持 function calling不依赖纯提示词工程准确性高模型内部约束中高依赖提示词遵循度灵活性只能输出一个符合 Schema 的对象可与其他解析器组合处理任意格式适用场景对格式要求极高的提取、分类任务通用任务、兼容老模型、复杂复合输出Token 消耗通常较低后台处理稍高格式指令占 token我的建议如果你用的模型支持函数调用优先用with_structured_output它更可靠。当你需要输出多种格式、或者模型不支持结构化输出时PydanticOutputParser就是救场利器。两者掌握了你将游刃有余。七、今日收获与下篇预告今天我们搭建起了从模型文本到结构化数据的关键桥梁你理解了输出解析器的核心使命自动解析、校验、修复模型的文本输出。你快速浏览了四大常用解析器并深入实战了PydanticOutputParser从 Schema 定义到链式调用一气呵成。你知道了OutputFixingParser如何自动修正模型的格式错误提升了鲁棒性。你厘清了with_structured_output与解析器各自的优劣势能根据场景做出理智选择。至此LangChain 的核心组件——模型、提示词、链、工具、记忆、输出解析——你已经全部解锁。它们就像一块块精密的积木等待你拼装出真正能解决问题的应用。接下来我们将进入本系列最激动人心的模块RAG 实战。从下一篇《RAG 全景图给你的 AI 装上“外挂知识库”》开始我们将用所学的一切亲手构建一个能回答私有知识库问题的智能问答系统。模型将不再只靠自己的记忆答题而是能随时翻阅你提供的文档。知识的疆界将由你亲手打破。下一篇见

相关新闻

最新新闻

日新闻

周新闻

月新闻