基座模型
目的
为什么智能体中最强大的组件,恰恰是那个其输出永远无法作为返回结果执行的组件?
智能体的每一轮都是一次基座模型调用。运行时发送由消息、工具定义和限制构成的上下文,模型返回一个提议:一些文本、一个结构化对象,或调用某个工具的请求,并附带一个停止理由。该提议流畅且往往正确,但它是未经验证的;同一请求发送两次可能得到不同结果;并且它有一个随模型写入的每个 token 以及智能体在下一轮重新发送的每个 token 而增长的代价。把干净停止误认为任务完成、把格式良好的对象误认为正确对象、把模型调用误认为廉价调用,会让后续每一个机制都建立在错误假设之上。因此,一次调用是一份包含三个部分的契约:模型读取什么、返回什么,以及它消耗多少成本。单次调用只运行一轮,调用之间不保留任何状态,且不作用于任何外部对象,因此它不引入任何 H·S·A 暴露面;本书后续各部分都以这一份契约为起点,向外度量地平线、状态与权限。
学习目标
- 说明基座模型如何将 token 上下文转换为提议,以及哪些与调用的决策属于运行时。
- 在固定上下文窗口内按 token 预算一次模型调用,为输出预留余量。
- 说明模型调用为何是非确定性的,包括在 temperature 为零时,以及这对回放与评估意味着什么。
- 规范模型调用的请求与响应:消息与角色、工具定义、输出与推理限制、停止理由,以及标准化的状态信封。
- 区分语法约束解码与训练得到的工具调用格式,并区分语法有效性与正确性。
- 估算单次调用的延迟,以及多轮轨迹的 token 成本,分别在有与无前缀缓存的情况下。
- 以匹配预算下的已验证任务成功率而非解析率来评估不同的模型接口。
模型调用边界
“看似合理失败”故障模型 (Fail-Plausible 故障模型) 与零环境权限 (智能体系统时刻) 已经告诉运行时不要信任模型所输出的内容,但它们并未说明调用发往何处、返回什么,以及沿途每个决策由哪个组件负责。单次调用只运行一轮,调用之间不保留任何内容,且不作用于任何外部对象,因此它不引入任何 H·S·A 暴露面 (H·S·A 暴露面),也是后续各部分度量这些暴露面的起点。
跟踪一次调用从运行时到加速器再返回的全过程,会出现三个组件,各自职责不同、失败方式也不同。 运行时编排提示并判定结果,服务守护进程调度加速器,而模型——一组冻结的参数权重 \(\Theta\),由矩阵乘法流水线进行评估——计算出下一个 token 的分布。机器学习领域的术语掩盖了这一分工,而 表 1 则说明了每个熟悉的模型术语一旦落到这条路径上会分别变成什么。
| 机器学习概念 | 系统架构翻译 | 系统故障模式与运行含义 |
|---|---|---|
| 提示词/上下文窗口 | 分阶段只读输入缓冲区;注意力计算所用的连续虚拟内存工作区。 | 缓冲区溢出、注意力退化、上下文截断,以及缓存驱逐抖动。 |
| 自回归生成 | 迭代推理循环,在静态权重 \(\Theta\) 上执行顺序张量收缩核。 | 内存带宽饥饿、高尾延迟,以及无界增长的顺序依赖链。 |
| logit/softmax 分布 | 词表 \(\mathcal{V}\) 上的未归一化对数几率向量,映射为概率单纯形 \(\Delta^{\vert\mathcal{V}\vert-1}\)。 | 采样熵漂移、分布尾部污染,以及极端的 logit 数值不稳定性。 |
| 幻觉 | 未被捕获的语义不变量违反;生成语法有效但事实虚构的状态。 | 在名义正常的传输与解析状态下的“看似合理失败”静默数据损坏。 |
| 工具调用/函数调用 | 未经验证的候选 RPC 调用规范,写入主机内存托管区。 | 远程接口签名不匹配、参数注入、未授权能力调用。 |
| HTTP 200 OK/模型生成完成 | 对未经验证的候选响应信封的传输层投递确认。 | 投递谬误:传输成功被等同于语义正确性或任务完成。 |
在这条路径上,零环境权限具有精确的物理含义。当模型生成字符串 rm -rf /,或生成一个请求删除数据库表的 JSON 对象时,主机上的任何字节都不会改变。输出是存放于加速器高带宽内存(HBM)中的一组整数 token 标识符。它穿越互连结构,推理守护进程将其解码为字符,最终落入由主机运行时拥有的用户态缓冲区。在那里,它以内存托管形式保留,直到运行时决定如何处理它。
这一物理边界将现代智能体运行时划分为清晰的三层架构 (图 1)。最底层是神经核心,由稠密矩阵乘法硬件单元(如 GPU Streaming Multiprocessors 或 TPU Tensor Cores)构成,在驻留于高带宽内存(HBM)中的静态参数矩阵 \(\mathbf{\Theta}\) 上执行底层张量收缩。中介对神经核心访问的是推理服务守护进程,一个高性能系统服务(如 vLLM、SGLang,或优化后的厂商运行时),负责管理物理加速器分配、调度批量化推理请求、通过 PagedAttention 管理 key-value 张量内存,并协调自回归生成循环。最终,运行于主机用户态的是主机智能体运行时,即权威监督者。主机运行时拥有环境状态,持有管理凭据,编排模型上下文,强制硬件资源与延迟预算,并在授予执行权限之前验证所有候选输出。
如 图 1 所示,这些层级由物理硬件和传输接口分隔。第 1 层(主机智能体运行时)通过本地 IPC 或网络边界(HTTP/2 或 gRPC),向第 2 层(推理服务守护进程)分发带类型的 RPC 请求。第 2 层将请求转换为批量计算流,通过 PCIe Gen5 或 NVLink 互连启动 CUDA 内核,驱动第 3 层(神经核心)。第 3 层不具有任何环境固有权限。其计算单元仅输出采样得到的 token 标识符(\(y_t\));这些标识符经互连返回守护进程进行信封封装,再返回主机运行时进行验证,验证发生在 加速器—主机架构边界 所述加速器—主机边界的主机侧。
下面的定义使用运行时检查单次调用时所用的术语,陈述 Fail-Plausible 故障模型 在单次调用中的貌似正常型故障模型。
Definition 0.2: 貌似正常型故障
貌似正常型故障 是一种执行故障形态:非特权神经执行核心输出动作提议 \(a_{\text{prop}} \sim \pi_\theta(\cdot \mid c_t)\),该提议满足句法规则 \(\mathcal{L}(G)\),并在环境中执行,返回退出码 0,却使环境状态转移到语义规范允许的范围(\(s_t \in \mathcal{I} \implies s_{t+1} \notin \mathcal{I}\))之外。
- 重要性:揭示了常规软件监控和分布式看门狗(
if (exit_code != 0) retry())在智能体系统中失效的原因:表面上的流畅表达和进程成功退出经常掩盖灾难性的语义退化。 - 区别:与故障停止型故障(组件明显崩溃并确定性地停止执行)或拜占庭故障(对抗性节点通过网络通道故意偏离预期行为)不同,貌似正常型故障源于对冻结训练分布的统计似然优化,而这种优化并未以物理环境状态为依据。
- 常见误区:依赖进程返回码或模型自报的完成情况(“我已验证该缺陷已修复”)作为成功证据;可靠运行需要监督机制设置隔离屏障,并由外部验证预言机校验物理状态变化。
第二种错误发生在传输层,本章将其称为 交付谬误。在朴素的软件实现中,智能体系统向推理服务发送 HTTP 请求,收到 HTTP 200 OK 响应状态,成功将响应体解析为 JSON,随后直接提交该动作。这将传输交付与任务完成混为一谈。HTTP 200 OK 仅表明传输层成功通过网络接口传输了数据包,且推理守护进程完成了生成循环而未崩溃。它完全不能说明模型是否解决了任务、是否遭遇上下文截断、是否触发内部安全拒绝,或是否生成了基于幻觉的能力请求。
健壮的主机运行时通过将所有入站原始推理响应归一化为结构化状态信封来隔离这一边界。运行时评估生成是否名义完成(COMPLETED)、是否在到达自然终止 token 前耗尽了已分配的 token 预算(TRUNCATED)、是否被加速器级安全过滤器中止(REFUSED),或是否遇到不可恢复的网络或硬件断开(TRANSPORT_FAILURE)。仅携带干净状态信封的候选才会被转发至监督者的验证流水线,从而确立 图 2 所示的闭环执行边界。
图 2 中的执行生命周期跨越物理权限边界,呈现四个顺序阶段。在第 1 阶段(上下文准备与预算分配),主机监督者构建提示序列 \(\mathbf{x} = (x_1, \dots, x_M)\),分配运行 token 限额 \(K_{\max}\),设定墙钟截止时间 \(T_{\max}\),并将解码超参数封装为带类型的 RPC 请求。推理引擎接收该载荷,调度批量化分配并计算提示前缀(GEMM),随后进入自回归解码循环(第 2 阶段)。在每个解码步,融合 logit 掩码抑制不合语法的 token,在 softmax 归约之前将采样向量追加至设备 KV 缓存页。当遇到序列结束分隔符或上限约束时,第 3 阶段将候选 token 封装为归一化响应信封,并附带经核验的用量核算。最后,第 4 阶段(验证与动作派发)在宿主内存托管中接收该载荷,对候选工具调用执行 AST 验证与沙箱 ACL 检查,之后才授权副作用派发。
干净的信封使候选通过判断,而非通过执行。模型对其自身输出的判定不具证据效力(认识论边界:受强制的约束域与语义正确性),因此运行时仅依据模型之外确定性门控的证据接受候选,例如编译器、类型检查器、静态分析器和测试套件。这些门控提供了 闭合证据等级 的闭环证据层级中的静态检查与测试,而 节 4 针对单次调用构建它们。
主机监督者与神经核心之间的物理边界同样施加了严格的互连与内存约束。一个常见的架构问题是:推理评估与随机采样的边界应位于何处——是让加速器将原始未归一化的 logit 流回宿主 CPU,由主机运行时本地采样 token,还是让采样直接在加速器硅片上执行?
对互连流量的定量分析揭示了为何 logit 采样必须完全位于加速器上,从而使 token ID 成为跨宿主接口不可再分的原子交换单元。
粗略估算 0.1: **对数概率连接瓶颈**
计算加速器将原始 16 位浮点 logit(fp16,每个 logit 2 字节)回传至宿主 CPU 供采样,与传输离散 32 位整数 token 标识符(uint32,每个 token 4 字节)之间所需的连续互连带宽。评估主机侧采样在细粒度 PCIe 传输开销下的系统可行性。
解答:
情形 1:通过互连传输原始 logit 向量。 对于每个新生成的 token,加速器产生维度为 \(|V|\) 的稠密未归一化 logit 向量。按每个元素 2 字节: \[\text{Payload per token} = 128{,}000 \times 2\text{ bytes} = 256{,}000\text{ bytes} = 256\text{ KB/token}\]
对于跨越全部 64 个流聚合的批量化生成吞吐量: \[\text{Aggregate token rate} = B \times R = 64 \times 40\text{ tokens/second} = 2{,}560\text{ tokens/second}\]
互连上的连续数据传输率为: \[\text{Bandwidth}_{\text{logits}} = 2{,}560\text{ tokens/second} \times 256\text{ KB/token} = 655{,}360\text{ KB/second} = 655.36\text{ MB/second}\]
虽然峰值理论 PCIe 4.0 \(\times 16\) 总线提供约 31.5 GB/s 的单方向带宽,但该吞吐量假设存在大尺寸、连续的直接内存访问(DMA)事务。与此假设相悖,自回归服务循环以极小的异步突发方式派发这些 256 KB 缓冲区,每秒 2,560 次。在该传输粒度下,PCIe 事务打包开销、主机中断处理、DMA 完成同步停顿以及主机内存总线争用会劣化性能,并在解码循环中引入显著抖动。若词表扩展至 \(|V| =\) 256,000,或并发度提升至 \(B =\) 256,带宽需求将超过 5.24 GB/s,严重饱和系统的互连队列。
情形 2:在加速器硅片上执行 logit 归约。 若 top-\(p\)、top-\(k\)、温度缩放与多项式分类采样直接在加速器内核内执行,则加速器将 256 KB 维的 logit 向量归约为单个标量 token ID: \[\text{Payload per token} = 4\text{ bytes/token}\]
互连上的连续带宽为: \[\text{Bandwidth}_{\text{tokens}} = 2{,}560\text{ tokens/second} \times 4\text{ bytes/token} = 10{,}240\text{ bytes/second} \approx 10.24\text{ KB/second}\]
结论: 在加速器硅片上执行 logit 采样,可将互连带宽压力降低 64,000×: \[\frac{256{,}000\text{ bytes}}{4\text{ bytes}} = 64{,}000\times\] 该降低将互连拥塞转化为可忽略的 10.24 KB/s 流,从而释放主机—加速器互连,用于大规模模型权重更新与输入上下文摄取。离散的 token 标识符是模型调用边界强制的、带宽最优的接口货币。
Checkpoint 0.1: 评估模型调用边界
在分析离散 token 表示之前,先验证你对随机执行层级与主机边界的架构理解:
因此,运行时拥有每一个具有后果的决定,而 运行时在模型调用周围拥有的内容 说明了每个熟悉的模型术语要求运行时做什么。
| 模型术语 | 运行时职责 | 若运行时忽略该术语则产生的故障 |
|---|---|---|
| 上下文窗口 | 组装上下文并保留它,连同输出限制,置于窗口内 | 输入或输出被截断;工具调用在参数中间被切断 |
| 采样设置 | 为每次调用选择它们,并连同输出一起记录 | 无法解释或复现的轨迹 |
| 工具调用 | 校验、授权并执行它,然后以消息形式返回结果 | 对环境的畸形或未授权影响 |
| 停止原因 | 依据它路由循环:分派、验证、隔离或升级 | 被截断或被拒绝的输出被当作已完成处理 |
| 流畅但错误的输出 | 用模型之外的检查,依据环境核对该提议 | 通过所有表面测试的合理错误 |
| 成功响应 | 将传输成功视为提议的送达,而非任务的完成 | 交付谬误:把状态码当作正确性的证据 |
离散 token 表示
基础模型无法读取字符串。当人类程序员和软件工具之间交换结构化 Unicode 文本时,现代加速器的张量收缩流水线仅以稠密、固定维度的浮点数组运行。弥合这一语义鸿沟需要一个非特权序列化层:分词器。在软件接口上,分词器表现为一个离散的、双向的转码器,将可变长度的字节流映射为取自有限词表的有界整数标识符序列 \(\mathcal{V}\)。在硬件接口上,这些整数标识符却承担着更为严苛的物理角色:它们索引模型主内存嵌入表的行偏移,其累计序列长度 \(S\) 决定了加速器注意力缓存的物理高带宽内存(HBM)占用。
分词器本质上是一个统计字节压缩器,而非感知语法的编译器词法分析器;这一架构层面的区别与编程语言语法树产生了严重的阻抗失配,放大了结构化序列化格式的延迟与内存开销,并对加速器硬件施加了刚性的物理内存负担。 当智能体监督器分派提示或摄取执行轨迹时,它必须把 token 视为物理资源分配,而非抽象的词汇单元,因为它们消耗硅片内存带宽,并约束神经引擎的执行视界。
分词边界
传统编译器前端使用确定性的、由语法驱动的词法分析器来划分源文本。编译器词法分析器将字符流映射为由形式语言规范定义的带类型 token 流(例如 IDENTIFIER、KEYWORD_DEF 或 OPERATOR_PLUS)。在开放域智能体系统中,这种确定性的方法会立即失效。自然语言具有丰富的形态多样性,而程序执行轨迹包含一组无界的开放词表字符串:动态生成的 UUID、密码学哈希、base64 载荷、混淆后的 URL,以及任意变量名,例如 getUserById_v2_final。一个试图为这个开放词表宇宙编制目录的词级词表将膨胀至数百万条条目,耗尽主机内存并稀释统计训练效率。反过来,将词级词表限制在固定阈值,会迫使任何未见的 token 坍缩为未登录词(<UNK>)哨兵,不可挽回地破坏语法结构与执行语义。
在相反的架构极端上,纯字符级分词器在极小的固定字母表(例如原始 Unicode 的 256 个字节值)上运行。字符词表虽然将 \(|\mathcal{V}|\) 的占用压缩到最小,却使序列长度 \(S\) 相对于自然词膨胀四到五倍。在 Transformer 架构中,自注意力在所有输入位置之间评估两两交互,其计算复杂度随序列长度呈平方增长(\(O(S^2)\))。将序列长度膨胀 \(4\times\) 会导致预填充计算操作与中间激活内存出现灾难性的 \((4)^2 = 16\times\) 激增。字符级分词以词表简洁性换取无法接受的硬件评估代价。
现代推理引擎使用字节对编码(BPE)来解决这一权衡,这是一种直接作用于字节序列的数据驱动子词分词算法。从单个字节基元的基础词表 \(|\mathcal{V}_{\text{base}}| = 256\) 开始,BPE 分析大规模语料,迭代地识别并合并最高频的相邻字节对,形成复合子词 token。该合并过程持续进行,直到达到目标词表规模 \(|\mathcal{V}|\),现代基础模型通常为 \(32{,}000\) 到 \(128{,}000\) 条条目(在大规模前沿架构中可扩展至 \(256{,}000\))。高频字符串(例如常见关键词 return 或自然语言词根 process)聚合成单个原子 token ID,而低频标识符则优雅地碎裂为更短子词或基础字节的序列。BPE 保证序列长度有界,同时消除了未登录词失败模式:任何任意二进制载荷或未知标识符都可以序列化为由构成字节 token 组成的回退序列。
嵌入表内存开销: 一个具有 \(|\mathcal{V}| = 128{,}000\) 行、隐藏维度为 \(d_{\text{model}} = 4096\) 的嵌入矩阵,若以 16 位精度存储,则占用: \[128{,}000 \times 4096 \times 2\text{ bytes} \approx 1.05\text{ GB}\] 若输出去嵌入投影未将其权重与 \(\mathbf{W}_{\text{embed}}\) 绑定,则在加载单个 Transformer 层之前,仅词表表示就消耗超过 \(2.1\text{ GB}\) 的加速器 HBM。
一旦字符串被序列化为离散整数 token ID 数组 \(\mathbf{t} = [t_1, t_2, \dots, t_S]\),其中每个 \(t_i \in \{0, 1, \dots, |\mathcal{V}|-1\}\),主机运行时便将该缓冲区置于加速器内存中。在硬件硅片上,模型的第一个计算操作是嵌入表查找。在数学上,该操作等价于用一个 one-hot 向量 \(\mathbf{e}_{t_i} \in \{0, 1\}^{|\mathcal{V}|}\) 乘以权重矩阵 \(\mathbf{W}_{\text{embed}} \in \mathbb{R}^{|\mathcal{V}| \times d_{\text{model}}}\)。然而,在物理加速器内核中,在一个 \(128{,}000\) 维向量上执行稀疏矩阵乘法会浪费硅片计算资源。取而代之的是,加速器内存控制器执行直接的行提取操作。整数数值 \(t_i\) 充当基地址内存步长指针:
\[\text{Offset}(t_i) = t_i \cdot d_{\text{model}} \cdot b\]
其中 \(b\) 表示每个元素的数值精度(以字节计,例如 \(b=2\) 对应 16 位浮点格式,如 FP16 或 BF16)。加速器内存层次结构将连续的行向量 \(\text{Offset}(t_i)\) 从片外高带宽内存(HBM)拉取到片上流式多处理器(SM)寄存器与暂存存储器 SRAM。离散整数 ID 序列由此被物化为稠密激活张量 \(\mathbf{X} \in \mathbb{R}^{S \times d_{\text{model}}}\),准备进入多头注意力流水线。
结构层面的阻抗失配
由于 BPE 依据原始字符流上的统计频率构建合并表,它对形式化编程语言语法、语法树和缩进作用域完全无感。这种分歧造成了主机环境中确定性编译器与面向神经引擎的子词分词器之间的架构阻抗失配。
考虑编译器的抽象语法树(AST)。编译器词法分析器严格将空白视为分隔符(在 Python 等缩进敏感语言中,空白是显式的块分隔符),无论函数名出现在行上的何处,都产生不变的 IDENTIFIER token。相比之下,统计子词分词器会依据语料共现统计,贪婪地将前导空白直接合并为字母数字子词。
import tiktoken
enc = tiktoken.get_encoding("cl100k_base")
# Top-level module definition vs. 4-space indented class method
unindented = enc.encode("def get_user_id():")
indented = enc.encode(" def get_user_id():")
print(f"Unindented tokens: {unindented}")
# Output: [755, 1146, 3110, 482, 3341] (def -> 755)
print(f"Indented tokens: {indented}")
# Output: [262, 711, 1146, 3110, 482, 3341] (space -> 262, def -> 711)正如上方的实证轨迹所示,在模块作用域中定义 def get_user_id(): 会生成 token ID 755,对应关键词 def。将完全相同的声明放在类定义内并缩进四个空格,会将该构造拆分为 token 262(表示四个空格),后接 token 711(表示 def)。在加速器芯片上,第 755 行和第 711 行属于 \(\mathbf{W}_{\text{embed}}\),是 \(\mathbb{R}^{d_{\text{model}}}\) 中完全独立的向量。它们不共享任何权重、内存地址或结构关联。神经网络必须耗费统计学习容量,仅仅为了发现第 755 行和第 711 行在不同缩进上下文中表示完全相同的语法关键词;图 3 展示了这种结构上的脱节。
在 图 3(面板 1)中,确定性编译器词法分析器生成不变的 AST 语法 token 序列(KEYWORD: 'def'、IDENTIFIER: 'get_user_id'、PARAMETERS: ()、COLON: ':'),仅将缩进视为层级作用域属性(BLOCK_SCOPE)。然而,在面板 2 中,子词 BPE 根据贪婪共现统计将代码拆碎。情形 A(模块作用域)生成五个 token([755, 1146, 3110, 482, 3341]),而情形 B(缩进四个空格)则扩展为六个 token([262, 711, 1146, 3110, 482, 3341])。追踪到加速器的物理嵌入表 \(\mathbf{W}_{\text{embed}}\) 可以发现,第 755 行和第 711 行位于互不重叠的内存地址(\(\text{Row } 755 \cap \text{Row } 711 = \emptyset\)),迫使 Transformer 早期的自注意力层在开始任何语义推理之前,先耗费表示容量来重新构建词法同一性。
KEYWORD: 'def'、IDENTIFIER: 'get_user_id')赋予不变的语法标识,严格将前导空白视为块作用域属性。在面板 2 中,BPE 根据贪婪字符合并将语法拆碎:模块级 def 映射为 token ID 755,而缩进四个空格的 def 则被拆分为空白 token ID 262,后接 token ID 711。在 GPU 高带宽内存中,嵌入矩阵 \(\mathbf{W}_{\text{embed}}\) 的第 755 行和第 711 行是完全独立的参数向量,既不共享内存,也没有共同的结构标识。
当智能体运行时交换 JSON、YAML 或 XML 等结构化序列化格式时,这种结构性摩擦会急剧加剧。现代智能体监督器依赖结构化格式,对工具调用、shell 命令和环境反馈实施模式验证。然而,标准 BPE 词表主要针对自然语言文本进行优化,其中单词由单个空格分隔。结构化模式不符合这些统计分布:其中充斥着双引号(")、冒号(:)、花括号({、})、转义反斜杠(\)和换行符(\n)等语法分隔符。
当智能体通过 JSON 调用工具时,这些结构分隔符无法与周围的字母数字内容合并,而是碎裂为孤立的单字符或单字节 token。包含选项标志、引号和正则表达式的嵌套 shell 命令会付出极高的序列化开销,膨胀为庞大的低信息量 token 数组。
| 载荷领域 | 内容样本描述 | 原始字符数 | token 数量 | 字节数 / token | 压缩比(字符数/token) |
|---|---|---|---|---|---|
| 技术文本 | 系统架构文档 | 4,120 | 1,005 | 4.10 | 4.10 |
| Python 源代码 | 算法逻辑与标准库 | 3,850 | 1,132 | 3.40 | 3.40 |
| 标准 JSON 载荷 | 扁平键值参数与标识符 | 2,940 | 1,176 | 2.50 | 2.50 |
| 转义后的 JSON 工具调用 | 包含选项标志、引号和正则表达式的嵌套 bash 命令 | 2,180 | 1,282 | 1.70 | 1.70 |
| 十六进制哈希 / UUID | SHA-256 摘要与原始字节串 | 1,024 | 682 | 1.50 | 1.50 |
如 表 2 所列,自然语言文本能够高效压缩,每个 token 约承载 4.1 个字符。相比之下,转义后的 JSON 工具调用降至每个 token 仅承载 1.7 个字符,信息密度下降 58%。宿主智能体系统仅为传输语法框架,就直接承担了 43% 的 token 膨胀代价,将昂贵的加速器上下文容量和内存带宽耗费在模式开销上,而非实质性的问题求解逻辑上。
上下文预算动态
智能体运行时设计中的一个常见系统错误,是依赖简单的经验法则,例如广为引用的“一个 token 等于四个字符”这一启发式规则。虽然这种近似适用于连续的英文段落,但 表 2 表明,将其用于源代码、编译器诊断轨迹和 JSON RPC 封装时,它会完全失效。
考虑一个正在监控构建失败的智能体。一份 8 KB 的编译器轨迹包含 ANSI 转义序列、内存地址和文件路径,按照每个 token 对应 4 个字符的启发式规则,其预算将被估算为约 2,000 个 token。实际上,子词碎裂会使 token 数量超过 5,000。如果宿主监督器根据字符数分配上下文内存,就会意外突破推理引擎的物理上下文上限。
每个基础模型都在严格的架构上下文窗口 \(S_{\max}\) 内运行,该窗口由其位置嵌入方案(例如旋转位置嵌入,即 RoPE)的参数化方式决定。此外,智能体运行时必须始终保留生成余量 \(K_{\max}\),以便模型输出推理轨迹和工具调用封装。因此,宿主上下文暂存管理器必须强制执行严格的动态预算约束:
\[S \le S_{\max} - K_{\max}\]
如果未受管理的上下文摄取流水线将 \(S\) 推高至超过 \(S_{\max} - K_{\max}\),推理运行时就会遇到硬性截断边界。一旦累计序列长度 \(S + K\) 达到 \(S_{\max}\),自回归解码循环便会无条件停止,将其完成状态设置为长度耗尽状态(finish_reason == "length")。
{"tool": "execute_command", "command": "find /var/log -name '*.log' -exec grep -H 'FATAL' {} \;如上方的截断轨迹所示,触及物理上下文边界会使生成过程在中途终止。在结构化工具调用中,输出终止时会留下未闭合的引号、缺失的右花括号和被截断的参数。如果直接将这一不完整字符串转发给外部 JSON 解析器或 shell 环境,系统就会以不可预测的方式发生故障。损坏的命令字符串可能执行非预期的破坏性操作,反序列化器崩溃也可能在智能体监督器中触发未处理的异常。
因此,在预算耗尽(finish_reason == "length")的情况下生成的候选结果,或缺少闭合分隔符的候选结果,均不可信。由于模型不具备任何隐式授予的权限,损坏的负载只有在运行时将其传递出去时才可能造成危害,因此运行时必须将其排除在所有执行路径之外,并丢弃其提出的任何状态变更。节 5 将这一规则落实为对状态封装的检查。
Checkpoint 0.2: 上下文耗尽与隔离不变量
在暂存候选模型输出以供分派至环境之前,应验证运行时对生成截断边界的处理:
发生生成边界故障时,宿主运行时必须调用显式的上下文压缩策略(例如裁剪较早的工具执行轮次),或向用户报告不可恢复的资源耗尽故障。未经验证、仅部分生成的 token 流绝不能越过隔离边界,进入正在运行的操作系统环境。
键值缓存的物理内存占用
离散 token 表示并非仅是输入阶段的抽象;在智能体执行的整个期间,每个活跃 token 都会占用物理硬件内存。尽管输入嵌入的收集操作仅在初始提示处理过程中执行一次,每个 token 都会在加速器的高带宽内存中留下持久的占用,即键值(KV)缓存。
在仅解码器 Transformer 中,生成每个新 token 都需要对所有先前的 token 位置计算自注意力。为避免冗余的 \(O(S^2)\) 计算开销,即在每个自回归步骤中重新计算历史 token 的键(\(\mathbf{K}\))和值(\(\mathbf{V}\))投影张量,推理引擎会将这些中间投影矩阵存储在加速器内存缓冲区中。
该缓存的物理内存占用与已处理的 token 数量成正比。设:
- \(L\) 为模型中 Transformer 层的总数。
- \(n_{\text{kv}}\) 为每层键值注意力头的数量。
- \(d_{\text{head}}\) 为每个注意力头的维度(\(d_{\text{head}} = d_{\text{model}} / n_{\text{q}}\),其中 \(n_{\text{q}}\) 为查询头的数量)。
- \(b\) 为数值精度对应的每元素字节数(\(b=2\) 对应 16 位精度 FP16/BF16;\(b=1\) 对应 8 位 FP8)。
在整个模型中,单个 token 位置的 KV 缓存所占用的物理内存可直接根据其张量维度推导:
\[\text{Mem}_{\text{KV,token}} = 2 \cdot L \cdot (n_{\text{kv}} \cdot d_{\text{head}}) \cdot b \quad \left[\frac{\text{bytes}}{\text{token}}\right]\]
各个组成因子反映了注意力架构的物理结构:
- 因子 2: 缓存必须为每个 token 位置存储两个不同的投影张量:注意力键向量 \(\mathbf{k}\) 和注意力值向量 \(\mathbf{v}\)。
- 层深度(\(L\)): 每个 Transformer 层都计算独立的注意力投影;缓存必须保留全部 \(L\) 层的状态。
- 头宽度(\(n_{\text{kv}} \cdot d_{\text{head}}\)): 在早期的多头注意力(MHA)设计中,键值头的数量等于查询头的数量(\(n_{\text{kv}} = n_{\text{q}}\))。现代长上下文架构采用分组查询注意力(GQA),其中多个查询头共享一个键值头(\(n_{\text{kv}} \ll n_{\text{q}}\)),从而使缓存状态的总量减少一个数量级。
- 存储精度(\(b\)): 字长决定了每个张量元素的内存流量和内存占用。
对于包含 \(S\) 个 token 的活跃上下文,分配给 KV 缓存的物理内存总量呈线性增长:
\[\text{Mem}_{\text{KV}}(S) = S \cdot \text{Mem}_{\text{KV,token}}\]
这种内存占用的线性增长带来了一项严苛的系统约束:在加速器硬件上,上下文长度的增加会直接导致物理容量趋于饱和。
粗略估算 0.2: 128k 长上下文推理节点中的 KV 缓存内存爆炸
考虑部署在前沿模型上的智能体编程助手,其架构与 Llama-3-70B 相匹配。网络参数如下:
- 层深度:\(L =\) 80
- Query 头数量:\(n_{\text{q}} =\) 64
- Key-Value 头数量(GQA):\(n_{\text{kv}} =\) 8
- 头维度:\(d_{\text{head}} =\) 128(隐藏维度 \(d_{\text{model}} = 64 \times 128 =\) 8,192)
- 默认精度:FP16(\(b = 2\text{ bytes}\))
首先,计算存储单个 token 的 KV 缓存投影所需的内存:
\[\text{Mem}_{\text{KV,token}} = 2 \cdot 80 \cdot (8 \cdot 128) \cdot 2 = 327{,}680\text{ bytes/token} = 320\text{ KiB/token}\]
现在,考虑智能体在大型仓库的上下文上执行复杂的代码库分析,准备一个包含 \(S =\) 128,000 个 token 的活跃上下文窗口。仅由 KV 缓存所要求的内存为:
\[\text{Mem}_{\text{KV}}(128\text{k}) = 128{,}000 \times 327{,}680\text{ bytes} = 41{,}943{,}040{,}000\text{ bytes} \approx 41.94\text{ GB}\]
假设该服务节点配备了行业标准的 NVIDIA A100-SXM4-80GB 或 H100-SXM5-80GB 加速器,其 High-Bandwidth Memory(HBM)容量为 80 GB。为运行这个 70B 参数模型,运行时使用 8 位量化权重,并分配静态 CUDA 工作区、通信暂存存储器(scratchpads)和执行缓冲区,占用基线常驻占用量为 70 GB:
\[W = 70.00\text{ GB}\]
当智能体尝试摄取 128k 上下文时,加速器硅片上所需的总物理内存为:
\[\text{Mem}_{\text{total, FP16}} = 70.00\text{ GB} + 41.94\text{ GB} = 111.94\text{ GB}\]
由于 111.94 GB \(>\) 80 GB,分配量突破了物理容量,导致服务运行时以 CUDA Out-of-Memory(OOM)故障崩溃。
为缓解这一瓶颈,系统工程师可能尝试将 KV 缓存量化到 8 位精度(FP8,其中 \(b = 1\text{ byte}\))。将存储精度减半可将每个 token 的内存占用降至 163,840 字节/token,从而得到:
\[\text{Mem}_{\text{KV, FP8}}(128\text{k}) = 128{,}000 \times 163{,}840\text{ bytes} \approx 20.97\text{ GB}\]
在 FP8 下重新评估加速器的总物理内存占用为:
\[\text{Mem}_{\text{total, FP8}} = 70.00\text{ GB} + 20.97\text{ GB} = 90.97\text{ GB}\]
即使采用 8 位量化的 KV 缓存,90.97 GB \(>\) 80 GB。服务引擎仍会在 80 GB 设备上崩溃。
在生产环境中,解决这一故障模式需要两种结构性系统干预之一:
- 张量并行(\(TP \ge 2\)): 系统将模型权重和 8 个 KV 头分片到两台或更多相互连接的 GPU 上。在 \(TP = 2\) 下,每台 GPU 仅持有 4 个 KV 头(FP8 下为 10.49 GB,FP16 下为 20.97 GB)以及一半的模型权重(35 GB),使每台 GPU 的内存占用远低于 80 GB 阈值。
- 硬件迁移: 系统将升级至下一代加速器,其物理 HBM 容量更大,例如 NVIDIA H200(141 GB HBM3e)或 NVIDIA B200(192 GB HBM3e),这些设备可以舒适地容纳模型权重和大型连续 KV 缓冲区。
因此,离散的 token 表示决定了整个推理引擎的资源生命周期。一个 token 最初是统计子词索引,指向嵌入表中的一行;随后对结构化系统 schema 施加可量化的序列化开销;最终决定智能体的上下文是否能够适配加速器硅片的物理内存边界。
当宿主运行时将输入上下文序列化为离散 token 标识符数组、将它们的嵌入向量暂存于加速器 SRAM,并在 High-Bandwidth Memory 中分配其物理 Key-Value 投影缓冲区后,基础模型便已准备好生成响应。然而,生成候选动作并非一次原子、单遍的计算。与初始上下文摄取阶段(并行同时处理所有已暂存的 token)不同,生成新的输出需要一个迭代执行循环:评估网络、采样单个离散 token,并将其追加回输入缓冲区。这便引出了推理引擎的运行核心:服务运行时如何在并行加速器硅片上编排这个不可约地串行、自回归的生成循环?
自回归生成
自回归生成循环是现代语言模型服务的根本执行周期,它将一个本质上并行的张量加速器转化为一个同步的、逐步推进的状态机。尽管现代加速器硬件包含数万个算术单元,旨在在大规模矩阵乘法中达到饱和,但文本生成却迫使这一计算结构进入一条迭代的、串行依赖链:要输出 \(K\) 个输出 token,运行时必须依次向网络派发 \(K\) 次前向传播。每次传播都会评估模型,在离散词表中产生一个概率分布,采样恰好一个 token,并将其追加到上下文缓冲区,随后下一次前向传播才能开始。
核心概念:自回归分解 一种概率契约,其中 token 序列的联合似然分解为条件概率的乘积,每个条件概率都以所有先前已输出的 token 为条件。
序列生成的根本困境在于:加速器无法计算 token \(t\),直到 token \(t-1\) 的离散身份被最终确定并绑定到 Key-Value 缓存。 生成序列需要一条迭代式服务循环,反复评估模型并采样 token,从而沿单条输出路径形成不可约的串行因果依赖。对于智能体系统工程师而言,这一运行现实既决定了模型调用的墙钟延迟特性,也决定了候选工具调用与结构化计划所发出的非确定性接口边界。
自回归分解
从数学上讲,基础模型并不会在一次整体计算中生成整个序列 \(\mathbf{y} = (y_1, y_2, \dots, y_K)\)。相反,它定义了一个在输入提示 \(\mathbf{x} = (x_1, x_2, \dots, x_S)\) 条件下对候选 token 序列的联合概率分布。依据概率链式法则,该联合分布严格分解为条件下一个 token 概率的定向乘积(公式 1):
\[P(y_{1:K} \mid x_{1:S}) = \prod_{t=1}^{K} P(y_t \mid x_{1:S}, y_{1:t-1}) \tag{1}\]
在此分解中,上下文条件 token \(y_t\) 由两个不同的部分组成:由宿主应用提供的静态、不可变输入前缀 \(x_{1:S}\),以及由解码循环先前迭代产生的动态前缀 \(y_{<t} = (y_1, \dots, y_{t-1})\)。在每个生成步骤 \(t\),神经网络充当一个参数化函数 \(\mathbf{f}_\Theta\),将当前序列历史 \((x_{1:S}, y_{<t})\) 映射为离散词表 \(\mathcal{V}\) 上跨词表的未归一化分数向量(公式 2):
\[\mathbf{z}_t = \mathbf{f}_\Theta(x_{1:S}, y_{<t}) \in \mathbb{R}^{|\mathcal{V}|} \tag{2}\]
向量 \(\mathbf{z}_t\) 包含模型的 logits。将这些原始实值分数投影到概率单纯形 \(\Delta^{|\mathcal{V}|-1}\),即得到条件多项分布,从中选出下一个 token \(y_t\)。
由于词表规模 \(|\mathcal{V}|\) 通常在 \(32{,}000\) 到 \(128{,}000\) 个唯一子词 token 之间,长度为 \(K\) 的不同输出序列总数为 \(|\mathcal{V}|^K\)。对于长度适中的输出序列,例如 \(K = 512\),该输出空间的基数(\(|\mathcal{V}|^{512} \approx 10^{2400}\))使得全局序列优化——例如发现使联合似然最大化的精确序列 \(\arg\max_{\mathbf{y}} P(\mathbf{y} \mid \mathbf{x})\)——在计算上不可行。
经典搜索过程(如束搜索)在每个步骤保留一小池候选假设,但其内存消耗随束宽线性增长,并引入显著的解码同步开销。现代高吞吐量推理引擎与智能体运行时几乎普遍放弃束搜索,转而沿单条轨迹采用逐点采样或贪心选择。
服务状态机
要在物理硬件上执行这一数学分解,服务运行时将神经网络封装进一个迭代控制循环。该循环在迭代之间维护动态执行状态,协调内存缓冲区、设备内核与终止分隔符。
服务状态机在每个步骤 \(t\) 跟踪四个主要结构:活跃 token 输入、加速器持久 Key-Value(KV)缓存张量、已输出的 logits 向量,以及单调的序列历史。执行序列依次经过五个同步阶段:
- 内核派发: 运行时将最近选出的词元 \(y_{t-1}\) 输入加速器上的模型计算图,并引用先前步骤累积的键张量和值张量。
- Logit 投影: 网络的最后一层通过语言模型头 \(\mathbf{W}_{\text{embed}}^T\) 对归一化后的隐藏激活向量进行投影,得到 logit 向量 \(\mathbf{z}_t \in \mathbb{R}^{|\mathcal{V}|}\)。
- 离散化内核: 运行时对 \(\mathbf{z}_t\) 进行缩放,并直接在设备上执行采样或 argmax 内核,确定单个离散的整数词元 ID \(y_t \in [0, |\mathcal{V}|-1]\)。
- 状态提交: 内部投影向量 \(\mathbf{k}_t\) 和 \(\mathbf{v}_t\) 在步骤 \(t\) 期间计算得到,并被追加到加速器高带宽内存(HBM)中分配的物理 KV 缓存内存中。
- 边界评估: 主机端监督程序根据预先注册的停止条件检查 \(y_t\)。若某个边界条件的求值结果为真,则循环终止;否则,\(y_t\) 成为步骤 \(t+1\) 的输入。
def decode_loop(model, kv_cache, prompt_tokens, stop_token_ids, max_tokens):
generated = []
current_token = prompt_tokens[-1]
for _ in range(max_tokens):
logits = model.forward_decode_step(current_token, kv_cache)
next_token = sample_simplex(logits, temperature=0.7, top_p=0.9)
generated.append(next_token)
if next_token in stop_token_ids:
break
current_token = next_token
return generated步骤 5 中评估的终止条件是运行时的主要执行护栏,作用于 表 3 中汇总的状态分量。若缺乏严格的终止检查,模型可能陷入重复的词元循环而无限运行,或持续生成推测性文本,直到物理 KV 缓存耗尽其分配的缓冲区。
| 状态分量 | 记号 | 物理载体 | 内存生命周期 |
|---|---|---|---|
| 当前步输入词元 | \(y_{t-1}\) | 加速器 SRAM / 寄存器 | 单个步骤(\(1\) 次迭代) |
| 未归一化的 logits | \(\mathbf{z}_t\) | 加速器 SRAM / 高带宽内存 | 每步的临时向量 |
| KV 缓存张量 | \(\mathbf{K}_{1:t}, \mathbf{V}_{1:t}\) | 加速器高带宽内存 | 在整个序列期间持续保留 |
| 序列账本 | \(\mathbf{y}_{1:t}\) | 主机系统内存(DRAM) | 持久化的主机事务记录 |
主机监督器在边界评估期间执行三种不同的停止条件检查:
- 分词器的序列结束标记(EOS): 模型输出一个预留的结构词元(例如
<|endoftext|>或<|im_end|>),表明其学得的统计先验已收敛至序列完成状态。 - 主机停止分隔符: 运行时将输出的子词序列与应用指定的字节串(例如
\nObservation:或</tool_call>)进行匹配,在生成过程越过外部架构边界时立即终止模型执行。 - 资源上限(\(T_{\max}\)): 循环达到严格的最大输出词元数限制 \(T_{\max}\),从而防止无法终止的循环,并强制实施预算隔离。
因果串行化屏障
对于深谙乱序、超标量微处理器设计的工程师而言,这一迭代循环显得极其低效。现代微处理器通过在指令流中向前探查数十或数百个周期、以不同于程序顺序的顺序执行指令,以及利用复杂的分支预测器越过条件跳转进行推测执行,发掘大量指令级并行性(ILP)。人们自然会问:为什么高吞吐量的张量加速器不能推测性地计算词元 \(t+50\),同时对词元 \(t\) 进行采样?
障碍在于自注意力机制的数学结构,以及词元词表极大的基数。在多层 Transformer 中,查询向量 \(\mathbf{Q}_t\)、键向量 \(\mathbf{K}_t\) 和值向量 \(\mathbf{V}_t\) 在第 \(l\) 层针对步骤 \(t\) 计算得到,并直接依赖于第 \(l-1\) 层输出的上下文表示(公式 3):
\[\operatorname{Attention}(\mathbf{Q}_t, \mathbf{K}_{1:t}, \mathbf{V}_{1:t}) = \operatorname{softmax}\left(\frac{\mathbf{Q}_t \mathbf{K}_{1:t}^T}{\sqrt{d_k}}\right) \mathbf{V}_{1:t} \tag{3}\]
这里,\(\mathbf{K}_{1:t}\) 和 \(\mathbf{V}_{1:t}\) 表示从提示开始直至步骤 \(t\) 的键和值的完整拼接历史。关键在于,\(\mathbf{Q}_t\) 直接由 \(y_{t-1}\) 的嵌入经较低层的变换得到。如果词元 \(y_{t-1}\) 的离散身份发生变化,第一层的输入向量就会改变,导致此后的每个中间表示,直至 \(\mathbf{Q}_t\)、\(\mathbf{K}_t\) 和 \(\mathbf{V}_t\),都变得完全不同。
对比:分支预测与单纯形推测 CPU 分支预测器在两个明确的指令地址(\(0\) 或 \(1\))之间进行选择。自回归模型则在每一步都要在由 \(|\mathcal{V}| \ge 32{,}000\) 种可能转移构成的单纯形上进行分支选择。
在通用 CPU 上,条件分支是二元的,具有很强的时间和空间相关性,因此分支预测准确率可超过 95%。然而,在计算自回归语言模型的加速器上,每一步的分支因子都为 \(|\mathcal{V}| \approx 32{,}000\) 至 \(128{,}000\)。如果不确定中间步骤的选择,仅向前推测四个词元,就需要展开一棵包含 \(|\mathcal{V}|^4 \approx 10^{18}\) 条并行执行路径的组合树——这远远超出任何物理数据中心的总计算能力。
因此,生成过程受到一道绝对的因果串行化屏障的约束。词元 \(y_t\) 的身份依赖于 \(y_{t-1}\);\(y_{t+1}\) 的身份依赖于 \(y_t\);不存在任何数学上的捷径,能让引擎计算步骤 \(t+1\) 的状态表示,而无需先对 \(y_t\) 作出具体选择。尽管推测解码等技术可以利用较小的辅助模型提出候选线性序列,主模型仍必须依据自身按序构建的 KV 表示来验证这些词元,如 图 4 所示。对于标准的自回归解码循环,实际执行耗时严格随生成词元的数量 \(K\) 线性增长。
图 4 中的推测解码架构通过三阶段流水线解决内存带宽瓶颈,同时精确保持数学分布的一致性。在阶段 1(顺序草稿提议)中,超轻量级草稿模型 \(M_q\)(1B–3B 参数,延迟比 \(c = T_q / T_p \approx 0.1\))依次生成由 \(K = 4\) 个候选 token \((\tilde{x}_1, \dots, \tilde{x}_4)\) 组成的推测序列,其草稿概率为 \(q_k\)。由于 \(M_q\) 可完全容纳于加速器 SRAM 或 L2 缓存中,该生成过程能以极低延迟完成。在阶段 2(批量目标验证)中,主要的 70B 目标模型 \(M_p\) 通过单次批量 GEMM 前向传播,同时为全部 \(K\) 个候选打分,评估目标概率 \(p(x_k \mid x_{<k})\),并计算逐元素接受判据:
\[\alpha_k = \min\left(1, \; \frac{p_k}{q_k}\right)\]
对于每个候选步骤,服务运行框架抽取一个均匀随机变量 \(u_k \sim U[0, 1]\)。若 \(u_k \le \alpha_k\),则接受该候选。在 图 4 的轨迹中,token \(k=1\)("cursor"、\(\alpha_1 = 1.00\))和 \(k=2\)(" ="、\(\alpha_2 = 1.00\))均被无条件接受。在步骤 \(k=3\)(" db.cursor"),目标模型赋予的概率低于草稿模型(\(p_3 = 0.21\) 与 \(q_3 = 0.89\) 相比),得到 \(\alpha_3 = 0.236\);抽取 \(u_3 = 0.45 > \alpha_3\) 会触发拒绝陷阱,并停止对候选 \(k=4\) 的进一步验证。在阶段 3(回滚与残差提交)中,运行时将已接受的槽位 \(t+1\) 和 \(t+2\) 提交到物理 GPU HBM,使未经验证的槽位 \(t+4\) 失效,并采样替换 token \(x_{\text{corr}} =\) " conn.cursor",采样所依据的是归一化残差分布:
\[p_{\text{res}}(v) = \frac{\max(0, \; p(v) - q(v))}{\sum_{w \in \mathcal{V}} \max(0, \; p(w) - q(w))}\]
这保证了组合输出分布与直接从 70B 目标模型采样所得的分布逐位完全一致,同时在单个目标模型步骤中生成 3 个 token(实际运行时间加速比为 \(\rho \approx 2.14\times\))。
在词表单纯形上采样
当一个执行步骤输出未归一化的 logit 向量 \(\mathbf{z}_t \in \mathbb{R}^{|\mathcal{V}|}\) 后,运行时必须将这些原始分数映射为词表单纯形上的概率分布。该变换由温度缩放参数 \(\tau > 0\) 控制,该参数在应用 softmax 算子(公式 4)之前调整分布的相对尖锐程度:
\[P(y_t = v \mid x_{1:S}, y_{<t}) = \frac{\exp\left(z_{t, v} / \tau\right)}{\sum_{w \in \mathcal{V}} \exp\left(z_{t, w} / \tau\right)} \tag{4}\]
温度参数在整个输出空间中发挥熵调制器的作用:
贪心极限 (\(\tau \to 0\)): 当 \(\tau\) 趋近于零时,最大 logit \(\max_w z_{t, w}\) 与所有竞争分数之间的相对数值差异被放大并趋于无穷大。softmax 函数坍缩为完全集中于 argmax 的狄拉克 delta 分布: \[\lim_{\tau \to 0} P(y_t = v \mid x_{1:S}, y_{<t}) = \begin{cases} 1 & \text{if } v = \arg\max_{w \in \mathcal{V}} z_{t, w} \\ 0 & \text{otherwise} \end{cases}\] 贪心解码是完全确定性的。对于相同的提示词和固定的运行时配置,引擎始终会沿着序列空间中完全相同的路径遍历。
校准先验 (\(\tau = 1.0\)): 输出分布直接反映神经网络未经缩放、经交叉熵校准的预测。
高熵 (\(\tau \gg 1.0\)): 当 \(\tau \to \infty\) 时,缩放后的 logits \(z_{t, v} / \tau\) 趋近于零。指数项 \(\exp(0)\) 等于 1,使分布逐渐变平,趋于整个词表上的均匀类别分布:\(P(y_t = v) \to \frac{1}{|\mathcal{V}|}\)。
在整个词表 \(\mathcal{V}\) 上进行无约束的随机采样,经常导致自动化智能体出现灾难性失败。由于语言模型词表包含数万个子词,分布极端尾部的总概率质量不可忽略,其中包括生僻的 Unicode 序列、语法错误和低概率词元。当采样从这一长尾中抽取词元时,错误会进一步累积:在后续步骤 \(t+1\) 中,模型以这个格式错误的词元为条件进行预测,经常导致下游推理偏离正轨。
为抑制这一尾部,服务运行时在归一化之前应用截断过滤器:
Top-\(k\) 与 Top-\(p\) 截断 Top-\(k\) 无论确定性如何,都施加固定的排名上限。Top-\(p\) 则根据概率分布的累积形态动态扩展或收缩候选集。
Top-\(k\) 截断: 运行时对 logit 向量排序,并设置 \(z_{t, v} = -\infty\),作用于所有排名低于固定阈值 \(k \in \mathbb{N}^+\) 的词元: \[\mathcal{V}_k = \{v \in \mathcal{V} \mid \operatorname{rank}(z_{t, v}) \le k\}\] 尽管 top-\(k\) 保证运行时绝不会考虑排名在前 \(k\) 个候选之外的词元,但其固定边界难以适应模型置信度的变化。如果模型高度确定(例如,预测函数调用的右括号),排名第一的候选可能占据 \(99\%\) 的概率质量,但 top-\(k\) 仍强制纳入 \(k-1\) 个无关选项。反之,如果概率分布在数十个合理的同义词之间较为平坦,top-\(k\) 会过早截断可行的续写。
Top-\(p\)(核)截断: 核截断不固定候选数量,而是动态调整候选集的规模,将其设为累积概率质量超过指定阈值的最小子集 \(\mathcal{V}_p \subseteq \mathcal{V}\),该阈值为 \(p \in (0, 1]\): \[\mathcal{V}_p = \arg\min_{\mathcal{S} \subseteq \mathcal{V}} |\mathcal{S}| \quad \text{subject to} \quad \sum_{v \in \mathcal{S}} P(v \mid x_{1:S}, y_{<t}) \ge p\] 所有位于 \(\mathcal{V}_p\) 之外的词元,其 logits 都被屏蔽为 \(-\infty\),剩余分数则重新归一化。在高确定性下,\(|\mathcal{V}_p|\) 自然缩减为一到两个词元;在高熵下,\(|\mathcal{V}_p|\) 则扩展以容纳庞大的候选池。
粗略估算 0.3: 在词表 Simplex 上的对数几率缩放与截断
步骤 1:单位温度下的基线 Softmax(\(\tau = 1.0\)) 首先计算指数项 \(\exp(z_i)\): \[\exp(\mathbf{z}_t) = [162754.8, 36315.5, 8103.1, 403.4, 20.1]\] 将各项求和得到 \(\sum_i \exp(z_i) =\) 207596.9。将每一项除以分母可得: \[\mathbf{P}_{\tau=1.0} = [0.7840, 0.1749, 0.0390, 0.0019, 0.0001]\]
步骤 2:低温度锐化(\(\tau = 0.5\)) 将对数几率缩放为 \(\tau = 0.5\),这使每个指数项翻倍:\(\mathbf{z}_t / 0.5 = [24.0, 21.0, 18.0, 12.0, 6.0]\)。 计算新的指数项: \[\exp(\mathbf{z}_t / 0.5) = [2.649 \times 10^{10}, 1.319 \times 10^9, 6.566 \times 10^7, 1.628 \times 10^5, 403.4]\] 求和几乎完全由最高频 token 主导:\(\sum_i \exp(z_i / 0.5) \approx 2.788 \times 10^{10}\)。 归一化后得到锐化后的概率: \[\mathbf{P}_{\tau=0.5} = [0.9502, 0.0473, 0.0024, 0.0000, 0.0000]\] 降低温度会将总概率质量中的 95 percent 集中于最高频 token \(v_1\),从而大幅降低生成步骤的熵。
步骤 3:核采样截断(\(p =\) 0.90,\(\tau = 1.0\)) 从未经缩放的概率 \(\mathbf{P}_{\tau=1.0} = [0.7840, 0.1749, 0.0390, 0.0019, 0.0001]\) 出发,将 token 按降序排列并计算其累积分布:
- Token \(v_1\):\(P(v_1) = 0.7840\)(累积:\(0.7840 < 0.90\))
- Token \(v_2\):\(P(v_2) = 0.1749\)(累积:\(0.7840 + 0.1749 = 0.9589 \ge 0.90\))
累积阈值 0.90 在纳入 \(v_2\) 后被超过。因此,核集合为 \(\mathcal{V}_p = \{v_1, v_2\}\)。 将 token \(v_3, v_4, v_5\) 的对数几率设为 \(-\infty\)。对幸存子集 \(\{v_1, v_2\}\) 重新归一化: \[\text{Denominator} = 0.7840 + 0.1749 = 0.9589\] \[P_{\text{nucleus}}(v_1) = \frac{0.7840}{0.9589} \approx 0.8176, \quad P_{\text{nucleus}}(v_2) = \frac{0.1749}{0.9589} \approx 0.1824\] token \(v_3, v_4,\) 与 \(v_5\) 获得零概率质量,从而消除了尾部风险,同时保持了两个合理候选之间的比例式随机选择。
对于智能体系统设计师而言,在确定性贪心解码(\(\tau = 0\))与核采样(\(p < 1.0, \tau > 0\))之间进行选择,代表了一种在可复现性与鲁棒性之间的架构权衡:
- 确定性与可测试性: 贪心解码在模型接口上提供严格的确定性。对于编译器工具链、数据库查询和系统配置任务,确定性至关重要:针对确定性模型执行的回归测试会产生可复现的轨迹,使工程师能够在不面对采样方差的情况下隔离下游运行时逻辑中的缺陷。
- 路径退化: 尽管具有可复现性,贪心解码对病态吸引子具有独特的脆弱性。如果未校准的模型进入重复循环(例如输出重复空白,或在两条相互矛盾的逻辑语句之间循环),贪心 argmax 将在触发该循环的步骤 \(t+m\) 上选择与步骤 \(t\) 完全相同的 token,从而将生成锁定为无限循环,直到 \(T_{\max}\) 耗尽。通过核采样注入适度的熵(\(p = 0.95, \tau = 0.7\))会扰动这些确定性吸引子盆地,使生成得以摆脱重复循环。
假设自回归服务循环在未遇到异常硬件异常的情况下完成了对词表单纯形的遍历。逐步来看,它已评估因果注意力层,以较高的个体条件似然采样 token,并在遇到指定的停止分隔符时干净地停止。此时,主机系统已将一条完整、流畅的候选序列 \(\mathbf{y}_{1:K}\) 保留在内存托管中。
如此高的序列似然是否表明生成的载荷有效、语法结构正确,或在操作上安全?并非如此。自回归循环仅针对训练分布下的统计似然进行优化;它没有关于系统真实情况的内部模型,不了解操作系统的不变量,也没有机制来验证所提议的 shell 命令或数据库事务会成功执行还是破坏状态。基础模型在此纯粹充当了一个无权限的假设生成器。在任何输出的候选序列获得修改外部系统状态的权限之前,宿主智能体运行时必须将该提议提交至显式、确定性的候选序列验证流程。
候选序列验证
考虑一个执行系统维护任务的智能体运行时:基础模型完成自回归解码阶段,输出一个包含 shell 命令的候选序列,该命令旨在清除过期的临时文件:rm -rf /var/log/app_temp_${ENV}/*。这条生成轨迹上的每个 token 都是在其条件概率超过 0.95 的情况下采样得到的;整个序列在模型的参数分布下具有极高的统计似然。然而,如果宿主环境尚未为变量 ENV 赋值,shell 就会将该字符串解释为 rm -rf /var/log/app_temp_/*;更糟的是,如果模型在斜杠前幻觉生成了一个空白 token,就会将其解释为 rm -rf /。实际的操作系统并不评估统计似然;它会通过 POSIX 接口盲目执行该指令,截断文件系统层级结构,造成不可恢复的状态破坏。
序列似然衡量的是训练语料中的统计典型性,而非操作正确性、语义真实性或系统不变量的保持情况。 基础模型产生的是假设,而非经过验证的操作命令。由于模型不具备任何环境权限(节 1),上述命令无法自行执行,是否执行由运行时决定。宿主智能体运行时必须将每个输出的候选序列暂存于受控的内存托管区,并在授权任何状态转换之前,使其通过多层、确定性的验证边界。
认识论鸿沟
在自回归生成过程中,赋予完整候选序列 \(\mathbf{y}_{1:K} = (y_1, y_2, \dots, y_K)\) 的概率,以提示 \(\mathbf{x}\) 和模型权重 \(\Theta\) 为条件,由各个 token 的似然乘积给出:
\[P(\mathbf{y}_{1:K} \mid \mathbf{x}; \Theta) = \prod_{t=1}^K P(y_t \mid \mathbf{x}, \mathbf{y}_{<t}; \Theta)\]
标准训练目标——在数十亿份从网络抓取的文档和源代码仓库上最小化交叉熵——使历史文本上的这一概率最大化。然而,语言语料中的统计似然与实际计算硬件上的逻辑有效性和操作有效性之间存在显著差异。
公开训练数据集充斥着已弃用的 API 签名、有缺陷的论坛代码片段、幻觉生成的命令行选项,以及语法结构错误的配置脚本。当自回归解码循环采样使 \(P(\mathbf{y}_{1:K} \mid \mathbf{x}; \Theta)\) 最大化的 token 时,它选择的是这一异构语料库中的典型序列,而非满足宿主环境形式化不变量的序列。此外,模型无法直接获知宿主操作系统的内核状态、文件系统层级结构或网络拓扑,只能依赖序列化到 \(\mathbf{x}\) 中的静态上下文。即使这些上下文完全准确,模型执行的仍是统计续写,而非形式化定理证明。
这种差异正是从解码循环内部观察到的 节 1 中的“看似合理却实际失败”故障。输出在语法上流畅、语义上连贯,却会产生错误的副作用。候选工具调用可能引用不存在的数据库列、幻觉生成 API 参数,或输出颠倒的布尔逻辑,而其 token 级概率仍可与完全正确的代码相媲美。
考虑下面这条具体的失败轨迹:模型以很高的统计置信度生成了一个候选配置补丁,却虚构了一个不存在的参数:
$ pydantic-validator validate --schema deploy_schema.json --input candidate.json
ValidationError: 1 validation error for DeployConfig
worker_threads
Extra inputs are not permitted [type=extra_forbidden, input_value=16]
Found 1 validation failure in candidate payload staged in escrow.模型生成 "worker_threads": 16,是因为多线程配置在服务器软件中十分普遍。然而,目标微服务架构强制采用异步单线程事件循环,使得这一属性成为一个无效的配置条目,会阻止服务初始化。
内存托管机制
零环境权限保护主机资源免受 fail-plausible 候选的侵害。模型不持有任何系统句柄、文件描述符或网络套接字,仅通过一个由主机运行时管理的输入输出内存接口进行通信。当自回归引擎发射候选 token 时,主机运行时会截获该流并将其放入内存托管。
内存托管是一个临时的、由主机分配的缓冲区,用于将未验证的候选序列与运行执行环境隔离开来。token 会被累加、解码为文本或二进制负载,并被结构化为符号候选表示,而无需授予它们能力 token。在托管期间,候选序列纯粹是被动的数据;它无法修改寄存器、操纵磁盘块,也无法传输网络数据报。
主机监督器中每个候选序列的生命周期遵循一套严格的、不可旁路的状态机:
EMITTED:模型通过加速器接口在主机侧环形缓冲区中生成 token。STAGED_ESCROW:运行时检测到序列结束分隔符或生成预算上限,锁定托管缓冲区,并构造候选对象。VALIDATING:主机运行时将已准备阶段的负载分派至确定性的验证边界。模型在此阶段无法修改负载。COMMITTED或REJECTED:如果边界中的每一道验证门都通过,运行时签发执行能力,将该候选提升为可执行的系统命令。如果任何一道门拒绝该负载,候选将被丢弃,并合成一个错误信封用于诊断日志或后续处理。
自回归自我检查的谬误
一种诱人但根本上有缺陷的验证方法是自回归自我检查——提示基础模型检查其自身生成的续写内容,并回答该提议的动作是否正确。从业者常构造如下形式的提示:“你生成了上述 shell 命令。请仔细审查它。它是否正确且可以安全执行?回答 YES 或 NO。”
这种方法违反了系统学中独立验证这一基本原则。从架构角度看,自我检查假定一个无权限的推理引擎可以充当自身的参考监视器。这一假定在三个机制层面不成立:
首先,相关参数偏差。评估该候选序列的模型与生成该候选的模型共享完全相同的权重矩阵 \(\Theta\)、相同的 token 嵌入,以及相同的训练分布先验。如果该模型的注意力权重在生成阶段因该模式在低质量训练数据中出现频繁而偏向某个幻觉出的 CLI 标志,那么在验证提示中激活的将是完全相同的注意力头,从而确认了该幻觉。生成器与评估者会遭受共模失效。
其次,提示框架下的非对称校准。自回归模型容易受到谄媚和确认偏差的影响。当提示上下文呈现一个既有序列时,模型的注意力机制会将概率质量分配给肯定该上下文内部连贯性的 token,而非与之相矛盾的 token。自我检查器在无效序列上发射 YES 的先验概率,远高于外部无偏裁判如此行事的可能性。
第三,未验证概率的无限递归。基础模型无法发射布尔保证;它发射的是词表单纯形上的概率分布。即使某个模型赋予概率 \(P(\text{"YES"} \mid \mathbf{y}) = 0.99\),该数值也并不能闭合某个不变量。如果系统要求对验证者本身进行验证,就必须启动第二次自我检查,由此形成级联:
\[P(\text{invariant closed}) = \prod_{j=1}^M P(\text{verdict}_j = \text{VALID}) < 1.0\]
由于每个评估步骤都会以独立的概率引入采样误差,级联的自回归检查会累积延迟与推理成本,同时使根本性的不确定性始终无法闭合。
在智能体架构中,基础模型是一个中间假设生成器。根据不变量闭合原则(不变闭包原则),任务正确性只能在主机运行时端点得到确立,而确立方式是由持有环境真值权威的确定性验证工具完成的。在形式化方法术语中,诸如编译器、linter 或 schema 解析器之类的确定性软件验证器,就其检查的不变量而言提供健全性。它从不批准违反这些不变量之一的负载(\(P(\text{PASS} \mid \text{Defective}) = 0\) 指被检查的不变量),尽管它对它并未检查的不变量不作任何陈述。自回归自我检查器既不提供健全性,也不提供完备性。它会经常批准无效负载(假阳性),并拒绝有效但新颖的结构(假阴性),因此不具备充当参考监视器的资格。
确定性验证边界
与其依赖模型自我反思,稳健的智能体架构会构建一个位于神经推理引擎之外的 确定性验证边界。该边界由一系列专用软件验证器组成的流水线构成,每个验证器都充当一道筛网,拦截保存在内存托管中的候选载荷,并将其与显式的、非概率性的不变式进行比对。
验证边界以分层结构组织,如 确定性验证边界 所总结。运行时按照计算成本递增的顺序安排检查,从而在将主机资源投入昂贵的语义评估之前,先为粗粒度结构错误提供快速拒绝路径。
| 验证层 | 门控机制 | 所强制的不变式 | 延迟开销 | 真实权威 |
|---|---|---|---|---|
| 1. 词法与句法 | 流式解析器、AST 构建器 | 有效语法、配平的分隔符、完整的 JSON/YAML 编码 | \(< 100\,\mu\text{s}\) | 形式语言语法 |
| 2. 结构与模式 | 类型化反序列化器(Pydantic、Protobuf) | 参数存在性、类型符合性、有界范围、枚举有效性 | \(0.1 - 1\,\text{ms}\) | 静态模式定义 |
| 3. 静态语义 | 静态检查工具、类型检查器(tsc、mypy) |
作用域、已解析标识符、符号表存在性、导入 | \(10 - 500\,\text{ms}\) | 主机工作区符号表 |
| 4. 动态行为 | 沙箱化试运行、模拟执行 | 退出码为零、状态断言满足、预算遵守 | \(50\,\text{ms} - 5\,\text{s}\) | 隔离运行时执行 |
确定性验证边界中的分层架构在候选评估过程中强制实施 快速失败 原则。如果候选序列包含畸形语法(例如未闭合的引号或非法的 JSON 分隔符),第 1 层会在不到 100 微秒内捕获该缺陷。主机监督器会立即中止进一步评估,丢弃无效载荷,而不消耗启动类型检查器所需的毫秒数或执行动态测试所需的秒数。
第 2 层验证候选是否与目标工具的编程接口契约相匹配。如果未获授权的模型提出了缺少必需参数的 API 调用、意外的字段或超出范围的数值,类型化模式验证器会确定性地拒绝该操作。
第 3 层处理当前代码库或运行上下文内的语义有效性。一个候选代码编辑可能语法完美的 Python,并完全符合函数调用模式,却试图调用在当前 git 修订中被弃用或移除的函数。静态分析工具、静态检查工具和类型检查器会将抽象语法树(AST)与主机权威符号表进行比对,验证所有被引用的标识符和类型确实存在。
最后,第 4 层通过在隔离环境中编排候选来评估动态行为,以观察其副作用。如果候选通过了全部静态门控,运行时可以执行试运行或单元测试套件,以验证所提议的命令以退出码零终止,并满足显式的后置条件断言。
关键架构洞见在于,验证边界将 候选解的生成 与 不变式的验证 干净地分离开来。基础模型在巨大的可能动作空间中提供启发式搜索,这是任何组合算法都难以轻易导航的。确定性验证边界提供绝对的、非概率性的不变式强制,这是任何神经网络都无法内在保证的。通过将未获授权的概率性生成器与权威确定性验证器配对,智能体运行时便从非确定性组件中构建出可靠的系统。
为了在正在运行的智能体架构中落实这一验证边界,主机系统不能将基础模型调用视为非正式的字符串入、字符串出操作。一个返回未经修饰文本流的原始 API 调用,会使运行时无法区分生成自然中止、输出在令牌预算上限处被截断,还是连接因传输超时而终止。为了强制确定性验证,主机运行时必须通过严格类型化的远程过程调用(RPC)契约来治理每一次模型交互。该契约必须确立无歧义的运行边界——规定最大预填充和解码配额、硬性执行延迟超时,以及封装候选载荷与其物理服务元数据的结构化状态信封。接下来我们将转向该基础模型调用契约的架构规范。
调用契约
将基础模型调用视为未经修饰的 Unix 管道——从未经授权的生成器向主机运行时流式传输任意 UTF-8 字符——会在分布式软件系统中立即形成失败边界。当标准远程过程调用(RPC)遇到执行故障时,其传输层会呈现类型化错误,其运行时会拆除已分配的缓冲区,而调用进程则保留其本地不变式。相比之下,不受约束的语言模型调用会以模棱两可的方式失败。如果加速器在自回归解码循环中途耗尽内存预算或达到序列长度上限,它会突然中止令牌生成,而不发出闭合语法、变量边界或结构终结符。对于一个朴素的主机消费者而言,被中断的 bash 调用或截断的抽象语法树(AST)看起来并非灾难性的硬件中止,而只是一个普通的、尽管语法上不完整的字符串。
基础模型调用是一种昂贵的、有状态的、非确定性的远程过程调用,运行在稀缺的加速器内存之上。为了防止部分、畸形或失控的执行破坏主机环境,智能体运行时必须通过严格类型化的契约来治理每一次调用,该契约以显式的令牌和延迟上限为界,通过流式取消原语进行监控,并被封装在标准化的状态信封中。
将模型调用视为类型化 RPC,即强制实施 Saltzer 与 Kaashoek 的 模块化边界强制 原则:主机系统从不信任未经授权的子系统自行监管其执行边界,或干净地报告其内部资源耗尽。
形式化请求规范
在稳健的智能体运行时中,对底层基础模型的调用不能通过临时的字符串格式化进行中介。主机运行时必须将该调用形式化为不可变、类型化的请求元组:
\[\mathcal{R} = \langle \mathbf{x}, \text{ModelID}, K_{\max}, T_{\max}, \mathcal{S}, \mathbf{\Theta}_{\text{sample}} \rangle\]
其中,\(\mathbf{x} = (x_1, x_2, \dots, x_S)\) 表示编排于主机上下文中的提示词令牌标识符序列,取自模型词表 \(\mathcal{V}\),使得提示词长度满足 \(S \le S_{\max}\)。ModelID 将执行唯一绑定到特定的参数检查点 \(\mathbf{\Theta}\) 与权重量化布局。超参数向量 \(\mathbf{\Theta}_{\text{sample}} = (\tau, \text{top\_p})\) 支配自回归采样过程中从原始 logits 到输出令牌的随机映射。
参数 \(K_{\max}\) 与 \(T_{\max}\) 是主机监督器在模型之下机械式封顶的上限,正如不变式闭合原则(不变闭包原则)对每一个资源边界所要求的那样。生成上限 \(K_{\max}\) 规定了加速器获准向序列追加的新令牌的最大数量。如果没有显式的 \(K_{\max}\),陷入重复语义循环或对抗性思维链扩展的自回归解码循环会持续分配键值(KV)缓存内存,直至耗尽加速器的物理高带宽内存(HBM)。这既会耗尽主机进程的截止时间,也会挤占共享加速器池的并发请求。时钟截止时间 \(T_{\max}\) 定义了该调用的绝对延迟超时。如果服务运行时遭遇网络拥塞、队列停滞,或解码步骤过慢而无法在 \(T_{\max}\) 内完成序列,主机运行时将切断传输通道。除令牌与截止时间上限外,该契约还强制规定 主机缓冲区余量边界:监督器对未解析载荷的内存分配施加严格限制(\(M_{\text{staging}} \le M_{\max}\))。这确保了一个行为异常的模型在发出深度嵌套数组、臃肿的 data URI,或恶意 JSON 放大炸弹时,既无法诱发堆耗尽,也不会对监督器进程触发主机内核的内存不足(oom-killer)。
请求边界必须满足不变式 \(S + K_{\max} \le S_{\text{total}}\),其中 \(S_{\text{total}}\) 是模型架构的位置编码方案与物理 KV 缓存分页预算所能支持的最大上下文长度。
最后,请求指定一组离散停止序列 \(\mathcal{S} \subset \mathcal{V}^*\)。这些令牌组合会向加速器服务引擎明确发出信号,表明未经授权的模型已完成其逻辑候选的生成。当自回归解码循环发出任何序列 \(s \in \mathcal{S}\) 时,服务引擎必须立即中止令牌生成,并将执行控制交还主机监督器,绕过 \(K_{\max}\) 内剩余的分配余量。
流式执行机制
由于自回归令牌生成在解码阶段受限于加速器内存带宽,生成数千个令牌本质上是一个缓慢的物理过程。以每秒 40 个令牌的速度在企业级加速器上执行 \(K_{\max} = 2{,}048\) 个令牌的生成预算,需要连续计算超过 50 秒。如果主机智能体运行时将该调用作为单体阻塞式 RPC 执行——同步等待全部 \(K_{\max}\) 个令牌实体化后再检查载荷——那么智能体将放弃对正在运行进程的全部动态监督。
为保持运行控制,调用契约必须强制在复用传输协议(如 HTTP/2 帧、gRPC 或 Server-Sent Events(SSE))之上执行增量令牌流式传输。在这种流式模型下,每个令牌标识符 \(y_t\) 会被封装成数据包,并在其 logit 向量于加速器上被采样的瞬间,通过网络边界传输至主机运行时。
流式从根本上改变了主机智能体运行的安全与效率态势:它使 反应式流式检查 成为可能。随着增量令牌流 \(\mathbf{y}_{1:t} = (y_1, \dots, y_t)\) 穿越网络套接字,主机运行时中的未经授权的流消费者会将正在形成的字节序列交由轻量级的部分验证状态机处理,从而确立协议序列,如 图 5 所示。
沿着 图 5 所示的时间线,令牌交付在传输边界上以异步方式发生。在解码步骤 \(t=1\) 与 \(t=2\),GPU 采样出离散令牌(\(y_1 =\) "{"、\(y_2 =\) "query"),将每个令牌封装在 HTTP/2 DATA 帧中。到达后,主机侧的增量确定性有限自动机(DFA)会验证部分前缀是否满足模式语法,推进解析器状态 \(q_0 \to q_1 \to q_2\),并将令牌编排到未经授权的暂存隔离区中。在加速器侧,GPU HBM 中的物理内存页保持锁定,以保留该序列的键值激活。
名义流式传输持续进行,直到 token 96,此时不privileged模型发出未授权指令或非法终止符("DROP")。主机流式消费端评估自动机转换 \(\delta^*(q_{95}, y_{96}) = \emptyset\);遇到未定义转换会立即触发不变量违反陷阱。与其被动等待剩余生成预算耗尽,主机监督端执行两项协调动作:清除隔离的托管缓冲区(保证没有任何未授权副作用到达真实执行器),并通过套接字立即派发 HTTP/2 RST_STREAM 取消帧,携带错误码 CANCEL。
这一提前取消对加速器硬件的后果是立即且深远的。收到取消帧后,推理守护进程中止解码工作线程,将序列标识符从连续批调度器中驱逐,并把全部物理 KV 缓存页释放回加速器的内存分配器。如 0.4 所推导,在输出上限为 4,096 个 token 的情况下,在 token 96 处取消可节省多达 4,000 个后续解码步骤,约合 84 秒(按单流速率 节 7)。
HTTP/2 RST_STREAM 取消帧。推理服务终止解码工作线程,将请求从连续批队列中驱逐,并即时释放 GPU 高带宽内存中的物理 KV 缓存页。
粗略估算 0.4: 通过提前流式取消回收内存与带宽
首先,我们计算单个 token 在所有层中占用的物理 KV 缓存内存: \[M_{\text{token}} = 2 \times (\text{Key} + \text{Value}) \times L \times H_{KV} \times d\] \[M_{\text{token}} = 2 \times 2 \times 80 \times 8 \times 128\text{ bytes} = 327{,}680\text{ bytes} = 320\text{ KiB per token}\]
假设主机为复杂的代码重构任务指定了 \(K_{\max} =\) 4,096 个 token 的生成预算。在第 \(t =\) 96 个解码 token,模型幻觉出一个违反智能体运行时工具 schema 的无效命令前缀。
若主机被动等待完成,推理引擎将执行剩余的 \(4{,}096 - 96 =\) 4,000 个解码步骤。该单条序列在这些步骤中锁定的物理 KV 缓存内存为: \[\text{Memory Allocated} = 4{,}000 \text{ tokens} \times 320\text{ KiB/token} = 1{,}280{,}000\text{ KiB} \approx 1.22\text{ GiB}\]
此外,在自回归解码阶段,推理引擎必须将整个 \(70\times 10^9\) 参数模型从高带宽内存流式传输到张量核心,每个解码步骤都要如此。以 16 位精度存储时,模型权重占用: \[\text{Weight Footprint} = 70 \times 10^9 \times 2\text{ bytes} = 140\text{ Gigabytes}\]
通过立即 RST_STREAM 在 token 96 处取消,主机监督端使加速器免于执行 4,000 次受内存带宽限制的解码迭代。这消除了对以下内存传输总量的需求: \[\text{Bandwidth Saved} = 4{,}000 \text{ steps} \times 140\text{ GB/step} = 560\text{ Terabytes}\] 从而为并发服务批次释放可观的执行能力。
归一化状态信封
稳健的运行时架构拒绝原始字符串返回。相反,每次模型调用都必须解析为权威且归一化的状态信封 \(\mathcal{E}\):
\[\mathcal{E} = \langle \text{status}, \mathbf{y}, \mathbf{m} \rangle\]
载荷 \(\mathbf{y}\) 包含累计 token 序列,而 \(\mathbf{m}\) 是记录硬件级执行遥测的元数据记录,包括预填充延迟、解码步骤数、提示 token 数 \(S\)、生成 token 数 \(K\),以及加速器终止标志。
信封的核心是归一化的 status 判别器。由于分布式推理引擎、云 API 和本地运行时通过相互冲突的 schema 与传输码报告运行状态,主机智能体监督端将所有原始结果归一化为封闭状态分类法,详见 表 4。
| 状态标志 | 终止条件 | 载荷完整性 | 可接受的主机动作 |
|---|---|---|---|
COMPLETED |
模型在限制内发出自然 EOS 或停止 token \(s \in \mathcal{S}\)。 | 结构完整;完整生成的候选字符串。 | 从托管区释放载荷;转发至验证器。 |
TRUNCATED |
执行在发出停止 token 前达到 token 上限 \(K_{\max}\)。 | 语法断裂;不完整的 AST 或截断的 CLI 标志。 | 永久隔离。 丢弃候选;绝不执行。 |
REFUSED |
模型安全分类器或系统护栏阻止了生成。 | 解释性策略字符串或空缓冲区。 | 终止轨迹;记录治理策略违规。 |
TRANSPORT_FAILURE |
网络套接字断开、HTTP 5xx 错误,或超时 \(T_{\max}\) 已过期。 | 空或分片网络缓冲区。 | 记录传输失败;处理连接故障。 |
REJECTED |
主机侧流监控检测到结构性不变量违反。 | 截断字符串,直至故障点。 | 永久隔离。 将失败路由至运行时监督端。 |
CANCELED |
主机监督端因外部信号主动发出 RST_STREAM。 |
任意部分 token 序列。 | 驱逐载荷;回收主机内存资源。 |
FAULTED |
引擎侧 CUDA OOM、内核崩溃,或硬件看门狗触发。 | 空载荷。 | 告警集群管理器;隔离故障加速器节点。 |
表 4 中的封闭分类法使运行时能够以信封的单个字段表述一次调用的安全规则。
Principle 1: 隔离不变量
COMPLETED 状态的载荷并非完整候选,不得进入验证、编译或执行动作。
含义:运行时在解包载荷之前先检查信封状态,并将所有其他状态发送至其在 表 4 中的恢复路径,而绝不以原样直接执行。任何在 token 配额处截断分叉的搜索,对其截断的分支同样继承该规则。
TRUNCATED 载荷最直观地说明了隔离不变量的必要性。当自回归生成器耗尽生成上限 \(K_{\max}\) 时,token 序列会在占据末位槽位的任意 token 处任意终止。考虑一个不privileged模型生成一条用于清理临时构建产物的 shell 命令。模型意图的完整候选字符串可能是:
rm -rf /tmp/scratch/cache_dir若 token 上限 \(K_{\max}\) 恰在模型发出路径前缀时达到,则网络缓冲区中交付的截断载荷可能为:
rm -rf /tmp/scratch若这条未经验证、被截断的字符串绕过主机信封检查并被直接传入执行沙箱,它将执行一项改变文件删除范围的操作,销毁整个暂存目录,而非目标缓存子目录。在代码合成管线中,被截断的 AST 同样会导致级联的编译器失败,从而污染后续执行上下文。
为强制实施隔离不变量,主机运行时在解包其内容之前实现一道严格的网关检查,先检查调用信封:
def release_payload_from_escrow(envelope: InvocationEnvelope) -> CandidateString:
"""Enforces the Quarantining Invariant at the host boundary."""
if envelope.status != InvocationStatus.COMPLETED:
raise QuarantinedPayloadError(
status=envelope.status,
tokens_emitted=envelope.metadata.generated_tokens,
detail="Payload halted abnormally; strictly barred from actuation."
)
# The payload is structurally complete; it may now enter verification.
return envelope.payload通过强制这道网关检查,宿主运行时保证不完整、中断或发生故障的生成结果被保留在内存托管(escrow)中,并在其可能影响外部世界之前予以丢弃。
虽然带类型的 RPC 契约、流式取消以及状态信封能够成功将宿主系统隔离于畸形或截断的载荷之外,但被动拒绝在经济性和计算效率上仍然低效。如果模型生成了非法的句法结构,宿主系统会检测到错误、发出 RST_STREAM,并将该结果隔离——然而,截至该时点所消耗的全部加速器预填充操作和解码迭代都被永久浪费。如果宿主智能体运行时已经知道输出必须满足的形式文法或模式,那么允许模型自由采样非法 token,直到在边界处才将其拒绝,就构成了对计算能力的根本性浪费。这一张力提出了一个架构层面的问题:宿主运行时能否将结构约束直接推入加速器的解码循环,从而确保模型在根本上就不具备发出句法非法 token 的能力?接下来我们将讨论文法引导解码的机制。
文法引导解码
当非特权基础模型在标准自回归解码下生成结构化数据时,在生成数百个 token 之后发出的单个错误字节会使整个载荷失效。缺少引号、非法转义字符或未闭合的花括号,都会导致下游 JSON、SQL 或 XML 解析器以致命句法错误中止。在一种朴素的宿主监督架构中,句法验证仅在 token 生成完成后才进行,宿主智能体运行时必须丢弃整个序列并重新发起调用。这种被动拒绝会消耗大量内存带宽、抬高服务成本,并丢弃预填充和解码迭代期间累积的全部中间加速器状态。事后验证的根本缺陷是架构性的:它允许非特权预测器在庞大的词表空间中自由搜索,而绝大多数候选路径都违反基本的句法不变量。
语法约束解码将结构句法强制从宿主的事后解析器直接转移到加速器的 token 选择阶段。通过将形式文法编译为自动机,并在采样之前动态将合法转移掩码投影到候选 logit 上,服务运行时保证所发射的序列严格符合目标规范,从而消除句法错误,同时底层语义正确性仍完全未经验证。
自动机驱动的 token 掩码
为了在加速器硅片上强制结构句法,宿主智能体运行时必须将高层模式——例如 JSON Schemata、正则表达式或上下文无关文法(CFGs)——编译为能够在解码循环中评估 token 合法性的低层状态机。正则表达式和非递归句法模板可直接编译为确定性有限自动机(DFA)。具有任意嵌套的上下文无关结构,例如递归 JSON 对象或配平的数学表达式,则编译为配备显式解析栈 \(S_{\text{parse}}\) 的下推自动机(PDA)。形式上,确定性自动机由元组 \(\mathcal{A} = (Q, \Sigma, \delta, q_0, F)\) 定义,其中 \(Q\) 是解析器状态集合,\(\Sigma\) 是有效的 UTF-8 字节值字母表,\(\delta: Q \times \Sigma \to Q\) 是状态转移函数,\(q_0 \in Q\) 是初始状态,\(F \subseteq Q\) 是接受状态集合。
语法约束解码通过在概率分布中直接修剪非法转移来强制形式句法规则,确保每个生成的字节串都被所管辖的自动机接受。
形式语言理论中的字符级或字节级字母表 \(\Sigma\) 与基础模型所采用的离散子词词表 \(\mathcal{V}\) 之间存在根本性的系统不匹配。现代分词器将文本切分为数万个长度可变的子词字节序列,而不是单个字符。单个 token \(y \in \mathcal{V}\) 可能表示跨越结构标点、空白和字面字符的多字节字符串,例如 ",\n \"status\":" 或 " true}"。因此,自动机无法将 token 作为原子字母表符号进行评估;它必须验证该 token 的构成字节序列是否形成通过转移图的连续、合法路径。
设 token \(i \in \mathcal{V}\) 对应字节序列 \(\mathbf{b}^{(i)} = (b_1^{(i)}, b_2^{(i)}, \dots, b_m^{(i)})\)。对于当前自动机状态 \(q \in Q\),token \(i\) 有效,当且仅当存在一个中间状态序列 \((q^{(0)}, q^{(1)}, \dots, q^{(m)})\),使得 \(q^{(0)} = q\) 成立,且每个相继的字节转移均有定义:
\[q^{(j)} = \delta\left(q^{(j-1)}, b_j^{(i)}\right) \neq \emptyset \quad \forall j \in \{1, \dots, m\}\]
如果该序列中的任何中间转移遇到未定义的转移 \(\emptyset\),则 token \(i\) 违反文法,必须被禁止。运行时预先计算或动态查询有效词表 token 的集合 \(\mathcal{V}_{\text{valid}}(q) \subseteq \mathcal{V}\),该集合对应状态 \(q\):
\[\mathcal{V}_{\text{valid}}(q) = \left\{ i \in \mathcal{V} \;\middle|\; \delta^*\left(q, \mathbf{b}^{(i)}\right) \neq \emptyset \right\}\]
其中,\(\delta^*\) 表示在完整字节序列(表 5)上求值的扩展转移函数。
| 自动机状态 (\(q_t\)) | 输入 token 前缀 | 允许的结构终结符 | 候选 token 示例 | 被屏蔽的 token 示例 |
|---|---|---|---|---|
EXPECT_KEY |
{" |
字母数字键名、闭合引号 (") |
"id", "status", "name" |
123, true, [, { |
EXPECT_COLON |
{"id" |
空白字符、冒号 (:) |
":", ": ", " : " |
",", "}", "id", true |
EXPECT_VALUE_INT |
{"id": |
数字、负号 (-) |
"0", "42", "-1" |
"true", "\"admin\"", "," |
Definition 0.3: 文法约束解码
文法约束解码 是一种同步 logit 过滤协议,将非特权模型的下一个 token 分布在数学上限制于形式文法 \(G\),具体通过依赖状态的 logit 掩码 \(M_i(q_t) \in \{0, -\infty\}\) 实现。
- 重要性:直接在 logit 层面保证采样得到的 token 符合形式结构文法(如 JSON Schema、SQL AST 或 Python 文法),其概率为 \(1.0\),从而消除句法解析失败。
- 区别:事后验证允许采样出格式错误的 token,随后拒绝整个生成结果或重新生成;文法约束解码则在 softmax 归约之前,在 GPU SRAM 中向无效词表索引对应的 logit 注入负无穷偏置。
- 常见陷阱:在主机 CPU 上执行自动机状态转移,并在每个解码步骤触发同步 PCIe 中断,引入数毫秒级的总线传输停顿,使 token 生成吞吐量下降一个数量级。
在自回归解码步骤 \(t\),Transformer 模型执行其非特权前向计算 \(\mathbf{f}_{\mathbf{\Theta}}\),在反嵌入层计算未归一化的 logit 向量 \(\mathbf{z}_t \in \mathbb{R}^{|\mathcal{V}|}\)。在应用 softmax 算子或采样 token 之前,服务运行时注入 logit 掩码向量 \(\mathbf{M}(q_t) \in \{0, -\infty\}^{|\mathcal{V}|}\),该向量由当前解析器状态 \(q_t\) 决定:
\[M_i(q_t) = \begin{cases} 0 & \text{if } i \in \mathcal{V}_{\text{valid}}(q_t) \\ -\infty & \text{if } i \notin \mathcal{V}_{\text{valid}}(q_t) \end{cases}\]
施加掩码后的 logit \(\mathbf{z}_t' = \mathbf{z}_t + \mathbf{M}(q_t)\) 随后通过分类 softmax 函数归一化,得到实际使用的概率分布 \(p_t\):
\[p_{t, i} = \frac{\exp(z_{t, i}')}{\sum_{j \in \mathcal{V}} \exp(z_{t, j}')} = \begin{cases} \frac{\exp(z_{t, i})}{\sum_{k \in \mathcal{V}_{\text{valid}}(q_t)} \exp(z_{t, k})} & \text{if } i \in \mathcal{V}_{\text{valid}}(q_t) \\ 0 & \text{if } i \notin \mathcal{V}_{\text{valid}}(q_t) \end{cases}\]
由于 \(p_{t, i} = 0\) 对所有不属于 \(\mathcal{V}_{\text{valid}}(q_t)\) 的 token 均成立,因此任何采样算法——无论是贪心 argmax 选择、温度缩放采样,还是 top-\(p\) 核采样过滤——在数学上都只能选择符合文法的 token。采样得到 \(y_t \sim p_t\) 后,运行时将解析器状态更新为 \(q_{t+1} = \delta^*(q_t, \mathbf{b}^{(y_t)})\),使自动机与模型的自回归解码循环同步推进(图 6)。
图 6 中的端到端系统架构通过三个与硬件对齐的阶段,直接在 logit 层面强制句法保证。
在第一阶段(Ahead-of-Time Schema Compilation,即提前式模式编译),输入的工具规范(如 Pydantic 模型)编译为正则表达式和确定性有限自动机(DFA)。对于每个离散自动机状态 \(q \in Q\),编译器预先计算一个打包位掩码 \(\mathbf{B}[q] \in \{0, 1\}^{\lceil |\mathcal{V}|/64 \rceil}\),其中每一位标记对应词表 token 的合法性。整个表格(\(8\text{ MiB}\),覆盖 512 个状态与 131k 词表)被直接镜像到 GPU 设备内存中。
在第二阶段(融合 GPU logit 掩码内核,即融合 GPU logit 掩码内核),未嵌入层输出不受约束的 logit \(\mathbf{z}_t\)(其中不合文法的 token,如 "SELECT" 或 "I think",可能持有任意高的分数)。一个定制的 CUDA/Triton 内核读取当前状态的位掩码 \(\mathbf{B}[q_t]\),并在 softmax 归约之前直接于片上 SRAM 中向所有非法索引注入 \(-\infty\),从而在数学上强制 \(P(v \notin \mathcal{V}_{\text{valid}} \mid q_t) = \exp(-\infty) / \Sigma \equiv 0.00\%\)。
在第三阶段(Synchronous State Advance,即同步状态推进),所采样的 token \(y_t\)(保证合法)在 GPU 寄存器内推进自动机状态 \(q_{t+1} = \delta^*(q_t, \mathbf{b}^{(y_t)})\),更新步骤 \(t+1\) 的当前掩码指针,而无需触发宿主 CPU 中断或 PCIe 总线传输。
加速器位掩码执行
尽管 logit 掩码的理论表述十分直接,但高效实现会暴露严重的硬件延迟瓶颈。在朴素的宿主监督架构中,宿主 CPU 在外部监督文法转移。在每个解码迭代中,加速器完成其矩阵-向量乘法(GEMV),将采样出的 token ID 写入统一的主机—设备内存,并通过 PCIe 总线发出中断。一个宿主运行时进程接收该 token,更新自动机状态,识别出 \(\mathcal{V}_{\text{valid}}(q_{t+1})\),将合法 token ID 打包为掩码,并在下一次前向传递可以执行之前,通过 PCIe 将掩码传回设备内存。
主机—设备掩码阶段的延迟画像详见 表 6。
| 流水线阶段 | 物理子系统 | 典型延迟 | 硬件运行影响 |
|---|---|---|---|
| 词元生成(GEMV) | 加速器张量核心 | \(1 - 20\text{ ms}\) | 前向矩阵-向量参数搬运 |
| 词元传输与中断 | PCIe 总线 / 主机 OS 中断 | \(5 - 15\ \mu\text{s}\) | 加速器执行流水线同步停顿 |
| 自动机状态转换 | 宿主 CPU 核心 | \(2 - 10\ \mu\text{s}\) | 线程上下文切换与 DFA 表查找 |
| 位掩码构建 | 主机 CPU 内存总线 | \(10 - 30\ \mu\text{s}\) | 将合法 token ID 打包为二进制位向量 |
| 向设备传输 DMA 数据 | PCIe Gen5 \(\times 16\) DMA | \(15 - 40\ \mu\text{s}\) | 主机到设备内存写入 VRAM |
| 在设备端应用掩码 | 加速器片上 SRAM | \(< 1\ \mu\text{s}\) | 逐元素 logit 加法 (\(-\infty\)) 与 softmax |
这种由主机中介的设计会引入灾难性的同步停顿。在现代服务器级加速器上,单 token 解码延迟随模型参数数量、张量并行度和批大小在 1 到 20 毫秒之间变化。与此同时,在理想条件下,每个步骤的主机—设备 PCIe 往返、内核启动开销以及操作系统线程调度会引入 20 到 100 微秒的延迟;当主机核心出现线程争用时,会进一步上升到数百微秒。由于自回归解码严格串行,主机—设备同步会迫使加速器的执行流串行化,导致 GPU 张量核心停顿并低效利用高带宽内存(HBM)。
为消除 PCIe 同步瓶颈,高性能推理运行时将文法约束编译为紧凑的位掩码数据结构,并直接在加速器内存中维护。对于词表大小 \(|\mathcal{V}|\),token 验证掩码被编码为打包二进制位向量:
\[\mathbf{B}(q) \in \{0, 1\}^{\lceil |\mathcal{V}| / 64 \rceil}\]
其中每个 64 位无符号整数表示 64 个连续词表 token ID 的合法性。对于具有 \(|\mathcal{V}| = 131{,}072\) 个 token 的开放权重架构,单个自动机状态的位掩码恰好需要 \(131{,}072 / 8 = 16{,}384\text{ bytes}\)(\(16\text{ KiB}\))。如果目标模式编译为具有 \(|Q| = 512\) 个不同状态的自动机,则整个转移与合法性表占用 \(512 \times 16\text{ KiB} = 8\text{ MiB}\) 的连续内存。
粗略估算 0.5: 语法位掩码的内存占用与传输延迟
1. 内存占用与缓存驻留: 稠密有效性表需要:
\[\text{Storage} = 512 \text{ states} \times 16{,}384 \text{ bytes/state} = 8{,}388{,}608 \text{ bytes} = 8\text{ MiB}\]
8 MB 的内存占用不到设备 HBM 总容量的 0.01%(80 GB),并且可以完全容纳在加速器的 50 MB 片上 L2 缓存中。将该表预先载入 L2 缓存后,定制的 GPU 掩码内核便可按 L2 缓存带宽读取当前使用的 16 KB 位掩码(\(\approx\) 12 TB/s),完成内存读取所需的时间为:
\[t_{\text{fetch}} = \frac{16\text{ KiB}}{12\text{ TB/s}} \approx 1.33\text{ ns}\]
位掩码查找直接融合到逐元素 logit 偏置与 softmax 归约内核中,产生的执行开销可忽略不计(\(< 2\ \mu\text{s}\)),且完全无需与主机 CPU 同步。
2. 主机驱动的同步开销: 反过来,假设运行时通过 PCIe Gen5 将状态求值交由主机 CPU 执行。每个解码步骤都会产生以下开销:
- 将采样得到的 token ID 从设备传输到主机(\(4\text{ bytes}\)):\(\approx\) 1.5 μs(互连传输与驱动程序开销)。
- 主机 CPU 上下文切换、线程调度与 DFA 状态转移:\(\approx\) 8 μs。
- 将 16 KB 位掩码通过 DMA 从主机传输到设备:
\[t_{\text{DMA}} = \frac{16{,}384\text{ bytes}}{64\times 10^9\text{ bytes/s}} + t_{\text{packet}} \approx 0.26\ \mu\text{s} + 2.5\ \mu\text{s} = 2.76\ \mu\text{s}\]
- GPU 内核重新启动与流同步:\(\approx\) 5 μs。
每个 token 的主机同步总延迟为:
\[t_{\text{host\_overhead}} \approx 1.5 + 8.0 + 2.76 + 5.0 = 17.26\ \mu\text{s}\]
对于包含 \(S =\) 500 个 token 的输出序列,主机驱动的掩码处理在理想条件下会引入 8.63 ms 的纯空闲停顿时间。在存在多租户调度争用的实际主机系统负载下,这一额外开销往往增至每个 token \(50\text{--}150\ \mu\text{s}\)(总计 \(25\text{--}75\text{ ms}\)),使 token 生成吞吐量下降 \(15\%\) 至 \(35\%\)。
对于具有递归嵌套或复杂正则表达式的语法,当状态空间 \(|Q|\) 增长到数千个状态时,为所有状态分配稠密位掩码会变得低效。服务系统通过压缩状态转移前缀树和推测式位掩码生成来解决这一问题。运行时将子词 token 组织为基于字节序列构建的基数树,从而仅遍历与当前模式深度匹配的活跃分支。此外,通过运行异步 CPU 工作线程来预判后续解析器路径,主机监督程序可以在 GPU 内存中预先填充存放后续位掩码的环形缓冲区,持续为加速器的解码流提供数据,避免因同步往返而阻塞。
句法层面的分界
语法引导解码在字符串表示的边界上建立了确定性保证:输出的 token 序列可被证明符合指定形式语言的良构要求。这一保证对系统集成极具价值,因为它消除了 JSON 解码异常、未闭合的引号和格式错误的字段名。然而,系统设计者经常陷入一种危险的架构概念混淆:假定句法有效性意味着语义正确性。
Saltzer 与 Kaashoek 的模块化划分原则要求,不得将接口表示误认为功能验证;验证字符串的语法规则,并不能确立其所表达的底层命题在实际运行中是否成立。
遵循 Saltzer 与 Kaashoek 的模块化原则,必须严格区分表示与计算。语法掩码仅作用于词法 token 和语法树。它完全无法感知外部环境状态、数据库一致性、操作系统文件系统或断言在数学上是否成立。
考虑一个负责生成结构化 SQL 变更语句以调整库存水平的智能体。 约束文法 强制严格的 ANSI SQL 语法。在 logit 掩码下,基础模型在物理上无法发射未闭合的字符串字面量或非法 SQL 关键字。然而,所发射的语句可能指向不存在的数据库表、违反外键约束,或执行一个未建索引的连接,从而耗尽服务器内存。语法掩码保证该载荷可被数据库引擎解析,但它对逻辑损坏或授权失败(表 7)不提供任何保护。
| 验证维度 | 由语法掩码约束? | 强制机制 | 所预防的失效模式 |
|---|---|---|---|
| 语法符合性 | 是 | 片上 logit 掩码(\(z_i \to -\infty\)) | 解析错误、格式错误的括号、无效类型 |
| 模式完整性 | 是 | 自动机状态推进(\(q \in F\)) | 截断的载荷、缺失的必需属性 |
| 引用完整性 | 否 | 数据库目录 / 外键校验 | 不存在的表或列引用 |
| 语义不变量 | 否 | 主机监督线程 / 确定性单元测试 | 逻辑上不可能的输出、算术倒置 |
| 授权边界 | 否 | 引用监视器 / 操作系统访问控制 | 权限升级、超出范围的资源访问 |
除语法划分之外,刚性的语法约束还会引入一种严重的失效模式,称为模式强制(schema forcing)。当不受约束的基础模型遇到歧义提示、缺失记录,或超出其参数化知识的问题时,其概率质量自然会集中于自然语言免责声明、澄清查询或错误报告 token(例如 "Error: record not found")。
如果主机运行时将该模型绑定到一个严格输出模式,而该模式未显式提供错误或未知状态——例如要求立即输出一个包含 {"customer_id": int, "credit_score": int} 的 JSON 对象——掩码引擎会强制将所有解释性、对话式或错误信号 token 的 logit 设为 \(-\infty\)。模型的概率分布被人为截断,仅保留满足结构模式的 token,正如 表 8 所示。
| 候选 token 序列 | 自然 logit(\(z_i\)) | 自然概率 \(P(y_t)\) | 掩码后 logit(\(z_i'\)) | 约束后概率 \(P_{\text{mask}}(y_t)\) | 语义角色 |
|---|---|---|---|---|---|
"Error: ID not found" |
\(+3.82\) | \(0.82\) | \(-\infty\) | \(0.00\) | 认识论错误免责声明(被抑制) |
"{" |
\(+1.90\) | \(0.12\) | \(+1.90\) | \(1.00\) | 模式分隔符(被人为强制) |
"Unable to resolve" |
\(+1.21\) | \(0.06\) | \(-\infty\) | \(0.00\) | 认识论不确定性信号(被抑制) |
一旦模型被强制进入模式的开括号,它会继续推进到必需字段。由于无法表达其认识论不确定性,模型只能从允许的整数词表中采样 token。它接着发射一个虚构的客户标识符(例如 948102)和一个伪造的分数(例如 720)。通过激进地截断输出分布以保留结构格式,语法掩码将可观察的认识论失败转化为沉默的、貌似成功的语义幻觉。
为缓解模式强制,主机运行时必须设计稳健的模式,显式提供语法有效的逃生路径,例如允许结构化错误对象的联合类型({"status": "error", "code": int, "message": str})。即便如此,主机监督线程仍必须将每一个语法约束的载荷视为不可信候选假设。语法掩码在模型之下机械地闭合语法属性,这正如解码所能满足的不变量闭合原则(不变闭包原则)一样。语义验证仍由外部验证门负责。
Checkpoint 0.3: 评估受约束的语法解码
在评估加速器服务机制与内存带宽约束之前,先验证你对结构化生成权衡的理解:
加速器服务延迟
在加速器硅片上执行自回归基础模型面临着一个严峻的物理分野:处理一个包含数千 token 的提示词可实现稠密矩阵计算单元的接近峰值利用率;而发射每一个后续输出 token,则会使这些相同的计算单元因参数张量需经内存总线搬运而面临数据饥饿。对于将自主子任务委托给非特权基础模型的软件系统,这一二分法将服务延迟从抽象的运行成本转变为一道硬性架构边界。智能体运行时不能把模型调用视为统一的单位时间过程调用:一次消耗大量提示词以输出四个 token 工具调用的调用,与一次发射不受约束、数百 token 的推理轨迹的调用,在资源画像、成本结构和延迟画像上截然不同。
模型调用延迟在计算受限的提示词预填充与内存带宽受限的 token 解码之间被拆分;决定智能体响应时间的主导瓶颈取决于提示词长度、输出 token 数量,以及服务引擎是处理单条轨迹还是批处理多个请求。 理解加速器硬件的物理边界,使系统工程师能够组织提示词、配置工具接口,并建立与当代硬件底层机制相一致的超时契约。
端到端调用延迟的分解
为管理智能体任务的执行预算,主机监督线程必须将墙钟调用延迟分解为其构成的物理阶段与运行阶段。当智能体发射请求以评估模型 \(\mathbf{f}_\Theta\) 对输入序列 \(\mathbf{x}\) 生成续写 \(\mathbf{y}\) 时,总耗时 \(T_{\text{call}}\) 由五个离散的延迟分量(公式 5)决定:
\[T_{\text{call}} \approx \underbrace{T_{\text{queue}} + T_{\text{prefill}}(S)}_{\text{TTFT}} + K \cdot t_{\text{tok}} = T_{\text{prep}} + T_{\text{queue}} + T_{\text{prefill}} + T_{\text{decode}} + T_{\text{post}} \tag{5}\]
运行延迟指标 在生产服务运行时中,\(T_{\text{prefill}}\) 通常报告为首个 token 时间(TTFT),而 \(T_{\text{decode}}\) 的增量步骤延迟则测量为token 间延迟(ITL)。总生成时间主要由 \(\text{ITL} \times K\) 主导。
预处理阶段 \(T_{\text{prep}}\) 代表主机 CPU 开销。它涵盖提示词组装、字符串序列化、字节对编码(BPE)分词,以及——若强制结构化解码约束——引导 logit 掩码的下推自动机的编译或重置。在优化的 C++ 或 Rust 分词流水线中,\(T_{\text{prep}}\) 对于短提示词通常低于 1 毫秒,但它随提示词长度线性增长,并在序列化大型检索文档或多兆字节工具模式时可能消耗数十毫秒。
排队延迟 \(T_{\text{queue}}\) 捕获 token 化请求在加速器的调度积压队列中等待的时间,直到开始在加速器硅片上执行。在专为单个智能体服务的本地单租户部署中,\(T_{\text{queue}}\) 趋近于零。然而,在共享的企业集群或商用多租户 API 端点中,\(T_{\text{queue}}\) 成为一个由到达率、动态优先级类别和批处理调度策略决定的非确定性随机变量。在集群饱和期间,排队抖动经常主导智能体工具循环的尾延迟(\(p99\))。
预填充延迟 \(T_{\text{prefill}}\) 衡量加速器摄取长度为 \(S\) 的整个提示词序列、计算所有 Transformer 层的内部键值表示、并评估条件分布 \(P(y_1 \mid \mathbf{x})\) 以采样首个生成 token 所需的时长。由于所有 \(S\) 个提示词 token 事先已知,该阶段以高度并行的矩阵乘法序列执行。
自回归解码延迟 \(T_{\text{decode}}\) 代表生成后续 \(K - 1\) 个输出 token 所需的累计时间。由于自回归生成具有不可约的串行因果依赖——步骤 \(k\) 必须等到 token \(y_{k-1}\) 被采样并将其键值投影追加到加速器内存后才能开始——该阶段无法在生成维度上进行并行化。它展开为 \(K\) 次互不相同的执行轮次:
\[T_{\text{decode}} = \sum_{k=1}^{K} T_{\text{decode}}^{(k)}\]
最后,后处理延迟 \(T_{\text{post}}\) 捕获主机监督线程将发射的 token ID 反 token 化为 UTF-8 字节流、解析结构化信封(如 JSON 工具调用),并在将控制交还给智能体策略之前执行初始模式验证的开销。
def roofline_decode_latency(params_billion: float, bytes_per_param: float,
bandwidth_tb_s: float, tokens_k: int) -> float:
"""Computes theoretical memory-bound decode latency for batch size B=1."""
model_bytes = params_billion * 1e9 * bytes_per_param
bus_bandwidth = bandwidth_tb_s * 1e12
seconds_per_token = model_bytes / bus_bandwidth
return seconds_per_token * tokens_k这一分解揭示了智能体架构中一个关键的不对称性。软件智能体通常会构建出庞大的提示上下文(\(S \in [10^3, 10^5]\)),其中包含系统指令、环境状态和既往执行历史,但其即时的运行目标往往只是一个紧凑的动作——一个由二十个 token 构成的结构化调用(\(K \in [10^1, 10^2]\))。尽管提示的规模比响应高出几个数量级(\(S \gg K\)),\(T_{\text{decode}}\) 的墙钟时间却常常超过 \(T_{\text{prefill}}\)。这种不对称性的物理根源在于硬件 Roofline 模型。
对于一个含 70.6 十亿参数、权重为 8 位的模型,若由单台当前数据中心加速器(承载该模型的最小部署)提供服务,且内存带宽为 3.35 TB/s,则单条流每个解码步至少需要 21.1 ms,而每个提示 token 在加速器的峰值算术速率下约消耗 71 μs 的预填充。因此,一个输出 token 的时间成本约为提示 token 的 295 倍。
对于首个 turn,8,000 个 token 的预填充在该下限下约需 0.57 秒,解码 200 个 token 则约需 4.2 秒。每次调用中,输出决定了延迟。
预填充与解码:加速器 Roofline 边界
任何数值工作负载在加速器硅片上的性能,都受两个基本物理上限约束:其算术单元的峰值浮点计算能力(\(\pi\),单位为 FLOPs/秒),以及总线将数据从设备高带宽内存(HBM)送入片上静态随机访问存储器(SRAM)寄存器的峰值带宽(\(\beta\),单位为字节/秒)。
运行强度,即算术强度 \(I\),通过计算所执行浮点运算数与跨总线传输的内存流量总体积之比,来刻画工作负载的算法效率:
\[I = \frac{\text{Floating-Point Operations (FLOPs)}}{\text{Memory Traffic (Bytes)}}\]
预填充在 4,096 FLOPs/byte 处饱和张量核心计算,而未批处理解码被困于内存斜率上的 1 FLOP/byte(为什么输出的成本高于输入 推导脊点在各代加速器上的取值)。
Williams-Waterman-Patterson Roofline 模型确立了内核可达性能 \(P\) 等于其硬件计算上限与带宽支持吞吐量的最小值:
\[P = \min(\pi, \; \beta \cdot I)\]
硬件 脊点 \(I^* = \pi / \beta\) 定义了两个根本不同的计算形态之间的运行边界。在现代加速器硅片(如 NVIDIA H100 SXM GPU)上,16 位浮点张量核心计算上限达到 \(\pi \approx 9.89 \times 10^{14}\text{ FLOPs/s}\)(989 TFLOP/s 的密集半精度计算),而 HBM3 子系统提供峰值内存带宽 \(\beta \approx 3.35 \times 10^{12}\text{ bytes/s}\)(3.35 TB/s)。由此得到的脊点为:
\[I^* = \frac{9.89 \times 10^{14}\text{ FLOPs/s}}{3.35 \times 10^{12}\text{ bytes/s}} \approx 295.2\text{ FLOPs/byte}\]
为使加速器的矩阵运算单元饱和、避免浪费计算周期,数值内核必须为每跨一次内存总线获取的单个字节至少执行 295 次浮点运算,从而确立了 Roofline 执行形态 与 图 7 所强调的预填充与解码之间的深刻分野。
| 运行维度 | 提示预填充阶段 | 自回归解码阶段 |
|---|---|---|
| 主要数学内核 | 通用矩阵-矩阵乘法(GEMM) | 通用矩阵-向量乘法(GEMV) |
| 输入张量形状 | 激活矩阵:\(\mathbf{X} \in \mathbb{R}^{S \times d}\) | 激活向量:\(\mathbf{x} \in \mathbb{R}^{1 \times d}\) |
| 权重张量形状 | 参数矩阵:\(\mathbf{W} \in \mathbb{R}^{d \times d_{\text{out}}}\) | 参数矩阵:\(\mathbf{W} \in \mathbb{R}^{d \times d_{\text{out}}}\) |
| 算术强度(\(I\)) | \(I \approx \frac{2 \cdot S}{\text{bytes\_per\_param}} \gg I^*\) | \(I \approx \frac{2}{\text{bytes\_per\_param}} \ll I^*\) |
| 物理瓶颈 | 计算受限(张量核心 ALU 饱和) | 内存带宽受限(HBM 总线饱和) |
| 硬件利用率 | 高(\(50\%\text{--}80\%\) 的峰值 TFLOP/s) | 可忽略(\(< 1\%\) 的峰值 TFLOP/s,\(B=1\)) |
| 延迟缩放定律 | 在计算受限前随 \(S\) 次线性增长 | 随输出 token 严格线性增长 \(K\) |
这两个执行阶段的架构差异在 图 7 中被定量绘制。左侧的硬件 roofline 曲线绘制可达浮点性能 \(P\) 随运行强度 \(\mathcal{I}\) 的变化,受内存带宽斜率(\(B_{\text{mem}} = 3.35\text{ TB/s}\))与峰值 BF16 张量核心上限(\(P_{\text{peak}} = 989\text{ TFLOP/s}\))约束。右侧的内核矩阵几何则揭示了这一性能差异的根本结构成因:提示预填充在一个二维激活矩阵与参数权重之间求值,将权重获取分摊到全部序列行;而未批处理解码则退化为单行向量乘以整个权重张量。
在提示预填充阶段,加速器会同时评估 transformer 的前馈层与投影层,覆盖全部 \(S\) 个 token。输入激活张量是一个二维矩阵 \(\mathbf{X} \in \mathbb{R}^{S \times d}\),与静态参数权重张量 \(\mathbf{W} \in \mathbb{R}^{d \times d_{\text{out}}}\) 相乘。该操作以稠密通用矩阵-矩阵乘法(GEMM)执行。
在一个含 \(P = |\Theta|\) 参数、以 16 位精度(每个参数 2 字节)存储的模型中,加载权重张量需经总线传输 \(2P\) 字节。在 \(S\) 个 token 上执行该矩阵乘法需要 \(2 \cdot P \cdot S\) 次浮点运算。因此,预填充阶段的算术强度为:
\[I_{\text{prefill}} \approx \frac{2 \cdot P \cdot S}{2 \cdot P} = S\text{ FLOPs/byte}\]
当智能体提供 \(S = 4{,}096\) 个 token 的上下文时,运行强度达到 \(I_{\text{prefill}} \approx 4{,}096\text{ FLOPs/byte}\)。由于 \(4{,}096 \gg I^*\),预填充在 Roofline 曲线的计算受限平台上运行得相当深入。矩阵单元以高利用率运行,延迟 \(T_{\text{prefill}}\) 主要随总算术运算数除以张量核心吞吐率 \(\pi\) 而缩放。
在自回归解码阶段,情况完全反转。由于每个生成步只为恰好一个新采样 token 评估模型,输入激活坍缩为单个行向量 \(\mathbf{x} \in \mathbb{R}^{1 \times d}\)。线性投影此时以通用矩阵-向量乘法(GEMV)执行。加速器仍须将整个参数权重矩阵 \(\mathbf{W}\) 从 HBM 扫入 SRAM 寄存器,传输 \(2P\) 字节。然而,它仅针对该单向量执行 \(2 \cdot P \cdot 1\) 次浮点运算。
暂且忽略过去 key-value 状态的瞬时检索开销,单个解码步的算术强度为:
\[I_{\text{decode}} \approx \frac{2 \cdot P \cdot 1}{2 \cdot P} = 1\text{ FLOP/byte}\]
若参数量化至 8 位精度(每个参数 1 字节),运行强度将翻倍至 \(I_{\text{decode}} = 2\text{ FLOPs/byte}\)。无论采用何种精度,\(I_{\text{decode}}\) 都仍比硬件脊点 \(I^* \approx 295.2\text{ FLOPs/byte}\) 低两个数量级以上。解码阶段运行于内存带宽受限斜率的极端底部。
内存带宽搬运
低算术强度的物理后果是:token 解码的延迟并非由加速器计算得有多快所决定,而是由其内存控制器将参数权重沿物理走线从 HBM 扫入处理寄存器有多快所决定。
现代加速器的片上 SRAM 缓存内存受硅片面积物理限制,通常在所有流式多处理器之间合计提供 40 兆字节到 100 兆字节存储。包含数十亿参数的基础模型无法容纳于片上缓存。一个含 700 亿参数的模型在 16 位精度下占用 140 吉字节,量化为 8 位表示时则为 70 吉字节。因此,参数张量必须驻留在通过硅片中介器互连的片外 HBM 封装中。
为生成单个输出 token,加速器必须将整个 70 吉字节的模型经总线传输,将权重载入本地寄存器,与单个 token 激活向量计算内积,再从本地寄存器存储中丢弃权重,为下一层的参数张量腾出空间。为生成下一个 token,硬件必须从头重复整个序列。
粗略估算 0.6: 单 token 生成的 Roofline 界限
首先,计算仅将模型参数经内存总线从 HBM 搬运至 SRAM 所需的时间:
\[T_{\text{mem}} = \frac{\text{Model Footprint (Bytes)}}{\text{Memory Bandwidth (Bytes/s)}} = \frac{70 \times 10^9\text{ bytes}}{3.35 \times 10^{12}\text{ bytes/s}} \approx 0.020895\text{ seconds} \approx 20.90\text{ ms}\]
接着,计算在计算单元以 100% 效率运行的情况下,执行浮点运算所需的理论时间:
\[T_{\text{comp}} = \frac{2 \cdot P \cdot 1\text{ FLOPs}}{\text{Peak Compute Throughput (FLOPs/s)}} = \frac{1.40 \times 10^{11}\text{ FLOPs}}{9.89 \times 10^{14}\text{ FLOPs/s}} \approx 0.0001415\text{ seconds} \approx 0.14\text{ ms}\]
可达到的单步延迟受这两个物理时长中的最大值约束:
\[T_{\text{step}} \ge \max(T_{\text{comp}}, \; T_{\text{mem}}) = \max(0.14\text{ ms}, \; 20.90\text{ ms}) = 20.90\text{ ms}\]
在本次单 token 生成步骤中,加速器矩阵运算电路的算术利用率 \(\eta\) 为:
\[\eta = \frac{T_{\text{comp}}}{T_{\text{mem}}} = \frac{0.14\text{ ms}}{20.90\text{ ms}} \approx 0.00678 \quad (0.68\%)\]
在该步骤中,加速器中超过 99.3 percent 的矩阵运算单元完全空闲。该轨迹可达到的最大解码速度为:
\[\text{Throughput} \le \frac{1\text{ token}}{0.020895\text{ seconds}} \approx 47.8\text{ tokens/second}\]
这一定量事实说明了多租户推理运行时为何依赖请求批处理。如果服务运行时将 \(B\) 个独立的客户端请求组成一批,它只需将模型权重 \(\mathbf{W}\) 经内存总线加载一次,然后将其与激活矩阵 \(\mathbf{X} \in \mathbb{R}^{B \times d}\) 相乘;该矩阵同时表示全部 \(B\) 条流的当前 token。
由于内存流量固定为模型的内存占用,而浮点运算量随 \(B\) 线性增长,解码的运算强度随批大小成正比增长:
\[I_{\text{decode}}(B) \approx \frac{2 \cdot B \cdot P}{P \cdot \text{bytes\_per\_param}} = \frac{2 \cdot B}{\text{bytes\_per\_param}}\]
通过将批大小提高到硬件脊点以上——使 H100 GPU 上的 8 位模型达到 \(B \ge 148\)——服务运行时将硬件重新推入计算受限形态。这将参数加载成本分摊到数百名并发用户上,从而最大化服务器的总吞吐量(整个集群每秒输出的 token 数)。
然而,对于自主智能体而言,服务层面的批处理带来了一个突出的系统困境。智能体的执行本质上是一个闭环的顺序过程。智能体观察世界,向模型发送提示,等待动作 token 序列生成完毕,在外部环境中执行所选工具,并将工具输出纳入后续提示。
由于第 \(t+1\) 步的提示严格依赖于第 \(t\) 步所调用工具实际产生的副作用,智能体无法预先生成未来的 token,也无法在自身轨迹的连续步骤之间并行执行。沿着自身的执行路径,智能体以批大小 \(B = 1\) 运行,因此,批处理这一带宽受限解码的常规解决方法(原则 1)无法缩短其关键路径。轨迹步骤生命周期 概述了由此形成的单步执行的各个阶段。
| 执行阶段 | 硬件瓶颈 | 主导资源 | 延迟特征 | 算术利用率 |
|---|---|---|---|---|
| 提示词预填充 | 计算受限 | 加速器张量核心 | \(50 - 300\text{ ms}\)(取决于提示词) | 高(\(40\% - 70\%\) 峰值 TFLOPS) |
| 动作解码(\(B=1\)) | 内存带宽受限 | HBM 权重搬运 | \(20.9\text{ ms/token}\)(H100 上 70B FP8) | 极低(\(< 1\%\) 峰值算术能力) |
| 工具执行 | 主机 I/O / 网络受限 | 主机 CPU、磁盘、网络 | \(10 - 2{,}000\text{ ms}\)(取决于系统) | 加速器零活动(GPU 空闲) |
| 观测结果暂存 | 主机—设备传输 | PCIe 总线与主机 RAM | \(1 - 10\text{ ms}\) | 可忽略的 DMA 传输开销 |
当智能体运行时向使用大规模动态批次的多租户共享服务引擎发起调用,以最大化 GPU 效率时,智能体承受显著的排队延迟(\(T_{\text{queue}}\))与延迟抖动。智能体工具循环的每一步都会因服务引擎聚合来自其他网络客户端的请求以组装高效批次而经历调度暂停。
相反,如果系统工程师为智能体独占配置专用的、不批处理的加速器硬件,以最小化智能体的周期时间(\(T_{\text{queue}} \to 0\)),那么物理硬件的计算效率将低于 1%。主机系统承担了加速器的全部功耗、硬件资本与热力学成本,却只利用其内存总线。在企业级服务器采购成本约为 \(\$30{,}000\) per NVIDIA H100 (or \(\$3.50/\text{hr}\)(按需云定价)的情况下,\(0.68\%\) 的算术利用率意味着超过 \(99\%\) 的摊还硬件资本与运营冷却预算被浪费,用于维持空闲的矩阵运算硬件,同时却在内存总线上等待。这种严重的资本效率低下,正是推动解耦式服务架构(将物理加速器划分为专门的预填充节点(饱和计算)和解码节点(最大化内存吞吐))的主要经济动因。
计算受限的预填充与内存受限的解码之间的物理不对称性,对智能体系统架构施加了严苛的经济与时间权衡。单个冗长的工具调用所发出的数百个不受限 token,其加速器时间成本比处理一个千 token 提示词高出数个数量级,而空闲的张量核心则在等待权重经由内存总线传输时持续消耗能量。当系统设计者试图优化这一流水线——无论是通过细粒度提示词压缩、语法约束解码、投机执行,还是专用工具格式——他们如何严谨地判断某种架构干预是否带来真实性能收益?由于诸如原始 token 生成速度或孤立 JSON 解析准确率等表面指标无法捕捉多轮问题求解的复合动力学,系统工程师需要一种基于端到端任务完成、并以不变资源预算为基准的实证基准测试方法。
多轮轨迹成本累积
轨迹由许多次调用组成,而模型在它们之间不保留任何内容。因此,每一轮都会重新发送到目前为止的整个对话,再加上新的工具结果,提示词随之逐轮增长。如果首个提示词包含 \(S_0\) 个 token,而每轮追加 \(\Delta\) 个模型输出与工具结果 token,那么包含 \(N\) 轮的轨迹总共发送
\[S_{\text{sent}} = \sum_{t=0}^{N-1} \left(S_0 + t\Delta\right) = N S_0 + \Delta \frac{N(N-1)}{2} \tag{6}\]
个提示词 token,其数量随轮数的平方增长。
服务可以免去大部分此类工作。当新提示词以与较早提示词完全相同的 token 开始时,服务可以复用为该共享前缀构建的 KV 缓存,并仅对新后缀执行预填充。这就是前缀缓存 (Zheng 等 2024年)。在智能体循环中,几乎每一轮提示词都是上一轮的扩展,因此借助缓存,每轮只需预填充其 \(\Delta\) 个新 token。节省效果取决于前缀保持逐字节完全一致。上下文早期的一处编辑,例如系统提示词中的时间戳或重新排序的工具列表,都会从该点起使缓存失效。如何布局上下文以保持前缀稳定,是 上下文工程 的主题;服务如何存储与匹配缓存前缀,则是 跨轮次前缀缓存 的主题。下面的笔记本分别对一条轨迹进行带缓存与不带缓存的定价。
粗略估算 0.7: 三十轮轨迹的价格
数学:在不使用缓存的情况下,公式 6 给出 \(N S_0 + \Delta\,N(N-1)/2 =\) 892,500 个提示词 token,对应 \(N K =\) 6,000 个输出 token,因此重发输入占所处理全部 token 的 99.3%。预填充这些提示词 token 约需 64 秒,解码输出约需 126 秒。使用前缀缓存后,仅首个提示词以及后续每轮的新 token 需要预填充,共 \(S_0 + (N-1)\Delta =\) 51,500 个 token,约为原来的 17 倍少,预填充时间降至约 3.7 秒。到最后一轮时,上下文包含 51,500 个 token,其 16 位精度的 KV 缓存约占 16.9 GB,与约 70.6 GB 的权重相当。二者合计约需 87.5 GB,超过任何激活或运行时缓冲区之前单个加速器所能容纳的 85.9 GB,因此设定解码下限的单加速器部署无法使该轨迹的最后一轮驻留。
系统学洞见:在智能体自身的关键路径上,6,000 个输出 token 仍然耗时最多,因为每个 token 都是一个串行的、内存受限的步骤。然而,该轨迹的工作量主要由其重发的提示词 token 主导,而前缀缓存只有在上下文被布局为每轮提示词都完整延续上一轮时,才能消除其中几乎全部工作。
两种成本视角回答的是不同问题。延迟是智能体自身轨迹所经历的量,在该路径上智能体以单一流运行。每次调用都必须等待前一轮的工具结果,因此智能体无法对自己的步骤进行批处理,而批处理这一通常用于缓解内存受限解码的对策,并不能缩短其关键路径。成本则是服务集群所经历的量。集群将许多智能体的解码步骤合并批处理,因此每步读取的权重被多个流共享,生成 token 的成本随之趋近于其算术成本,约 \(2P\) 次运算,与提示词 token 相同。此时,集群账单随所处理 token 总数增长,而对单个智能体而言,该数量主要是重发输入。输出决定延迟,重发输入决定成本。集群批处理及其排队效应推导见 轨迹排队,而按每接受任务美元计价一条轨迹则是 智能体经济学 的工作。
长上下文同样消耗内存。笔记本中最后一轮的 KV 缓存占模型自身权重的相当大一部分,大到单个加速器无法同时容纳二者,并且该缓存会驻留到服务将其保留为止的整个期间,包括智能体等待慢速工具的时候。因此,运行大量轨迹的服务会将模型分摊到服务节点的各加速器上,并在节点层面配置内存;决定保留、淘汰还是重算该状态,属于 KV 缓存管理 的内容。
Checkpoint 0.4: 对调用与轨迹的定价
相同的 token 数量对“耗时多久”和“花费多少”给出不同的答案。
提出一个请求成本低廉,但将其完整写出成本高昂,且其成本高度依赖于运行时要求它采用的形式。选择这一形式,是本章针对单次调用所做的最后决策。
接口基准测试
仅凭智能体调用接口的语法解析吞吐量或 schema 遵循度来评估该接口,会产生一种架构上的错觉。评估智能体调用接口的系统工程师面临一个具有欺骗性的测量陷阱:为快速、无错误解析而优化的接口,往往会损害物理硬件上模型的实际问题解决能力。将不受特权约束的基础模型 \(\mathbf{f}_{\mathbf{\Theta}}\) 限制为通过解码期 logit 掩码发出严格 JSON schema,可以保证 100% 的语法解析率(\(R_{\text{syntax}} = 1.0\)),但实证基准测试经常显示,这种结构性的束缚会压低下游端到端任务完成度。相反,允许不受约束的自由形式自然语言生成,可以最大化中间暂存推理 token 可用的生成预算,但它会给主机监督器带来脆弱的正则表达式解析器、非确定性的结构提取失败,以及输出 token 的失控膨胀。
支配接口选择的架构原则是:调用契约不能依据局部的语法指标来评判,而必须在不变的计算、延迟与内存预算下,依据下游可验证的任务成功度进行评估。一种接口设计,是在提示词预填充开销、解码串行延迟、上下文窗口消耗,以及不受特权模型的语义表达能力之间进行的物理权衡。为了客观比较相互竞争的调用接口,系统设计者必须保持底层模型参数 \(\mathbf{\Theta}\)、评估夹具与资源预算包络不变,并追踪语法约束如何扰动有效解上的概率分布。
受控系统基准测试:不变的资源预算包络
在经典计算机体系结构中,指令集扩展或内存层次结构的改动,绝不会被孤立地评估;它会在标准化的工作负载下经过基准测试,同时严格钳制时钟频率、硅片面积与热设计功耗。在智能体系统工程中,核心计算引擎是一个不受特权约束、非确定性的基础模型,因此评估调用接口需要建立一套完全相同的不变预算包络。若不固定资源预算包络,某项接口修改建议——例如将非结构化文本响应替换为结构化 JSON-RPC 调用——可能仅仅因为被无意允许消耗更多上下文 token、执行额外的投机解码轮次,或突破主机墙钟延迟上限,而显得可靠性更优。
针对智能体接口的严谨系统基准测试,会在所有实验条件下强制施加三项正交不变量:
- 模型与服务引擎不变量:模型参数 \(\mathbf{\Theta}\)、量化精度(如 FP8 或 BF16)、采样超参数(温度 \(\tau\)、top-\(p\) 与频率惩罚),以及推理运行时设置(引擎内存池分配、批处理调度与执行线程配置),必须严格一致。
- 环境与夹具不变量:基准测试必须针对冻结的仓库快照、预置的数据库状态、完全相同的外部工具端点 schema,以及由密封单元测试套件、编译器和静态分析 linter 组成的确定性主机验证框架执行。
- 物理预算包络:总序列预算 \(S_{\text{total}} = M + K \le S_{\max}\)、端到端延迟上限 \(T_{\text{total}} \le T_{\max}\),以及允许的最大主机内存占用,必须在所有候选接口之间保持不变。
智能体接口中的古德哈特定律: 当代理指标(如 JSON schema 有效性)\(R_{\text{syntax}}\) 成为优化目标时,接口设计者就有风险选择出那些以操作正确性(\(\text{PASS}\))为直接代价来最大化解析成功率的协议。
钳制提示词 token 数量 \(M\) 与生成预算 \(K\) 的必要性,直接源于 Transformer 架构的二次与线性规模定律。如果接口契约 A 要求一个包含完整 JSON Schema 定义、TypeScript 接口与少样本语法示例的 1,200 token 系统提示词,而接口契约 B 只要求一个 200 token 的系统提示词,指定紧凑的 Search/Replace 分隔符格式,那么接口 A 会立即引入提示词膨胀惩罚:
\[\Delta M = M_A - M_B = 1{,}000 \text{ tokens}\]
在固定上下文窗口为 \(S_{\max} = 8{,}192\) 个 token 的不变上下文中,Interface A 从宿主系统夺取了 1,000 个 token 的实质性问题上下文——例如相关的堆栈跟踪、文件依赖关系或编译器错误诊断信息。此外,由于 prompt 预填充时间随序列长度按 \(T_{\text{prefill}} \propto M\) 增长(在未优化的注意力实现中呈平方增长),Interface A 将宝贵的毫秒数转移到了加速器生成首个候选 token 之前的计算受限预填充阶段。钳制资源包络后,系统基准测试必须计入这一结构性开销,以衡量 Interface A 的语法保证是否值得其所消耗上下文容量。
架构分类
宿主智能体运行时通过四种主要的接口原型与基础模型进行交互,每种原型都在宿主侧解析复杂度与加速器侧生成效率之间取得平衡:
自由文本加分隔符提取: 模型生成不受约束的自然语言,其中穿插非正式标记(例如标准 Markdown 三重反引符块或 XML 标签)。宿主运行时依赖正则表达式或流式字符串扫描器来隔离候选载荷。虽然该接口几乎不引起 prompt 膨胀(\(\Delta M \approx 0\)),并为生成序列在发出具体动作之前积累中间暂存(scratchpad)token 提供了不受限的容量,但它表现出最低的结构有效性(\(R_{\text{syntax}} \ll 1.0\))。分隔符缺失、未转义的靶字符串,或意外的对话式填充内容,都会在宿主参考监控器处导致灾难性的提取失败。
语法约束的 JSON-RPC: 模型词表分布在每个解码步骤 \(t\) 处均通过有限状态自动机或上下文无关文法 logit 掩码进行过滤,如 节 6 中所形式化定义。这保证了所发出的候选序列 \(\mathbf{y}\) 能够被标准反序列化器严格解析(\(R_{\text{syntax}} = 1.0\))。然而,这种结构性保证带来了沉重的结构性税。模型必须发出数百个结构性 token——语法空白、结构花括号、转义引号以及冗余的键标签——这些 token 全部消耗受 GPU 内存带宽限制的加速器解码周期(\(T_{\text{decode}} \propto K\))。此外,强制严格的 JSON 模式常常迫使生成以不自然的序列化顺序发出键值字段,例如在自回归循环尚未发出必需的中间推理 token 之前,就先输出了一个 action_input 载荷。
锚定搜索/替换突变块: 该接口专门针对代码修改和文件系统变更进行了优化,要求模型输出一个目标文件标识符,随后是精确匹配的文本块及其提议的替换内容,并以唯一的哨兵字符串加以界定。与其将整个 500 行的源文件重写以修改三行逻辑,不如仅发出局部 diff 上下文。由于每个输出 token 都需支付完整的权重读取(原则 1),输出长度是未批处理的智能体仍然能够控制的成本,而该接口直接削减了 \(K\)。主要失败模式从语法解析错误转移到锚点匹配故障:自回归生成在搜索块中发出幻觉的行内容或错位的子词 token 边界,致使宿主运行时无法在权威源文件中定位替换目标。权衡结果有利于代码编辑采用锚定块。0.9 中的工作示例将 \(K\) 从 \(1{,}850\) 缩减至 \(80\) token,并将轮次延迟削减超过 \(14\times\),足以将测试调试周期保持在交互式与 SLA 时限之内。
单体文件重新生成: 模型在标准化包络内发出修改后文件的完整文本。虽然该接口彻底消除了锚点匹配故障与 AST 重建歧义,但它将解码税最大化。重新生成数千行未变更内容会饱和加速器内存总线、消耗加速器上下文内存,并提高序列中途发生不可恢复的自回归采样错误的累积概率。
表 9 汇总了这四种接口范式在物理系统维度上的表现,对比其底层加速器资源画像与宿主监督器的失败特征。
| 接口范式 | 结构有效性 (\(R_{\text{syntax}}\)) | Prompt 开销 (\(\Delta M\)) | 生成开销 (\(\Delta K\)) | 主要加速器瓶颈 | 宿主侧主要失败模式 | 任务完成 (\(\text{PASS}\)) |
|---|---|---|---|---|---|---|
| 自由文本 + 正则 | 低 (\(0.75 - 0.90\)) | 基线 (\(0\)) | 可变 | 解码内存总线 | 分隔符缺失;解析崩溃 | 低—中等 |
| 语法掩码 JSON | 绝对 (\(1.00\)) | 高 (\(+300\text{ to }+800\)) | 高 (\(+150\text{ to }+500\)) | 解码内存总线(膨胀 \(K\)) | 语义反转;键序陷阱 | 中等 |
| 搜索/替换 diff | 高 (\(0.94 - 0.98\)) | 低 (\(+50\text{ to }+150\)) | 极小 (\(+20\text{ to }+60\)) | 预填充计算(较大 \(M\)) | 锚点不匹配;陈旧上下文冲突 | 高 |
| 单体重写 | 高 (\(0.95 - 0.99\)) | 低 (\(+20\text{ to }+50\)) | 极端 (\(+1{,}000\text{ to }+10{,}000\)) | 解码内存总线(高 \(K\)) | 上下文容量耗尽;文件中途发散 | 低 |
数据表明,语法完美性并不与端到端任务成功相关。语法掩码 JSON 虽然完全消除了解析崩溃,但其结构性开销会推高 \(K\),从而同时消耗执行时间与注意力容量。相反,搜索/替换 diff 块仅承受轻微的语法与锚点惩罚,但其对解码 token 的大幅削减(\(\Delta K\))使得绝大多数 token 预算可用于实质性推理与上下文编排。
指标层级:从语法合规到验证性闭环
为了判断一项接口修改是否构成真正的系统改进,必须在明确的指标层级上评估性能,该层级从底层序列化机制逐步推进到高层系统验证,如 表 10 所述。
| 评估层级 | 指标维度 | 具体可观测指标 | 架构边界 |
|---|---|---|---|
| 第 3 级 | 验证性任务闭环 | \(\text{PASS}\) 率(密封测试套件、编译器干净构建) | 权威系统边界 |
| 第 2 级 | 硬件与延迟效率 | \(\text{TTFT}\)、解码延迟 (\(T_{\text{decode}}\))、上下文内存占用 | 系统资源成本 |
| 第 1 级 | 语法有效性 | 语法遵循 (\(R_{\text{syntax}}\))、模式解析成功 | 表面代理指标 |
第 1 级:语法有效性率(\(R_{\text{syntax}}\))。 该指标衡量模型发出的原始候选 token 序列 \(\mathbf{y}\) 符合接口结构语法的概率,使得宿主反序列化器能够在不抛出格式异常的情况下解包预期的命令:
\[R_{\text{syntax}} = \frac{1}{N} \sum_{i=1}^N \mathbb{I}\Big(\text{parse}(\mathbf{y}_i) \neq \bot\Big)\]
虽然这是自动执行的必要前提条件,但 \(R_{\text{syntax}}\) 本质上是一个表面性指标。候选序列可以取得完美的语法有效性,同时传输一项完全不可执行的操作——例如调用不存在的编译器标志,或将语法有效但语义荒谬的源代码写入文件。
第 2 级:延迟与硬件效率。 该指标捕捉生成候选序列所需的物理系统成本,可分解为首次 token 时间(\(\text{TTFT}\))与总解码延迟:
\[\text{TTFT} = T_{\text{prep}} + T_{\text{queue}} + T_{\text{prefill}}\]
\[T_{\text{decode}} = \sum_{t=1}^K \left( \frac{\text{Bytes}(\mathbf{W}) + \text{Bytes}(\mathbf{KV}_t)}{\text{BW}_{\text{mem}}} + T_{\text{mask}} \right)\]
其中 \(T_{\text{mask}}\) 表示应用语法掩码的每步成本,当掩码如 节 6 所述融合进加速器解码内核时接近零,而在该小节排除的宿主驱动设计中则达到每个 token 数十微秒。若接口因要求结构性样板而推高 \(K\),则会直接放大每个生成 token 所承受的内存总线读取惩罚。
第 3 级:验证性任务完成率(\(\text{PASS}\))。 任务正确性无法由中间组件或语法验证器加以认证。依据不变闭环原则(不变闭包原则),它仅在应用边界得到认证,此时宿主监督器运行确定性的验证门:
\[\text{PASS} = \frac{1}{N} \sum_{i=1}^N \mathbb{I}\Big(\text{verify}\big(\text{exec}(\mathbf{x}, \text{parse}(\mathbf{y}_i))\big) = \text{PASS}\Big)\]
在此,\(\text{exec}\) 在隔离工作区内执行解析后的载荷,\(\text{verify}\) 则对由此产生的环境状态施加密封回归测试、静态检查器与运行时集成检查。未能通过 \(R_{\text{syntax}}\) 的候选序列直接记为零分,而通过 \(R_{\text{syntax}} = 1.0\) 却因编译失败或破坏不变测试套件而同样记为零分的序列也是如此。
仅针对 第 1 级 或 第 2 级 指标进行优化而忽视 第 3 级,属于根本性的架构错误。以下工作示例说明了接口经过结构性简化设计后,如何使加速器集群陷入瘫痪,同时降低验证性任务闭环。
粗略估算 0.8: 在不变预算下的定量接口评测
- 模型参数:\(P = 70 \times 10^9\) 权重,采用 FP8 格式(\(\text{Bytes}(\mathbf{W}) = 70 \times 10^9 \text{ bytes}\))。
- 内存带宽:\(\text{BW}_{\text{mem}} = 3.35 \times 10^{12} \text{ bytes/sec}\)(\(3.35 \text{ TB/s}\))。
- 计算吞吐量:\(R_{\text{peak}} = 989 \times 10^{12} \text{ FLOPS}\)(BF16 张量核心,非稀疏)。
- 不变工作负载上下文:基线 prompt \(M_{\text{base}} =\) 8,192 个 token。
- 不变延迟上限:\(T_{\max} =\) 15 s。未批处理服务(\(b=1\))。忽略 \(T_{\text{queue}}\) 与 \(T_{\text{prep}}\)。
团队评估两种相互竞争的接口设计,用于在 400 行源文件中实现一个 5 行的缺陷修复:
- 接口 1(单体 JSON 重写): prompt 要求模型在严格的 JSON 包络内输出整个修改后的文件:
{"path": "...", "content": "..."}。- Prompt 开销:\(\Delta M_1 =\) 350 个 token(JSON 模式 + 少样本指令)。
- 生成量:\(K_1 =\) 1,850 个 token(JSON 语法、转义、完整文件内容)。
- 解析可靠性:\(R_{\text{syntax}} =\) 0.99。
- 接口 2(锚定搜索/替换 diff): prompt 要求模型输出局部 diff 标记:
<<<<<<< SEARCH ... ======= ... >>>>>>>。- Prompt 开销:\(\Delta M_2 =\) 120 个 token(diff 语法定义)。
- 生成量:\(K_2 =\) 80 个 token(搜索上下文行、替换行、分隔符)。
- 解析可靠性:\(R_{\text{syntax}} =\) 0.95(偶尔出现锚点不匹配)。
计算两种接口的总执行时间(\(T_{\text{total}} = T_{\text{prefill}} + T_{\text{decode}}\)),评估其对延迟上限 \(T_{\max}\) 的符合情况,并在同等加速器配置下分析其验证性任务吞吐量。
解答:
步骤 1:计算预填充延迟(\(T_{\text{prefill}}\))。 回顾预填充是计算受限的,每个 prompt token 执行 \(2P\) 次浮点运算: \[\text{FLOPs} = 2 \times P \times M\]
对于接口 1: \[M_1 = M_{\text{base}} + \Delta M_1 = 8{,}192 + 350 = 8{,}542 \text{ tokens}\] \[T_{\text{prefill}, 1} = \frac{2 \times (70 \times 10^9) \times 8{,}542}{989 \times 10^{12}} = \frac{1.196 \times 10^{15}}{9.89 \times 10^{14}} \approx 1.21 \text{ seconds}\]
对于接口 2: \[M_2 = M_{\text{base}} + \Delta M_2 = 8{,}192 + 120 = 8{,}312 \text{ tokens}\] \[T_{\text{prefill}, 2} = \frac{2 \times (70 \times 10^9) \times 8{,}312}{989 \times 10^{12}} = \frac{1.164 \times 10^{15}}{9.89 \times 10^{14}} \approx 1.18 \text{ seconds}\]
步骤 2:计算解码延迟(\(T_{\text{decode}}\))。 在批处理大小为 \(b=1\) 时,自回归解码阶段严格受内存带宽限制。每个生成的 token 都需要通过总线从 HBM3 内存读取整个 \(70 \text{ GB}\) 模型参数权重张量: \[t_{\text{token}} = \frac{\text{Bytes}(\mathbf{W})}{\text{BW}_{\text{mem}}} = \frac{70 \times 10^9 \text{ bytes}}{3.35 \times 10^{12} \text{ bytes/sec}} \approx 0.0209 \text{ seconds/token} = 20.9 \text{ ms/token}\]
对于接口 1(\(K_1 =\) 1,850 个 token): \[T_{\text{decode}, 1} = K_1 \times t_{\text{token}} = 1{,}850 \times 0.0209 \approx 38.67 \text{ seconds}\] \[T_{\text{total}, 1} = T_{\text{prefill}, 1} + T_{\text{decode}, 1} = 1.21 + 38.67 = 39.88 \text{ seconds}\]
对于接口 2(\(K_2 =\) 80 个 token): \[T_{\text{decode}, 2} = K_2 \times t_{\text{token}} = 80 \times 0.0209 \approx 1.67 \text{ seconds}\] \[T_{\text{total}, 2} = T_{\text{prefill}, 2} + T_{\text{decode}, 2} = 1.18 + 1.67 = 2.85 \text{ seconds}\]
步骤 3:针对 \(T_{\max} =\) 15 s 进行系统评估。 接口 1 得到 \(T_{\text{total}, 1} = 39.88 \text{ s}\),超出延迟上限 166 percent。宿主运行时将调用状态包络标记为 TRANSPORT_FAILURE(因超时而到期),并中止 RPC 连接,从而在 SLA 下得到有效任务完成率为 \(\text{PASS}_1 = 0.0\),尽管其解析可靠性很高(\(R_{\text{syntax}} =\) 0.99)。
接口 2 在 \(T_{\text{total}, 2} = 2.85 \text{ s}\) 内完成,远低于 15 s 的上限,返回的状态封装为 COMPLETED。即使计入其 \(5\%\) 的锚点解析失败率(\(R_{\text{syntax}} =\) 0.95),剩余 \(95\%\) 的候选仍会交付给验证框架。若模型对有效差异补丁的语义错误修复准确率为 60 percent,则接口 2 的端到端经验证闭环率为: \[\text{PASS}_2 = 0.95 \times 0.60 = 0.57 \quad (57\%)\]
通过将解码 token 数减少 95.7 percent,接口 2 消除了内存总线饱和,实现了 14× 的延迟降低,并将一个在运行层面不可行的接口转化为高性能系统契约。
对调用接口的实证测量揭示了基础模型引擎的根本运行边界。单次调用产生一条无特权的随机候选序列。当该候选存在歧义、语法损坏或逻辑错误时,宿主系统无法通过表面的提示调整或更严格的语法约束来摆脱失败。接口优化可以尽量减少 token 开销和内存带宽饱和,但无法弥合静态自回归预测固有的认识论鸿沟。
在考察系统如何通过搜索树、验证循环和外部环境扩展推理时计算,以克服这些单次调用的边界之前,我们必须先直面那些经常导致生产部署失败的深层架构误解。以下分析将逐一剖析软件工程师将无特权的统计预测器误认为具有特权的确定性操作系统内核时,所产生的长期存在的谬误与陷阱。
粗略估算 0.9: 时限内修复同一个错误的两种接口
计算:使用 \(T_{\text{call}} \approx S\,t_{\text{prefill}} + K\,t_{\text{tok}}\),并采用 节 7 的下限,重写约需 40 秒,差异补丁约需 2.3 秒。两者的耗时均由解码主导,差异补丁的速度约为重写的 17 倍。重写超过时限,因此运行时会以状态 TIMED_OUT 放弃该调用,其经验证的成功率为零,无论其解析表现原本会有多好。差异补丁在时限内完成,其经验证的成功率等于锚点匹配率与测试通过率的乘积。
结果:差异补丁约有 57% 的任务通过验证,而在这一时限下,重写没有任何任务通过验证。
系统洞见:解析成功率较低的接口完成了多得多的经验证修复,因为它将输出 token 数减少了一个数量级以上,而输出 token 数决定了延迟。应在相同预算下根据经验证的成功率评判接口,绝不能仅凭解析成功率。
谬误与陷阱
当软件工程师从传统的确定性分布式系统迁移到基础模型架构时,他们经常将常规操作系统抽象套用到神经推理引擎上。他们将模型调用视为恒定时间的远程过程调用,将语法层面的模式符合性误认为语义正确性,并假设协议层的 HTTP 状态码能够验证任务是否成功。一个不具备任何环境隐式权限的统计序列生成器,既不具备算术逻辑单元的执行确定性,也不具备 ACID 数据库的事务保证。
将 token 生成的统计机制误认为确定性程序执行,是智能体系统在生产环境中脆弱性的首要根因。 围绕基础模型构建具备韧性的软件,需要破除四个长期存在的谬误与陷阱,它们横跨加速器内存总线与宿主验证框架之间的物理边界。
谬误: 一次模型响应就是一次前向传播。
习惯于客户端—服务器 RPC 的软件工程师经常认为,调用 response = model.generate(prompt) 代表一次原子计算执行——类似于一次编译器调用、一次数据库查询或一次矩阵变换。这种心智模型掩盖了加速器芯片上并行提示预填充阶段与串行自回归解码阶段之间的物理执行分离。
一次模型调用并非作为一个整体式张量运算执行。它从预填充阶段开始,在单次并行张量计算中并发处理全部 \(S\) 个提示词元。预填充计算主要由计算受限的通用矩阵乘法(GEMM)内核构成,这些内核以高算术强度运行,充分占满加速器的张量核心,同时为所有注意力头生成并存储初始键值状态。预填充完成后,生成包含 \(K\) 个词元的补全序列,恰好需要 \(K\) 次独立且严格串行的前向传播,每次都经过全部 Transformer 层 \(\mathbf{f}_\Theta\)。
每个解码步骤 \(t \in \{1, \dots, K\}\) 恰好消耗一个词元 \(y_{t-1}\),通过嵌入表 \(\mathbf{W}_{\text{embed}}\) 对其进行投影,针对所有已缓存的历史键值状态 \(\mathbf{k}_{1:S+t-1}\) 和 \(\mathbf{v}_{1:S+t-1}\) 计算注意力,将新计算出的键值对追加到为 KV 缓存分配的物理存储空间中,并通过反嵌入头投影最终隐藏状态,输出 logit 向量 \(\mathbf{z}_t \in \mathbb{R}^{|\mathcal{V}|}\)。在这一未批处理的解码阶段,算术强度骤降至每传输一个字节约 \(1\text{ FLOP}\)。生成每个词元都需要将整个参数矩阵 \(\mathbf{\Theta}\) 从高带宽内存(HBM)经内存总线流式传输到片上 SRAM 寄存器中,仅用于处理一个标量词元位置。
考虑对一个采用 16 位精度的 700 亿参数模型进行未批处理调用(\(b=1\)),其权重占用 \(|\mathbf{\Theta}| \approx 140\text{ GB}\),运行所用加速器的峰值内存带宽为 \(\beta = 3.35\text{ TB/s}\)。将这些权重从 HBM 传输到 SRAM 所需的物理时间存在一个不可消除的下限:
\[t_{\text{step}} = \frac{140 \times 10^9\text{ bytes}}{3.35 \times 10^{12}\text{ bytes/s}} \approx 41.8\text{ ms/token}\]
这一物理瓶颈将生成吞吐量限制在约 \(24\text{ tokens/s}\),无论有多少张量计算单元处于空闲状态。因此,生成包含 \(K = 1{,}024\) 个词元的输出并非一次调用;它包含 1 次并行 GEMM 预填充计算,随后是 1,024 次串行 GEMV 计算,每次都要经内存总线传输 140 GB 数据,连续重复 1,024 次,累计串行内存传输时间超过 42 秒。系统架构师必须将预填充调度与解码调度解耦,采用迭代级连续批处理,在并发请求之间摊销权重传输成本,并严格执行生成上限 \(K_{\max}\),以防止内存总线饱和失控。
陷阱: 将调用完成视为任务完成。
应用运行时经常将协议层面的终止误认为领域层面的语义成功。当推理服务器以状态 200 OK 终止 HTTP 连接,并输出包含 finish_reason: "stop" 的响应封装时,简单的编排器会将该智能体步骤记录为成功,随后直接进行状态修改或下游任务派发。
底层传输层和执行层无法判定高层不变量是否成立。HTTP 200 OK 所携带的 finish_reason: "stop",与 COMPLETED 封装一样,只能确认以下事项:
- 底层 TCP 传输连接保持打开,未发生套接字超时;
- 加速器运行时未遇到未处理的 CUDA 崩溃或内存不足故障;
- 自回归解码循环遇到了序列结束分隔符(
<|eos|>)或指定的停止字符串,且此时尚未达到 \(K_{\max}\)。
这一协议状态无法提供任何证据来证明候选序列 \(\mathbf{y}\) 是否符合事实、结构是否安全或功能是否正确。该序列可能包含无效的 Python 语法,输出针对不存在的数据库列的 SQL 查询,凭空编造会删除用户工作区的 shell 选项,或引入悄无声息的逻辑回归,进而破坏应用状态。
将协议完成视为任务完成,会使幻觉和语法错误绕过宿主系统的防护机制。智能体运行时必须将所有模型补全结果视为不可信的候选方案,暂存于内存中等待验证。当且仅当确定性的外部验证关卡(编译器、代码检查器、静态类型检查器及沙箱测试执行套件 \(\mathcal{E}\))在隔离环境中执行候选方案,并断言显式验证谓词 \(\text{PASS} = 1\) 成立时,任务才能转为完成状态。模型自行判断的完成只是一项未经验证的断言;宿主系统的确定性验证框架才是唯一权威的真值依据。
谬误: 有效的 JSON 意味着工具调用安全且正确。
随着语法引导解码引擎的发展,这类引擎通过解码时的 logit 掩码强制执行上下文无关文法和 JSON Schema 约束,工程师常常认为,只要生成的工具调用能够顺利解析为有效的 JSON,该调用就是安全、可执行且功能正确的。
语法约束严格作用于加速器解码循环中的字符级语法层面。通过跟踪下推自动机或确定性有限自动机的状态 \(q \in Q\),并在每个解码步骤 \(t\) 执行这一过程,运行时将所有会违反语法规则的词表 token 的值屏蔽为 \(-\infty\)。这以数学上的确定性保证括号配对、引号闭合以及字段类型符合正则表达式,从而达到 \(S_{\text{parse}} = 100\%\) 的解析成功率。
然而,语法有效性与语义真实性、引用完整性及操作系统安全性完全正交:
- 引用无效性: 工具调用载荷
{"command": "read_file", "path": "/var/log/syslog"}完全符合模式的类型约束,但目标路径可能不存在,可能是越出项目根目录的非法符号链接,也可能已被并发进程解除链接。 - 语义与类型不变量: 调用
{"action": "allocate_buffer", "capacity_bytes": -2147483648}或{"operation": "drop_partition", "target": "*"}遵守 JSON 的整数和字符串规范,却在下游系统中引发灾难性的整数下溢或数据表删除。 - 对抗性注入: 包含 shell 元字符、目录遍历序列(
../../etc/shadow)或 SQL 注入字符串的参数载荷完全满足字符串正则表达式约束,却在主机 shell 中通过命令注入执行任意命令。 - 模式幻觉与漂移: 模型可以生成语法上毫无瑕疵的 JSON,其中却包含过时的参数名、虚构的标志或相互矛盾的配置选项,导致目标工具处理程序因未处理的异常而崩溃。
将语法上的模式符合性与操作安全性混为一谈,违反了完全仲裁原则。语法引导解码仅解决语法问题,其保障范围仅限于此。主机运行时的引用监视器必须拦截每个候选载荷,依据隔离沙箱边界规范化文件系统路径,根据领域取值范围校验数值参数,依据显式的能力安全矩阵评估操作,并在无特权沙箱中执行调用。
陷阱: 将未完成、拒绝和传输故障合并到通用重试循环中。
当智能体框架在模型调用或工具执行期间遇到异常时,开发者常常用简单的 try-catch 块包裹调用边界,统一采用指数退避,并用完全相同的提示词重试。这将所有故障都视为类似网络丢包的瞬态、幂等 I/O 异常。
在智能体机器学习系统中,调用失败可能源自四个根本不同的故障域,每个故障域都需要彼此不兼容的架构恢复路径:
- Token 预算耗尽(
finish_reason: "length"): 由于序列达到 token 上限 \(K_{\max}\) 或填满上下文窗口 \(S_{\max}\),生成过程提前终止。使用相同参数重试相同提示词,会确定性地复现相同的 token 数量,消耗相同的计算预算,触及相同的内存瓶颈,并在相同的序列位置截断。恢复需要动态压缩上下文、压缩提示词前缀,或发出复用现有 KV 缓存的续写提示词。 - 策略拒绝与对齐过滤器(
finish_reason: "content_filter"): 模型的安全分类器或对齐后置过滤器拦截了提示词或生成的 token。重试固定不变的提示词,会在模型权重上复现相同的激活轨迹,消耗推理 token,并可能触发账户限流。恢复需要上报给人工监督者、回退到专门的领域策略,或调整提示词的封装形式。 - 确定性语义工具故障: 当工具返回非零退出码、编译错误或文件访问失败时,在未更新上下文历史的情况下重试模型调用,会使模型缺乏诊断反馈,导致其反复臆造相同的无效工具调用。恢复需要捕获结构化的标准错误输出跟踪信息,将其格式化为新的环境观测 token 序列,并追加到历史记录中,以实现闭环自我纠正。
- 瞬态传输故障: 只有瞬态网络超时、HTTP 429 限流和 503 后端服务不可用,才属于能够通过指数退避、随机抖动和熔断器副本故障转移得到缓解的基础设施故障。
将这些不同的故障模式合并到一概重试的循环中,必然导致 token 预算迅速耗尽、延迟放大和无声的应用死锁。主机运行时必须通过带类型的状态封装管理所有调用,将执行结果划分为彼此正交的恢复类别,并针对每种不同的故障模式执行专门的缓解策略。
这四个错误源于同一个根因:每个错误都赋予模型调用一个它并不具备的属性,无论是单次前向传播的成本、表示任务已完成的状态、因可解析而安全的载荷,还是会被重试修复的失败。每种情况下的修复,都是将加速器上的统计解码循环与主机运行时(host runtime)所拥有的验证框架分离开来。
摘要
一次基础模型调用,在加速器高带宽存储器上计算一次学习得到的统计变换,将分阶段的离散 token 嵌入前缀转换为固定词表 \(\mathcal{V}\) 上的概率分布序列。在物理加速器硅片上,该操作分裂为两个互不相交的执行形态:一个计算受限的张量收缩(\(\text{GEMM}\)),用于预填充因果前缀;随后是一个不可约地串行、受内存带宽限制的矩阵—向量乘(\(\text{GEMV}\)),沿时间自回归地推进,从不断扩大的键值(\(KV\))缓存中读取并追加。由于模型本身不具备任何环境权威(ambient authority),它所发出的是候选结果,即一种统计假设,而非经验验证过的运行结果。
治理这一统计引擎,要求主机智能体运行时将模型调用视为受显式资源预算约束、并由确定性验证门限(verification gates)界定的不可信远程过程调用(RPC)。运行时将上下文编排为物理 token 序列,通过解码期 logits 掩码强制语法结构,在归一化的状态信封内拦截发出的 token,并在提交状态变更之前,依据外部软件不变量校验所有候选动作。
要点回顾: 喂饱内存总线,还是浪费硅片
- token 是离散的整数索引,而非语言概念。 基于字符串的智能体逻辑与加速器矩阵数学之间的边界,由一个固定的词表 \(\mathcal{V}\) 所中介,该词表由字节对编码的整数构成。子词分词引入了结构碎片化、词表 token 化偏移,以及与编程语言抽象语法树(AST)之间的表示不匹配,从而决定了嵌入表的维度布局 \(\mathbf{W}_{\text{embed}}\) 以及加速器 \(KV\) 缓存的物理内存分配。
- 自回归解码在加速器内存上施加了一条不可约地串行的因果依赖链。 提示词预填充在批尺寸与序列维度上高效并行,表现为计算受限的矩阵乘法;而 token 生成则严格逐步推进(\(t \to t+1\))。每个解码步骤都需要通过内存总线流式传输数十亿个模型权重 \(\mathbf{\Theta}\) 与数 GB 的 \(KV\) 缓存,以采样单个 token,因此单流解码的吞吐量受限于加速器内存带宽,而非峰值算术浮点能力。
- 序列似然与结构有效性并不能确立真值、安全性或权威。 较高的联合概率 \(P(\mathbf{y} \mid \mathbf{x})\) 仅表示与预训练分布存在统计一致性,而非经验正确性或与实际物理真值一致。同样,语法引导解码通过掩码无效词表 logits 保证与形式语言的结构性合规,却使语义有效性完全处于未验证状态。所有候选序列都仍是非特权假设,需要外部验证。
- 调用契约必须强制显式的物理预算,并评估归一化后的结果信封。 模型调用不能被当作透明的本地函数调用。可靠的智能体运行时将每次调用封装为受硬性时限(\(T_{\max}\))、严格上下文配额(\(S_{\max}\))、显式采样参数以及状态信封所治理的带类型远程过程调用,该状态信封以彼此正交的方式对完成、预算耗尽、语法违规与传输故障进行分类。
- 输出 token 而非提示词 token 决定了智能体的延迟。 端到端调用延迟可分解为提示词预填充(\(T_{\text{prefill}}\))与 token 解码(\(T_{\text{decode}}\))。在批尺寸为 1 时,每个输出 token 都要将完整权重张量流式传输过内存总线,因此一个输出 token 所耗费的时间约为预填充阶段处理一个提示词 token 的两倍。除非提示词长度约为输出长度的 150 倍或更长,否则解码始终占主导;缩短 \(K\) 是智能体最直接可用的延迟控制手段。
本章先为单一方案定价,再构建治理该方案的契约。在批尺寸为 1 时,每个输出 token 都会读取完整权重张量;接口基准测试表明,将调用从整文件重写改为锚定 diff,使该调用从错过时限变为在时限内大幅提前完成,因此受内存带宽限制的解码(原则 1)不仅是服务层面的事实,也是接口设计的一条规则。状态信封、流式取消与设备端语法掩码将不变量闭合原则(不变闭包原则)应用于一次调用,在模型之下封闭语法与资源边界,而将任务正确性留给外部验证。
后续内容: 从单一候选到审慎计算
测试时计算(测试时审慎推理)针对这一物理限制,将生成方式从单候选生成转变为结构化的推理期审慎推理。我们考察主机运行时如何在执行过程中分配额外的计算预算,探索搜索树、协调并行 rollout、管理回退,并集成外部验证器,从而将原始、未经验证的 token 候选转化为稳健、可验证的系统解决方案。
