Python API#

LLM 除了提供命令行界面外,还提供了用于执行提示的 Python API。

理解此 API 对于编写 插件也很重要。

基本提示执行#

要针对 gpt-4o-mini 模型运行提示,请运行此代码:

import llm

model = llm.get_model("gpt-4o-mini")
# key= is optional, you can configure the key in other ways
response = model.prompt(
    "Five surprising names for a pet pelican",
    key="sk-..."
)
print(response.text())

请注意,提示直到您调用 response.text() 方法时才会被评估 - 这是一种延迟加载的形式。

如果您在响应被评估之前检查它,它将看起来像这样:

<Response prompt='Your prompt' text='... not yet done ...'>

llm.get_model() 函数接受模型 ID 或别名。您也可以省略它以使用当前配置的默认模型,如果您未更改默认设置,则默认模型为 gpt-4o-mini

在此示例中,密钥由 Python 代码设置。您还可以使用 OPENAI_API_KEY 环境变量提供密钥,或者使用 llm keys set openai 命令将其存储在 keys.json 文件中,请参阅API 密钥管理

response__str__() 方法也返回响应文本,因此您可以这样做:

print(llm.get_model().prompt("Five surprising names for a pet pelican"))

您可以运行此命令查看可用模型及其别名的列表:

llm models

如果您已设置 OPENAI_API_KEY 环境变量,则可以省略 model.key = 行。

使用无效模型 ID 调用 llm.get_model() 将引发 llm.UnknownModelError 异常。

系统提示#

对于接受系统提示的模型,将其作为 system="..." 传入:

response = model.prompt(
    "Five surprising names for a pet pelican",
    system="Answer like GlaDOS"
)

附件#

接受多模态输入(图像、音频、视频等)的模型可以使用 attachments= 关键字参数传递附件。该参数接受一个 llm.Attachment() 实例列表。

此示例显示了两个附件 - 一个来自文件路径,一个来自 URL:

import llm

model = llm.get_model("gpt-4o-mini")
response = model.prompt(
    "Describe these images",
    attachments=[
        llm.Attachment(path="pelican.jpg"),
        llm.Attachment(url="https://static.simonwillison.net/static/2024/pelicans.jpg"),
    ]
)

使用 llm.Attachment(content=b"binary image content here") 直接传递二进制内容。

您可以使用 model.attachment_types 集合检查模型支持哪些附件类型(如果有):

model = llm.get_model("gpt-4o-mini")
print(model.attachment_types)
# {'image/gif', 'image/png', 'image/jpeg', 'image/webp'}

if "image/jpeg" in model.attachment_types:
    # Use a JPEG attachment here
    ...

Schema#

CLI 工具一样,一些模型支持传入 JSON schema 用于生成响应。

您可以将其作为 Python 字典或 Pydantic BaseModel 子类传递给 prompt(schema=) 参数:

import llm, json
from pydantic import BaseModel

class Dog(BaseModel):
    name: str
    age: int

model = llm.get_model("gpt-4o-mini")
response = model.prompt("Describe a nice dog", schema=Dog)
dog = json.loads(response.text())
print(dog)
# {"name":"Buddy","age":3}

您也可以直接传递 schema,像这样:

response = model.prompt("Describe a nice dog", schema={
    "properties": {
        "name": {"title": "Name", "type": "string"},
        "age": {"title": "Age", "type": "integer"},
    },
    "required": ["name", "age"],
    "title": "Dog",
    "type": "object",
})

您还可以通过 llm.schema_dsl(schema_dsl) 函数使用 LLM 的替代 schema 语法。这为简单情况构建 JSON schema 提供了一种快速方法:

print(model.prompt(
    "Describe a nice dog with a surprising name",
    schema=llm.schema_dsl("name, age int, bio")
))

传入 multi=True 以生成一个返回与该规范匹配的多个项目的 schema。

print(model.prompt(
    "Describe 3 nice dogs with surprising names",
    schema=llm.schema_dsl("name, age int, bio", multi=True)
))

片段#

还可以从 Python API 访问 CLI 工具中的片段系统,方法是将 fragments= 和/或 system_fragments= 字符串列表传递给 prompt() 方法:

response = model.prompt(
    "What do these documents say about dogs?",
    fragments=[
        open("dogs1.txt").read(),
        open("dogs2.txt").read(),
    ],
    system_fragments=[
        "You answer questions like Snoopy",
    ]
)

这种机制在 Python 中的实用性有限,因为您也可以直接将这些字符串的内容组合到 prompt=system= 字符串中。

如果您正在使用 LLM 将提示存储到 SQLite 数据库的机制,那么片段会变得更有趣,但这部分尚未成为稳定、文档化的 Python API 的一部分。

一些模型插件可能包含利用片段的功能,例如 llm-anthropic 旨在将它们用作利用 Claude 提示缓存系统机制的一部分。

模型选项#

对于支持选项的模型(使用 llm models --options 查看),您可以将选项作为关键字参数传递给 .prompt() 方法:

model = llm.get_model()
print(model.prompt("Names for otters", temperature=0.2))

传递 API 密钥#

接受 API 密钥的模型应在其 model.prompt() 方法中接受一个附加的 key= 参数:

model = llm.get_model("gpt-4o-mini")
print(model.prompt("Names for beavers", key="sk-..."))

如果您不提供此参数,LLM 将尝试从环境变量(OpenAI 为 OPENAI_API_KEY,其他插件使用不同的变量)或使用 llm keys set 命令保存的密钥中查找它。

某些模型插件可能尚未升级以处理 key= 参数,在这种情况下,您需要使用其他机制之一。

来自插件的模型#

您作为插件安装的任何模型也将通过此机制可用,例如,使用 llm-anthropic 使用 Anthropic 的 Claude 3.5 Sonnet 模型:

pip install llm-anthropic

然后在您的 Python 代码中:

import llm

model = llm.get_model("claude-3.5-sonnet")
# Use this if you have not set the key using 'llm keys set claude':
model.key = 'YOUR_API_KEY_HERE'
response = model.prompt("Five surprising names for a pet pelican")
print(response.text())

有些模型完全不使用 API 密钥。

访问底层 JSON#

大多数模型插件还提供了提示响应的 JSON 版本。其结构在不同的模型插件之间会有所不同,因此基于此构建的代码可能只适用于特定的模型提供者。

您可以使用 response.json() 方法将此 JSON 数据作为 Python 字典访问:

import llm
from pprint import pprint

model = llm.get_model("gpt-4o-mini")
response = model.prompt("3 names for an otter")
json_data = response.json()
pprint(json_data)

以下是 GPT-4o mini 的示例输出:

{'content': 'Sure! Here are three fun names for an otter:\n'
            '\n'
            '1. **Splash**\n'
            '2. **Bubbles**\n'
            '3. **Otto** \n'
            '\n'
            'Feel free to mix and match or use these as inspiration!',
 'created': 1739291215,
 'finish_reason': 'stop',
 'id': 'chatcmpl-AznO31yxgBjZ4zrzBOwJvHEWgdTaf',
 'model': 'gpt-4o-mini-2024-07-18',
 'object': 'chat.completion.chunk',
 'usage': {'completion_tokens': 43,
           'completion_tokens_details': {'accepted_prediction_tokens': 0,
                                         'audio_tokens': 0,
                                         'reasoning_tokens': 0,
                                         'rejected_prediction_tokens': 0},
           'prompt_tokens': 13,
           'prompt_tokens_details': {'audio_tokens': 0, 'cached_tokens': 0},
           'total_tokens': 56}}

Token 使用量#

许多模型可以返回执行提示时使用的 token 数量的计数。

response.usage() 方法提供了对此的抽象:

pprint(response.usage())

示例输出

Usage(input=5,
      output=2,
      details={'candidatesTokensDetails': [{'modality': 'TEXT',
                                            'tokenCount': 2}],
               'promptTokensDetails': [{'modality': 'TEXT', 'tokenCount': 5}]})

.input.output 属性是整数,表示输入和输出 token 的数量。.details 属性可能是一个包含其他自定义值的字典,这些值因模型而异。

流式响应#

对于支持的模型,您可以在生成响应时进行流式传输,像这样:

response = model.prompt("Five diabolical names for a pet goat")
for chunk in response:
    print(chunk, end="")

前面描述的 response.text() 方法为您完成了此操作 - 它遍历迭代器并将结果收集到一个字符串中。

如果响应已被评估,response.text() 将继续返回相同的字符串。

异步模型#

一些插件提供了其支持模型的异步版本,适用于与 Python asyncio 一起使用。

要使用异步模型,请使用 llm.get_async_model() 函数而不是 llm.get_model()

import llm
model = llm.get_async_model("gpt-4o")

然后您可以使用 await model.prompt(...) 运行提示:

response = await model.prompt(
    "Five surprising names for a pet pelican"
)
print(await response.text())

或者使用 async for chunk in ... 在生成响应时进行流式传输:

async for chunk in model.prompt(
    "Five surprising names for a pet pelican"
):
    print(chunk, end="", flush=True)

await model.prompt() 方法接受与同步 model.prompt() 方法相同的参数,用于选项、附件以及 key= 等。

对话#

LLM 支持对话,您可以在持续进行的对话中向模型提出后续问题。

要开始新对话,请使用 model.conversation() 方法:

model = llm.get_model()
conversation = model.conversation()

然后您可以使用 conversation.prompt() 方法在此对话中执行提示:

response = conversation.prompt("Five fun facts about pelicans")
print(response.text())

这与 model.prompt() 方法完全相同,不同之处在于对话将跨多个提示进行维护。因此,如果您接下来运行此代码:

response2 = conversation.prompt("Now do skunks")
print(response2.text())

您将获得关于臭鼬的五个有趣事实。

conversation.prompt() 方法也支持附件:

response = conversation.prompt(
    "Describe these birds",
    attachments=[
        llm.Attachment(url="https://static.simonwillison.net/static/2024/pelicans.jpg")
    ]
)

访问 conversation.responses 可获取对话中至今返回的所有响应列表。

列出模型#

llm.get_models() 列表返回所有可用模型的列表,包括来自插件的模型。

import llm

for model in llm.get_models():
    print(model.model_id)

使用 llm.get_async_models() 列出异步模型。

for model in llm.get_async_models():
    print(model.model_id)

响应完成后运行代码#

对于某些应用程序,例如跟踪应用程序使用的 token,在响应执行完毕后立即执行代码可能很有用:

您可以使用 response.on_done(callback) 方法来实现此操作,该方法会在响应完成后(所有 token 都已返回)立即调用您的回调函数。

您提供的方法签名是 def callback(response) - 在使用异步模型时,它可以选择是一个 async def 方法。

示例用法

import llm

model = llm.get_model("gpt-4o-mini")
response = model.prompt("a poem about a hippo")
response.on_done(lambda response: print(response.usage()))
print(response.text())

输出如下:

Usage(input=20, output=494, details={})
In a sunlit glade by a bubbling brook,
Lived a hefty hippo, with a curious look.
...

或者使用 asyncio 模型,在这种情况下您需要 await response.on_done(done) 以将回调排入队列:

import asyncio, llm

async def run():
    model = llm.get_async_model("gpt-4o-mini")
    response = model.prompt("a short poem about a brick")
    async def done(response):
        print(await response.usage())
        print(await response.text())
    await response.on_done(done)
    print(await response.text())

asyncio.run(run())

其他函数#

llm 顶级包包含一些有用的实用函数。

set_alias(alias, model_id)#

llm.set_alias() 函数可用于定义新别名:

import llm

llm.set_alias("mini", "gpt-4o-mini")

第二个参数可以是模型标识符或另一个别名,在这种情况下,该别名将被解析。

如果 aliases.json 文件不存在或包含无效 JSON,则会创建或覆盖该文件。

remove_alias(alias)#

aliases.json 文件中删除给定名称的别名。

如果别名不存在,则引发 KeyError

import llm

llm.remove_alias("turbo")

set_default_model(alias)#

这将默认模型设置为给定的模型 ID 或别名。对默认设置的任何更改将保存在 LLM 配置文件夹中,并将影响系统上所有使用 LLM 的程序,包括 llm CLI 工具。

import llm

llm.set_default_model("claude-3.5-sonnet")

get_default_model()#

这返回当前配置的默认模型,如果未设置默认模型,则返回 gpt-4o-mini

import llm

model_id = llm.get_default_model()

要检测是否未设置默认值,您可以使用以下模式:

if llm.get_default_model(default=None) is None:
    print("No default has been set")

这里的 default= 参数指定了在没有配置默认值时应返回的值。

set_default_embedding_model(alias) 和 get_default_embedding_model()#

这两个方法与 set_default_model()get_default_model() 工作方式相同,但用于默认嵌入模型