Skip to content

LangChain 使用 with_structured_output 規範 LLM 輸出格式

Posted on:February 22, 2026 at 

概述

常常會遇到需要規範 LLM 輸出格式的需求,這種情況可以使用 LangChain 提供的 with_structured_output 方法,用來規範輸出

JSON

以下是規定要用 JSON 格式做回傳

prompt = "幫我介紹 1 個國家,用 JSON 回應並且有 `chinese_name`、`english_name`、`capital` 和`international_code` 這些關鍵字"

structured_llm = model.with_structured_output(method="json_mode")

result = structured_llm.invoke(prompt)

print(result)

由於我是使用 OpenAI 的 LLM,所以輸入的 prompt 需要有 JSON 這個關鍵字,否則會出現以下錯誤,由於不同 LLM 的規範可能有所不同因此需特別注意

Error code: 400 - {'error': {'message': "'messages' must contain the word 'json' in some form, to use 'response_format' of type 'json_object'.", 'type': 'invalid_request_error', 'param': 'messages', 'code': None}}

正確結果:

{
    "chinese_name": "日本", 
    "english_name": "Japan", 
    "capital": "東京", 
    "international_code": "JP"
}

可以看到他正確的使用了 JSON 作為回傳的格式

BaseModel

接下來介紹一下使用 pydanticBaseModel 來做為自定義的回傳格式

class Country(BaseModel):
    chinese_name: str = Field(description="國家的中文名稱")
    english_name: str = Field(description="國家的英文")
    capital: str = Field(description="國家的首都")
    international_code: int = Field(description="國際電話國碼")

structured_llm = model.with_structured_output(Country)

result = structured_llm.invoke("幫我介紹 1 個國家")

print(result.chinese_name)
print(result)

輸出的結果可以直接使用 attribute 的方式來存取

正確結果:

日本
chinese_name='日本' english_name='Japan' capital='東京' international_code=81

這裡可以看到他回傳的格式符合我們定義的物件格式,並且型別也是正確的,這裡也需要注意 LLM 會綜合參考變數名稱的語意與 description。例如我修改 description 使其與變數名稱不相符

class Country(BaseModel):
    chinese_name: str = Field(description="國家的中文名稱")
    english_name: str = Field(description="國家的英文名稱")
    capital: str = Field(description="位於哪洲")
    international_code: int = Field(description="國際電話國碼")

輸出結果:

日本
chinese_name='日本' english_name='Japan' capital='Tokyo' international_code=81

接著,我讓 attribute 的名稱變得沒有意義

class Country(BaseModel):
    chinese_name: str = Field(description="國家的中文名稱")
    english_name: str = Field(description="國家的英文名稱")
    tmp: str = Field(description="位於哪洲")
    international_code: int = Field(description="國際電話國碼")

輸出結果:

日本
chinese_name='日本' english_name='Japan' tmp='Asia' international_code=81

這裡可以發現他是根據 description 回傳結果

Retry

with_structured_output 方法後面還可以接 with_retry 方法,用來對於型別轉換做錯誤重試,也能一併處理 API 呼叫過程中的網路問題(如 Timeout 或 Rate Limit 超出限制),可以設定 stop_after_attempt 作為重試的次數限制,如果沒有設定則預設為 3 次

prompt = "幫我介紹 1 個國家,用 JSON 回應並且有 `chinese_name`、`english_name`、`capital` 和`international_code` 這些關鍵字"

structured_llm = model.with_structured_output(method="json_mode").with_retry(stop_after_attempt=5)

result = structured_llm.invoke(prompt)

print(result)

Reference