一、问题
我们希望LLM的回答的结果具有格式,最好是JSON格式(Python字典), 这样有利于后续的调用。
#普通格式
姓名 张三
年龄 34
兴趣 打篮球、踢足球、游泳、打游戏
#JSON格式
{
"name": "张三",
"age": 34,
"hobby": [
"打篮球",
"踢足球",
"游泳",
"打游戏"
]
}
如何从 「普通格式」转为 结构化的「JSON格式」?这里就用到 Instructor库 。
二、Instructor介绍
Instructor 是一个 Python 库,它使处理大型语言模型 (LLM) 的结构化输出变得轻而易举。它建立在 Pydantic 之上,提供了一个简单、透明且用户友好的 API 来管理验证、重试和流式响应。
2.1 Instructor的主要特征
- 定义输出样式:指定 Pydantic 模型来定义 LLM 输出的结构
- 失败重试管理:轻松配置请求失败的重试次数
- 样式验证:使用 Pydantic 验证确保 LLM 响应符合您的期望
- 灵活的后端:与 OpenAI 之外的各种 LLM 提供商无缝集成
2.2 安装
pip install instructor
2.3 样例
import instructor
from pydantic import BaseModel
from openai import OpenAI
# Define your desired output structure
class UserInfo(BaseModel):
name: str
age: int
# Patch the OpenAI client
client = instructor.from_openai(OpenAI())
# Extract structured data from natural language
user_info = client.chat.completions.create(
model="gpt-3.5-turbo",
response_model=UserInfo,
messages=[{"role": "user", "content": "John Doe is 30 years old."}],
)
print(user_info.name)
#> John Doe
print(user_info.age)
#> 30
注意,本部分的样例仅供观看,因为chatGPT 限制中国大陆用户使用,所以不论是你还是大邓,运行此代码会失败。但文章末尾会提供本地电脑可运行的实验代码。
三、结构化输出实验
3.1 环境配置
假设已在本地安装Ollama软件, 也使用ollama安装了相应的大语言模型(如qwen2:7b、llama3.1:8b等)。 如果之前没有进行这些操作, 请阅读 教程 | 如何使用 Ollama 下载 & 使用本地大语言模型
3.2 代码
只要完成2.2、3.1,本章节的代码是可以运行出结果的。 不做过多解释,直接上代码,大家看运行结果。
from openai import OpenAI
from pydantic import BaseModel
from typing import List
import os
import instructor
#结构化输出
class UserDetail(BaseModel):
name: str
age: int
hobby: List[str]
#Prompt提示
PROMPT_TEXT = "根据自我介绍文本内容,从中提取出姓名、年龄、兴趣"
#实验数据
introduction_text = '我是张三,今年34岁, 来自黑龙江省, 我的兴趣爱好有打篮球、踢足球、游泳、打游戏。'
client = instructor.from_openai(
OpenAI(
base_url="http://localhost:11434/v1",
api_key="NA", # required, but unused
),
mode = instructor.Mode.JSON,
)
resp = client.chat.completions.create(
model = "qwen2:7b",
messages=[
{"role": "system", "content": PROMPT_TEXT},
{"role": "user", "content": introduction_text}
],
response_model = UserDetail,
max_retries = 3
)
print(resp.model_dump_json(indent=2))
Run
{
"name": "张三",
"age": 34,
"hobby": [
"打篮球",
"踢足球",
"游泳",
"打游戏"
]
}
resp的数据类型为UserDetail, 是代码中是我们定义的 UserDetail 类。该类具有一些方法,也可直接 resp.dict() 转化为dict
查看 resp 的数据类型
print(resp.dict())
print(type(resp.dict()))
Run
{'name': '张三', 'age': 34, 'hobby': ['打篮球', '踢足球', '游泳', '打游戏']}
<class 'dict'>