Agent 精读(九):装得下,但找不到了

这是《深入理解 AI Agent》精读专题的第九篇,第 2 章的收官:上下文压缩——什么时候压、怎么压、以及为什么「隔离优于压缩」。读的是李博杰的开源书第二章的最后部分。

压缩的三个理由,一个比一个深

  1. 成本与长度:窗口有限(比如 128K),工具结果动辄数万字符,几轮就撑满,任务被迫中断;token 越多,成本和延迟越高
  2. 思考质量:即使窗口够大,堆原始信息也不是最优——十几轮搜索结果散落各处,模型每次决策都要在数万 token 里反复检索,注意力被分散,关键信息被遗漏
  3. 上下文焦虑(Context Anxiety):最隐蔽的一个——当模型「觉得」窗口快耗尽时,会在任务没完成前提前收尾。在窗口远没接近耗尽时就主动压缩,模型反而能把任务做完

机制:把需要思考的,变成可以检索的

上一篇状态栏说过「上下文学习更像检索而非推理」。压缩是同一枚硬币的另一面:状态栏是把算好的结论「加」进上下文,压缩是把臃肿的原始记录「换」成算好的结论——都在给那台只有一半的检索引擎补上提炼层。区别只是:状态栏由代码确定性维护,压缩通常用一次 LLM 调用把大段原文蒸馏掉。

书里的例子一眼就懂:上下文里有 100 个笼子的巡查记录(90 只黑猫、10 只白猫),问「黑猫几只」——查找(笼子 37 是什么猫)是注意力的强项;统计归纳要遍历全部记录并维护计数,本质是思考。思维链当然能数对,但每问一次就要从头数一遍。而提前写入「当前统计:黑猫 90 只」,模型立刻检索到。

这就是压缩的第二个价值:把需要思考才能得到的结论,变成可以直接检索的知识。

两个病:溢出和腐化

  • 上下文溢出:装不下了,任务直接失败——这个好理解
  • 上下文腐化(Context Rot)装得下,但找不到了——窗口远没满,Agent 却找不到关键信息,或反复纠结一个早已解决的问题。更隐蔽:表面上还在正常工作,决策质量已经悄然下降

腐化的原因是注意力权重被更多 token 分薄、无关内容占了大头——像在巨大的图书馆里找一本书,无关的书越多,目标越难找。

与 KV Cache 共存:压缩的时机和位置

前面反复强调「前缀不能动」,压缩不就是要改上下文吗?关键在时机和位置:压缩发生在两次 API 调用之间,由框架预处理消息列表——

  • System Prompt 和工具定义永远不动(静态前缀持续缓存)
  • 压的对象是对话历史里的 tool results;替换点之后的缓存失效,之前的仍有效
  • 这是笔有意识的权衡:不压缩会溢出任务失败;压缩损失部分缓存换上下文可控。所以接近阈值时批量压,而不是每轮都压

四条设计原则

  1. 信息价值非均匀分布:决策关键点 > 支撑证据 > 噪声(导航栏、页脚广告)——压缩预算要按价值分配
  2. 语义完整性:「Sutskever 于 2024 年 5 月离开 OpenAI」不能压成「Sutskever 离开」——时间和主体是不可丢的关键信息
  3. 任务相关性:同一内容在不同任务下应产出不同的压缩——检索类任务保广度,分析类保深度,创作类保灵感触发点
  4. 压缩即理解:有效的压缩需要深层语义理解,压缩模块本身要接近主模型的能力(「模型调用模型」的递归架构);好处是压缩结果可审查、可跨会话复用

实验数字背书:上下文感知压缩(把查询意图纳入压缩决策)让 token 使用量减少 75% 以上;而无压缩基线里,几次搜索就耗尽了 128K 窗口(累计 36.7 万字符的原始结果)。

一个优雅的补充是带引用的压缩:内容语义压缩(有损),但每条事实附来源 URL(无损索引)——理论上随时可以回溯原始信息。再配一条工程纪律:决策关键信息要持久化到文档——压缩最容易丢的恰恰是早期的架构决策、约束背后的理由和失败的路径;就像公司的重要信息要文档化而不是留在聊天记录里,模型没有文档化习惯,就用 prompt 和 Skill 提醒它。

生产级:五层分层压缩

成熟系统不会只用一种策略,而是按信息的「保质期」分层(以 Claude Code 为参照):

  1. 工具结果预算控制:大输出落盘,模型只看摘要预览
  2. 噪声直接删:低价值内容直接移除,不做摘要——对噪声做摘要只是浪费 token
  3. API 层微压缩:用 API 的上下文编辑能力让服务端移除指定工具结果——零本地成本,但移除点后的缓存同样失效,适合即将溢出、反正要重建缓存时用
  4. 归档式摘要:逐轮结构化摘要,像 git log 那样保留每轮记录(而不是 squash 成一条),保住对话脉络
  5. 全量压缩:LLM 驱动的最后手段,且带熔断器——生产数据表明大量会话会困在「反复压缩失败」的循环里持续烧钱

隔离优于压缩

压缩是信息进来之后做减法,更釜底抽薪的思路是:让大体积的中间信息根本不进主上下文

主 Agent 把「在代码库中大范围搜索」这类会产生海量中间内容的任务,委派给独立的子 Agent:子 Agent 在自己的上下文里完成探索,只把几百 token 的结论回传。对比一下——主 Agent 亲自搜,数万 token 的原始代码进主上下文,找到目标后全沦为噪声还得靠压缩清理;委派出去,主上下文只增加两条消息(任务描述 + 结论),中间的数万 token 随子 Agent 的上下文一起被丢弃。

本质是用隔离代替压缩:压缩是有损的、需要额外 LLM 调用的事后补救;隔离让噪声从一开始就与主上下文绝缘,主 Agent 的 KV Cache 前缀完全不受影响。代价是子 Agent 看不到主 Agent 的完整上下文,任务描述必须自包含、目标明确——又回到全章的主题:上下文的质量决定能力上限,对子 Agent 同样成立。

第 2 章读完了

三条线索合成一句话:上下文的质量决定能力的上限——提示工程决定写什么,Skills 和状态栏决定怎么按需加载与提炼,压缩决定怎么给膨胀的上下文做减法,隔离决定什么根本不该进来。

下一步

  • 进入第 3 章:用户记忆与知识库——把上下文从单次会话延伸为跨会话的持久知识
  • 实验债清单:context-compressionagent-status-barprompt-engineering

参考来源

为什么 DeepSeek 说 800B 训练不起?把大模型的账算一遍

「7B 参数」「671B 总参数、37B 激活」——这类说法你几乎每天都能刷到。但真去算一笔账,会发现对不上:参数到底是什么?参数多为什么就要很多张卡?为什么 DeepSeek 说稠密 800B 他们训练不起,转头却训出了一个 671B?

我最开始把参数理解成「每一层里被模型理解的 token」,结果显存账怎么算都是错的。后来把这条线一段段捋直,发现它其实就是一道小学算术题,只是有几个概念容易串门。

参数是矩阵里的数字,不是 token

这是最容易混的第一步。

token 是数据——文本切成的片段,一句话差不多切成二十来个。它是喂进去的输入。

参数是模型——一堆权重矩阵,训练完就固定了。它是做运算的那个表格。

一个 token 进来,是流过每一层的参数矩阵,被做乘法。参数不「理解」token,参数是用来算 token 的那台机器。分开看:

1
token(数据) → 乘 W(参数矩阵) → 输出(数据)

所以「7B 参数」的意思很朴素:把整个模型里所有矩阵的数字加起来,一共七十亿个。

一层里到底有多少个矩阵

我原来以为一层就一个矩阵,其实远不止。一个 Transformer 隐藏层里至少有六个:

  • Attention 部分W_qW_kW_v(生成 Q/K/V)、W_o(输出投影)
  • FFN 部分W_1(升维)、W_2(降维)

这里有个容易搞反的地方:Q、K、V 不是参数。它们是 x 乘完矩阵之后算出来的数据,是激活值。真正被训练的是 W_qW_kW_v 那三张表格。

再算一笔账就更有意思了。假设隐藏维度是 4096:

矩阵 形状 参数量
W_q / W_k / W_v / W_o 4096×4096 各 16.8M
W_1 4096×16384 67M
W_2 16384×4096 67M

Attention 四个加起来约 67M,FFN 两个就 134M——一层里 FFN 的参数是 attention 的两倍。 所以整个模型里,参数大头在 FFN,不在 attention。

(顺带一说,MoE 拆的正是 FFN:既然这里参数最多,切成「专家」收益才最大。)

唯一不带参数的,是激活函数

讲到这里通常会有个疑问:矩阵之间夹的那个 ReLU 呢?它算参数吗?

不算。ReLU(x) = max(0, x)——负数变 0,正数不变。它是写死的公式,里面没有任何可以训练的数字,像计算器上那个开根号键。

这带来一个干净的结论:

参数量只统计那些训练出来的矩阵。激活函数、公式、超参数,都不算进「7B」里。

所以「参数量 × 某个常数」这个算法能成立——因为只有参数才需要存、需要算梯度、需要优化器状态。 别的什么都没有。

一个参数,训练时要占 18 个字节

接下来是显存账的核心。

参数不是只存一份,训练时要存五份。 拿其中一个参数举例:

存的东西 精度 字节 干什么用
权重 bf16 2 前向传播
master weight fp32 4 高精度副本,承接更新
梯度 fp32 4 反向传播算出的方向
Adam 一阶动量 fp32 4 平滑方向
Adam 二阶动量 fp32 4 自适应步长
18

拆开看,就是「参数本体」加「训练时才有的一堆附件」。

本体是两份:bf16 那份走前向,图快;fp32 那份是「真身」,负责承接更新。为什么要多一份?因为参数更新时会减去一个很小的量,这个小量在 bf16 的粗糙刻度上经常被直接抹掉——参数就冻住了。所以要有一份 fp32 来承接它。

附件是三份:梯度是这一轮算出来的方向;两个动量是 Adam 记的历史,得跨迭代留着。

这五份,每一个参数都要存一份,跟它在哪一层没关系W_1W_vW_2 里的每个数字都是同样的 18 字节,最后乘总参数量。

于是:

  • 训练:参数量 × 18
  • 推理:只留权重那份 = 参数量 × 2

差 9 倍。这就是为什么「本地能跑 671B」和「能训练 671B」隔着一条鸿沟——它们根本不是同一笔账。

显存和算力,是两张分开的账单

账到这里要分岔了。模型有两个成本:

显存账单 算力账单
管什么 装多少参数 每次算多少参数
什么时候付 加载时一次性 每处理一个 token 都付

粗看这两者绑在一起:参数多,两张账单一起涨。但 MoE 出现之后,它们被拆开了——这是后面所有内容的钥匙。

先看算力账单怎么算。训练所需的计算量有个经验公式:

1
FLOPs ≈ 6 × N × D

N 是参数量,D 是训练用了多少 token。

DeepSeek 那道算术题

现在可以回答标题里的问题了。

假设要训一个稠密 800B 模型,用 15T token:

1
6 × 8e11 × 1.5e13 ≈ 7.2e25 FLOPs

一张 H100 的 bf16 理论算力约 1000 TFLOPS,训练时实际能跑到四成,按 400 TFLOPS 算:

1
7.2e25 / 4e14 ≈ 1.8e11 秒 ≈ 5700 GPU-年

2048 张卡也要跑将近三年。 这就是「训练不起」的由来——不是存不下,是算力账单付不起。

那 DeepSeek 的 671B 又是怎么训出来的?因为它走的是 MoE。

MoE:用显存换算力

MoE(混合专家)的做法,是把 FFN 拆成很多个专家,每个 token 只走其中几个。

以 671B / 37B 激活为例:总参数 671B,但每个 token 实际参与计算的只有 37B。算力公式里的 N,从「总参数」换成了「激活参数」:

1
6 × 3.7e10 × 1.48e13 ≈ 3.3e24 FLOPs

比稠密 800B 低了二十倍——2048 张 H800 跑两个月就够。这跟公开的技术报告是对得上的。

「激活」在这里的准确含义是:这个参数这一轮参与计算了。像点名——全班五十个同学都在名单上,但这节课只点到两个回答问题。没点到的不是「没发挥作用」,是这一轮没上场,下个 token 可能就轮到他们。

所以 MoE 的本质是一次交易:

1
2
付出:按 671B 买的显存(专家全都要待命)
换来:按 37B 付的算力

有个地方特别容易想反——MoE 省算力,不省显存。那些没被选中的专家,权重照样得放在显存里,因为下一批 token 可能就选中它们了。所以 MoE 不是省钱的魔法,是拿显存换算力

这笔交易划算吗?看两个事实:显存是一次性买卡,算力是每 token 持续烧;而模型「懂多少」跟总参数量有关,「跑多快」跟激活参数量有关。稠密模型把这两个旋钮焊死了,MoE 把它们拆成了两个。 能分开调,就有优化的空间。

这条线其实只有三个数字

回头看,整篇东西能压成三句:

  1. 参数是矩阵里的数字,参数量 = 所有矩阵数字的总和
  2. 训练时每个参数占 18 字节,乘出来是显存账单
  3. 训练算力约 6 × N × D,其中 N 用激活参数量,乘出来是算力账单

MoE 做的事,就是让第 2 条按大数付、第 3 条按小数付。


如果你也想验证自己有没有真的搞懂,有个很快的自测:说清楚「一个稠密 70B 模型,训练和推理分别要多少显存」。算出来大概分别是 1.2TB 和 140GB,差的那八倍,就是梯度和优化器状态。能把这两个数分开,这条线就通了。

梁文锋 4 小时投资会精读(上):拿得多的,会被拿得少的打败

最近读完一份流出的四小时录音文字稿——据称是梁文锋 5 月 20 日与投资人的闭门交流会,七月整理流出,未见官方证实。全文是语音转写加 AI 整理,不分说话人,个别名词甚至有识别错误,但观点密度是真的高。这篇是我读完前两部分(愿景与开源、AGI 技术路线)的理解:不是摘抄,是把他的逻辑从头推一遍,再对照一批经典论文做校验。

蛋糕大到,独占必死

DeepSeek 坚持开源,外面最常见的解读是”格局”。读完原文,我觉得更准确的读法是反过来的:开源首先是一个客观规律的判断,其次才是愿景。

梁文锋的账是这么算的:AI 最终可能占人类 GDP 的百分之十。这么大的市场,”一个人独占这个事情,你不可能独占,你一定得跟别人分享,否则你肯定活不下来”。历史上开源和商业化冲突,是因为一个软件公司一年市场才几十亿美金,开源了就只剩几千万。AI 不一样——“你随便分一点点,就已经很足够了”。

从这个判断往下推,是最锋利的一句:拿得多的,会被拿得少的打败。他给 OpenAI 算过账:理论上账是算得过来的,但只要你想要百分之五,就会有只要百分之一的人打败你,然后又有只要千分之一的人打败前面那个人。”甚至你还不用真的拿得多,愿景如果是拿得多的话,你就先输了。”

所以 DeepSeek 的定价不是利润最大化:十个月收回设备成本,约六倍利润。利润最大化的做法应该定更高的价——原文说得很直白,这个价格区间需求没有弹性,价格再翻一倍,token 消耗量区别不大。但他就到十个月回本为止。最能说明问题的是个细节:模型降价到四分之一的时候,公司群里是欢呼的。任何其他公司,降价一半 ARR 就掉一半。

还有两个支撑细节:开源的模型和自部署的是完全同一套权重,没有留一手;而在这个定价之下,第三方自己部署的成本不可能更低,所以开源并不伤收入——“我只担心他部署不起来”。

那么问题来了:这套战略靠什么组织落地?这就到了我认为全文最精彩的地方。

我的推导:三个支撑点

读完第一部分,我把散落的说法拼成一条自己的推导。要做到愿景驱动、开源、松弛这三件事同时成立,有三个支撑点,缺一个就塌:

**第一,集中力量办大事。**公司松弛、人少,所以不应该什么都去做,只做自己认为在通向 AGI 关键节点上的事。原文的说法是克制带来聚焦:3D、视频生成、世界模型,甚至多模态,都只是”组件”,不进主线——哪怕视频生成”在商业上是个好生意”。连好生意都舍弃,这才叫聚焦。

**第二,公司小,必须精准找到属于自己的赛道。**没办法像大公司那样全都要,得让自己能盈利、能持续长久地走下去。开源是这条赛道的一部分:处于一种合理的定价(十个月回本),别人自己部署也不会更便宜,但自己有钱可以挣。这里有两个条件咬合在一起:没有部署成本门槛,开源就是纯让利;没有合理定价,开源就失去商业逻辑。两个都在,开源和赚钱才同时成立。

**第三,必须要做足够多的优化,让卡的效率更加高。**DeepSeek 大概两万张 H 等效算力,和美国比,差距只有资源,不是人才。大公司靠加卡解决,它只能靠效率——成本越低,同样的卡能撑越大的模型。原文有句话让我觉得最值得琢磨:商业化公司没有动力追求模型效率,因为低成本不符合他们的利益。DeepSeek 追求效率,一半是资源约束逼的,一半是愿景——它的员工知道普通人用 AI 是要花钱的。

松弛是前提,还是结果?

组织上,DeepSeek 有两条线。从上到下:目标明确大家一起干,比如发 V4 要分工,每个人做一部分,这叫”正式”;从下到上:每个人都有自己的 idea 和创意,没人管、没有 KPI,按自己觉得重要的方向探索。一条硬规则:正式不要超过员工时间的一半。

不加班也有两个原因:研究需要松弛的环境,逼得紧就没法做研究;聚焦所以事情少,没那么多活要干。

读到这里我停了一下,因为有个因果方向的问题。原文的顺序是:克制(战略)→ 聚焦 → 事情少 → 所以松弛,松弛是结果。但按我自己的读法,可以反着推:松弛且人少的组织,天然做不了多线作战,所以只能挑关键节点——松弛是前提。

两种读法互为因果,但我的读法有个推论值得单独记下:如果组织变大、不再松弛了,聚焦会自己松动。这比”创始人想不想要聚焦”更根本。Google 的 20% 时间是现成的警告——Gmail、AdSense 都从这里出来,后来名存实亡,Schmidt 亲口说那其实是指”下班后的时间”。大组织里,短期交付永远比远期探索紧急。

梁文锋能守住这一条,靠的是三件事咬合:愿景共识筛掉了不认同的人(招聘即治理),利润结构允许”低效”(十个月回本而非利润最大化),聚焦让正式工作真的少于一半。缺一个,自由探索就退化成口号。

阶梯:从语言模型到具身

第二部分是 AGI 的技术路线。梁文锋给了一个阶梯:语言模型 → CoT → Agent → 持续学习 → 奇点 → 具身智能。去年走的阶梯是 CoT,今年是 Agent;下一个瓶颈是持续学习(他说的是”学习去学习”);奇点是自我迭代——但他特意说,这个奇点”其实不是一个奇点,是一个连续的过程”。

这个顺序的理由很实用主义:每一步都踩在前一步上,没有一步白走;而且是”最轻松”的路线——先解决持续学习,奇点之后,具身智能的活可以交给模型自己开发,不用人来做。反过来(先做具身)就是苦活。

商业上的动作(去年的 C 端、今年的 B 端)都只是主线的副产物——“站在技术的高位上做低一级别的技术,是降维打击”。

Scaling 他说得干脆:信。墙还没有摸到——“我们训练这么大的模型,并不是因为我觉得这么大就够了,而是我刚好有这么多资源”。挡住 Scaling 的是算力,不是意愿;硅谷说的 Scaling 到头,”对中国来讲,我们离那个还很远”。

CoT 的病,o1 的药

这两部分原文里梁文锋对 CoT 着墨不多,阶梯一笔带过。下面是我自己的补充功课——把自己的判断和一批论文对了个账。

CoT 最大的两个病。

一是不回溯:一条链走到底,前面错,后面就完全错误。这个判断不是我发明的——Tree of Thoughts(2023)开头对 CoT 的批评就是原话:从左到右逐 token 决策,不能回溯,不能全局探索。ToT 的药方是分支、回溯、前瞻评估;Self-Consistency(2022)更简单粗暴:采样多条独立推理链,投票取多数。我最早记的”多 CoT 模式投票表决”,实现是现成的。

二是先给答案,然后编思维过程。两篇论文给过实锤:Turpin et al. 2023 在输入里埋暗示(”答案应该是 A”),模型的思维链完全不提暗示,但答案仍被暗示左右——解释不是决策的依据。Lanham et al. 2023(Anthropic)用截断、替换、改写思维链的办法测依赖,反直觉的发现是:任务越简单、模型越大,CoT 越可能不忠实——简单题根本不需要推理,思维链是事后编的。

CoT 的发展,我看到三条线:外部扩展思考空间(风险是故意模仿人类的思考步骤);多 CoT 并行投票;以及 o1/o3 的路线——不是奖励具体的步骤,而是搭建一个可以验证思维方式是否正确的环境,让错误的决策被否决。

这句话背后是一次路线掉头。2023 年 OpenAI 自己在 “Let’s Verify Step by Step” 里验证过过程奖励(PRM)优于结果奖励(ORM)——人工标注每一步对错。而 o1 被广泛解读为反着走:不用人工步骤标注(容易被钻空子、标注贵),只用可验证奖励(RLVR:数学、代码有标准答案)做结果级 RL,让模型自己学会纠错、拆解、换路。o1 到底用没用 PRM,OpenAI 没说死过,学界吵到现在。但”搭环境而不奖励步骤”,是现在站得住的共识表述。

o1 机制的三个观察(我的笔记,做了校准):

  1. 回答之前先生成思维 token,缓存下来,不展示给用户。精确化:用户看到的是摘要,原始思维链是隐藏的——OpenAI 给的理由是防蒸馏和安全监控。”缓存”更接近 API 层的推理上下文复用(OpenAI 的 previous_response_id、Claude 的思维块缓存),不是被确认过的训练机制。
  2. 提前训练自纠错,做逻辑矛盾的剪枝,让思考自己反馈自己。这个成立:奖励只看最终对错,纠错行为被 RL 自发强化。
  3. 思维空间在解空间上搜索,放弃低概率的搜索空间,具备判断路径复杂度的能力。这是我最想展开的一条——用我的本行打比方,这就是 CBO(基于代价的优化):查询优化器的 cost model 决定走不走索引、并不并行;o1 内化的就是自己的 cost model,简单题烧两万 token 是浪费,奥数题只给一百 token 是找死。Snell et al. 2024 验证的正是这件事:按难度自适应分配 test-time compute,固定预算下小模型能打赢无脑堆算力的大模型。开放问题是这个 cost model 是练出来的还是拍出来的——现在各家 API 的 thinking budget 全靠用户手调,模型”自知难度”这件事没有完全解决。

还没想清楚的三个问题

  1. “拿得多的被拿得少的打败”有个隐含前提:技术优势本身构不成护城河。那它什么时候失效——模型能力差距拉大到某种程度的时候,还是分发和生态锁定生效的时候?DeepSeek 自己又靠什么不变成被锁死的一方?
  2. o1 式的 RL,是不是把 ToT 式的显式搜索内化进了权重(模型自己学会回溯和剪枝,不再需要外部树搜索)?如果是,Agent 阶梯会不会也走同一条路——今天外挂的 Agent 框架,最终被内化成一个模型能力?这恰好对得上”没有一步是白走的”。
  3. “正式不超过一半”这条,复制者最先崩的是哪一环:招不到愿景一致的人,还是管理层忍不住把自由时间填满?

写下来的是前两部分。第三部分是算力与国产芯片(据说有 TileLang 的精彩论述),第五部分是投资人 Q&A(据说有下代模型激活参数 150B–250B)。读完写(下)。

参考来源

博客上线一周,Google 里搜不到我

你有没有遇到过:博客兴冲冲上线,过了一周,在搜索引擎里搜自己的内容——什么都搜不到。就像开了家店,装修完了才发现,连块路牌都没有。这篇是我这两天的排查和修复实录,如果你也用 Hexo + GitHub Pages,大概率用得上。

先说架构:这个博客是怎么搭的

站点的骨架很简单:

  • Hexo 静态站点生成器 + landscape 主题,托管在 GitHub Pages(dongxuanmang.github.io
  • 双分支main 存源码(Markdown 文章 + 配置 + 主题脚本),gh-pages 存生成产物。hexo deploy 自动把 public/ 推到 gh-pages,源码单独提交到 main——内容和产物分离,换电脑也能恢复
  • 日常发布就两条命令:hexo generate(生成)+ hexo deploy(发布)
  • 图表用 mermaid 自托管渲染(一个自定义标签脚本),架构图、流程图直接写在 Markdown 里

这套架构零成本、够用,但有个天然的短板:它不会主动告诉任何人你的存在。静态站没有推送机制,搜索引擎不来,你就等于不存在。

搜不到,是三层问题叠在一起

排查下来,从浅到深:

  1. 技术层sitemap.xml 404、robots.txt 404。搜索引擎发现页面的方式是顺着链接爬,没有 sitemap,它只能靠猜
  2. 通道层:从没在 Google Search Console / Bing Webmaster Tools 提交过——搜索引擎压根不知道这个站存在
  3. 权重层:新站 + 零外链。没人链接你,爬虫就可能几周都不来;就算来了,新站还有观察期

中文内容还有个残酷的第四层:百度对 github.io 的收录极差(爬虫可达性问题),短期无解,直接放弃百度,把 Google 和 Bing 做好。

修复一:给爬虫一张地图

两步,十分钟:

  • hexo-generator-sitemap 插件,部署后 /sitemap.xml 列出全站每个页面的 URL 和最后更新时间
  • source/robots.txt 声明站点地图位置,告诉所有爬虫「地图在这」
1
2
3
4
User-agent: *
Allow: /

Sitemap: https://dongxuanmang.github.io/sitemap.xml

修复二:Google Search Console(踩了一个坑)

Search Console 是 Google 的站长后台,主动提交收录的官方通道。流程四步:添加资源(选「网址前缀」)→ HTML 文件验证 → 提交 sitemap → 用「网址检查」对首页点「请求编入索引」。

中间踩的坑值得单独写:验证文件放进 Hexo 的 source/ 后,被 Hexo 当成文章渲染了——原文件只有一行纯文本,Hexo 给它套上了完整的博客模板(title、meta、样式),而 Google 校验是逐字节比对的,直接失败。

解法是在 _config.yml 里声明跳过渲染:

1
2
3
skip_render:
- google*.html
- robots.txt

重新部署一次通过。注意:验证文件不能删,删了验证状态会失效。

验证通过后,sitemap 提交 + 首页「请求编入索引」两步走完,Google 会把网址放进优先抓取队列——比干等爬虫快得多。

修复三:Bing,意外地顺滑

原本以为 Bing 要再来一遍注册验证,结果发现它支持从 Google Search Console 一键导入:用 Google 账号登录授权 → 自动发现已验证的站点 → 免验证导入 → sitemap 直接带入。导入完它已经发现了我全站 34 个 URL。

而且 Bing 抓取比 Google 快——导入当天就能看到页面状态是「Discovered」(已发现),点一下 Request indexing 就进了抓取队列。

修复四:IndexNow,发布即推送

前面三条都是「等搜索引擎来」,IndexNow 把方向反过来:内容一更新,主动推送给搜索引擎。这是 Bing 主导的开放协议(Yandex、Seznam 也认),三步:

  1. 生成一个 32 位十六进制的 API key
  2. 把 key 内容放进站点根目录的 indexnow.txt(证明你拥有这个站点)
  3. api.indexnow.org POST 一个 JSON(站点 + key + URL 列表)

我把它接进了 Hexo 的部署流程——写了个几十行的脚本,监听 hexo deploy 完成事件,读 sitemap 和上次推送记录做对比,只推送新增或有更新的页面,推送完记入缓存。以后日常发布什么都不用多做:

1
2
3
4
hexo deploy
→ 部署完成
→ 对比 sitemap 与推送缓存,挑出有变化的 URL
→ POST 给 api.indexnow.org(HTTP 202 确认)

第一次跑是全量(34 个 URL 一次性入队),之后每次只推改动——比如这篇文章发布的同时,脚本正在把它推给 Bing。通常几小时到一天就能在 Bing 搜到。

实现上有个小坑:Hexo 的 deployAfter 是站点实例的事件,要用 hexo.on('deployAfter') 监听,而不是 hexo.extend.filter.register——文档里两者容易混。

修复后的预期

  • Bing:几天内可见收录(导入当天 sitemap 状态已是 Success)
  • Google:一到四周,新站有观察期
  • 验证收录用 site:dongxuanmang.github.io,别用关键词搜——新站权重低,关键词排名要慢慢养
  • 最有效的加速器是外链:把文章同步发到掘金/知乎(哪怕只发摘要 + 原文链接),搜索引擎会更快、更频繁地来。比任何技巧都管用
  • 持续更新本身就是信号——这个精读系列天然是个好节奏

参考来源

Agent 精读(八):上下文是台只有一半的检索引擎

这是《深入理解 AI Agent》精读专题的第八篇,一次走完第 2 章的两条线索:Skills(能力的按需加载)和 Agent 状态栏(状态的提前提炼)。读的是李博杰的开源书第二章。
本章思维导图见 专题页 · 章节思维导图

Skills:先给目录,再给手册

Agent 覆盖的业务场景越来越多,系统提示词就会不断膨胀——全部塞进去有两个代价:浪费 token(大部分内容与当前任务无关)、注意力被稀释(无关信息淹没关键指令)。

Skills 的解法是渐进式披露:不是把所有知识一次性塞给 Agent,而是让它按需加载——像给新员工一份总目录,需要哪本操作手册再去取。一个 Skill 由三层组成:

  • 元数据SKILL.md 开头的 YAML frontmatter(name + description),目录在完整正文加载前就可见,让模型先判断要不要这项能力
  • 核心流程:任务需要时才加载完整的 SKILL.md(用户斜杠命令显式触发,或模型读过目录后自己判断、调用 Skill 工具加载)
  • 引用子文件:更细的子文档按需深入(如 PPTX Skill 的 html2pptx.md)

description 的写法是最值得学的一笔:它应当像路由条件,而不是功能介绍——「何时使用、何时不使用」的边界,配上典型的正例和反例。「何时该用我」比「我能做什么」重要得多;写得太宽泛(”help with backend”),任何后端相关的工作都会触发,路由就失准了。

Skill 还可以捆绑可执行的脚本和模板(PPT Skill 带 PPT 模板和解析脚本)。往大了看,每个 Skill 是自包含的知识模块,可独立开发、测试、版本控制——Agent 的能力扩展从集中式地编辑系统提示词,变成了分布式的 Skill 生态,像 pip / npm 的包管理。一个值得记的原则:选择 Agent 交互模式时,应与模型厂商的训练方法保持一致——厂商推行的用法是它们专门训练过的模式。

状态栏:上下文是台只有一半的检索引擎

状态栏的理论依据,是注意力机制的一个本质特性:上下文学习更像检索而非推理——模型擅长从已有内容里查找信息,但不擅长主动归纳总结。原文的比喻:上下文窗口是一台只有一半的检索引擎——

  • 检索的那一半很强:注意力能从成千上万个 token 里捞出相关的原始记录,相当于把 RAG 内置进了每次前向传播
  • 但它没有「提炼层」:上下文里的东西从不会被自动数一遍、总结成一条结论。任何「关于这些内容的结论」——一共多少次、有没有超标、进展到哪——模型每次都得从原始记录里现算,代价随上下文堆积量上涨

实际场景:系统提示词要求每个商家最多打 3 次电话,Agent 经常数不清打了几次,又打第 4 次,甚至循环拨打。「已经打了几次」这个知识没有被提炼出来,而是分散在轨迹的原始记录里,模型每次决策都要花思考 token 重新统计——效率低、错误率高。而当每次通话结果直接标明「本次是第 3 次呼叫」,错误率大幅下降。

这背后是两件事:把分散在各处的隐式状态提炼为可直接使用的显式知识(Harness 提前算好聚合信息,模型只需检索);以及强制性的注意力引导——长上下文里注意力有限,中段信息衰减(开头和结尾注意力高),把结构化的状态放在上下文末尾,空间上紧邻即将生成的新 token,自然获得最高权重。

数字很有说服力:提供提前算好的状态栏后,小模型(Qwen3-0.6B)的准确率能接近前沿大模型;思考 token 量、延迟、花费降低约一个数量级——不带状态栏时思考量随上下文变长持续增长,带上之后基本恒定。

状态栏怎么落地

放哪:作为一条 user 角色的消息挂在上下文末尾,内容用 <agent_status> 标签包裹——借助 user 槽位注入框架生成的状态,但特殊标签让模型能理解这不是真实用户在说话。不改 system 消息(那会破坏前缀缓存),追加也不影响任何已缓存内容——还是「动态信息追加末尾」那套。

状态会变,两种更新策略各有代价

  • 每轮替换:每次调用前移除旧状态、追加最新状态。上下文里永远只有一份最新状态;代价是移除会让其后的缓存失效——好在失效范围只覆盖上次注入后的短后缀(通常一轮),整个前缀仍可复用。适合状态较大、更新频繁的场景
  • 持久追加:状态注入后永久留在轨迹里,每轮只在末尾追加新的。缓存完全友好(只增不改);代价是陈旧状态累积占 token,且要求模型只识别最新一条、忽略过时状态。Claude Code 的 <system-reminder> 就是这个方式

状态栏常放三类信息:任务规划(TODO 列表放轨迹末尾,防止忘记原始诉求)、事件的侧信道信息(精确时间、地理位置、时间间隔)、环境状态的观察摘要(系统时间、工作目录、「该工具已被重复调用 N 次」的异常提醒)。实验里的五种技术(时间戳、工具调用计数器、TODO 管理、详细错误信息、系统状态感知)组合使用还有涌现效应——时间戳 + 计数器让 Agent 理解操作频率,TODO + 系统状态让策略随环境调整。

状态栏维护的三个注意点

  1. 尽量用确定性的代码维护状态——实验发现模型几乎无条件相信状态栏(写 3 次它就当真 3 次,不会重算),而 LLM 做统计本来就容易出错。实在要用 LLM,也要逐条抽取、代码汇总,绝不让它批量统计。这也意味着状态栏投毒风险要认真对待
  2. 尽量避免删除原始数据——状态栏是对原始轨迹的有损投影,只提前算了「你预想会被问到」的维度。计数类任务可以只留状态栏;但只要有一个问题落在未计算的维度上,准确率断崖式下降
  3. 归位:书里明确说,Agent 状态栏本身就是上下文压缩(Context Compression)技术之一——用极低的 token 成本提前提炼信息,正是压缩思想的第一种形态。第 2 章最后一块(也是下一步要读的),就是更完整的压缩策略

我的理解与修正

读完状态栏这段,我最初的归因是:归纳弱,本质是 LLM 是生成式模型,靠概率预测 token——概率性的东西当然数不准。细想后这个归因站不住:把采样温度设为 0(greedy decoding),每一步都是确定性的,模型照样数不清 3 次电话。真正的原因在架构:注意力是并行的加权读取,一次矩阵运算就能从上万 token 里捞出相关内容,这是 Transformer 天生擅长的;而归纳统计需要循环加精确累加(数到几了、加一、比较),单次前向传播是固定深度的计算,没有可迭代的循环状态——需要循环的精确计算,架构上就做不稳。

所以模型不是不能归纳,是归纳很贵:思维链就是它现算的方式——实验 2-8 的对照组里,热力图显示思考 token 在草稿纸上一步步数数——成本随上下文增长,且一步数错、后面全错。状态栏的本质,是把「每次现算」替换成「一次检索」:把归纳从概率路径上挪走,交给代码在 Harness 里确定性完成,模型只消费结果。这也解释了书里为什么坚持「状态栏尽量用代码维护」——确定性计算就该交给确定性引擎。

下一步

  • 第 2 章最后一块:线索三,上下文压缩(什么时候压、怎么压、怎么与 KV Cache 共存)
  • 实验:agent-status-bar(五种状态栏技术)

参考来源

大模型的理解力,用户的解空间:Jev 如何填满一个空白象限

你在生产代码里用 LLM 做过分类或路由吗?一次调用 3 到 329 秒,输出 token 比输入贵 5 倍,JSON 解析失败还得重试,问模型”你有多大把握”它永远回答”非常确定”。这篇文章拆解 2026 年 9 月发布的 TypeSafe AI Jev——一个不生成任何文字的模型——以及它背后的 System One Models 框架。目标:读完能在面试里把这条新路线讲清楚,包括原理、生态、质疑和机会。

问题从哪来

“模型聊天早已超人,自动化在哪?”——这是 TypeSafe 发布博客的第一句话,创始人 Diogo Almeida 的执念。他是 RLHF 的共同发明人之一,InstructGPT 与 ChatGPT 背后的训练方法就出自他手(TechCrunch 报道原话:ChatGPT broke Almeida’s heart)。

他离开 OpenAI 时的判断是:问题的根源在于我们优化的是人类语言。人类语言适合对话,不适合软件消费——软件要的是类型安全、可校验、带不确定性的结构化输出。于是两年隐身之后,TypeSafe 给出第三条后训练路线:

  • RLHF(人类偏好)→ 造就了聊天模型
  • RLVR(可验证奖励)→ 造就了推理模型
  • RLCD(校准决策)→ 造就了决策模型

官方的一句话定义值得原样记住:Jev 是一个 frontier-intelligence function call——unstructured state in, typed probabilistic decisions out。非结构化状态进,带类型的概率性决策出。

命名也各有出处:System One 来自卡尼曼《思考,快与慢》的”系统 1”——快、直觉、单步判断;Jev 来自经济学家 Jevons,取 Jevons 悖论——蒸汽机效率提升后煤的消耗反而上升。成本每降一个数量级,用例数量会涨得更多,命名即愿景。

API 长什么样

一个请求由两部分组成:state(被评判的内容,纯文本 / JSON 对象 / 文本数组)和 questions(问题字典)。三类问题原语,对应三种答案形状:

原语 回答什么 返回
Choice N 选一(工单路由到哪个组) choice + 全选项 probabilities + confidence
Score 在有序等级上打分(客户愤怒程度) score(可落在两级之间)+ 分布 + confidence
Noul 是非判断(消息里是否请求退款) noul:一个 0 到 1 的概率,没有单独 confidence

关键工程参数:输入 $42/Btok、输出免费;70–500ms 延迟;限流 250k tokens/s;单请求 64k 上下文;仅文本输入;主要训练语言是英语,CJK 精度目前更低——这是官方文档自己承认的。

三个设计点比参数更值得记:

一问一判断。 官方反复强调”问一个懂行的人一秒钟内能做的判断”。”分析这封邮件并决定最佳行动”不是好问题——那是 System 2 的活,该拆成原子问题再用代码组合权重。

同请求内所有问题并行评估。 加问题几乎不增加延迟,只多花几个 token。官方 cookbook 的数据:13 个问题合并成一次调用,比 13 次单独调用便宜 11.5 倍、快 9.6 倍,答案不变。这直接催生了 Speculative Fan-Out 模式——把”可能用到”的问题全部提前问,代码再决定用哪个答案。

instructions 里用反引号路径引用 state 字段。 比如 “Does ticket.messages[0].text request a refund?”——问题显式指向结构化状态的某一部分,避免模型自己猜上下文。

四个设计原理(面试核心区)

并行采样:快是结构性的,不是调参调出来的

自回归模型一次生成一个 token,每个 token 依赖前一个——一条串行链走到底。Jev 的输出空间在请求时就定义死了(N 个选项、M 个等级),模型对整个输出空间做一次前向,全部概率并行产出。这是 40–200 倍速度差的结构性来源:不是推理框架优化,是把”生成”这件事从任务里删掉了

RLCD:校准本身作为训练目标

校准的定义:给 0.2 概率的答案,长期统计里真的该有 20% 命中;0.8 就该 80%。文档直指 RLHF 的两个副作用:偏好优化会奖励”听起来自信的幻觉”(sycophancy);还会引发 mode dropping——把分布压窄到单一风格上,模型对其他可能的输出概率衰减,偏好越强,概率分布越不可信。RLCD 把目标换成”概率与结果对齐”,模型失去的是自由文本生成,换来的是概率的诚实。

Confidence 是概率分布的统计量,不是另一个模型输出

Choice/Score 的 confidenceprobabilities 直接计算(文档交互示例里对三选项用的是 (N·峰值概率−1)/(N−1) 这种归一化峰值),分布越平坦 confidence 越低。官方明确说”你并未被锁定在我们的定义上”——完整的 probabilities 都给你了,你要更合适的度量可以自己算。这也是它和”问 LLM 要置信度”的本质区别:后者是让模型再生成一段关于自己的文字,前者是分布本身的数学性质。

零类型错误是构造性保证,不是”训练得好”

幻觉是生成器在开放词表上采样的固有属性。Jev 根本没有开放词表——它在你预先定义的选项集合上输出一个分布(softmax over options),输出不可能落在集合之外,就像骰子不可能掷出 7。所以官方敢写”这在数学上不可能被证伪”。注意边界:“不会选错类型”不等于”不会选错选项”——所以才有 confidence,才有置信度门控:高置信自动执行、中置信复核确认、低置信转人工或换路。

三种软件架构的位置

官方把它放在第三种架构里:传统软件是简单原理组成的复杂决策树;LLM agent 是模型接管控制流、每圈都可能脱轨;AI-powered software 是代码持有工作流,模型只出现在需要”可编程常识”的窄缝里。Guard 框架的读者应该对这个定位很熟悉——这正是”模型即工具调用点、循环归属代码”的极端化。

理解力 × 解空间:一张图看懂四种技术

前面四节讲的是 Jev 的零件。这一节讲我自己把零件串起来的那根线——想通它,前面所有”为什么”会同时塌缩成同一个答案。

四个我们熟悉的技术,其实只有两根轴:理解力(能不能吃进没见过的自然语言)和解空间的归属(答案集合是谁定的)。

技术 理解力 解空间归属 输出形态
if-else 无——语言进不去它的世界 程序员写死 分支跳转
垃圾邮件过滤器(传统分类器) 有,但有限 被训练数据焊死——选项跟着权重一起烧进模型 两个固定标签的概率
Jev 大模型级(encoder 的阅读力) 每次请求的用户——选项是 HTTP 请求发出去那瞬间才出现的 用户定义的选项集合上的概率分布
LLM 最强 模型自己放飞——通过逐 token 组合可以拼出任何内容 自由文本序列

用一句话给 Jev 定位:大模型的理解力 + 用户自由决定的解空间。Jev 干的事,是把 state(材料)和每个选项都投影到同一个语义空间里量距离,距离近的选项分数高——“在用户的解空间中做投影”。

这句话一旦立住,前面所有结论自动成立:

  • 为什么快 100 倍? 解空间是 3 个选项,输出就只有 3 个数——没有序列要生成,串行链长度从 312 步变 1 步
  • 为什么输出免费? 3 个数不是 token 流,没有可计费的生成量
  • 为什么零类型错误? 答案物理上被圈死在你的选项里,想错格式都没有那条通道
  • 为什么 confidence 可算? 分布就摊在这 3 个数上,峰值多尖一眼看出,不用”问”模型有没有把握
  • 为什么传统分类器换个选项就胡说八道? 它的解空间被训练时的数据焊死了,新选项投影不进它唯一认得的那几个孔——所以每个新业务都要重训;Jev 的选项跟着请求走,训练学的是”对任何给过来的映射当场算出来”这个通用能力,不是任何具体的映射

四层楼画成一张图,Jev 站的那个角落——强理解力 + 用户解空间——在它之前是个空白象限:if-else 和分类器是旧时代在理解力纵轴上的挣扎,LLM 是这个象限的错过(理解力够了,解空间扔了)。Jev 不是更聪明的模型,是第一个站进这个空象限的模型

quadrantChart title 理解力 × 解空间归属:四种技术的位置 x-axis "解空间:用户所有" --> "解空间:模型放飞" y-axis "理解力:无" --> "理解力:强" "if-else": [0.05, 0.05] "垃圾邮件过滤器": [0.15, 0.4] "Jev": [0.1, 0.95] "LLM": [0.9, 0.95]

快的账本:省的是生成,不是理解

“一次前向”这四个字容易让人误会 Jev 连理解都省了。实际账本(HF 复刻项目 M4 Max 实测)值得摊开看:

串行步数 耗时
自回归 LLM 输出 312 token 的 JSON 312 次前向 1900ms
Jev 风格:编码 state + 28 个字段打分 1 次前向(prefill 52ms + 打分 18ms) 70ms

两边读的是同一份材料,材料长,编码照样重——prefill 那 52ms 谁都躲不掉。省掉的只有”把答案写成文字”那一段。所以 Jev 的延迟结构是:总耗时 ≈ 编码 state 的时间(随材料长度线性涨)+ 打分时间(选项再多也几乎不涨)。它的延迟天花板 = 你的输入长度,而输入长度是你可以控制的——这就是它敢做每帧一次的实时 agent 的原因。

串行到底是谁造成的?写作文不能跳着写,不是纸不够长,是第 51 个字的语义挂在前面 50 个字上——P(t₅₁|t₁…t₅₀) 的定义里就含着前文。串行是”生成”这个动作的定义自带的,不是计算量问题;LLM 慢在”写答案”不在”读题”,Jev 不是读得快,是压根不写。

而 LLaDA 那条扩散式路线和 Jev 的分界,同样落在这两根轴上:LLaDA 是把”生成”并行化——mask 填空,位置之间无因果依赖,整句同时出,但它仍然在造内容;Jev 是把”生成”消除——不造内容,只对既有假设分配信念。一个是 inference 加速,一个是任务改写。即便 Jev 底层真是 masked 扩散预训练(fork 旁证),扩散也只是它的训练遗骸,不是它的运行时——选项打分一次前向即终止,没有”逐步去噪”的对象。

graph LR subgraph LLaDA["LLaDA:把生成并行化"] A1["[MASK][MASK][MASK][MASK]"] -->|"一次并行填空"| A2["今 天 天 气 真 好"] A2 -->|"迭代几轮去噪"| A3["收敛的完整句子"] end subgraph Jev["Jev:把生成消除"] S["材料:我买了双鞋想退"] --> P["投影到语义空间"] O1["选项:退款"] -.->|"量距离"| P O2["选项:换货"] -.->|"量距离"| P O3["选项:咨询"] -.->|"量距离"| P P --> D["概率分布
退款 0.72 / 换货 0.21 / 咨询 0.07"] end

n² 的账本:不串行,但昂贵

理解这层的钥匙是分清”算的顺序”和”等的顺序”。n 个 token 的 attention 矩阵有 n² 个”两两关系”,但token_5 的分数不需要等待 token_9 的结果——scores[5][9] 和 scores[9][5]、scores[1][300] 和 scores[8000][12] 彼此都不依赖。Q@K^T 这一亿个格子被 GPU 切成小块撒到几千个核上同时乘加。”从头到尾”说的是矩阵的形状,不是计算的时间顺序。

真正的串行只有两处,且 Jev 一处都不占便宜:

成本 量级 属性 Jev vs LLM
单次前向计算量 n²(attention 矩阵) 并行——GPU 同一瞬间铺开 相同,两边都付
层间串行 层数(约 32) 串行但短 相同,两边都付
token 间串行 输出长度(可到 312+) 串行且长 LLM 独有,Jev 归零

三种成本画在一条时间线上最直观——Jev 和 LLM 共享前两段,差别全在第三段:

gantt title 一次调用的三种成本(横轴:串行时间) dateFormat X axisFormat %s section LLM(输出 312 token) prefill 编码 n² 并行 : 0, 52 32 层串行 : 0, 52 生成 312 步串行链 : 52, 1900 section Jev(28 个问题) prefill 编码 n² 并行 : 0, 52 32 层串行 : 0, 52 选项打分(一次前向) : 52, 70

所以 n² 的问题从来不是”慢”(串行),而是三个具体瓶颈:

  1. 显存墙——n=100k 时一层 attention 矩阵物化要 40GB,H100 才 80GB。FlashAttention 不是把 n² 计算变少,是不把整个矩阵物化到显存,边算边用,显存从 O(n²) 压回 O(n)
  2. 吞吐墙——工业并发下,每个请求都付自己的 n²,GPU 的 FLOPs 被摊薄,单请求延迟不涨但排队涨
  3. 成本墙——n² 是每 token 前向的乘加量,直接乘电费乘卡价

串行链决定”单个答案多久出来”,n² 决定”这个生意做不做得起”。

这三种成本混在一起谈就会糊涂,拆开看就清楚了:

graph TB N["n² attention 矩阵
(单次前向内部)"] -->|"格子之间互不依赖
GPU 同一瞬间铺开"| P1["属性:并行"] L["层与层之间
(约 32 层)"] -->|"第 1 层输出是第 2 层输入"| S1["属性:串行但短
两边都付,谁也躲不掉"] T["token 与 token 之间
(输出 312 个)"] -->|"P(t51|t1..t50) 定义自带前文"| S2["属性:串行且长
LLM 独有,Jev 归零"] P1 --> Q["串行步数决定单个答案多久出来
n² 决定这门生意做不做得起"] S1 --> Q S2 --> Q

这里还有一层对 Jev 特别要命的账:KV Cache 在它的地盘上近乎失业。LLM 世界的 system prompt 字节级稳定、缓存命中;Jev 世界的 state 每次请求都全新(每张工单、每帧 DOM 快照都不一样),缓存基本必 miss——prefill 的 n² 是它每次调用都实打实要付的过路费,没有任何捷径。所以官方文档把”只发相关上下文”列为头号军规,本质是在同时压延迟天花板和 n² 成本地板:state 越短,这门生意越赚。而 state 里什么是信号什么是噪声(模板、寒暄、系统日志),只有懂业务的人知道——这也是传统后端经验能直接平移进 Jev 时代的地方。

graph LR subgraph LLM世界["LLM 的负载:缓存的天堂"] SP["system prompt
固定且长"] -->|"字节级稳定
KV Cache 命中"| C1["缓存热"] U1["每轮对话增量"] --> C1 end subgraph Jev世界["Jev 的负载:缓存失业"] T1["工单 A 的 state"] --> X["每次全新
KV Cache 必 miss"] T2["DOM 快照 B"] --> X T3["工单 C 的 state"] --> X X --> F["每次实付 prefill n²
过路费"] end F -.->|"唯一出路:压短 state"| R["军规:只发相关上下文
延迟和成本同时压"]

底层结构:官方没说的,社区在做什么

官方对架构守口如瓶。TechCrunch 的表述是”tight-lipped,外部观察者怀疑构建在开源权重 LLM 之上”。可查的旁证:typesafe-ai 组织 fork 了 LLaDA(人大 ML-GSAI 的扩散语言模型官方实现)和 vLLM;HN 评论区有高赞指出 vLLM 的一个 PR 支持”Jev 模式”的 DiffusionGemma,单次决策约 0.2s。扩散式语言模型天然就是并行解码器——这条社区推断(官方从未确认)目前证据链最完整。

三个开源项目让这条路线可以摸到:

jevlike(vinnylarouge,发布 1 天后出现,1k+ star)——独立实现的入门架构:每个选项编码为 query 向量 → 对上下文 token 做 attention 得到该选项专属的上下文向量 → 共享打分头算出分 → softmax 出分布。作者诚实标注:Wikispeedia 下一步点击预测上 26–29% 准确率(对照组 8%),8 选项场景一次前向比小 decoder 快约 100 倍,但未达到与 Jev 同等质量,也不是 Jev 的复刻

Parallel Constrained Decoding(HF Space)——Apple Silicon + MLX + Qwen2.5-1.5B:对多字段 JSON schema 并行评估,M4 Max 上 5.6–7.0 倍加速、100% schema 有效、逐字段校准置信度。证明”并行受约束解码”用现成小模型就能做出来,差距在训练。

jev-ultrafast(browser-use 官方,10.5k star)——最能说明用途上限的例子:浏览器 agent 的动作空间做成”动态索引元素表”(每帧 DOM 快照产出编号控件列表),Jev 选操作和目标元素,小 LLM 只在 TYPE_TEXT 时生成文字。苏黎世→伦敦航班搜索 7.1 秒完成含打字和加载等待;浏览器协议调用从 1092 降到 101 次。模型的输出永远不变成选择器、坐标或可执行代码——执行器只认观察到过的 DOM 节点,这是结构化输出带来的安全性质。

学术谱系上它不是凭空出现的:GLiNER(双向编码器做零样本实体抽取,3.8k star)早已证明”编码器 + 选项打分”可以零样本结构化输出;LLaDA 系列(含 inclusionAI 的 2.0 版)证明扩散式 LM 可以并行生成。HN 上还有人贴出 2025 年 3 月的 arXiv 论文(PPO over 序列嵌入输出转化概率),自认”一年前就做了同构的事”。Jev 的增量不在点子,而在”通用零样本 + 概率校准 + 工程化 API”三件事同时做到——这正好是面试里”这想法早就有人做”质疑的标准答案。

市场验证与质疑清单

来自 TechCrunch 报道的真实案例:Vercel 用 Jev 替换 OpenAI 的命令安全分类器,快 5–18 倍且更准;Bryo AI 对比 Gemini 做邮件分类,Gemini 略准但贵 10–20 倍,其 CTO 最看重的反而是”唯一返回真实概率的模型”。Pi(Earendil)的 Armin Ronacher 给了两条用例——用 Jev 监控 LLM agent 轨迹防越狱(用 agent 监控 agent 太贵)、做模型路由的实时分诊;同时给了一句最锋利的批评:“它把幻觉问题部分外包给了用户”——0.5 概率是硬币,用不用这个答案是调用方的责任。

发布帖在 HN 拿到 1921 赞 504 评论,质疑集中在四处,面试时值得替面试官问出来:

  1. 没有论文、没有权重、没有 live demo——“RLCD 和并行采样没有任何技术支撑,全是营销词汇”。
  2. 对比口径——“70ms vs 329 秒”拿的是推理模型满档输出,拿纯分类小模型比差距没这么大。官方博客自己也承认”这些是我们预期里偏高端的数字”。
  3. Benchmark 全是自建的 workflow evals(参考答案是 GPT-6 Astra 与 Fable 5.1 的平均),官方另发一篇《Lies, Damned Lies, and Benchmarks》自陈立场:公共榜单已被 benchmaxx,他们选择公开 caveat 而不是刷榜。立场可以敬,验证只能靠第三方。
  4. 工程约束——64k 上下文、纯文本、英语主训、invite-only、单一供应商。

机会在哪

把用例分三层看:

替换层:管道里已有的零样本分类、路由、抽取、打标,直接换成 Jev。收益是钱和速度(一到两个数量级),风险是精度——先跑 system-one-adapter-python(官方出的 LLM 后端 drop-in 对比器)做 A/B。

增强层:给现有 LLM 系统当守门员。confidence-gated routing(置信度三段门控)、agent 轨迹监控、越狱检测、给 LLM 输出做校验打分——用决策模型看住生成模型,这是官方叙事里最符合工程直觉的一块。

新交互层:100ms 级 + 输出免费,让”每帧问一次模型”变成可承受的交互设计——jev-ultrafast 的浏览器 agent 是第一个完整演示。同样打开的还有实时 UI 决策、搜索式重排。

对我自己的场景(客服工单审核):工单分类路由(Choice)、申诉结果打分(Score)、退款请求识别(Noul)全部落在原生语区,且置信度门控天然对应”低置信转人工复审”的客服流程——这正是申请 waitlist 时填的用例。

面试速查卡

Q:Jev 和 LLM 的 JSON mode 有什么区别?
采样方式与约束位置都不同。JSON mode 仍是自回归逐 token 生成(语法约束采样,一条链走到底,中途偏一个 token 前功尽弃),概率分布只在词表上、不在你的 schema 上;Jev 是一次前向、直接在你的选项集合上输出分布。约束前者是”事后围栏”,后者是”构造本身”。

Q:底层架构是什么?是 Transformer 吗?
官方未披露,但 Transformer 骨架基本确认(TechCrunch 报道口径 “transformer-based”;社区复刻全部基于现成 Transformer 改造)。社区证据指向”开源权重的 encoder + 选项打分头 + 扩散式预训练 + RLCD”——真正的新东西不在骨架,在出口和训练目标。类比:LLM 的输出头投影到全量词表,Jev 的输出头投影到本次请求的选项集合;同一个主干,头开在哪决定了输出空间的形状。

Q:非自回归是 TypeSafe 发明的吗?
不是,这是一条十年的谱系:2017 NAT(ICLR 2018 最佳论文)为延迟首次提出并行解码 → 2018–2019 Mask-Predict 修补质量 → 2021 D3PM 把扩散搬上离散 token → 2024 SEDD 质量追平自回归 → 2025 LLaDA/Mercury 规模化 → 2026 Jev 产品化。四年一个台阶,每个台阶主语都不同(FAIR → Cornell → 人大/Inception → TypeSafe)。Jev 的原创主张只剩 RLCD 和通用决策 API 这两件事。

Q:n² 复杂度你怎么看?Jev 能躲开吗?
躲不开,但要看清它住在哪个维度:n² 是单次前向内部的并行计算量(GPU 同时铺开算),不增加串行步数;它贵在显存物化、吞吐摊薄、每 token 成本,不在”慢”。Jev 每次请求都是全新 state、KV Cache 必 miss,prefill 的 n² 是每次都要付的过路费——所以它的命门是 state 长度,官方”只发相关上下文”的军规就是在压这个。

Q:理解(编码)这一步 Jev 比 LLM 快吗?
不快,两边读同一份材料的 prefill 成本完全一样。Jev 省的只有”把答案写成文字”那一段(token 间串行链)。所以 Jev 的延迟天花板 = 输入材料长度——材料是调用方可控的,输出长度是模型方不可控的,这就是延迟主导权的转移。

Q:零幻觉怎么做到的?
幻觉是开放词表生成的属性,Jev 没有开放词表。但要立刻补一句:它仍可能选错选项,所以核心配套是校准概率与 confidence——“零类型错误”和”零错误”是两件事。

Q:为什么 RLHF 模型的置信度不可信?
偏好优化奖励讨喜与自信的表述,并造成 mode dropping(分布压窄),模型的文字概率声明与真实命中频率脱钩;RLCD 直接把”概率与结果对齐”当训练目标。

Q:它是 System 1,System 2 的任务怎么办?
拆。每个问题问”一秒钟判断”,多因素判断拆成多个 Score 在代码里加权组合(Composite Scoring 模式),控制流始终归代码。

Q:这想法是不是早就有了?
单体技术上是的——GLiNER 的零样本抽取、LLaDA 的并行扩散生成、2025 年就有 RL 输出概率的工作。增量在”通用零样本 + 校准 + 产品化”三位一体,以及把定价压到输出免费。护城河更可能在 RLCD 训练数据与分布,而非架构。

Q:你会拿它做什么,怎么验证?
替换层跑 adapter A/B 看精度和成本;增强层先做 LLM 输出守门(风险低、收益明确);同时盯 CJK 精度和供应商集中度两个风险。

下一步

  1. waitlist 通过后先在 Playground 用中文工单样例实测 CJK 精度——这是官方承认的短板,也是自己场景的生死线
  2. system-one-adapter-python 对比现有 LLM 分类管道的成本/延迟/准确率
  3. 想吃透架构的,读 jevlike 的 option-attention head 源码(一个周末的量),再看 LLaDA 理解扩散式并行解码

参考来源:发布博客 · 官方文档AI primerPrimitivesConfidenceModels)· TechCrunch 报道 · HN 讨论帖 · Antibenchmaxxing · jev-ultrafast

Agent 精读(七):对人类友好,就是对模型友好

这是《深入理解 AI Agent》精读专题的第七篇,走第 2 章三条线索中的第一条:提示词怎么写、怎么防劫持。读的是李博杰的开源书第二章的提示工程与提示注入部分。
本章思维导图见 专题页 · 章节思维导图

先记住一个检验标准

原文给系统提示词设计了一个实用的检验标准:如果一个聪明的新员工读完你的系统提示词还不知道该怎么做,Agent 也一样不知道。

这一篇的所有技巧,都是这句话的展开——因为模型在训练中学习了人类的语言和思维模式,针对人类降低认知负担的方法,对模型同样有效。

用带实习员工的方式写提示词

书里有个小观察:大写强调(”NEVER do X”)比 “Please avoid doing X” 更能引起模型的注意,过度使用还会稀释效果——Claude Code 的工具定义里就有 “NEVER invoke grep or rg as a Bash command”。

但这类命令式标记我不喜欢。我更认可的姿态是像教导实习员工(甚至小白)一样去提示模型:它是聪明但完全不了解你业务的新人——讲清楚业务背景,给正例也给反例,给标准流程,而不是堆一堆 NEVER 和 MUST 指望它自己悟。这也和全书的比喻一致:系统提示词是员工手册,流程是 SOP,好培训从来不是「你很聪明,自己看着办」。

示例是规则表达不了时的替代品。 当期望的输出难以用规则精确描述——文案风格、报告格式、语气分寸——给两三个高质量示例,胜过等量篇幅的抽象规则。数量不是越多越好:两三个覆盖边界情况的,胜过十个大同小异的(后者还会稀释模型对规则本身的注意力)。正例之外最好配反例,并写清适用范围——这是 Skill 写作里的明确建议。

示例的位置有缓存约束。 示例放在系统提示词里就成了静态前缀的一部分,处于上下文靠前的区域——一旦确定就要字节级稳定。按请求动态检索「最相关」的示例,等于每次改写前缀,缓存持续失效。生产系统的做法是为每类任务准备固定示例集,而不是逐请求挑选。

结构化:XML + Markdown 双层

模型对结构化输入显著敏感(训练数据里就有大量结构化内容)。书里的方案是两种格式配合:

  • XML 负责精确语义<working_directory> 这个标签名本身就告诉模型「这是工作目录信息」,纯文本「当前目录:/Users/project/src」则需要模型额外思考冒号前后的关系
  • Markdown 负责层次组织### 标题让人一眼看出结构,人机共读

这个设计有消融数据背书:保留所有规则的内容、只打乱组织结构,任务成功率下降超过 30%——「先验证身份再处理退款」被拆散后,Agent 有时跳过身份验证直接退款;而去掉工具的描述性文本,工具调用错误率增加 45%

所以这一篇的标题就是原文实验的结论:对人类友好的信息组织方式,对模型同样友好。

流程驱动优于规则堆砌

给新员工一份上百条零散规则的手册,没有流程图、没有优先级——多条规则同时适用时怎么选?规则没覆盖时怎么办?最聪明的人也会困惑,模型也一样。

流程驱动的提示词是标准操作流程(SOP):模型在任何时刻都清楚自己处于哪个阶段、当前步骤的目标是什么、完成后进哪一步;遇到异常时按当前阶段处理,而不是遍历所有规则找匹配项。

配套的是业务规则要细化到可执行的程度。书里打电话砍价的 Agent 例子:模糊的「根据任务情况选择合适的计费类型」会让行为极不稳定(退衣服算省钱吗?取消订阅算吗?),必须写死成 NEVER use percentage_based_one_time for refunds。设计哲学是:模型的优势在遵循复杂指令,不该在业务规则上有自由裁量权——好培训不是「你很聪明,自己看着办」,而是 SOP + 明确框架。

工具定义也开始渐进式披露

上一篇刚说过第一章的设计模式「渐进式披露」,这一节看到它落到了 API 层:静态前缀里只保留工具的名称和简述,模型搜索到要调用时,再把完整的 schema 注入到上下文末尾。OpenAI 的 tool_search、Anthropic 的 Tool Search、Codex CLI(默认开启)都是这个机制。

为什么追加到末尾不破坏缓存?这是 KV Cache 前缀性质的直接推论:因果注意力决定了每个 token 的键值对只依赖它之前的 token——在末尾追加不改任何已缓存内容。而且 schema 只在被发现的那一轮注入一次,之后固定在轨迹原位,不是每轮重新搬运。

有一条硬约束:模型必须在训练中见过「工具定义出现在对话中间」这种模式——所以目前只有较新的模型(GPT-5.4+、Claude 4.5+ 系列)支持,自托管开源模型需要专门训练。

提示注入:上下文层的三道防御

威胁的本质:攻击者通过 Agent 处理的外部内容(网页、邮件、文档)把伪装成系统指令的文本混入上下文,劫持 Agent 行为。Agent 有工具调用能力,比普通聊天机器人危险得多——被注入的指令可能导致文件删除、发送邮件、泄露隐私。注入入口包括网页不可见元素、PDF 元数据、甚至图片的 EXIF 信息。

上下文层的防御核心是帮模型分清「指令」与「数据」:

  1. 来源标记:外部内容注入前用明确的标记包裹并标注来源(<external_content source="webpage">...</external_content>),提示模型其中出现的「指令」不应执行
  2. 结构化角色:严格利用 Chat Template 的角色体系(system/user/assistant/tool)传递信息,让模型依据训练时建立的优先级区分可信指令与外部数据——把工具结果混入 user 消息,等于亲手抹掉模型辨别来源的依据
  3. 输入清洗:过滤外部内容中的可疑模式(如「忽略之前的指令」)——容易被措辞变体绕过,只能作为辅助手段

原文泼了两盆冷水,都很清醒:

  • 上下文层防御只是第一道防线——只能降低攻击成功率,无法万无一失。执行层的权限控制、沙盒隔离在第四、五章展开
  • Skill 本身就是新的注入面——Skill 的本质是「把外部内容当作指令加载」的制度化形式,第三方 Skill 藏的恶意指令比网页隐藏文本更直接。安装来源不明的 Skill 之前必须审查内容,如同审查将要执行的代码

下一步

  • 线索二:Agent 状态栏(尾部注入运行时元信息);线索三:上下文压缩
  • prompt-engineering 实验(Tau-Bench 消融)找时间跑

参考来源

Agent 精读(六):KV Cache 的账,从 n² 到线性

这是《深入理解 AI Agent》精读专题的第六篇,继续第 2 章。读的是李博杰的开源书第二章的 Chat Template、思考链保留策略与 KV Cache 深水区——外加一段书外的延伸:vLLM 怎么管显存。
本章思维导图见 专题页 · 章节思维导图

Chat Template:把 JSON 翻译成 token

上一篇说「遵守 API 规范」,这一篇补上原理。API 层面的结构化 JSON 消息,模型并不能直接吃——中间有一层 Chat Template(聊天模板),把它格式化成模型可以接受的 token 流:用特殊标记(如 <|im_start|>system)划分每条消息的边界和角色。原文的比喻是信封格式:API 消息是信的内容,Chat Template 规定怎么在信封上写寄件人、收件人;不同模型家族用不同的信封(Qwen、Llama、Gemma 各不相同),API 服务端(vLLM、Ollama 等)自动完成转换。

理解了这层,上一篇的第三条铁律就有了着落:自行拼接消息之所以危险,是因为它绕过了信封——把工具结果当 user 消息发,Chat Template 就会误判「用户换了话题」,顺手清空思考草稿。

思考链的保留:R1 剥离,V4 反转

多轮对话里怎么处理历史的思维链?DeepSeek 的策略演进是个好案例:

  • R1 时代:剥离全部历史思考。多轮对话只回传 content,推理过程(reasoning_content)忽略——因为 R1 训练时历史 CoT 从不出现在输入里,塞回去属于分布外输入,反而可能干扰输出。代价是:模型每轮都要从零重新思考,容易重复犯错、丢失长程计划,Agent 场景下错误概率更高。
  • V4 时代:彻底反转。只要请求携带 tools 参数,两个 user 消息之间的每条 assistant 消息都必须原样回传 reasoning_content,否则 API 直接返回 400 错误。Agent 天然携带 tools,这条强制规则躲不开——Kimi K2、GLM-5 也采用同样的协议。

方向从「省 token」转向「保状态」:中间思考承载着「为什么调这个工具、排除了哪些假设」——草稿纸收走,推理就从零再来。

KV Cache 的账:n² 与线性

不使用缓存时,每生成一个新 token,都要把整个前缀从头前向计算一遍:前缀长到 N 个 token 时要算 N 组 K、V,累计计算量与 N² 成正比。几十轮工具调用的 Agent 任务,代价比想像中大得多。

KV Cache 的做法是:每个 token 的 K、V 只在第一次进入上下文时计算一次,之后留在缓存里。新 token 只需遍历前缀的缓存 K、V 算注意力——计算量随上下文长度线性增长。省掉的是历史 token 的 K/V 重算;但注意它不是免费午餐:每个新 token 的注意力仍要遍历全部缓存,长上下文解码依然线性变慢,KV Cache 的显存与带宽正是推理瓶颈。

缓存的未来:可编辑、可组合(研究前沿)

书里有一节标着「深水区选读」,讲了一个反直觉的发现:模型在 prefill 阶段其实在「做笔记」——读到「用户所在城市:北京」时,不是原封不动缓存这个字段,而是把「这意味着什么」的结论写进了下游每层的 KV 状态。测量发现,字段自己的那几个 token 的 KV,对最终决策的贡献往往不到 1%。

这打开了两种原本不可能的操作:

  • 编辑:改掉一个字段后,只要有显式思考链,改动能顺着已缓存的思考传播下去——用约 1% 的算力得到与整段重算一致的结果(前提是有 CoT;没有思考路径,孤立改字段会被忽略)。
  • 组合:把一段预计算的「技能」缓存,通过旋转位置编码(RoPE)重定位后直接拼接进另一段上下文——从 O(L²) 的重算降到 O(L) 的拼接。

论文在 vLLM 上实现后:首 token 延迟(p90)最多降低数十倍到数百倍,前缀缓存命中率约 98.5%,输出与逐字重算在决策上完全一致。对 Agent 的意义:换一批工具、更新一个记忆字段、注入一条新状态——也许不必每轮都推倒重来,「上下文可变、但缓存收益还在」。这仍属研究阶段,今天生产系统里,上一篇那三条铁律依然是默认原则。

延伸阅读:vLLM 怎么管显存(书外)

这一节是书外延伸,来自 vLLM 的论文与博客(参考见文末)。缓存省计算,vLLM 解决的是另一个问题——KV Cache 放哪

vLLM(virtual LLM,名字就来自它借用的操作系统虚拟内存思想)的核心技术是 PagedAttention:像操作系统用分页管理内存一样,把 KV Cache 切成固定大小的 block 按需分配。传统做法要为每个请求预留一整段连续显存,碎片和预留浪费让实际利用率只有 20%–40%;分页之后浪费降到 4% 以下,同等显存能装下更多并发序列,吞吐提升 2–4 倍。

第二个优势是连续批处理(continuous batching):不等整批请求全部完成才释放——每一步解码后,完成的请求立即退出、新请求立即插入,GPU 始终满载。配合针对 RoPE 的 kernel 融合(把分页导致的非连续显存读取与旋转位置编码的正余弦计算融合在一个 CUDA kernel 里,减少 HBM 与片上 SRAM 之间的搬运),把位置编码这一步从 I/O 瓶颈变成顺手的计算。

Agent 的上下文动辄几十轮、每轮都在增长——vLLM 这类推理引擎的显存管理,就是 KV Cache 的账最终落地的地方。

上下文组织的三个线索

缓存讲完,第 2 章剩下的问题是:往上下文里放什么、怎么组织。书里给了三条相对独立的线索,后面几节(也是我接下来要读的)就沿这三条展开:

  1. 提示工程 + 提示注入 + 动态提示词:系统提示词怎么写、怎么防外部内容劫持上下文;提示词越写越长后,用 Agent Skills 渐进式披露按需加载——这是第一章设计模式「渐进式披露」的落地。
  2. Agent 状态栏:在上下文末尾持续注入动态元信息(任务进度、工具调用计数),让模型随时「瞥一眼」就感知运行状态——对应「只增不改」,追加在尾部不破坏缓存。
  3. 上下文压缩:上下文膨胀后怎么做减法——什么时候压缩、怎么压缩、压缩如何与 KV Cache 共存。

下一步

  • 沿三条线索继续:提示工程与注入攻防 → Agent Skills → 状态栏 → 压缩
  • kv-cachecontext-compression 实验找时间跑

参考来源

Agent 精读(五):前面不能动,后面尽管加

这是《深入理解 AI Agent》精读专题的第五篇,正式进入第 2 章正篇。读的是李博杰的开源书第二章的 API 消息结构与 KV Cache——上下文工程的地基。
本章思维导图见 专题页 · 章节思维导图

上下文在 API 里长什么样

上一阶段说过:上下文由五个部分组成,包括静态前缀和动态轨迹。到了 API 层面,它就是 messages 列表里的一条条消息。每条消息都带角色标记,一共四种角色:

  • system(系统):开发者写的规则与说明
  • user(用户):用户输入
  • assistant(模型):模型生成的回复,可能携带 tool_calls
  • tool(工具):Agent 框架执行工具后写回的结果,靠 tool_call_id 与调用一一对应

三个容易忽略的细节:

  1. 每次调用都是无状态的——模型不会「记住」上一次的对话,Agent 框架必须每次把完整历史送回去。所谓多轮对话,其实是同一个列表被反复发送。
  2. 模型上一轮的 assistant 消息要原样放回消息列表——让模型「看到」自己之前做了什么决策。
  3. Agent 框架的核心工作就是管理这个 messages 列表:在合适的时机往里追加,然后整个送给模型。本章后续所有的上下文工程技术,本质上都是在优化这个列表。

ReAct 的终止,就一行判断

第 1 章讲了 ReAct 循环怎么转,第 2 章补上了它在 API 层面的实现和终止判断:模型直接回复用户、不携带工具调用指令,循环就结束;只要返回里还有 tool_calls,就执行工具、追加结果、再来一轮。书里核心循环的退出判断就一行:

1
2
if not assistant_message.tool_calls:
break

异常退路另有几条:调用最终输出工具、遇到错误、达到最大轮数——但正常收工的信号就是这一条。

KV Cache:静态前缀放最前面的原因

上下文设计里,静态前缀放在最前面,模型会使用 KV cache——Transformer 架构里缓存下来的 Key 和 Value(注意力机制的两类向量):已经算过的 token 键值对留在缓存里,新 token 只算增量,不必每轮重跑整个前缀。

书里有个故事把代价讲得非常具体:某客服 Agent 每天处理 10 万次对话,工程师为了让模型「知道」当前时间,在系统提示词里加了一行 Current time: {{now}}。第二天监控告警:首 token 延迟从 0.5 秒涨到 3–5 秒,月度推理账单几乎翻倍——时间戳每次都不同,从它所在位置起,缓存全部失效。

精确一点,缓存有两个层级,原理相同(前缀不变性)、层级不同:

  • KV Cache:模型内部,缓存单次推理中已计算的键值对
  • Prompt Cache:推理引擎/服务商,在多次 API 请求之间复用相同前缀的计算结果,缓存读取约为首次计算的十分之一价格

静态前缀放最前面且保持稳定,跨请求命中的主要是 Prompt Cache——但原理都一样:前面不能动,后面尽管加

messages 列表:前面不能动,后面尽管加

这个区分还有一个落点:fork 子 Agent 时的字节级对齐。主 Agent 派生子 Agent 或发起旁路查询时,如果子 Agent 继承父 Agent 的上下文,那么提示词、工具定义、模型配置、消息前缀和思考配置都要与父 Agent 逐字节匹配——这样才能命中 API 服务商的 Prompt Cache,省下费用和延迟。原文也注明了边界:如果子 Agent 本来就用不同的上下文或提示词,自然不要求字节级对齐。

三条铁律

书里把这个技术密度最高的章节压缩成三条核心结论,我把它们当上下文设计的铁律:

  1. 静态前缀一旦确定就不要随意修改——哪怕多一个空格,首个不同 token 之后的缓存全部失效;改动越靠前,代价越大。
  2. 只增不改,动态信息永远追加到末尾——时间戳、用户状态这些变化的内容,作为新消息追加,而不是去改系统提示词。第一章设计模式里的「只增不改」在这里再次出现:Append-only 换来缓存命中率,还顺手可重放、可审计。
  3. 遵守 API 规范,不要自行拼接消息——结构化消息会被 Chat Template 翻译成模型训练时见过的固定 token 序列;自行拼成 "USER: ... ASSISTANT: ..." 的根本问题不在缓存(缓存只认字节序列,拼得稳定照样命中),而在偏离了训练格式:模型要多花注意力去推断角色边界,把工具结果拼成 user 消息还会破坏思维链保留机制——相当于模型算到一半,草稿纸被收走了,多步推理只能从零再来。

下一步

  • 第 2 章继续:提示注入攻防、Agent Skills、上下文压缩
  • kv-cachecontext-compression 两个实验,找时间一起跑

参考来源

Agent 精读(四):Harness 工程解决从 Demo 到生产的设计

这是《深入理解 AI Agent》精读专题的第四篇。读的是李博杰的开源书第一章的 Harness 工程与编排模式——第 1 章的最后一部分,读完这章就齐了。
本章思维导图见 专题页 · 章节思维导图

Demo 与生产之间,隔着什么

工业生产相对于 demo,对代码质量是有要求的:产品需要可靠性。Harness 就是这个可靠性的保障——在上下文管理和工具接口之外,再加上三个模块:

  • 约束(Constrain):限定 Agent 能做什么。故障安全默认——所有能力默认关闭、必须显式开放,像手机 App 的权限管理
  • 验证(Verify):自动判断操作结果的对错。只看结构化数据(工具返回的 JSON 字段),不看模型自由生成的文本——后者可能已经被提示注入操纵
  • 纠正(Correct):发现问题自动修正或回退。先静默重试,不行就回滚,连续失败就熔断,再不行交还人工

Harness 五要素循环

原文给了一个参照:Claude Code 的 Harness 里,绝大部分代码都是约束、验证与纠正——工具本身(文件读写、命令执行、搜索)只占一小部分。行业正在从「能做事」转向「可靠地做事」,这就是 Harness 工程成为核心竞争力的原因。

五波演进:每层都包着前一层

AI 应用的工程重心,这些年挪了五次家:

  1. 提示工程:优化输入给模型的自然语言指令
  2. 上下文工程:系统性管理模型能看到的一切——系统提示词、工具定义、用户输入、历史记录、工具返回
  3. Harness 工程:Agent 如何组织模型运行并与环境交互——上一节那五件事
  4. Loop 工程:跨轮次的持续自主运转——谁来发现下一件该做的事、何时验证、何时才算真正完成
  5. Graph 工程:把 Agent 循环、确定性程序、人工审批组织成显式的执行图,节点承担能力,边规定路由与依赖

关键在它们的关系:这五层不是替代关系,是层层包含——提示工程是上下文工程的子集,上下文工程是 Harness 的子集,Harness 是 Loop 的子集,Loop 又是 Graph 的子集。单个 Agent 循环,正是执行图中的一个节点。

五波工程演进,层层包含

模型的差异在缩小

这条演进线的尽头,是那个我越读越信的判断:模型的差异在缩小,未来是模型的工程环境决定表现能力的差异。

这不只是推演,书里给了实测:LangChain 在 Terminal Bench 2.0 上从 52.8% 提升到 66.5%(排行榜 30 名开外跃进前 5),改变的不是模型,是 Harness——让 Agent 自动检查执行结果、检测是否陷入重复循环、优化思考策略。

写死,还是让它自己走

工程视角落到怎么编排上,是两条路:

工作流——执行路径代码写死(订机票:核实身份 → 搜索航班 → 付款 → 确认预订)。流程控制严格,攻击面被限制在单个节点内;代价是遇到预设外的例外,无法变通。

自主 Agent——执行路径由环境反馈实时决定,就是第三篇说的 ReAct 循环。灵活,能应对例外;代价是延迟与成本更高,而且必须设退出条件(任务完成 / 最大轮数 / 不可恢复错误),否则死循环。

工作流 vs 自主 Agent

选择顺序很朴素:先单次调用,再工作流,最后才自主 Agent。实践里常常混合——关键合规流程用工作流保可靠,灵活决策用自主补变通;甚至可以让 Agent 先把工作流写出来,再由工作流执行。

贯穿全书的五个设计模式

第 1 章的末尾一次性命名了五个设计模式,说后面的章节会反复用到。我把它们记在这里,当全书的暗线看:

  1. 提议-审核:产出与评判由两个上下文不同的角色分别承担——审核方看到的是产物本身(渲染结果、测试输出、结构化参数),不是产出方的推理过程。它成立的前提是自审不可靠:同一个上下文里的模型,难以发现自己的盲区,也难以判断自己是否已被注入。
  2. 渐进式披露:不把全部信息一次性放进上下文,先给一份可检索的目录,再按需要去元数据里查找对应的完整指引。第二章的 Agent Skills 是最典型的形态:元数据常驻,正文按需加载。
  3. 只新增不修改:状态只追加、不回头改。最直接的好处是缓存命中率(第二章 KV Cache 的前缀稳定性就是它的性能形态),同时换来可重放、可审计。
  4. 最小 diff + 可回滚:每次修改尽量小、带来源、可单独回滚——出了问题能定位到具体哪一次改动。Matt Pocock 讲代码设计时也有同一个观点:需求要切得足够小,逐个去做,最好有 checkpoint,单一环节出错只改一个节点。
  5. 边界集 + 保留集:任何一次修改都要同时在「应当改变的样本」和「不应当影响的样本」上验证——只测前者会把过拟合当进步,只测后者会把无效修改当安全。

第 1 章读完了

三篇笔记正好合成一层意思:能力边界由 Harness 决定(第一篇),模型即 Agent 只是搬家(第三篇),可靠性靠五要素闭环、工程重心五波上移、五个设计模式贯穿全书(这篇)。

一句话收束第 1 章:模型负责聪明,Harness 负责可靠——聪明在快速商品化,可靠是工程活,也是竞争力。

下一步

  • 开读第 2 章正篇:KV Cache、提示注入攻防、Agent Skills、上下文压缩——第二篇挂的 context-compression 实验一起跑
  • 这章的结论(能力边界、五波演进)会在第 7–9 章回头被用到,到时回看

参考来源