Python中的结构化和类型提示的GPT响应。
项目描述
gpt-json
gpt-json
是GPT的一个包装器,允许声明性地定义期望的输出格式。设置一个模式,编写一个提示,并将结果以漂亮的类型提示对象返回。
此库引入了以下功能
- 🏗️ Pydantic模式定义,用于类型转换和验证
- 🧵 提示模板,允许动态内容
- 🔎 支持视觉API、函数调用和标准聊天提示
- 🚕 轻量级输出转换,以修复损坏的json
- ♻️ 重复逻辑,用于最常见的API失败
- 📋 预测单个对象和对象列表
- ✈️ 轻量级依赖关系:仅OpenAI、pydantic和backoff
入门指南
pip install gpt-json
以下是使用它为简单任务生成模式的方法
import asyncio
from gpt_json import GPTJSON, GPTMessage, GPTMessageRole
from pydantic import BaseModel
class SentimentSchema(BaseModel):
sentiment: str
SYSTEM_PROMPT = """
Analyze the sentiment of the given text.
Respond with the following JSON schema:
{json_schema}
"""
async def runner():
gpt_json = GPTJSON[SentimentSchema](API_KEY)
payload = await gpt_json.run(
messages=[
GPTMessage(
role=GPTMessageRole.SYSTEM,
content=SYSTEM_PROMPT,
),
GPTMessage(
role=GPTMessageRole.USER,
content="Text: I love this product. It's the best thing ever!",
)
]
)
print(payload.response)
print(f"Detected sentiment: {payload.response.sentiment}")
asyncio.run(runner())
sentiment='positive'
Detected sentiment: positive
json_schema
是一个特殊关键字,将在运行时替换为模式定义。您应始终将其包含在有效负载中,以确保模型知道如何格式化结果。但是,您可以玩弄将此模式定义包含在何处;在系统提示中、用户提示中、开头或结尾。
您可以选择为模型添加类型提示以返回BaseSchema,或者提供多个BaseSchema的列表。这两种方法都有效
from gpt_json.gpt import GPTJSON, ListResponse
gpt_json_single = GPTJSON[SentimentSchema](API_KEY)
gpt_json_multiple = GPTJSON[ListResponse[SentimentSchema]](API_KEY)
如果您想更具体地了解模型如何填充字段,请通过“description”字段添加有关值的提示。这有助于模型理解您在寻找什么,并有助于它生成更好的结果。
from pydantic import BaseModel, Field
class SentimentSchema(BaseModel):
sentiment: int = Field(description="Either -1, 0, or 1.")
sentiment=1
Detected sentiment: 1
提示变量
除了json_schema
模板关键字之外,您还可以将任意变量添加到您的消息中。这允许您更轻松地插入用户生成的内容或根据先前消息的结果动态生成提示。
class QuoteSchema(BaseModel):
quotes: list[str]
SYSTEM_PROMPT = """
Generate fictitious quotes that are {sentiment}.
{json_schema}
"""
gpt_json = GPTJSON[QuoteSchema](API_KEY)
response = await gpt_json.run(
messages=[
GPTMessage(
role=GPTMessageRole.SYSTEM,
content=SYSTEM_PROMPT,
),
],
format_variables={"sentiment": "happy"},
)
在调用.run()
函数时,您可以传入填充此模板所需的值。这也适用于字段描述,因此您可以按字段指定自定义行为。
class QuoteSchema(BaseModel):
quotes: list[str] = Field(description="Max quantity {max_items}.")
SYSTEM_PROMPT = """
Generate fictitious quotes that are {sentiment}.
{json_schema}
"""
gpt_json = GPTJSON[QuoteSchema](API_KEY)
response = await gpt_json.run(
messages=[
GPTMessage(
role=GPTMessageRole.SYSTEM,
content=SYSTEM_PROMPT,
),
],
format_variables={"sentiment": "happy", "max_items": 5},
)
函数调用
gpt-3.5-turbo-0613
和gpt-4-0613
经过微调以支持函数调用的特定语法。我们在gpt-json
中也支持这种语法。以下是一个使用示例:
class UnitType(Enum):
CELSIUS = "celsius"
FAHRENHEIT = "fahrenheit"
class GetCurrentWeatherRequest(BaseModel):
location: str = Field(description="The city and state, e.g. San Francisco, CA")
unit: UnitType | None = None
class DataPayload(BaseModel):
data: str
def get_current_weather(request: GetCurrentWeatherRequest):
"""
Get the current weather in a given location
"""
weather_info = {
"location": request.location,
"temperature": "72",
"unit": request.unit,
"forecast": ["sunny", "windy"],
}
return json_dumps(weather_info)
async def runner():
gpt_json = GPTJSON[DataPayload](API_KEY, functions=[get_current_weather])
response = await gpt_json.run(
messages=[
GPTMessage(
role=GPTMessageRole.USER,
content="What's the weather like in Boston, in F?",
),
],
)
assert response.function_call == get_current_weather
assert response.function_arg == GetCurrentWeatherRequest(
location="Boston", unit=UnitType.FAHRENHEIT
)
响应提供原始函数以及格式化的Pydantic对象。如果用户想要执行函数,他们可以运行response.function_call(response.function_arg)。我们将get_current_weather函数和GetCurrentWeatherRequest参数解析为GPT期望的格式,因此更有可能返回正确的函数执行结果。
GPT不对返回函数的有效性做出保证。它们可能会虚构一个函数名或函数签名。为了解决这些问题,run()函数现在可以抛出两个新的异常:
InvalidFunctionResponse
- 函数名不正确。InvalidFunctionParameters
- 函数名正确,但与提供的输入架构不匹配。
其他配置
GPTJSON
类在初始化时支持其他配置参数。
参数 | 类型 | 描述 |
---|---|---|
model | GPTModelVersion | str | (默认: GPTModelVersion.GPT_4) - 为方便起见,我们提供了当前支持的GPT模型版本,在GPTModelVersion 枚举中。如果您想使用更具体的架构,也可以传递一个字符串值。 |
auto_trim | bool | (默认: False) - 如果您的输入提示太长,可能是由于动态注入的内容,将自动截断文本以为模型的响应创建足够的空间。 |
auto_trim_response_overhead | int | (默认: 0) - 如果您使用auto_trim,配置模型响应中允许的最大令牌数量。 |
**kwargs | Any | 您想要传递给底层GPT 类的任何其他参数,将直接传递。 |
转换
GPT(尤其是GPT-4)在格式化JSON响应方面相对较好,但并非完美。一些常见问题包括:
- 响应截断:由于GPT内部没有意识到其响应长度限制,JSON有效载荷有时会耗尽可用的令牌空间。这会导致一个损坏的JSON有效载荷,其中大部分数据是有效的,但JSON对象没有关闭,这不是有效的语法。在实际应用中,这种行为的许多情况实际上是可接受的——例如,如果您列出100个生成的字符串,有时您可以接受其中70个实际上渲染的字符串。在这种情况下,
gpt-json
将尝试通过重新创建JSON对象并关闭它来修复截断的有效载荷。 - 布尔变量:GPT有时会混淆有效的JSON布尔值与其他语言中使用的布尔令牌。最常见的是生成
True
而不是true
。gpt-json
将尝试修复这些值。
在调用gpt_json.run()
时,我们返回一个值元组
payload = await gpt_json.run(...)
print(transformations.fix_transforms)
FixTransforms(fixed_truncation=True, fixed_bools=False)
第一个对象是您生成的Pydantic模型。第二个对象是我们修正的存储对象FixTransforms
。此数据类包含上述支持的每个转换案例的标志。这允许您确定响应是否是从GPT JSON显式解析的,还是通过一些中间层传递以获得正确的输出。从那里,您可以根据自己的业务逻辑接受或拒绝响应。
您能提供帮助的地方:当然还有更多常见的(和不太常见的)失败区域。如果您看到这些问题,请向单元测试中添加测试用例。如果您可以编写处理程序来解决通用情况,请这样做。否则,将其标记为pytest.xfail
,我们将将其添加到待办事项列表中。
测试
我们使用poetry进行包管理。要运行捆绑的测试,请从github克隆包。
poetry install
poetry run pytest .
我们的重点是使单元测试尽可能稳健。GPT的可变性能在于其语言模型,而不是其JSON行为!这当然还是一个正在进行中的工作。如果你发现了一个测试套件中没有涵盖的边缘情况,请将其添加到测试套件中。
与其他库的比较
以下是一些解决相同问题的其他库的非详尽列表。它们中的任何一个都不与我的部署完全兼容(因此有这个库),但请检查它们。
jsonformer - 与任何Huggingface模型兼容,而gpt-json
专门针对GPT-X系列。GPT不输出logit概率或允许固定的解码器模板,因此无法应用相同的方法。
格式化
我们使用black和mypy进行格式化。您可以通过./lint.sh
辅助文件设置预提交git钩子来自动完成此操作。
如果您对代码库进行了大量格式化,请将您最近的提交添加到.git-blame-ignore-revs
文件中,并运行
git config blame.ignoreRevsFile .git-blame-ignore-revs
项目详情
下载文件
下载您平台的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源代码分发
构建分发
gpt_json-0.5.1.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | d7c02da83ac0c61f7f235bc6208452d8515a9363b9d9dc6475f9418926975bb0 |
|
MD5 | da78e2d50211f23c8bf85dbb8990db59 |
|
BLAKE2b-256 | 4ccc3bedda9c11cad93f817afa2cc803d8a59ac3231310787ddce8dc703c3cce |
gpt_json-0.5.1-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | dd0d36a727ce7e86ba8cc68a753b97b07fb6b14679cd4a572de65a37d3b45709 |
|
MD5 | 9d85c9f943f9f7403c5f5dc8b3812351 |
|
BLAKE2b-256 | a8e0ae420c146082dc4ba7193c776933ef895d85829e8cd3745eae74daf6870d |