概述
常常會遇到需要規範 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
接下來介紹一下使用 pydantic 的 BaseModel 來做為自定義的回傳格式
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)