Fructose:强类型 LLM 函数调用工具
为 LLM 调用提供类型安全的接口定义,降低 AI 集成的错误率。简化 LLM 应用开发的工程复杂度。
为 LLM 调用提供类型安全的接口定义,降低 AI 集成的错误率。简化 LLM 应用开发的工程复杂度。
Fructose 是一个 Python 包,用来为 LLM 调用创建可靠的、强类型的接口。
只需在类型注解函数上加上 @ai 装饰器,然后像调用普通函数一样调用它。这是一个轻量级的语法糖。
from fructose import Fructose
ai = Fructose()
@ai
def describe(animals: list[str]) -> str:
"""
Given a list of animals, use one word that'd describe them all.
"""
...
description = describe(["dog", "cat", "parrot", "goldfish"])
print(description) # -> "pets" type: str
@ai 装饰器会对函数进行内省并构建提示词,在调用函数时将其发送给 LLM 来执行任务。
基本类型 str bool int float
复合类型 list dict tuple Enum Optional
复杂数据类型 @dataclass
自定义提示词模板
本地函数调用
我们为这个项目在 Hacker News 推出后获得的热度感到无比自豪,但我们不得不将注意力转向其他地方。我们已暂停对 Fructose 的维护。如果你正在寻找一个更积极维护的包,可以查看 Instructor 或 Marvin。如果你喜欢 Fructose 并想在此基础上进行开发,欢迎 fork 创建自己的版本,或者提交 issue 请求成为维护者。
pip3 install fructose
目前它使用 OpenAI 执行提示词,所以你需要使用自己的 OpenAI API Key
export OPENAI_API_KEY=sk-abcdefghijklmnopqrstuvwxyz
from fructose import Fructose
from dataclasses import dataclass
ai = Fructose()
@dataclass
class Person:
name: str
hobbies: str
dislikes: str
obscure_inclinations: str
age: int
height: float
is_human: bool
@ai
def generate_fake_person_data() -> Person:
"""
Generate fake data for a cliche aspiring author
"""
...
person = generate_fake_person_data()
print(person)
Fructose 的 @ai 函数可以选择调用本地 Python 函数。是的,甚至可以调用其他 @ai 函数。
通过 @ai 装饰器的 uses 参数传入函数:@ai(uses = [func_1, func_2])
例如,下面是一个 Fructose 函数,它使用本地函数和 requests 库获取 HackerNews 评论:
from fructose import Fructose
import requests
from dataclasses import dataclass
ai = Fructose()
def get(uri: str) -> str:
"""
GET request to a URI
"""
return requests.get(uri).text
@dataclass
class Comment:
username: str
comment: str
@ai(uses=[get], debug=True)
def get_comments(uri: str) -> list[Comment]:
"""
Gets all base comments from a hacker news post
"""
...
result = get_comments("https://news.ycombinator.com/item?id=22963649")
for comment in result:
print(f"🧑 {comment.username}: \n💬 {comment.comment}\n")
本地函数调用目前需要:
并支持以下基本类型的参数:
str bool int float 和 list
通过 model 关键字选择 OpenAI 模型。默认为 gpt-4-turbo-preview
ai = Fructose(model = "gpt-3.5-turbo")
你可以配置自己的 OpenAI 客户端并与 Fructose 一起使用。这允许你执行诸如通过代理路由调用或使用与 OpenAI 兼容的 LLM API 等操作。
from fructose import Fructose
from openai import OpenAI
client = OpenAI(
base_url="http://my.test.server.example.com:8083",
http_client=httpx.Client(
proxies="http://my.test.proxy.example.com",
transport=httpx.HTTPTransport(local_address="0.0.0.0"),
),
)
ai = Fructose(client = client)
请注意 Fructose 对所有调用都使用 OpenAI 的 JSON 返回模式,并为函数调用使用 tools API。并非所有替代 LLM 提供商都支持这些功能,而且支持的提供商可能在 API 上存在细微差异。
你可以自由地通过自定义客户端(如上所示)或 OPENAI_BASE_URL 环境变量指向替代 API,但 Fructose 不会正式支持它。
Fructose 有一个轻量级的提示词包装器,在大多数情况下"开箱即用",但你可以使用下面的 Flavors 和 Templates 功能来修改它。注意:我们对这个特定的 API 不太满意,所以欢迎提出替代方案的建议。
Flavors 是可选的标志,用来改变提示词的行为。
random:在系统提示词中添加随机种子,以增加一些变异性
chain_of_thought:将调用分为两个步骤:思维链用于推理,然后进行结构化生成。
ai = Fructose(["random", "chain_of_thought"])
@ai(flavors=["random", "chain_of_thought"])
def my_func():
# ...
你可以使用 Jinja 模板语言带上自己的提示词模板。
要在函数级别使用自定义模板,在 @ai() 装饰器中使用 system_template_path 参数,加上指向你的 Jinja 模板文件的相对路径:
@ai(system_template_path="relative/path/to/my_template.jinja")
def my_func():
# ...
你也可以在装饰器级别设置此项,使其成为所有装饰函数的默认值。
模板必须包含以下变量:
func_doc_string:装饰函数的文档字符串
return_type_string:函数返回类型的字符串表示
参考见默认模板
如果使用了 chain_of_thought flavor,Fructose 将首先运行一个思维链调用,使用特殊的系统提示词。
在 @ai() 装饰器中使用 chain_of_thought_template_path 参数在函数级别自定义它。
@ai(
flavors = ["chain_of_thought"],
chain_of_thought_template_path="relative/path/to/my_template.jinja"
)
def my_func():
# ...
你也可以在装饰器级别设置此项,使其成为所有装饰函数的默认值。
参考见默认思维链模板
我们处于 v0 版本,这意味着版本之间的 API 不稳定。锁定你的版本号以确保新的构建不会破坏!另外要注意...由于 LLM 生成是非确定性的,调用可能也会中断!
从 LLM 获得有创意但强类型的响应在游戏开发场景中特别有用。
下面是一个外星生物合并/繁殖游戏的原型:https://twitter.com/entreprenik/status/1758948061202809066
从这个仓库的根目录:
python3 -m venv venv
. ./venv/bin/activate
用以下命令将 Fructose 安装到你的 pip 环境中:
pip3 install -e .
这会以可编辑模式安装 Fructose 包。所有 Fructose 的导入都会直接运行 ./src/fructose 中的 Fructose 源代码。
在 /examples 下你会找到不同的使用示例。可以这样运行它们:
python3 examples/fake_data.py
python3 -m pytest