文章目錄
- 一 LangChain輸出解析器概述
- 1.1 什么是輸出解析器?
- 1.2 主要功能與工作原理
- 1.3 常用解析器類型
- 二 主要輸出解析器類型
- 2.1 Pydantic/Json輸出解析器
- 2.2 結構化輸出解析器
- 2.3 列表解析器
- 2.4 日期解析器
- 2.5 Json輸出解析器
- 2.6 xml輸出解析器
- 三 高級使用技巧
- 3.1 自定義解析邏輯
- 3.2 重試與錯誤處理
- 3.3 多模式解析
- 四 實際應用示例
- 4.1 構建問答系統
- 4.2 性能優化建議
- 五 總結
一 LangChain輸出解析器概述
- LangChain輸出解析器是LangChain框架中的核心組件,主要用于將大型語言模型(LLM)生成的非結構化文本轉換為結構化數據格式。它允許開發者定義期望的輸出結構,并通過提示工程指導LLM生成符合該格式的響應。輸出解析器在驗證和轉換模型輸出時發揮著關鍵作用,確保數據能夠無縫集成到應用程序的工作流程中。
1.1 什么是輸出解析器?
輸出解析器是LangChain框架中的一類組件,專門負責兩大功能:
- 指令格式化:指導LLM如何格式化其輸出
- 結果解析:將LLM的文本響應轉換為結構化格式
與直接使用原始API調用相比,輸出解析器提供了更可靠、更可預測的結果處理方式,極大簡化了后續的數據處理流程。
1.2 主要功能與工作原理
- 輸出解析器通過兩個核心機制實現功能:首先通過get_format_instructions方法生成格式化指令,明確告知LLM輸出應遵循的結構;然后通過parse方法將LLM的原始響應解析為目標數據結構。這種雙重機制既保證了輸出的規范性,又提供了靈活的數據轉換能力。典型的應用場景包括將文本轉換為JSON對象、列表、枚舉值或特定領域對象等結構化數據。
1.3 常用解析器類型
- LangChain提供了豐富的內置解析器,包括ListParser(列表解析器)、DatetimeParser(日期時間解析器)、EnumParser(枚舉解析器)和PydanticOutputParser(JSON解析器)等。其中PydanticOutputParser特別強大,它基于Pydantic模型定義數據結構,可以處理嵌套復雜的JSON格式,并自動生成對應的格式指令。此外還有StructuredOutputParser用于處理自定義類結構,Auto-FixingParser可自動修復格式錯誤。
二 主要輸出解析器類型
LangChain提供了多種輸出解析器,適用于不同場景:
2.1 Pydantic/Json輸出解析器
-
- Pydantic/Json解析器允許您定義嚴格的輸出模式,確保LLM響應符合預期的數據結構,非常適合需要強類型驗證的場景。
from langchain.output_parsers import PydanticOutputParser
from pydantic import Field, BaseModelclass UserProfile(BaseModel):name: str = Field(description="用戶全名")age: int = Field(description="用戶年齡")hobbies: list[str] = Field(description="用戶愛好列表")parser = PydanticOutputParser(pydantic_object=UserProfile)
- 完整案例:
import os
from langchain_core.output_parsers import PydanticOutputParser
# from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import Field, BaseModel# 配置 API 易環境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"model=ChatOpenAI(model="gpt-4",temperature=0)# 定義期望的數據結構
class Joke(BaseModel):setup:str =Field(description="設置笑話的問題")punchline:str =Field(description="解決笑話的答案")# 用于提示語言模型填充數據結構的查詢意圖
joke_query="告訴我一個笑話"
# 設置解析器+將指令注入提示模板
# parser=JsonOutputParser(pydantic_object=Joke)
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(parser.get_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": {"setup": {"description": "設置笑話的問題", "title": "Setup", "type": "string"}, "punchline": {"description": "解決笑話的答案", "title": "Punchline", "type": "string"}}, "required": ["setup", "punchline"]}
"""
chain=prompt|model|parser
response=chain.invoke({"query":joke_query})
print(response)
"""
{'setup': '為什么計算機不能得感冒?', 'punchline': '因為它們有防火墻!'}
"""
2.2 結構化輸出解析器
- 當需要靈活定義輸出結構而不想引入Pydantic依賴時,結構化輸出解析器是理想選擇。
from langchain.output_parsers import StructuredOutputParser, ResponseSchemaresponse_schemas = [ResponseSchema(name="answer", description="問題的答案"),ResponseSchema(name="source", description="答案來源")
]parser = StructuredOutputParser.from_response_schemas(response_schemas)
- 完整代碼
import os
from langchain.output_parsers import StructuredOutputParser, ResponseSchema
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI# 配置 API 易環境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"model=ChatOpenAI(model="gpt-4",temperature=0)response_schemas = [ResponseSchema(name="answer", description="問題的答案"),ResponseSchema(name="source", description="答案來源")
]# 設置解析器+將指令注入提示模板
parser = StructuredOutputParser.from_response_schemas(response_schemas)prompt=PromptTemplate(template="回答用戶的查詢。\n{format_instructions}\n{query}\n",input_variables=["query"],partial_variables={"format_instructions":parser.get_format_instructions()}
)
print(parser.get_format_instructions())
"""
The output should be a markdown code snippet formatted in the following schema, including the leading and trailing "```json" and "```":{"answer": string // 問題的答案"source": string // 答案來源
}"""
chain=prompt|model|parser
# 用于提示語言模型填充數據結構的查詢意圖
joke_query="告訴我一個笑話"
response=chain.invoke({"query":joke_query})print(response)
"""
{'answer': '為什么數學書總是很憂傷?因為它有太多的問題!', 'source': '常見幽默笑話'}
"""
2.3 列表解析器
- 簡單高效地將逗號分隔的列表響應轉換為Python列表,適用于簡單的枚舉場景。
from langchain.output_parsers import CommaSeparatedListOutputParserparser = CommaSeparatedListOutputParser()
2.4 日期解析器
- 專門處理日期時間字符串,將其轉換為Python datetime對象,省去了手動解析的麻煩。
from langchain.output_parsers import DatetimeOutputParserparser = DatetimeOutputParser()
2.5 Json輸出解析器
- JSON作為現代API和Web應用中最常用的數據交換格式,LangChain提供了專門的JSON輸出解析器來簡化處理流程。
import osfrom langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI
from pydantic import Field, BaseModel# 配置 API 易環境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"model=ChatOpenAI(model="gpt-4",temperature=0)# 定義期望的數據結構
class Joke(BaseModel):setup:str =Field(description="設置笑話的問題")punchline:str =Field(description="解決笑話的答案")# 用于提示語言模型填充數據結構的查詢意圖
joke_query="告訴我一個笑話"
# 設置解析器+將指令注入提示模板
parser=JsonOutputParser(pydantic_object=Joke)
prompt=PromptTemplate(template="回答用戶的查詢。\n{format_instructions}\n{query}\n",input_variables=["query"],partial_variables={"format_instructions":parser.get_format_instructions()}
)
print(parser.get_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": {"setup": {"description": "設置笑話的問題", "title": "Setup", "type": "string"}, "punchline": {"description": "解決笑話的答案", "title": "Punchline", "type": "string"}}, "required": ["setup", "punchline"]}"""
chain=prompt|model|parser
response=chain.invoke({"query":joke_query})
for s in chain.stream({"query":joke_query}):print(s)"""
{}
{'setup': ''}
{'setup': '為'}
{'setup': '為什'}
{'setup': '為什么'}
{'setup': '為什么電'}
{'setup': '為什么電腦'}
{'setup': '為什么電腦很'}
{'setup': '為什么電腦很好'}
{'setup': '為什么電腦很好吃'}
{'setup': '為什么電腦很好吃?'}
{'setup': '為什么電腦很好吃?', 'punchline': ''}
{'setup': '為什么電腦很好吃?', 'punchline': '因'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們有'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們有很'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們有很多'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們有很多字'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們有很多字節'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們有很多字節('}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們有很多字節(bytes'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們有很多字節(bytes)'}
{'setup': '為什么電腦很好吃?', 'punchline': '因為它們有很多字節(bytes)!'}
"""
2.6 xml輸出解析器
- LangChain的XML輸出解析器為這些場景提供了專業支持。
import osfrom langchain_core.output_parsers import XMLOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_openai import ChatOpenAI# 配置 API 易環境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"model=ChatOpenAI(model="gpt-4",temperature=0)# 用于提示語言模型填充數據結構的查詢意圖
actor_query="生成周星馳的簡化電影作品列表,按照最新的時間降序"# 設置解析器+將指令注入提示模板
parser=XMLOutputParser(tags=["movies","actor","film","name","genre"])
prompt=PromptTemplate(template="回答用戶的查詢。\n{format_instructions}\n{query}\n",input_variables=["query"],partial_variables={"format_instructions":parser.get_format_instructions()}
)
print(parser.get_format_instructions())
- 執行輸出:
"""
The output should be formatted as a XML file.
1. Output should conform to the tags below.
2. If tags are not given, make them on your own.
3. Remember to always open and close all the tags.As an example, for the tags ["foo", "bar", "baz"]:
1. String "<foo><bar><baz></baz></bar>
</foo>" is a well-formatted instance of the schema.
2. String "<foo><bar></foo>" is a badly-formatted instance.
3. String "<foo><tag></tag>
</foo>" is a badly-formatted instance.Here are the output tags:['movies', 'actor', 'film', 'name', 'genre']
"""
chain=prompt|model
response=chain.invoke({"query":actor_query})
xml_output=parser.parse(response.content)
print(response.content)
"""
```xml
<movies><actor><name>周星馳</name><film><name>美人魚</name><genre>喜劇</genre><year>2016</year></film><film><name>西游降魔篇</name><genre>喜劇</genre><year>2013</year></film><film><name>長江七號</name><genre>科幻</genre><year>2008</year></film><film><name>功夫</name><genre>動作</genre><year>2004</year></film><film><name>少林足球</name><genre>喜劇</genre><year>2001</year></film></actor>
</movies>這是一個簡化的電影作品列表,列出了周星馳的一些電影,包括電影名稱、類型和年份。這個列表是按照最新的時間降序排列的。
"""
三 高級使用技巧
3.1 自定義解析邏輯
- 通過繼承BaseOutputParser,可以創建完全自定義的解析邏輯,處理特殊響應格式。
from langchain.output_parsers import BaseOutputParserclass BooleanParser(BaseOutputParser[bool]):def parse(self, text: str) -> bool:cleaned = text.strip().lower()if cleaned in ("yes", "true", "1"):return Trueelif cleaned in ("no", "false", "0"):return Falseraise ValueError(f"無法解析為布爾值: {text}")@propertydef _type(self) -> str:return "boolean_parser"
3.2 重試與錯誤處理
- 當初始解析失敗時,重試解析器會自動嘗試修正錯誤,顯著提高系統魯棒性。
from langchain.output_parsers import RetryWithErrorOutputParserretry_parser = RetryWithErrorOutputParser.from_llm(parser=parser,llm=chat_llm
)
3.3 多模式解析
- 輸出修正解析器可以檢測并嘗試自動修復格式錯誤的響應,特別適合生產環境中提高可靠性。
from langchain.output_parsers import OutputFixingParserfixing_parser = OutputFixingParser.from_llm(parser=parser, llm=chat_llm)
四 實際應用示例
4.1 構建問答系統
import osfrom langchain_core.output_parsers import JsonOutputParser
from langchain_openai import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from pydantic import BaseModel, Field# 配置 API 環境
os.environ["OPENAI_API_KEY"] = "hk-xxx"
os.environ["OPENAI_API_BASE"] = "https://api.openai-hk.com/v1"template = """根據上下文回答問題,并按照要求格式化輸出。
上下文: {context}
問題: {question}
{format_instructions}"""prompt = ChatPromptTemplate.from_template(template)
model = ChatOpenAI(model="gpt-4")# 定義輸出數據結構
class Answer(BaseModel):answer: str = Field(description="根據上下文回答問題")confidence: float = Field(description="回答的置信度")# 創建解析器
parser = JsonOutputParser(pydantic_model=Answer)chain = prompt | model | parserresult = chain.invoke({"context": "LangChain是一個LLM應用開發框架...","question": "LangChain是什么?","format_instructions": parser.get_format_instructions()
})print(result)
4.2 性能優化建議
- 清晰的指令:在提示中明確說明輸出格式要求。
- 漸進式解析:復雜結構可分步解析。
- 錯誤回退:實現備用解析策略。
- 緩存機制:對相同輸入緩存解析結果。
- 監控指標:跟蹤解析成功率,及時發現模式問題。
五 總結
- LangChain的輸出解析器組件為LLM應用開發提供了關鍵的結構化數據處理能力。通過合理選擇和使用各種解析器,開發者可以:
- 確保數據的一致性和可靠性
- 減少膠水代碼和手動解析工作
- 構建更健壯的生產級應用
- 專注于業務邏輯而非數據清洗