smartfunc:将 Docstring 转换为 LLM 函数
koaning/smartfunc
将 docstring 转换为 LLM 函数。
如果你对演示感兴趣,你可能会喜欢这个 YouTube 视频:
安装
uv pip install smartfunc
这是什么?
下面是一个使用此库的例子:
from smartfunc import backend
@backend("gpt-4")
def generate_summary(text: str):
"""生成以下文本的摘要:{{ text }}"""
pass
现在,generate_summary
函数将返回一个包含文本摘要的字符串。
它是如何工作的?
这个库包装了 llm library,它是由 Simon Willison 创建的。docstring
会被解析并转换为 Jinja2 模板,我们在运行时注入变量来生成提示。然后,我们使用装饰器提供的后端来运行提示并返回结果。
llm
库是极简的,虽然它不支持所有功能,但它确实提供了一个坚实的基础来构建。这个库主要用作在顶部添加一些语法糖的方法。不过,我们确实从 llm
库中获得了一些好处:
llm
库维护良好,拥有庞大的社区- 一个用于不同 LLM 提供商的 backends 生态系统
- 许多供应商都具有
async
支持,这允许我们进行微批量处理 - 许多供应商都具有 schema 支持,这允许我们使用 Pydantic 模型来定义响应
- 您可以使用
.env
文件来存储您的 API 密钥
额外功能
Schemas
以下代码段展示了如何创建一个可重用的后端装饰器,该装饰器使用系统提示。另请注意,我们如何能够使用 Pydantic 模型来定义响应。
from smartfunc import backend
from pydantic import BaseModel
from dotenv import load_dotenv
load_dotenv(".env")
class Summary(BaseModel):
summary: str
pros: list[str]
cons: list[str]
llmify = backend("gpt-4o-mini", system="You are a helpful assistant.", temperature=0.5)
@llmify
def generate_poke_desc(text: str) -> Summary:
"""Describe the following pokemon: {{ text }}"""
pass
print(generate_poke_desc("pikachu"))
这是我们收到的结果:
{
'summary': 'Pikachu is a small, electric-type Pokémon known for its adorable appearance and strong electrical abilities. It is recognized as the mascot of the Pokémon franchise, with distinctive features and a cheerful personality.',
'pros': [
'Iconic and recognizable worldwide',
'Strong electric attacks like Thunderbolt',
'Has a cute and friendly appearance',
'Evolves into Raichu with a Thunder Stone',
'Popular choice in Pokémon merchandise and media'
],
'cons': [
'Not very strong in higher-level battles',
'Weak against ground-type moves',
'Limited to electric-type attacks unless learned through TMs',
'Can be overshadowed by other powerful Pokémon in competitive play'
],
}
并非每个后端都支持 schema,但如果出现这种情况,您会收到一条有用的错误消息。
注意
您可能会看到这个例子,并想知道您是否应该使用 instructor。毕竟,该库对参数的验证有更多的支持,甚至还有一些用于多轮对话的实用程序。那么 ell 或 marvin 呢?
您会注意到 smartfunc
没有做那些其他库所做的一大堆事情。但这里的目标是简单,并专注于一组特定的功能。例如,instructor 需要您了解更多关于每个后端的信息。如果您想使用 claude 而不是 openai,那么您需要加载一个不同的库。类似地,我觉得所有其他平台都缺少类似的东西:async 支持或供应商自由。
这里的目标是在快速原型设计期间保持简单。您只需要确保安装了 llm
插件,就可以开始了。就这样。
内部函数提示工程
使用 smartfunc
最简单的方法是将提示放入 docstring
中并完成它。如果需要,您也可以在其中运行 jinja2,但如果您需要额外的灵活性,那么您也可以使用内部函数来编写 promopt
的逻辑。内部函数返回的任何字符串都将添加到 docstring
提示的后面。
import asyncio
from smartfunc import backend
from pydantic import BaseModel
from dotenv import load_dotenv
load_dotenv(".env")
class Summary(BaseModel):
summary: str
pros: list[str]
cons: list[str]
# This would also work, but has the benefit that you can use the inner function to write
# the logic of your prompt which allows for more flexible prompt engineering
@backend("gpt-4o-mini")
def generate_poke_desc(text: str) -> Summary:
"""Describe the following pokemon: {{ text }}"""
return " ... but make it sound as if you are a 10 year old child"
resp = generate_poke_desc("pikachu")
print(resp) # This response should now be more child-like
Async
该库还支持异步函数。如果您想进行微批量处理,或者想使用 llm
库中的异步后端,这将非常有用。
import asyncio
from smartfunc import async_backend
from pydantic import BaseModel
from dotenv import load_dotenv
load_dotenv(".env")
class Summary(BaseModel):
summary: str
pros: list[str]
cons: list[str]
@async_backend("gpt-4o-mini")
async def generate_poke_desc(text: str) -> Summary:
"""Describe the following pokemon: {{ text }}"""
pass
resp = asyncio.run(generate_poke_desc("pikachu"))
print(resp)
Debug 模式
该库还支持 debug 模式。如果您想查看使用的提示或查看返回的响应,这将非常有用。
import asyncio
from smartfunc import async_backend
from pydantic import BaseModel
from dotenv import load_dotenv
load_dotenv(".env")
class Summary(BaseModel):
summary: str
pros: list[str]
cons: list[str]
@async_backend("gpt-4o-mini", debug=True)
async def generate_poke_desc(text: str) -> Summary:
"""Describe the following pokemon: {{ text }}"""
pass
resp = asyncio.run(generate_poke_desc("pikachu"))
print(resp)
这将返回一个包含调试信息的字典。
{
'summary': 'Pikachu is a small, yellow, rodent-like Pokémon known for its electric powers and iconic status as the franchise mascot. It has long ears with black tips, red cheeks that store electricity, and a lightning bolt-shaped tail. Pikachu evolves from Pichu when leveled up with high friendship and can further evolve into Raichu when exposed to a Thunder Stone. Pikachu is often depicted as cheerful, playfully energetic, and is renowned for its ability to generate electricity, which it can unleash in powerful attacks such as Thunderbolt and Volt Tackle.',
'pros': [
'Iconic mascot of the Pokémon franchise', 'Popular among fans of all ages', 'Strong electric-type moves', 'Cute and friendly appearance'
],
'cons': [
'Limited range of evolution (only evolves into Raichu)', 'Commonly found, which may reduce uniqueness', 'Vulnerable to ground-type moves', 'Requires high friendship for evolution to Pichu, which can be a long process'
],
'_debug': {
'template': 'Describe the following pokemon: {{ text }}',
'func_name': 'generate_poke_desc',
'prompt': 'Describe the following pokemon: pikachu',
'system': None,
'template_inputs': {
'text': 'pikachu'
},
'backend_kwargs': {},
'datetime': '2025-03-13T16:05:44.754579',
'return_type': {
'properties': {
'summary': {'title': 'Summary', 'type': 'string'},
'pros': {'items': {'type': 'string'}, 'title': 'Pros', 'type': 'array'},
'cons': {'items': {'type': 'string'}, 'title': 'Cons', 'type': 'array'}
},
'required': ['summary', 'pros', 'cons'],
'title': 'Summary',
'type': 'object'
}
}
}