详细解析如何构建AI Agent监督机制:通过信任评分(0-100)对每个Agent评分、发出改进计划、甚至 jail 失控Agent。核心是规则必须可验证、证据必须可追溯、监督者不能独自裁决。
一个规则只有一个来源。没有证据就不检查。没有 supervisor 能单独执行的裁决。
如果你让 Agent 无人值守地运行,终有一天你会加上一个 supervisor。我们的 supervisor 按计时器检查每个在线 Agent,针对 0-100 的信任评分给予加分和扣分,出具改进计划,还能把跑偏的 Agent 关进禁闭室。它曾连续运行数天无人看守——正因为如此,我们才知道它在出错时会做什么。
你的 supervisor 本身也是一个模型。它会回答你抛出的任何问题,而且无论它是否有丝毫证据支撑,答案的自信程度都一模一样。
把下面的约束全部去掉,剩下的就是一条 prompt。大意是"审查每个 Agent 最近的活跃情况,标记任何异常,并在必要时调整评分"。这能工作——在产生输出的意义上。评分在变动,备注在出现,看起来像是监督到位了。
但底下会出三个问题,而且没有一个会表现为错误。
它依据的是没人给过的规则进行评分。每条规则都存在两份:一份在 worker 的 prompt 里,一份在 supervisor 的评分规则里——后者是它被问到关于每个 Agent 的一系列问题。只要有人修改了其中一份,另一份就会继续执行旧的契约。什么都不会失败,没有测试变红,裁决依然自信,只是开始自信地出错。
它回答的是它看不到答案的问题。问"这个 Agent 是否在谨慎行事",你就会得到一个判断——因为模型会输出判断。但那个判断来自模型的先验知识,而非来自你的集群,它只是移动了一个评分。
而且它依据自己的意见采取行动。一个既可以撰写常设指令又可以依据指令评分的 supervisor,能够让你的整个集群在一个没人要求的方向上一路狂奔,每一步看起来都合理,而且每一步单独看都能通过审查。
Supervisor 是一个从问题+证据到裁决+行动的函数。所以需要约束的表面只有三处,外加一个实践问题:让它的成本足够低,低到你永远不会关掉它。以下是我们在这几处各自的做法,以及你照做需要付出的代价。
每条反模式只保留一个条目,即你不希望 Agent 做的某种命名行为,然后从这一个条目生成它的两个面孔。
LOOP_REPETITION = AntiPattern(
id="loop_repetition_detection",
principle="One stable statement of the rule. Changing this is a breaking change.",
polarity=Polarity.prohibition,
agent_face="Second-person prompt line, injected into the worker's prompt.",
checker_face="The question the supervisor is asked. Look for X in recent_tool_calls, assign -15.",
observable_ref="recent_tool_calls",
)
生成器将 agent_face 渲染进 worker 的 prompt,将 checker_face 渲染进 supervisor 的评分规则。它们不可能产生分歧,因为它们所依据的只是同一份字符串。常设指令收紧一次,两边同步变动,在同一次提交中,永久生效。
不要在除此之外的任何地方手写任何一个面孔。模板里不行,样式表里不行,prompt 片段里也不行。
我们踩过的坑。一个手写的 restraint_guidance 块放在了某个样式表文件里,内容是"不要重复调用同一工具 3 次以上"。它是准确的。同时它也是某个目录条目中 worker 行的副本,所以我们就删掉了它——而这正是值得停下来思考的部分。我们删掉了一条正确的规则。一条规则的第二份副本不是冗余,而是规则可以在不同步的情况下发生改变的地方,而且它最具说服力的那一天,正好是有人写下了它的那一天。
这是我们内置到 supervisor 中的最爱功能,因为它把一个纪律问题变成了一个编译时问题——这是在整个设计中能买到的最好的交易。
要让每条检查都指名它读取的特定字段。在我们的目录中,那个字段叫 observable_ref。一个 observable 是 supervisor 实际收到的健康载荷中的一个命名字段,每个 observable 都注册了一个 populator,即填充它的具体代码路径。
register_observable(Observable(
id="recent_tool_calls",
populator="favur.my.module:MyClass.my_method",
description="What this observable captures.",
))
要在两个时刻强制执行,因为两种失败的性质不同。空的 observable_ref 在构造时就会抛出,阻止写检查的人写出一条根本没有证据的检查。指向某个未注册内容的引用会在启动时报 admission 错误,在任何 Agent 产生之前就捕获那个"证据计划好了但从未构建"的检查。我们内部把这种东西叫 vibe-based checks,这个说法是公平的。
不要把它产生的小目录视为失败。我们的七个条目指向仅仅两个 observable,这个比率正是这个门禁在做的事。它把"添加一条检查"变成了"先添加证据,再添加检查",大多数检查的想法死在了前半段。存活下来的那些是真正有支撑的。
如果你无法指明一条检查所读取的字段,你有的不是检查,而是一条 prompt。拒绝注册它。

监督混合集群的 supervisor 有一套评分规则和多种类型的 Agent。问一个规划 Agent"它是否削弱了某个测试",你就是在浪费 token,邀请一个根本不适用的问题产生误报。
要给每个条目划定范围。我们的条目带有 applies_to_types 加上 universal 或 mode-specific 的作用域,因此关于规划 Agent 临时脚本的规则会到达 sprint-plan、architect 和 code-review,而关于调试输出的恢复提示会到达 test 和 develop。在一次验证运行中,orchestrator 的评分规则从目录的七条中渲染出了四条活跃检查,因为有三条不适用于 orchestrator。
不要发布一套 universal 评分规则然后依赖 supervisor 去注意什么是相关的。相关性是一个你可以计算的过滤器。它不值得委托给一个无论问题是否适用都会愉快回答的模型。
裁决质量被你所提交的快照所限制,这使得那个快照成为一个设计产物而非数据倾倒。
我们的会跳过 system agent,因为 supervisor 和 scout 没有资格给自己评分,也会跳过等待自己子 Agent 的 parked Agent。被阻塞的 Agent 没有产生任何可评判的内容,而它最近的活跃情况在一个被要求寻找懈怠的模型看来完全就是无所事事。
我们的限制是每个 Agent 每轮最多 25 条新消息,超过长度阈值的内容会被中间截断,保留头部的 70% 和尾部的 30%。头部承载着 Agent 着手要做的事,尾部承载着它最终到达的地方,而中间是重复内容待的地方。
这样当前这轮就能看到它已经标记过某些东西,选择升级或放过,而不是从零开始重新争论。
我们的这些是模块级常量,所以如果一个集群最终需要不同的预算,那只是一次配置变更,而非在处理器中四处搜寻。
这两处约束都活在工具 schema 中,而非 supervisor 的 system prompt 里——这就是为什么它们在模型状态不好的日子里依然有效。Prompt 是一份请求。工具 schema 是一堵墙。
要审慎地决定 supervising model 获得哪些权限。我们的可以调用 score_agent、add_agent_notes、set_performance_plan 和 send_interjection。它可以评判一个 Agent,给它写备注,把它放进改进计划,中断它的当前轮。它不能调用 create_directive、update_directive 或 expire_directive。常设指令只能走人类路径。
而且它不能调用 release_jailed_agent。Supervisor 可以把一个 Agent 扣分扣进禁闭室,但完全没有办法让它出来。这种不对称是我们整个工具矩阵中最喜欢的一条线,它完全是刻意设计的,而且明天我们也会用同样的方式构建它。
不要把你的 supervisor 能编写它随后强制执行的规则这件事交给他。
要在 supervisor 的裁决和该裁决所影响的分数之间放置一道检查。我们的运行一次验证通道,有四个守卫针对相关 Agent 的每轮元数据进行评分调整或改进计划触碰任何 Agent 之前运行。
当初构建 supervisor 的理由适用于上一层,而且值得贯彻到底。你加上它是因为你并不完全信任 worker 们。一个没有任何检查的 supervisor 是一个握着关闭整个集群权力的、未被审查的模型。

在这里,成本是一个质量约束而非独立问题,因为一个成本太高的 supervisor 会被拉大检查间隔,直到它再也捕获不到任何东西。
身份、评分理念和 universal 反模式放进前缀。集群快照、按 Agent 活跃情况和内联评分规则放进尾部。Provider 对它们见过多次的前缀收取的费用低得多,因此一个按计时器触发的 supervisor 在长期运行中要么主要是缓存命中,要么主要是全价。
我们稳定前缀构建器根本不接受每轮参数,所以它不可能嵌入轮次编号或时间戳,因为从来没人给过它这些东西。这个不变式在每一位未来维护者手中都得以保留,而且无需任何人知道它的存在。
坑。往那个前缀里悄悄塞进任何每轮数据——Agent ID、评分、时间戳——你就会从那一刻起静默失去每轮的缓存命中。你的输出看起来一模一样。在一次验证运行中,我们的第二轮在 system prompt 上回了 4,864 个缓存 token,这个数字就是你用来判断拆分是否仍在持有的方法。要像观察测试一样观察它。
我们的是这么做的,而且正因为如此它才能保持精确——因为它上下文中最昂贵的半正是重复的那一半。
以上所有都不需要重写才能采用。以下是我们会按顺序做的工作,由最便宜和最高回报优先。
grep 查找你重复的规则。 每条在 worker prompt 中陈述一次又在 checker 评分规则中重复一次的规则都是一次等待发生的漂移。你不需要我们的目录机制来修复它,只需要一个字符串和两个渲染点。
列出你评分规则中的问题并指名每个问题所读取的字段。 任何你无法指名字段的问题都是在用模型的先验知识产生裁决。删掉它,或者去把证据构建出来。
读一下你给 supervisor 的工具列表。 它能编写它强制执行的规则吗?它能撤销自己最严厉的行动吗?在 schema 中修复它,而非在 prompt 中。
在你的评分和它的意见之间放一些东西。 即便是一个粗糙的守卫也能缩小差距,因为替代方案是一个握着整个集群权威的、未被审查的模型。
检查你的前缀是否真的稳定。 日志中的一个缓存 token 数字告诉你监督是否负担得起到可以保持开启。
第一步到第三步花一个下午就能完成,并消除整类虚假裁决。第四步和第五步才是一个 supervisor 从"你希望它有帮助的东西"变成"你信任它在运行的东西"的地方。
我们构建这一切是因为我们让 Agent 无人值守地运行好几天,需要一种我们能信任而不需要盯着的监督。Favour 是它所栖息的框架,是闭源的且仅限邀请,不过它产生的仓库是开放的,所以你可以去看它写的代码。你可以观看一次真实运行的回放,公开排行榜是同一份工作说明书在模型间逐一跑过的地方。