LLM 0.32a0 是一次重大且向后兼容的重构
摘要
LLM 0.32a0 对 Python 库和 CLI 工具进行了重大且向后兼容的重构,从简单的文本提示转变为支持消息序列和多部分响应,以更好地处理结构化 JSON 和工具调用等现代 LLM 功能。
暂无内容
查看缓存全文
缓存时间: 2026/05/08 07:14
# LLM 0.32a0 是一次主要的向后兼容重构
来源:https://simonwillison.net/2026/Apr/29/llm/
2026 年 4 月 29 日
我刚刚发布了 LLM 0.32a0(https://llm.datasette.io/en/latest/changelog.html#a0-2026-04-28),这是我为访问大型语言模型(LLM)而开发的 Python 库和 CLI 工具 LLM(https://llm.datasette.io/)的一个 alpha 版本,包含了一些我长期以来一直致力实现的重大变更。
以前的 LLM 版本以提示(prompts)和响应(responses)的概念来建模世界:向模型发送文本提示,返回文本响应。
``
import llm
model = llm.get_model("gpt-5.5")
response = model.prompt("Capital of France?")
print(response.text())
``
在 2023 年 4 月我开始开发这个库时,这种方式是有道理的。但自那以后,变化很大!
LLM 通过其插件系统(https://llm.datasette.io/en/stable/plugins/index.html)为数千种不同的模型提供了抽象层。然而,最初的抽象概念——接收文本输入并返回文本输出——已经无法代表我所需要的所有功能了。
随着时间的推移,LLM 自身增加了附件(https://simonwillison.net/2024/Oct/29/llm-multi-modal/)以处理图像、音频和视频输入,随后增加了模式(schemas)(https://simonwillison.net/2025/Feb/28/llm-schemas/)以输出结构化 JSON,再后来增加了工具(tools)(https://simonwillison.net/2025/May/27/llm-tools/)以执行工具调用。与此同时,LLM 也在不断进化,增加了对推理的支持以及返回图像等各种其他有趣的能力。
LLM 需要进化,以便更好地处理当今前沿模型能够处理的多样化输入和输出类型。
0.32a0 alpha 版本有两个关键变化:模型输入可以表示为消息序列,模型响应可以由不同类型的数据部分流组成。
#### 作为消息序列的提示
LLM 接受文本输入,但自从 ChatGPT 展示了双向对话界面的价值以来,最主流的提示方式是将该输入视为一系列对话轮次。
第一轮看起来可能像这样:
``
user: 法国的首都是哪里?
assistant:
``
(然后模型负责填充助手的回复。)
但随后的每一轮都需要重放直到该点为止的整个对话,就像一种剧本:
``
user: 法国的首都是哪里?
assistant: 巴黎
user: 德国呢?
assistant:
``
大多数主要供应商的 JSON API 都遵循这种模式。以下是使用 OpenAI 聊天完成 API(已被其他供应商广泛模仿)执行上述操作的示例:
``
curl https://api.openai.com/v1/chat/completions \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.5",
"messages": [
{
"role": "user",
"content": "法国的首都是哪里?"
},
{
"role": "assistant",
"content": "Paris"
},
{
"role": "user",
"content": "Germany?"
}
]
}'
``
在 0.32 之前,LLM 将这些建模为对话:
``
model = llm.get_model("gpt-5.5")
conversation = model.conversation()
r1 = conversation.prompt("Capital of France?")
print(r1.text())
# 输出 "Paris"
r2 = conversation.prompt("Germany?")
print(r2.text())
# 输出 "Berlin"
``
如果你从零开始构建与模型的对话,这行得通,但它没有提供一种从一开始就传入先前对话的方法。这使得诸如构建 OpenAI 聊天完成 API 的模拟这样的任务变得比应有的难度更大。
`llm` CLI 工具通过一种用于持久化和填充对话的自定义 SQLite 机制来解决这个问题,但这从未成为 LLM API 的稳定组成部分——而且在许多地方,你可能希望使用 Python 库而不必承诺使用 SQLite 作为存储层。
新的 alpha 版本现在支持此功能:
``
import llm
from llm import user, assistant
model = llm.get_model("gpt-5.5")
response = model.prompt(messages=[
user("Capital of France?"),
assistant("Paris"),
user("Germany?"),
])
print(response.text())
``
`llm.user()` 和 `llm.assistant()` 函数是新的构建器函数,旨在在 `messages=[]` 数组中使用。
之前的 `prompt=` 选项仍然有效,但 LLM 在后台将其升级为单项目消息数组。
你还可以对响应进行*回复*,作为构建对话的替代方案:
``
response2 = response.reply("How about Hungary?")
print(response2) # 默认 __str__() 调用 .text()
``
#### 流式传输部分
Alpha 版本中的另一个主要新接口涉及从提示中流式传输结果。
以前,LLM 支持如下所示的流式传输:
``
response = model.prompt("Generate an SVG of a pelican riding a bicycle")
for chunk in response:
print(chunk, end="")
``
或者这个异步变体:
``
import asyncio
import llm
model = llm.get_async_model("gpt-5.5")
response = model.prompt("Generate an SVG of a pelican riding a bicycle")
async def run():
async for chunk in response:
print(chunk, end="", flush=True)
asyncio.run(run())
``
当今许多模型返回混合类型的内容。针对 Claude 运行的提示可能会返回推理输出,然后是文本,然后是工具调用的 JSON 请求,然后是更多的文本内容。
有些模型甚至可以在服务器端执行工具,例如 OpenAI 的代码解释器工具(https://developers.openai.com/api/docs/guides/tools-code-interpreter?lang=curl)或 Anthropic 的网页搜索(https://platform.claude.com/docs/en/agents-and-tools/tool-use/web-search-tool)。这意味着模型的结果可以组合文本、工具调用、工具输出和其他格式。
多模态输出模型也开始出现,它们可以在流式响应中混合返回图像甚至音频片段(https://developers.openai.com/api/docs/guides/audio#add-audio-to-your-existing-application)。
新的 LLM alpha 版本将这些建模为已类型化的消息部分流。以下是作为 Python API 消费者的样子:
``
import asyncio
import llm
model = llm.get_model("gpt-5.5")
prompt = "invent 3 cool dogs, first talk about your motivations"
def describe_dog(name: str, bio: str) -> str:
"""记录假设狗的名字和传记。"""
return f"{name}: {bio}"
def sync_example():
response = model.prompt(
prompt,
tools=[describe_dog],
)
for event in response.stream_events():
if event.type == "text":
print(event.chunk, end="", flush=True)
elif event.type == "tool_call_name":
print(f"\nTool call: {event.chunk}(", end="", flush=True)
elif event.type == "tool_call_args":
print(event.chunk, end="", flush=True)
async def async_example():
model = llm.get_async_model("gpt-5.5")
response = model.prompt(
prompt,
tools=[describe_dog],
)
async for event in response.astream_events():
if event.type == "text":
print(event.chunk, end="", flush=True)
elif event.type == "tool_call_name":
print(f"\nTool call: {event.chunk}(", end="", flush=True)
elif event.type == "tool_call_args":
print(event.chunk, end="", flush=True)
sync_example()
asyncio.run(async_example())
``
示例输出(仅来自第一个同步示例):
> `我的动机:创造三只具有独特“酷”风格的令人难忘的狗——一只电影风格,一只冒险风格,一只迷人的混乱风格——这样每只都感觉像可以在自己的故事中担任主角。` `工具调用: describe_dog({"name": "Nova Jetpaw", "bio": "一只穿着小型飞行员护目镜、喜欢在月光下的海滩上奔跑的时尚银灰色灵缇犬。Nova 无畏、优雅,据称只是为了好玩就能跑赢无人机。"})` `工具调用: describe_dog({"name": "Mochi Thunderbark", "bio": "一只毛茸茸的柯基犬,戴着戏剧性的黑白金三角巾,拥有摇滚明星的自信。Mochi 个子小、声音大、忠诚,领导着一个完全由松鼠组成的社区“安全巡逻队”。"})` `工具调用: describe_dog({"name": "Atlas Snowfang", "bio": "一只巨大的白色哈士奇,拥有冰蓝色的眼睛和装满徒步零食的背包。Atlas 冷静、英勇,总是知道回家的路——即使在暴风雪、雾天或令人困惑的露营旅行中。"})`
在响应结束时,你可以调用 `response.execute_tool_calls()` 来实际运行请求的函数,或者发送 `response.reply()` 让工具被调用并将其返回值发送回模型:
``
print(response.reply("Tell me about the dogs"))
``
这种流式传输不同令牌类型的新机制意味着 CLI 工具现在可以将“思考”文本以与最终响应中文本不同的颜色显示。思考文本输出到 stderr,因此不会影响通过管道传输到其他工具的结果。
此示例使用 Claude Sonnet 4.6(带有更新的 `llm-anthropic`(https://github.com/simonw/llm-anthropic)插件的流式事件版本),因为 Anthropic 的模型将其推理文本作为响应的一部分返回:
``
llm -m claude-sonnet-4.6 'Think about 3 cool dogs then describe them' \
-o thinking_display 1
``
动画演示。以 ~/dev/scratch/llm-anthropic % uv run llm -m claude-sonnet-4.6 'Think about 3 cool dogs then describe them' -o thinking_display 1 开始,文本随后以灰色流式传输:用户希望我思考 3 只酷的狗然后描述它们。让我想出来 3 只有趣的、酷的狗并描述它们。然后切换为常规颜色的文本以输出描述狗的内容。
你可以使用新的 `-R/--no-reasoning` 标志抑制推理令牌的输出。令人惊讶的是,这成了此版本中唯一面向 CLI 的变更。
#### 一种序列化和反序列化响应的机制
如前所述,LLM 目前用于将对话持久化到 SQLite 的代码非常僵化。我在 0.32a0 中添加了一个新机制,应为 Python API 用户提供了一种自行实现替代方案的方法:
``
serializable = response.to_dict()
# serializable 是一个 JSON 样式的字典
# 将其存储在你喜欢的任何地方,然后膨胀它:
response = Response.from_dict(serializable)
``
返回的字典实际上是在新的 `llm/serialization.py`(https://github.com/simonw/llm/blob/main/llm/serialization.py)模块中定义的 `TypedDict`。
#### 下一步是什么?
我将其作为 alpha 版本发布,以便我可以升级各种插件,并在现实环境中测试新设计几天。除非 alpha 测试揭示我在整合所有内容时存在设计缺陷,否则我预计稳定的 0.32 版本将与此 alpha 版本非常相似。
还有一个剩下的大型任务:我想重新设计 SQLite 日志系统,以更好地捕获此新抽象返回的更细粒度细节。
理想情况下,我想将其建模为图,以最好地支持像 OpenAI 风格的聊天完成 API 这样的情况,其中相同的对话不断扩展并在每次提示时重复。我希望能够在不重复数据库中的内容的情况下存储这些内容。
我尚未决定这是否应成为 0.32 的功能,还是应将其保留到 0.33。
相似文章
llm 0.32a1
llm 0.32a1 版本发布说明。llm 是由 Simon Willison 开发的一个用于处理大语言模型的 Python 命令行工具和库。
llm 0.32a0
本文宣布 Simon Willison 开发的 'llm' 命令行工具发布 0.32a0 版本,并提供有关大型语言模型发展的月度简报。
llm 0.32a3
llm 0.32a3版本发布,这是Simon Willison的命令行工具的一个alpha版本,用于与大语言模型交互。
llm 0.32a2
llm CLI 工具已发布 0.32a2 版本,新增对 OpenAI /v1/responses 端点的支持,以启用 GPT-5 类模型的交错推理功能。
vllm-project/vllm v0.20.1
vLLM v0.20.1 是一个小版本更新,针对这款流行的开源大语言模型推理和服务库,继续保持其高吞吐量和高效内存管理的核心优势。