LangChain-3-输出解析器

概述

        在 LangChain 里,输出解析器扮演着极为关键的角色,它能把语言模型生成的原始文本输出转化为特定的数据结构或格式,让输出更便于处理、存储和进一步分析。

        输出解析器本质上是一个工具,主要用于解决语言模型输出的原始文本缺乏结构化、难以直接使用的问题。它依据预设的规则和格式,对模型输出进行解析和转换,将自由形式的文本转化为程序易于处理的结构化数据,像字典、列表、自定义对象等。

主要作用

        数据结构化:把模型输出的自然语言文本转换为结构化的数据,例如将一段描述用户信息的文本解析成包含姓名、年龄、职业等字段的字典,这样能更方便地进行后续的程序操作。

        错误处理:对模型输出进行格式验证,若输出不符合预先定义的格式,输出解析器会抛出错误或进行相应的处理,有助于及时发现和解决问题。

        标准化输出:保证输出具有统一的格式,使得不同运行实例或不同模型的输出能够进行有效的比较和分析。

常用解析器

1. PydanticOutputParser:用于解析为Pydantic模型,支持复杂结构和类型验证。

2. SimpleJsonOutputParser:解析简单的JSON输出为字典。

3. CommaSeparatedListOutputParser:解析逗号分隔的列表。

4. OutputFixingParser:用于自动修复格式错误的输出。

5. RetryOutputParser:在解析失败时尝试重新生成。

6. DatetimeOutputParser:解析日期时间字符串。

7. BooleanOutputParser:解析布尔值(如是/否,true/false)为Python布尔类型。

8. StructuredOutputParser:旧版的键值对结构化解析(现在推荐使用PydanticOutputParser)。

9. JsonOutputParser:解析JSON字符串(与SimpleJsonOutputParser类似,但可能更灵活)。

StrOutputParser 

        StrOutputParser 是 LangChain 中一个较为基础且简单的输出解析器,它的主要功能是原封不动地返回语言模型的输出,也就是将模型输出作为字符串进行处理,不会对输出内容进行额外的解析或转换操作。以下为你详细介绍:

功能与用途

        在很多情况下,我们可能并不需要对语言模型的输出进行复杂的结构化处理,只是单纯想获取模型输出的原始文本内容,这时 StrOutputParser 就非常适用。比如,当模型输出的本身就是一段完整且无需进一步解析的文本,像一篇文章、一首诗歌、一段故事等,使用 StrOutputParser 就能直接得到这些文本信息。

示例:

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

llm = ChatOpenAI(
    api_key="",
    base_url="https://api.baichuan-ai.com/v1",
    model="Baichuan3-Turbo"
)

prompt = PromptTemplate.from_template("你是一个ai助手,回答用户的提出的问题:{question}")

chain = prompt | llm | StrOutputParser()
print("使用StrOutputParser解析器:", chain.invoke({"question": "你是谁?"}))

chain2 = prompt | llm
print("未使用StrOutputParser解析器:", chain2.invoke({"question": "你是谁?"}))
使用StrOutputParser解析器: 我叫百川大模型,是由百川智能的工程师们创造的大语言模型,我可以和人类进行自然交流、解答问题、协助创作,帮助大众轻松、普惠的获得世界知识和专业服务。如果你有任何问题,可以随时向我提问。
未使用StrOutputParser解析器: content='我叫百川大模型,是由百川智能的工程师们创造的大语言模型,我可以和人类进行自然交流、解答问题、协助创作,帮助大众轻松、普惠的获得世界知识和专业服务。如果你有任何问题,可以随时向我提问。' additional_kwargs={'refusal': None} response_metadata={'token_usage': {'completion_tokens': 56, 'prompt_tokens': 75, 'total_tokens': 131, 'completion_tokens_details': None, 'prompt_tokens_details': None, 'search_count': 0}, 'model_name': 'Baichuan3-Turbo', 'system_fingerprint': None, 'id': 'chatcmpl-M9B8D0277GMeokv', 'service_tier': None, 'finish_reason': 'stop', 'logprobs': None} id='run--86b34110-b039-4b94-89a7-81a8de385fae-0' usage_metadata={'input_tokens': 75, 'output_tokens': 56, 'total_tokens': 131, 'input_token_details': {}, 'output_token_details': {}}

使用StrOutputParser 直接会帮我们将输出文本提取出来

SimpleJsonOutputParser

SimpleJsonOutputParser 是 LangChain 提供的一个轻量级的输出解析器,专门用于让大语言模型(LLM)以​​JSON 格式​​输出结构化数据,并将 LLM 的输出解析为 Python 的字典(dict)类型。

它的主要特点是:

  • ​简单易用​​:不需要复杂的配置或额外的依赖(如 Pydantic 模型)。

  • ​专注于 JSON 格式​​:让 LLM 输出符合 JSON 格式的字符串,然后将其解析为 Python 字典。

  • ​轻量级​​:相比 JsonOutputParser(支持 Pydantic 模型),它的功能更简单,但也更直接。

示例:

from langchain_core.output_parsers import PydanticOutputParser, JsonOutputParser, XMLOutputParser, \
    SimpleJsonOutputParser
from langchain_core.prompts import PromptTemplate
from pydantic import Field, BaseModel
from model.deepseek import deepseek_llm


class Joke(BaseModel):
    setup: str = Field(description="笑话中的铺垫问题,必须以?结尾")
    punchline: str = Field(description="笑话中回答铺垫问题的部分,通常是一种抖包袱方式回答铺垫问题,例如谐音,会错意等")


parser = SimpleJsonOutputParser(pydantic_object=Joke)
prompt = PromptTemplate(
    template="回答用户的查询.\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)
print("提示词模板:", prompt.partial_variables['format_instructions'])
chat_prompt = prompt | deepseek_llm
output = chat_prompt.invoke({"query": "请给我讲一个笑话"})
print("格式化后的结果:", parser.invoke(output))
提示词模板: 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": {"setup": {"description": "笑话中的铺垫问题,必须以?结尾", "title": "Setup", "type": "string"}, "punchline": {"description": "笑话中回答铺垫问题的部分,通常是一种抖包袱方式回答铺垫问题,例如谐音,会错意等", "title": "Punchline", "type": "string"}}, "required": ["setup", "punchline"]}
```
格式化后的结果: {'setup': '为什么程序员总是分不清万圣节和圣诞节?', 'punchline': '因为Oct 31等于Dec 25。'}

 PydanticOutputParser 

PydanticOutputParser 是 LangChain 中的一个输出解析器,它借助 Pydantic 库,能够把语言模型的输出解析为自定义的 Pydantic 模型实例,让输出数据更具结构化和类型安全。

from langchain_core.output_parsers import PydanticOutputParser, JsonOutputParser, XMLOutputParser, \
    SimpleJsonOutputParser
from langchain_core.prompts import PromptTemplate
from pydantic import Field, BaseModel
from model.deepseek import deepseek_llm


class Joke(BaseModel):
    setup: str = Field(description="笑话中的铺垫问题,必须以?结尾")
    punchline: str = Field(description="笑话中回答铺垫问题的部分,通常是一种抖包袱方式回答铺垫问题,例如谐音,会错意等")


parser = PydanticOutputParser(pydantic_object=Joke)
prompt = PromptTemplate(
    template="回答用户的查询.\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)
print("提示词模板:", prompt.partial_variables['format_instructions'])
prompt_and_model = prompt | deepseek_llm
output = prompt_and_model.invoke({"query": "请给我讲一个笑话"})
print("格式化后的结果:", parser.invoke(output))
​
from langchain_core.output_parsers import PydanticOutputParser, JsonOutputParser, XMLOutputParser, \
    SimpleJsonOutputParser
from langchain_core.prompts import PromptTemplate
from pydantic import Field, BaseModel
from model.deepseek import deepseek_llm


class Joke(BaseModel):
    setup: str = Field(description="笑话中的铺垫问题,必须以?结尾")
    punchline: str = Field(description="笑话中回答铺垫问题的部分,通常是一种抖包袱方式回答铺垫问题,例如谐音,会错意等")


parser = PydanticOutputParser(pydantic_object=Joke)
prompt = PromptTemplate(
    template="回答用户的查询.\n{format_instructions}\n{query}\n",
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)
print("提示词模板:", prompt.partial_variables['format_instructions'])
prompt_and_model = prompt | deepseek_llm
output = prompt_and_model.invoke({"query": "请给我讲一个笑话"})
print("格式化后的结果:", parser.invoke(output))

​

其它的解析器使用基本差不多,就不一一举例说明了,下面介绍两个特殊的解析器

OutputFixingParser

        OutputFixingParser 是 LangChain 提供的一个工具类,用于修复格式错误的输出并尝试再次解析为有效的结构化数据(如 Pydantic 模型)。

        当 LLM 的输出不符合指定的格式要求时(如 JSON 格式错误、字段缺失或类型不匹配),OutputFixingParser 会:
        1.捕获解析异常
        2.将错误的输出和解析器的要求发送给 LLM
        3.让 LLM 尝试生成一个符合格式的正确输出
        4.再次尝试解析

from typing import List
from langchain.output_parsers import OutputFixingParser
from langchain_core.exceptions import OutputParserException
from langchain_core.output_parsers import PydanticOutputParser
from pydantic import BaseModel, Field
from model.deepseek import deepseek_llm

class Actor(BaseModel):
    name: str = Field(description="演员的名字")
    film_names: List[str] = Field(description="演员参演的电影名称")

parser = PydanticOutputParser(pydantic_object=Actor)
#假设大模型输出了一个错误格式数据
misformatted = """{'name': 'Judi Dench', 'film_names': ['Forrest Gump']}"""

try:
    parser.parse(misformatted)
except OutputParserException as e:
    print("数据解析错误,让大模型修复")
    new_parser = OutputFixingParser.from_llm(parser=parser, llm=deepseek_llm)
    resp = new_parser.parse(misformatted)
    print("大模型修复后的输出",resp)

RetryOutputParser

        RetryOutputParser 是 LangChain 提供的一个输出解析器,用于在解析失败时自动重试生成符合指定格式的响应。它通常与 PydanticOutputParser 一起使用,以处理 LLM 输出不规范或结构错误的情况。

from langchain.output_parsers import RetryOutputParser
from langchain_core.exceptions import OutputParserException
from langchain_core.output_parsers import PydanticOutputParser
from langchain_core.prompts import PromptTemplate
from pydantic import BaseModel, Field

from model.deepseek import deepseek_llm

template = """
Based on the user question, provide an Action and Action Input for what
step should be taken.
{format_instructions}
Question: {query}
Response:
"""

class Action(BaseModel):
    action: str = Field(description="action to take")
    action_input: str = Field(description="input to the action")

parser = PydanticOutputParser(pydantic_object=Action)

prompt = PromptTemplate(
    template=template,
    input_variables=["query"],
    partial_variables={"format_instructions": parser.get_format_instructions()}
)

prompt_value = prompt.format_prompt(query='北京今天天气如何?')
#假设大模型输出了一个错误格式
bad_response = '{"action":"search"}'

try:
    parser.parse(bad_response)
except OutputParserException as e:
    print("解析出错了,开始重试了")
    retry_parser = RetryOutputParser.from_llm(parser=parser, llm=deepseek_llm)
    with_prompt = retry_parser.parse_with_prompt(bad_response, prompt_value)
    print("重试后的结果:",with_prompt)

 其它常用的结构化输出方式 

with_structured_output

with_structured_output 是 LangChain 提供的一个​​链式调用方法​​,它可以将一个普通的 LLM 或 Chain 转换为一个能够输出​​结构化数据​​的新 Chain。

它的核心作用是:

  • 让 LLM 按照指定的结构(如 JSON Schema 或 Pydantic 模型)输出数据。

  • 自动处理 LLM 输出的解析,将自由文本转换为 Python 中的结构化对象(如字典、Pydantic 模型实例等)。

通过 with_structured_output,开发者可以轻松构建需要​​精确数据格式​​的 LLM 应用,而无需手动编写复杂的 Prompt 或解析逻辑。openAI和Claude都是支持with_structured_output,很多国产大模型不支持with_structured_output ,使用前请充分测试,

import json
from typing import Optional
from langchain_core.prompts import PromptTemplate
from pydantic import BaseModel, Field
from langchainproject.langchain_demo.chatgpt import openapi_llm

#生成一个笑话的段子

class Joke(BaseModel):
    """
    笑话的结构类数据模型POVO
    """
    setup: str = Field(description="笑话的开头部分")
    punchline: str = Field(description="笑话的笑点")
    rating: Optional[int] = Field(description="笑话的评分范围1到10分", ge=1, le=10)


prompt_template = PromptTemplate.from_template("帮我生成一个关于{topic}的笑话.")
runnable = openapi_llm.with_structured_output(Joke)

chain = prompt_template | runnable
result = chain.invoke({"topic": "猫"})
print(result)
print(result.__dict__)
json_str = json.dumps(result.__dict__, ensure_ascii=False)
print(json_str)

使用工具调用格式化

bind_tools() 是 LangChain 提供的一个方法,用于将一组“工具”(Tools)绑定到一个 LLM 或 Chain 上。它的核心作用是:

  • ​扩展 LLM 的能力​​:让 LLM 在需要时可以“调用工具”来完成某些特定任务(如计算、查询、API 调用等)。

  • ​结构化工具调用​​:LangChain 会自动将工具的使用封装成一种标准化的格式,使得 LLM 可以通过自然语言描述来调用工具,而无需直接了解工具的具体实现细节。

from pydantic import BaseModel, Field

from langchainproject.langchain_demo.chatgpt import openapi_llm


class ResponseFormatter(BaseModel):
    answer: str = Field(description="对用户问题的答案")
    followup_question: str = Field(description="用户可能提出的后续问题")


runnable = openapi_llm.bind_tools([ResponseFormatter])

result = runnable.invoke("细胞的动力源是什么?")
print(result.tool_calls[-1]['args'])

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值