目录

浏览器智能体将一本书加入购物车。页面上已经显示了指定商品,任务也已完成。但智能体仍在继续点击。于是,同一本书又被加入了购物车。

下一步操作本身是有效的。错误在于决定继续操作。

Jev 的一种设计模式通过设置独立检查来解决这个问题。不向检查方展示主判断的问题或回答,只询问页面上是否已经显示了用户要求的结果。然后,由代码决定是否停止执行。

这个例子很好地体现了 Jev 的 16 种设计模式 ↗的价值。这些模式面向的是返回概率而非文字的模型。它们说明了如何定义问题、如何解读不确定的回答,以及如何让应用程序的行为受代码控制。

在将传统 LLM 用作分类器、验证器或操作选择器时,这些模式也很有用。核心问题是一样的:如何将模型不确定的评估转化为可靠的行为?

概率是判断的输入#

Jev 是 TypeSafe AI 的 System One 模型。根据文档,它接收状态和带类型的问题,并在约 300 毫秒内返回概率。它不会生成应用程序所需的文字。

问题类型包括:

  • noul: 回答“是”的概率。接近 0.5 的值并不意味着某种性质以中等程度存在,而是意味着模型无法区分选项。
  • choice: 从给定候选项中选择。它提供了 other 选项,用于所有候选项都不适用的情况。
  • score: 根据具体情境定义若干等级,再计算以概率加权的平均值。

作出判断的仍然是应用程序。它决定询问什么、什么样的回答可以允许执行操作,以及回答缺失时该怎么办。

下文中的数值均来自 Jev 各模式的说明页面。它们是各自项目中的示例,并不保证在其他应用程序中也有同样的表现。

1. 决定让模型判断什么#

前四种模式划定了模型评估与应用程序逻辑之间的边界。其中许多模式在概率返回之前就能预防问题。

1. Viewfinder(取景器):将状态缩减到必要的最小范围#

会发生什么: 发送整段对话会让判断变得困难。在文档的示例中,到第 200 次编辑时,输入已达到 40,000 个 token,准确率也从第一次编辑时的 0.84 降到了 0.52。

如何预防: 先定义判断所针对的单位,再附上该判断所需的上下文。检查编辑内容时,应发送相关改动及必要的周边文本,而不是完整的编辑历史。

2. Menu(菜单):列出候选项#

会发生什么: 让模型生成 CSS 选择器时,它可能返回不存在的 ID、匹配多个元素的选择器或无效语法。应用程序只有收到模型提出的目标后,才能验证它。

如何预防: 用代码列出有效目标,并为其分配标识符。让模型选择标识符,同时加入“均不适用”选项,使模型在候选项不足时能够拒绝选择。

3. Question bank(问题库):将规则转化为问题#

会发生什么: 反复要求大型模型解读整套策略,既耗时,判断也不一致。文档中的示例每次编辑约需 2 秒,成本为 1 美分。

如何预防: 将每条规则转化为针对可观察事实的具体问题。不要问“这好吗?”,而要问“这里是否包含 X?”。数量统计和日期比较交给代码处理。

4. Ghostwriter(代笔者):分离判断与生成#

会发生什么: 只返回概率的模型无法撰写要填入表单的文字。如果将整个工作流迁移到能够生成文字的大型模型上,在这个示例中,单步耗时就会从约 300 毫秒增加到 2 秒。

如何预防: 用 Jev 选择操作和目标。只有选中的操作需要文字时,才调用文本生成模型,并在检查其输出后再使用。

这些模式揭示了一个有用的区分:选择已有选项与创造新内容是两项不同的工作。为两者分别设置独立接口,可以让它们都更容易检查。

2. 理顺问题与检查的结构#

问题即使很短,也可能设计不佳。接下来的四种模式用于解决问题被平均后掩盖、不必要的串行调用,以及停止条件不足等情况。

5. Questionnaire(问卷):一次提交多个独立问题#

会发生什么: “这看起来像机器写的文章吗?”这类宽泛的问题,可能会让一个明显缺陷被其他没有问题的部分掩盖。在一个示例中,模型对包含可识别问题的段落返回了 0.52。

如何预防: 在一次请求中,针对具体缺陷提出多个独立问题。将检查拆成五类缺陷后,在 80 个示例中,检出数量从 58 个增加到了 63 个,而且在该次评估中,误报并未增加。

6. Prefetch(预取):提前询问分支问题#

会发生什么: 先询问操作,再调用一次模型询问操作目标,会产生本可避免的等待时间。两次各约 300 毫秒的调用,会让每一步等待模型的时间达到约 600 毫秒。

如何预防: 将可能分支中的问题一起发送。选定操作后,只读取对应分支的回答。不能将未使用的回答作为允许额外操作的依据。

7. Blind review(盲审):独立核验#

会发生什么: 智能体可能在任务完成后仍继续操作。再次点击,将同一本书作为第二本加入购物车,就是这样的例子。

如何预防: 在请求中加入独立的验证问题。提供页面上可观察到的事实,同时隐藏主判断的问题与回答,让验证方独立检查任务是否完成。

8. Funnel(漏斗):逐级分流#

会发生什么: 将所有情况都交给大型模型,会在简单判断上浪费资源。文档的示例中,检查 200 个文件花了 5 分钟和几美元,但其中 190 个文件没有问题。

如何预防: 按代码规则、Jev、大型模型或人工的顺序处理。某个阶段能够作出判断,就在该阶段停止,将成本较高的检查限定在仍有不确定性的情况。

实践中的启示是:将模型处理用在可能改变结果的地方。能够确定性判定的事实,用确定性检查处理。困难的判断则可以逐级转交给成本更高的检查。

3. 为概率赋予明确的含义#

仅凭概率,无法决定应该采取什么操作。0.62 可能足以支持添加评论,却不足以支持自动改写。

接下来的四种模式让这种解读更加明确。

9. Traffic light(交通信号灯):为不同操作设置阈值#

会发生什么: 不同操作共用一个阈值,会导致取舍失当。在超过 0.5 就阻止操作的设置下,检出的 14 个案例中有 12 个是误报。另一方面,将阈值提高到 0.9,又会漏掉被评为 0.62 的真实问题。

如何预防: 根据操作及其影响设置阈值。在这个示例中,改写使用 0.8,评论使用 0.5;操作越难撤销,就越需要充分的依据。

10. Grey zone(灰色地带):设置暂缓判断的区间#

会发生什么: 对于某些输入,模型无法给出足以支持判断的差异。在一个将截图混入输入的示例中,10 个回答全部落在 0.48~0.53 之间。

如何预防: 将 0.4~0.6 之类的中间区间视为“暂缓判断”。记录数量以便监控,但不要通过移动阈值,强行将其归入“是”或“否”的分支。

11. Thermostat(恒温器):滞回机制#

会发生什么: 只有一个阈值时,概率的轻微波动就会导致状态来回变化。在检测战斗状态时,将阈值设为 0.7 后,0.68、0.72、0.69、0.71 这些值导致状态反复切换。

如何预防: 为进入状态和退出状态设置不同阈值。例如,超过 0.8 时进入该状态,低于 0.6 时退出,在两者之间则保持此前的状态。

12. Scorecard(评分卡):组合多项评估#

会发生什么: 用 0~2 的尺度笼统询问命令风险时,回答可能几乎总是 1。这样的结果几乎无法说明究竟是哪种行为带来了风险。

如何预防: 询问删除、向外部发送、下载并执行内容等具体事实。使用应用程序负责人能够审核的规则,在代码中组合这些回答。

不能认为同一个概率阈值在不同问题中具有相同含义。每个问题都需要来自代表性输入的证据,每种操作也都需要处理不确定性的方针。

4. 应对失败,衡量实际运行效果#

即使问题设计得当,也可能收到格式不合法的响应。曾经有用的问题,也可能随着输入变化而失去作用。

最后四种模式处理的是这些运行中的问题。

13. Inspection(检查):验证接口契约#

会发生什么: 用零填补缺失回答,会让有问题的响应看起来无害。在文档的案例中,不完整的响应直接通过,监控也未能发现故障。

如何预防: 验证回答数量、概率范围以及选择结果的一致性。将不合法输出标记为“无回答”,与有效的低概率回答区分开来。

14. Fail open, fail closed(故障时放行或阻断):配置故障行为#

会发生什么: 故障可能导致保护失效,也可能让工作完全停滞。在一次持续 30 分钟的故障中,编辑器钩子未经检查就放行了操作,而构建服务器拒绝了所有命令。

如何预防: 提前决定,中断工作与执行未经检查的操作,哪一种代价更高。将这一行为设为明确的配置项,而不是让它成为异常处理的偶然结果。

15. Flight recorder(飞行记录器):记录与重放#

会发生什么: 如果日志只保留最终判断,就无法评估修改阈值的效果。要研究将删除阈值从 0.8 改为 0.9 的影响,就需要原始概率。

如何预防: 将判断逻辑写成纯函数。记录原始概率、判断结果、上一次判断结果及输入指纹,以便使用其他策略重新执行判断。

16. Check-up(定期检查):基于实测进行校准#

会发生什么: 准确性较低的问题可能持续使用数月。在 14 个问题中,有一个关于评论数量的问题,命中率只有约 20%,却连续三个月未被发现。

如何预防: 用至少 20 个真实输入评估每个问题,测量触发率、概率中位数和最大值。同时检查实际判断是否正确,停用那些几乎只产生噪声的问题。

重放与校准的目的不同。重放展示的是:对已记录的回答采用不同策略,会发生什么。校准则检查这些回答本身是否有用。

在用 LLM 作判断时,我会优先采用的三种模式#

对于已经用 LLM 批准、拒绝或分类输入的人,我建议优先采用以下三种模式。

1. Question bank(问题库)。 将“检查是否合规”这类笼统请求,替换为针对可明确识别条件的问题。这样就能清楚地看出,哪些部分应由代码处理,哪些部分需要模型判断。 2. Grey zone(灰色地带)。 将不确定性视为应用程序中的正式状态。强制二选一会掩盖不确定性。有了明确的“暂缓判断”结果,就可以转交审核或推迟操作。 3. Flight recorder(飞行记录器)。 保存重新审视判断所需的依据。没有原始回答和可重放的逻辑,调整阈值就只能靠猜测。

Menu 在从已知操作或目标中进行选择时尤其有用。将它与 Question bank 结合,就能理解为什么为每个候选项分别设置一个“是/否”问题,也可能是一种合理的设计。代码定义选项,模型评估选项。

不过,需要注意的是,各自独立的“是/否”回答并不会自动构成互斥选择。多个候选项可能都获得较高概率,也可能没有任何候选项满足条件。这两种情况都必须由代码定义处理方式。

这周,试着选出应用程序中的一个判断。将它改写为针对可观察事实的问题,定义回答不确定或缺失时的行为,并记录原始概率。然后,在用这个判断控制具有重大影响的操作之前,参照 Jev 的模式 ↗,检查至少 20 个真实输入。

目录