LLM 0.32 重构详解:消息序列输入与流式多类型响应设计

LLM 0.32a0发布,引入消息序列输入和类型化事件流等重大重构
Simon Willison发布开源项目LLM的0.32a0 alpha版本,进行了向后兼容的重大重构。核心变化包括:引入消息序列API对齐OpenAI Chat Completions格式,支持直接注入对话历史;新增stream_events API将响应建模为类型化事件流,区分文本、工具调用、推理等不同内容类型;提供通用的序列化/反序列化机制替代SQLite绑定。重构保持向后兼容,旧接口仍可使用。
概述
Simon Willison 发布了其开源项目 LLM 的 0.32a0 alpha 版本,这是一次重大的向后兼容重构。LLM 是一个 Python 库和 CLI 工具,通过插件系统提供对数千种不同大语言模型的统一抽象访问。Simon Willison 是 Django Web 框架的联合创始人,也是数据探索工具 Datasette 的作者,LLM 项目延续了他在 Datasette 中验证过的插件化架构理念——核心库只定义抽象接口,具体的模型适配(如 llm-anthropic、llm-gemini、llm-ollama 等插件)由社区独立开发和维护。这种设计使得开发者只需安装对应插件,就能用完全相同的代码调用 OpenAI、Anthropic、Google、本地 Ollama 等不同来源的模型。此次重构的核心目标是让 LLM 的抽象层能够跟上现代 AI 模型在输入输出多样性方面的快速演进。
为什么需要重构
LLM 项目始于 2023 年 4 月,最初的设计非常简单:文本输入,文本输出。
import llm
model = llm.get_model(\"gpt-5.5\")
response = model.prompt(\"Capital of France?\")
print(response.text())
然而两年多来,LLM 生态发生了巨大变化。LLM 库先后增加了附件(处理图像、音频、视频输入)、Schema(输出结构化 JSON)、工具调用等功能。同时,前沿模型不断进化,支持推理输出、图像生成、音频片段等多种能力。原有的"文本进、文本出"抽象已经无法满足需求。
核心变化一:消息序列作为输入
旧模式的局限
此前 LLM 通过 conversation 对象来处理多轮对话,但这种方式只能从头构建对话,无法直接注入一段已有的对话历史。这使得构建 OpenAI 兼容 API 等场景变得异常困难。虽然 CLI 工具通过 SQLite 持久化会话来绕过这个限制,但这从未成为稳定的 Python API 的一部分。
新的消息序列 API
0.32a0 引入了 llm.user() 和 llm.assistant() 构建函数,允许开发者直接传入完整的消息序列:
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())
这种设计直接对齐了 OpenAI Chat Completions API 的消息格式。OpenAI 的 Chat Completions API 采用消息数组作为输入,每条消息包含 role(如 system、user、assistant)和 content 字段,这种格式已成为行业事实标准——Anthropic、Google Gemini、Mistral 等主流模型提供商都提供了兼容或类似的接口。消息序列的核心优势在于将对话历史显式化,开发者可以精确控制上下文窗口中的每一条消息,实现历史注入、上下文裁剪、系统提示词管理等高级操作,这对构建 RAG 系统、Agent 框架和 API 网关等场景至关重要。LLM 0.32a0 的这一改动使得构建兼容服务、注入历史上下文等操作变得自然而简洁。原有的 prompt= 参数仍然有效,LLM 会在内部将其升级为单条消息数组。
此外,新版还支持对响应直接 reply,作为构建多轮对话的替代方式:
response2 = response.reply(\"How about Hungary?\")
核心变化二:流式多类型响应
问题背景
现代模型的输出不再是单一的文本流。一次 Claude 调用可能依次返回推理文本、正式回复、工具调用请求、工具执行结果等不同类型的内容。OpenAI 的代码解释器、Anthropic 的网页搜索等服务端工具更是让响应内容的类型组合变得复杂。多模态输出模型甚至可以在流式响应中混入图像或音频片段。
传统的流式响应(Streaming)是指模型在生成过程中逐 token 返回结果,而非等待完整生成后一次性返回,这种模式通常基于 Server-Sent Events(SSE)协议实现,能显著降低用户感知的首 token 延迟(Time to First Token, TTFT)。然而,随着模型能力的扩展,单次响应中可能交织多种内容类型:Anthropic Claude 的 extended thinking 功能会先输出推理链再输出最终答案,OpenAI 的 Code Interpreter 会在响应中嵌入代码执行结果,多模态模型甚至可能在文本流中穿插生成的图像。传统的纯文本流式接口无法区分这些不同类型的内容片段,因此需要引入类型化的事件流模型。
新的 stream_events API
新版本将响应建模为类型化消息部件的流。开发者可以通过 response.stream_events() 或异步版本 response.astream_events() 来逐事件处理:
for event in response.stream_events():
if event.type == \"text\":
print(event.chunk, end=\"\", flush=True)
elif event.type == \"tool_call_name\":
print(f\"\
Tool call: {event.chunk}(\", end=\"\", flush=True)
elif event.type == \"tool_call_args\":
print(event.chunk, end=\"\", flush=True)
这种设计带来了实际的用户体验提升。例如,CLI 工具现在可以用不同颜色显示"思考"文本和最终回复文本,推理内容输出到 stderr 以避免影响管道操作。配合更新后的 llm-anthropic 插件,Claude 的推理过程可以实时以灰色文字流式展示。
工具调用的完整闭环
响应结束后,可以调用 response.execute_tool_calls() 来执行模型请求的函数,或使用 response.reply() 自动调用工具并将返回值发送回模型,形成完整的 Agent 循环。
工具调用(Function Calling)是现代 LLM 应用的核心能力之一。模型在推理过程中可以决定调用预定义的外部函数(如搜索引擎、数据库查询、计算器等),应用层执行函数后将结果返回给模型,模型再基于结果继续推理。这种"模型请求→应用执行→结果回传"的循环是构建 AI Agent 的基础模式,也是 LangChain、CrewAI 等 Agent 框架的核心机制。LLM 0.32a0 通过 execute_tool_calls() 和 reply() 方法将这一循环内置到库中,使开发者无需依赖重量级框架即可实现轻量级的 Agent 功能,降低了构建自主决策系统的门槛。
序列化与反序列化机制
针对 SQLite 持久化过于僵硬的问题,0.32a0 提供了通用的序列化接口:
serializable = response.to_dict()
# 存储到任何地方
response = Response.from_dict(serializable)
返回的字典是一个定义在 llm/serialization.py 模块中的 TypedDict。TypedDict 是 Python 类型系统中的一个特性(PEP 589),允许为字典的每个键指定精确的类型注解,在保持字典灵活性的同时提供静态类型检查支持。LLM 选择 TypedDict 而非 Pydantic 模型或 dataclass 作为序列化格式,体现了对轻量级和互操作性的追求——返回的就是普通 Python 字典,可以直接用 json.dumps 序列化,也可以存入 MongoDB、Redis、文件系统等任意后端,无需引入额外的序列化/反序列化依赖。开发者可以自由选择存储后端,不再被绑定到 SQLite。
后续计划
此次发布为 alpha 版本,Simon Willison 计划在实际环境中验证几天后发布稳定版 0.32。他还在考虑重新设计 SQLite 日志系统,将对话建模为图结构,以避免在 OpenAI 风格的持续对话场景中产生重复数据存储。
LLM 项目从一开始就使用 SQLite 数据库记录所有对话日志,这与 Simon Willison 长期倡导的"SQLite 作为应用数据格式"理念一脉相承。然而,当前的线性对话存储模型在面对分支对话(如从同一上下文发起多个不同的后续提问)时会产生大量重复数据——每个分支都需要完整复制之前的对话历史。将对话建模为有向无环图(DAG)结构可以解决这一问题:每条消息作为图中的节点,对话分支通过边来表示,共享的历史上下文只需存储一份。这种设计类似于 Git 的提交图模型,能够高效表达复杂的对话拓扑。这一特性可能纳入 0.32 或推迟到 0.33。
设计哲学的启示
这次重构体现了优秀开源项目的演进策略:向后兼容的渐进式重构。旧的 prompt= 接口仍然有效,旧的迭代方式仍然可用,但新的抽象为未来的多模态、多工具、多类型响应场景打下了坚实基础。
对于正在构建 LLM 应用的开发者而言,这种"消息序列 + 类型化事件流"的模式值得借鉴——它既保持了简单场景的易用性,又为复杂场景提供了足够的表达力。
核心要点
- LLM 0.32a0 引入消息序列(messages)作为输入,允许直接注入完整对话历史,对齐 OpenAI Chat Completions API 格式
- 新增 stream_events API 将模型响应建模为类型化事件流,支持文本、工具调用、推理等不同类型内容的区分处理
- 提供通用的 to_dict/from_dict 序列化机制,让开发者不再被绑定到 SQLite 存储
- CLI 工具现在可以用不同颜色区分显示推理文本和最终回复,推理内容输出到 stderr
- 整体重构保持向后兼容,旧的 prompt= 参数和迭代方式仍然有效
相关推荐
科技前沿GitHub Agent HQ发布:AI编程工具进入平台化竞争时代
GitHub Universe大会发布Agent HQ平台,统一管理编码Agent,Copilot升级支持多模型集成。同期OpenAI完成重组,Anthropic新模型测试,NVIDIA开源系列AI模型,AI编程工具格局加速整合。
科技前沿Gemini 3.5 Flash在GDPval基准上实现巨大飞跃
Google Gemini 3.5 Flash在GDPval基准测试中超越Gemini 3.1 Pro,轻量级Flash模型借助后训练技术逼近前沿水平,重新定义性能与成本的平衡点,为AI应用开发者带来重大利好。
科技前沿Google Gemini Antigravity周配额三倍提升,AI编程不再受限
Google Gemini团队再次将Antigravity周配额提升至三倍,继日配额提升后再次加码。本文解析此次配额调整对开发者的实际影响,以及在AI编程助手竞争格局中的战略意义。