LangChain 教學:Output Parsers(輸出解析)— 結構化輸出(JSON、Pydantic)
簡介
在 LLM(大型語言模型)與應用程式之間,文字是唯一的橋樑。然而,純文字結果往往難以直接供程式碼使用,尤其在需要後續計算、資料庫寫入或 API 呼叫時更是如此。
為了讓 LLM 的回應能直接被程式處理,我們必須把「自由文字」轉換成結構化資料(如 JSON、Pydantic 物件),這就是 LangChain 中的 Output Parsers 所扮演的角色。
本單元將說明:
- 為什麼要使用結構化輸出。
- LangChain 內建的
JsonOutputParser與PydanticOutputParser如何運作。 - 實作範例、常見陷阱與最佳實踐,最後帶出幾個真實的應用情境。
掌握輸出解析,等於掌握了 LLM 與程式碼之間的「雙向翻譯」能力,讓你的 AI 應用從「聊天」升級為「自動化」!
核心概念
1. 輸出解析的基本流程
- Prompt 設計:在提示中明確告訴模型要回傳的結構(例如 JSON schema 或 Pydantic 類別)。
- LLM 呼叫:模型根據提示產生文字回應。
- Parser 解析:使用對應的
OutputParser把文字轉成程式可操作的物件。 - 後續處理:將解析後的資料傳遞給下游流程(資料庫、API、業務邏輯等)。
關鍵:Prompt 與 Parser 必須「說一致」——Prompt 中描述的結構必須與 Parser 能解析的格式相符,否則會產生解析錯誤。
2. JsonOutputParser
JsonOutputParser 是 LangChain 最簡單的結構化輸出工具,只需要 JSON Schema(或簡易說明)即可。它會在模型回傳文字後,嘗試以 json.loads 解析,若失敗會拋出 OutputParserException。
為什麼使用 JSON?
- 跨語言友好:幾乎所有程式語言都支援 JSON。
- 易於驗證:可以使用 JSON Schema 進行結構驗證。
- 可視化:在除錯或日誌中直接閱讀。
3. PydanticOutputParser
PydanticOutputParser 進一步結合了 Pydantic(Python 的資料模型驗證庫),讓我們可以:
- 定義型別(int、float、datetime、Enum 等)。
- 自動驗證:解析失敗時會回傳具體的錯誤訊息。
- 直接得到 Python 物件,省去手動
dict轉換。
適用情境:當你的應用需要嚴格的型別檢查、或是要把資料直接塞入 ORM、FastAPI 請求模型時,Pydantic 會是最佳選擇。
程式碼範例
以下範例均以 Python 為例,搭配 LangChain v0.0.XXX(請自行替換為最新版本)。
範例 1:最簡單的 JSON 輸出解析
from langchain import PromptTemplate, LLMChain
from langchain.llms import OpenAI
from langchain.output_parsers import JsonOutputParser
# 1️⃣ Prompt,要求回傳簡單的 JSON
prompt = PromptTemplate(
template="""
請以 JSON 格式回傳以下資訊:
- 使用者名稱 (string)
- 年齡 (integer)
- 是否為會員 (boolean)
輸出範例: {{example}}
""",
input_variables=[],
partial_variables={"example": '{"name":"Alice","age":30,"is_member":true}'}
)
# 2️⃣ LLM
llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0)
# 3️⃣ 建立 Chain
chain = LLMChain(prompt=prompt, llm=llm, output_parser=JsonOutputParser())
# 4️⃣ 呼叫
result = chain.run()
print(result) # => {'name': 'Alice', 'age': 30, 'is_member': True}
說明:
JsonOutputParser()會自動把模型回傳的文字轉成dict。temperature=0確保模型產生的 JSON 格式更一致。
範例 2:使用 JSON Schema 進行嚴格驗證
from langchain.output_parsers import JsonOutputParser
from langchain.schema import OutputParserException
# 定義 JSON Schema
schema = {
"type": "object",
"properties": {
"product_id": {"type": "string"},
"price": {"type": "number"},
"tags": {
"type": "array",
"items": {"type": "string"}
}
},
"required": ["product_id", "price"]
}
parser = JsonOutputParser(schema=schema)
raw_output = """{
"product_id": "P12345",
"price": 199.99,
"tags": ["electronics", "sale"]
}"""
try:
data = parser.parse(raw_output)
print(data) # 成功解析
except OutputParserException as e:
print("解析失敗:", e)
重點:若模型回傳的 JSON 缺少
price欄位,或price為字串而非數字,parse會拋出例外,讓你在程式層面即時捕獲錯誤。
範例 3:Pydantic 模型定義
from pydantic import BaseModel, Field, ValidationError
from langchain.output_parsers import PydanticOutputParser
class OrderInfo(BaseModel):
order_id: str = Field(..., description="訂單編號")
amount: float = Field(..., gt=0, description="金額,必須大於 0")
currency: str = Field(..., regex="^[A-Z]{3}$", description="三位大寫貨幣代碼")
items: list[str] = Field(..., description="商品名稱列表")
parser = PydanticOutputParser(pydantic_object=OrderInfo)
raw = """{
"order_id": "ORD-2025-001",
"amount": 1500.5,
"currency": "TWD",
"items": ["筆記型電腦", "滑鼠"]
}"""
try:
order = parser.parse(raw)
print(order) # <OrderInfo ...>
print(order.dict()) # 轉成 dict 方便後續處理
except ValidationError as ve:
print("驗證失敗:", ve)
說明:
gt=0、regex等限制會在解析階段自動檢查。- 若 LLM 回傳
"currency": "usd"(小寫),將觸發ValidationError,讓你即時知道資料不符合規範。
範例 4:結合 Prompt、LLM 與 PydanticOutputParser
from langchain import PromptTemplate, LLMChain
from langchain.llms import OpenAI
prompt = PromptTemplate(
template="""
你是一位客服機器人,請根據以下對話產生 JSON 回報,欄位如下:
- ticket_id (string)
- priority (enum: "low","medium","high")
- summary (string)
- resolved (boolean)
對話內容:
{conversation}
""",
input_variables=["conversation"]
)
# 使用 Pydantic 定義回報結構
class TicketReport(BaseModel):
ticket_id: str
priority: str
summary: str
resolved: bool
parser = PydanticOutputParser(pydantic_object=TicketReport)
chain = LLMChain(
llm=OpenAI(model_name="gpt-4o-mini", temperature=0),
prompt=prompt,
output_parser=parser
)
conversation = """
客戶: 我的訂單遲遲未送達,已經超過預計時間兩天。
客服: 很抱歉造成不便,我會立即幫您查詢。請問您的訂單編號是?
客戶: ORD-2025-009
"""
report = chain.run(conversation=conversation)
print(report) # TicketReport 物件
實務觀點:此範例展示了 完整的端到端流程:從自然語言對話 → LLM 回傳結構化 JSON → Pydantic 直接得到驗證過的 Python 物件,最後可直接寫入資料庫或觸發自動化流程。
範例 5:自訂錯誤回饋(Retry 機制)
from langchain.output_parsers import JsonOutputParser, OutputParserException
parser = JsonOutputParser()
def safe_parse(text: str, max_retry: int = 2) -> dict:
attempt = 0
while attempt <= max_retry:
try:
return parser.parse(text)
except OutputParserException as e:
attempt += 1
# 簡單的重試策略:請 LLM 再次產生符合 JSON 的回應
print(f"第 {attempt} 次解析失敗,嘗試重新產生…")
# 這裡假設有一個 `llm` 物件可呼叫
text = llm.invoke(f"請把以下文字重新整理成正確的 JSON:\n{text}")
raise RuntimeError("多次嘗試仍未成功解析")
技巧:結合 Retry 與 LLM 再次生成,可以大幅降低因模型偶爾產生不完整 JSON 而導致的失敗率。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方式 |
|---|---|---|
| 模型產生非 JSON 文字 | LLM 有時會在回應前後加上說明文字或程式碼區塊 (```json) | 在 Prompt 中加入「只回傳 JSON,別加任何說明」;或在 Parser 前使用正則把前後雜訊去掉 |
| 欄位順序或缺漏 | JSON Schema 要求的 required 欄位若缺失會拋錯 |
在 Prompt 中給予完整範例,或使用 Pydantic 的 default_factory 提供預設值 |
| 型別不符合 | 例如 "price": "199"(字串)而非數字 |
使用 Pydantic 的型別檢查,並在 Prompt 中明確說「price 必須是數字」 |
| Enum/Enum 值不一致 | priority 只接受 `low |
medium |
| 過長的 JSON 超過 token 限制 | 大量資料時,模型回傳會被截斷 | 考慮分批產生、或改用 list of objects + page token 機制 |
最佳實踐
- Prompt 先寫範例:提供一個完整、正確的 JSON 範例,讓模型學習格式。
- 固定輸出格式:使用
output_parser前,先在 Prompt 中加上「請直接回傳 JSON,不要加任何文字」的指示。 - 驗證層:永遠在程式碼層面做一次結構驗證(JSON Schema 或 Pydantic),即使模型看起來正確。
- 錯誤回饋機制:結合
try/except與 Retry,自動請模型重新產生,提升穩定性。 - 單元測試:把 Prompt、Parser、LLM 呼叫寫成測試,確保未來模型升級或 Prompt 變更不會破壞解析。
實際應用場景
| 場景 | 為何需要結構化輸出 | 典型實作 |
|---|---|---|
| 客服票務系統 | 從聊天記錄自動抽取 Ticket ID、優先權、解決狀態 | 使用 PydanticOutputParser 建立 TicketReport,直接寫入 Ticket DB |
| 金融報表產生 | LLM 生成的財務指標必須精確數值與單位 | 使用 JsonOutputParser 搭配 JSON Schema,確保 float、currency 正確 |
| 商品推薦引擎 | 輸出多個商品的 id、name、price 給前端 |
產生 JSON 陣列,前端直接解析渲染 UI |
| 自動化測試腳本 | 從自然語言需求產生測試案例的 title、steps、expected |
Pydantic 讓每個欄位都有型別與說明,減少手動校正 |
| 資料清洗管線 | LLM 讀取非結構化文字(如 PDF)並轉成結構化紀錄 | 先用 JsonOutputParser 把文字轉 dict,再交給 Pandas 處理 |
總結
- Output Parsers 是讓 LLM 與程式碼「說同一種語言」的關鍵橋樑。
- JSON 提供跨語言、輕量的結構化方式;Pydantic 則在 Python 生態系中提供型別安全、驗證完整的模型。
- 正確的 Prompt 設計、Schema/Pydantic 定義、以及 錯誤回饋機制,是避免解析失敗的三大法寶。
- 透過本篇提供的範例與實務建議,你可以迅速將 LLM 的自然語言輸出轉成可直接使用的資料,從而建構更可靠、可維護的 AI 應用。
下一步:挑選一個你目前正在開發的功能,試著把回傳的文字改寫為 JSON 或 Pydantic 物件,觀察開發效率與錯誤率的變化。祝你在 LangChain 的旅程中玩得開心、寫得更好! 🚀