〇、一行观察,一张公式#
先说个无法引用来源的观察:最近一个月,Command Code 在我这边的 Agent 使用时间大约占 15%。留下我的不是它换模型方便,是它在后台默默做的一件事——taste。
它是闭源的。GitHub 上那个 CommandCodeAI/command-code 仓库只有 .github、mods 和一份 readme,没有实现代码;文档里反复出现的 taste-1 也没有开源权重。所以能拆的只有两样东西:文档把管线描述得多细,以及官网那张公式图。
那张图值得单独看。图里写的是:
这不是什么神秘的新目标函数。它是带 KL 约束的策略优化——RLHF、PPO、GRPO 那一套的地基,外加一个预训练似然项防遗忘。真正有意思的问题不是”它用了什么公式”,而是:为什么一个判偏好的模型,可以用这套公式做得又便宜又稳,而让大模型自己写笔记就做不到?
一、管线:判决被夹在两个 LLM 中间#
文档给的管线是四步,中间那步是唯一不可替换的:
- 输入 LLM(可选):读你的 prompt、编辑、纠错 diff,转成结构化信号——“这次改动把 X 变成了 Y,因为……”
- taste-1:判断这条信号是不是真偏好、属于哪个类别(
cli、typescript、architecture……)、置信度多少。不生成长文本。 - 输出 LLM(可选):把判决写成可读的 markdown。
- CLI:存进
.commandcode/taste/**/taste.md,下一轮读回来。
模型可以按行配置:第 1、3 步用你选的任何模型,第 2 步固定。存储是纯文本、可 lint、可像 git 一样 push/pull——有三种包:项目级 .commandcode/taste/、用户级 ~/.commandcode/taste/、远端 commandcode.ai/<user>/taste。
一句话概括它的结构:LLM 负责把世界翻译成符号,判决模型负责在符号上做决定,LLM 再把决定翻译回文本。
管线本身没有新鲜事;新鲜的是中间那一步的代价结构和置信度语义。
二、公式三项,分别防什么#
把公式拆成三块看:
第一项:,在策略自己采样的动作上最大化奖励。注意 是从 里采的,不是从数据集里拿的——这是 on-policy,和 PPO 一样。
第二项:,对 SFT 参考模型的 KL 惩罚。 是刹车: 大,策略贴着参考模型走; 小,奖励说话。它防的是奖励黑客——奖励模型有洞,策略会往里钻。
第三项:,在预训练分布上的似然。它防的是能力漂移:模型改着改着,把原来的语言能力改没了。这是 RLHF 里常被忽略、但在小模型上最要命的一项。
三项合起来,就是一个”贴着旧模型改进、别跑偏、别忘本”的标准配方。所谓 neuro-symbolic,落在 上——奖励不是黑箱打分,而是一个带符号结构的判别器。
三、闭式解:为什么判决比生成便宜#
把第二项写成约束形式,这个问题有解析解。最大化
对 求变分,得到
这个式子的含义很直白:最优策略就是把参考策略按奖励指数重加权。它和 best-of-n、拒绝采样是同一件事的连续版本——采样 个、挑奖励最高的, 时收敛到这条曲线。
关键在分母 。如果 是自由文本, 要遍历整个词表上的所有序列,不可算,只能靠采样估计——这就是 LLM 推理按 token 计费、按 token 变慢的原因。
但如果动作空间是有限类别集,比如”这条信号属于 6 个类别里的哪一个、极性是 prefer 还是 avoid”,那么 很小, 可以直接精确枚举。没有采样方差,没有逐 token 解码,每来一条信号做一次固定量的计算。 文档说的”便宜约 100 倍、快约 8 倍”(厂商口径,未见独立复现),数学上就来自这里:不是工程优化省出来的,是动作空间小到可以算精确。
这也是它敢说”校准”的原因。有限空间上的分类器,置信度可以用验证集直接校准:说 0.8 的那批,实际正确率就该是 80%。自由文本生成没有这个性质。
顺带一个值得点破的细节:公式里写的是 。所以”不是 LLM”的准确含义是不生成文本、不可替换,不是”不是 Transformer”。它大概率仍是语言模型形状的网络,只是输出空间被符号层限死了。
四、和”模型自己写笔记”比,数学差在哪#
传统的 Agent 记忆是这样的:模型调用一个 memory_write 工具,把”用户喜欢 X”写进文件;下一轮再读回来。看起来很像,但四个地方在数学上站不住:
| 维度 | 模型自己写笔记 | taste 这类判决模型 |
|---|---|---|
| 输出 | 从 采样 | 从有限类别集上取 + 校准概率 |
| 证据不足时 | 补一个”开发者通常会喜欢”的默认值 | 返回低置信度或”不学习” |
| 置信度 | 模型自报的数字,没有训练信号约束 | 有标签可校准;错得多的那批置信度自动降 |
| 更新 | 重写整段文本,新条目静默覆盖旧条目 | 似然累积;冲突被标记,不被覆盖 |
| 代价 | 每轮重读全文, | 每条信号固定开销, |
第三行是最要命的。RLHF 训出来的模型系统性过度自信——人类标注者奖励”听起来确定”的回答,于是模型学会了自信的语调,而不是自信的准确率。把这种数字写进偏好库,等于把噪声当先验。
第四行是结构问题。文本记忆的更新是”覆盖”,而覆盖没有单调性:新写的一条可以抹掉十条旧证据。判决模型可以做成贝叶斯式的累积——这也是我们自己那套实现的做法:
证据按类型给权重(明确说过 1.0、被采纳 0.8、未被回滚 0.8、工具结果 0.5、推断 0.3、矛盾 −1.0、回滚 −1.0),判决模型的概率只作为伪计数进入,。这样设计的好处是:模型再自信也顶不穿证据不足——空证据下它说”certainly”,后验也只能到 0.75 附近。反过来,聊天模型自己报的置信度在我们的实现里被直接丢弃,理由写在代码注释里:一个未校准的数字进贝叶斯后验,比没有数字更糟。
五、它和外部判决模型是一家#
把 taste-1 和 TypeSafe 的 Jev 摆在一起看,会发现它们是同一类东西的两个实例。Jev 自称 System One Model:给它一个状态和一组类型化问题,返回选项、每个选项的概率、以及置信度,从不生成字符串。文档说它在决策基准上比前沿 LLM 便宜、快两个数量级(同样是厂商口径)。
这一类可以列一长串:
- 偏好/品味判决:taste-1、Jev
- 安全守卫:各类 guard 模型
- 奖励建模:RLHF 里的 RM
- 检索重排:reranker
- 路由:把请求分给哪个模型的 router
它们的共同判据只有一条:输出空间是不是类型化、有限。是,它就属于判决模型——便宜、可校准、可组合、可缓存;不是(自由文本),它就还是 LLM,贵、会飘、置信度不可信。
所以”taste 和判决模型差不多”这个直觉是对的。差别在于 taste-1 额外背了一套偏好空间的结构:类别闭合、冲突检测、按使用而非按写入计时的衰减。而 Command Code 和我们的区别,主要不在数学,在开放程度——它整套闭源,taste-1 不可替换;我们那套用可配置的 judge 角色接外部决策模型(typesafe/jev-latest 这类后端),并且和它的 taste.md 格式互通:同一个文件,两个工具都能读。
六、四个风险,别当软文看#
自举回路。 偏好信号里的”采纳/回滚”大多来自 agent 自己提出的改动。它提议、你接受、它学习——学到的是自己的口味,不是你的。这与模型坍缩是同一族问题,只是发生在偏好层。
反馈噪声。 你懒得回滚不等于同意。校准依赖标签质量,标签一脏,置信度会系统性偏高,而系统看起来更”确定”了。
可移植的另一面。 能 push、能分享、能组合,意味着偏好包可以被投毒、被团队规训、被当成入职配置分发。一个能改你代码风格的压缩包,和一段能改你 shell 的脚本,风险等级是同一档。
厂商数字。 100 倍便宜、8 倍快、两个数量级、15 次重复实验——全部来自厂商自己的文档,没有第三方复现。写进文章时只能当”他们声称”,不能当”实测”。
七、结论#
品味不是记忆。记忆是写下来的文本,品味是学出来的分布;文本没有似然,分布有。
这也解释了为什么这类功能最后都长成”判决模型夹在两个 LLM 中间”的形状:语言的部分交给会说话的东西,决定的部分交给会校准的东西。前者贵在 token,后者贵在标注——而标注,恰好是你每天敲键盘时免费产生的。
至于 Command Code 值不值得用:如果你已经有一套自己的规则文件,taste 的增量不大;如果你从来没写过规则,它替你写了,而且写得比你勤。这是它真正卖的东西——不是更聪明的模型,是一个不用你维护的先验。