实践:博客系统审核队列

前面几节讲了载体的原则和产出方法。这一节用一个真实项目走完全程。看粗略意图怎么在多轮共同产出里变成一份满足原则的载体。

案例是一个博客系统。产品团队想加一个新功能:文章审核队列。作者提交文章后进入队列,主编审核之后才能发布。

起点长什么样

起点是一句话。给博客系统增加一个文章审核队列,主编在发文前审核所有稿件。

这句话跟一份满足载体原则的 spec 相比差得很远。里面缺的东西列一下就知道差距。

审核的粒度是什么?主编看整篇稿子给一个通过或拒绝,还是可以精确到段落级别标注问题?

拒稿反馈怎么给作者?主编写一段评语,还是从预设的原因里选?

多个主编同时审核如何避免撞车?两个主编同时打开一篇稿子,一个通过一个拒绝,怎么处理?

被拒稿件能不能修改再提交?改多少次算够?改到第几次系统应该介入?

审核历史如何追溯?保留多久?什么样的查询要支持?

垃圾投稿要不要单独处理?跟正常投稿混在同一个队列里,还是先过一道垃圾过滤?误伤了怎么办?

通知怎么发?作者被拒的时候通知吗?主编开始审的时候通知吗?超时未审的时候通知谁?

超时的稿件怎么办?系统自动通过还是自动拒绝还是标红上升?

主编离职后交接怎么走?她在审的稿子交给谁?她审过的历史算不算数?

权限模型是什么?主编能删稿吗?能改稿吗?作者能撤回吗?

每一个缺项在执行时都会变成 Agent 的自由发挥。五个 Agent 各自发挥,最终产出各自漂移。要产出满足载体原则的 spec,这些缺项都要在执行开始前预先编码进 spec。

循环的四步

从起点到满足原则的载体,走的是多轮循环。每一轮包含四步。

第一步,大模型基于当前意图扩展出决策点。第一轮的时候,输入是那句起点意图。大模型扩展出的可能是二三十个决策点:上面列的那些加上更多。它把这些决策点结构化地列出来,每个点带简短的描述和几个候选选项。

第二步,大模型识别出其中人能判定的部分并抛回。二三十个决策点里,只有一部分是这一轮人需要判定的。判定标准是上一节讲的三层约束:领域、杠杆、呈现形式。三层都过的决策抛回。这一轮可能有五到八个决策符合条件。其他的决策,或者杠杆不够、或者当前信息不足以判定、或者领域不匹配抛回对象,这些暂时由大模型自己决定,或者转成可判定的形式留到后面几轮。

第三步,人做出判定。这一步的输入是抛回的问题清单,输出是选项加简短说明。人不需要写实现细节,只需要在几个已经翻译成产品行为的选项之间做选择。判定过程里如果发现某个选项其实自己还不确定,可以标记为"暂缓"让大模型自己先做一个默认,标记为需要后面再看。

第四步,大模型依据判定精修意图,并检查新意图和之前决策的一致性。大模型做两件事。第一件是把人的选择固化进意图,把选择的推理过程也写进去,为将来遇到边界情况的 Agent 提供推理依据。第二件是拿这个新增决策去检查它跟之前所有决策是否兼容。有冲突的地方标出来,可能进入下一轮抛回。

每一轮结束时,预编码的决策数量增加,边界条件更清晰,一致性经过一次覆盖检查。多轮之后,起点那句意图长成一份初步的完整载体。

前几轮:产品层决策

前几轮,载体是一个大块。审核队列的目的、涉及的角色、大致的用户旅程都放在一起。这个阶段自足性谈不上,单元大小也没到硬约束。大模型抛回的决策主要是产品层面的高杠杆决策。

第一轮抛回可能长这样。

"审核粒度选文章级还是段落级?

文章级:主编看整篇文章,通过或拒稿。操作简单,处理时间短,但反馈信号粗。

段落级:主编可以精确到段落级别标注问题。反馈信号细,作者容易理解,但主编工作量大,需要更好的编辑界面。"

"拒稿反馈是自由文字还是分类标签?

自由文字:主编写任意评语。灵活,可以精确解释问题,但耗时,风格因人而异。

分类标签:主编从预设的原因里选(比如'内容不合规'、'重复投稿'、'需要更多细节')。快,风格一致,但生硬,特殊情况覆盖不了。"

"主编协作是抢占式还是分派式?

抢占式:所有稿件对所有主编可见,谁先看谁审。管理简单,主编可以主动挑感兴趣的选题,但可能撞车,也可能有稿件长期没人认领。

分派式:系统根据某种规则把稿件分派给特定主编。分配公平,避免撞车,但需要有一套分派规则,主编丧失选题主动权。"

这几个都是产品经理能判定的。他给出选择:"文章级。理由:段落级需要的编辑界面成本太高,一期我们先做简单的。分类标签,但主编可以额外加自由文字备注。理由:标签保证效率,自由文字给灵活性。分派式,按照主编的擅长领域自动分派。理由:抢占式在我们的团队规模下容易撞车。"

大模型收到这三个判定,把它们固化进意图。同时把每个决策的推理写进去。"文章级审核。理由:一期不投资段落级界面,未来可能升级。边界:如果审核工作量很大主编要求更精细的反馈,回来考虑段落级。"这样写,将来子空间里的 Agent 遇到"要不要给这个字段加段落级支持"这类边界决策的时候,可以沿着推理判断。

大模型同时开始扩展下一层决策。既然是分派式,分派规则是什么?分派需要主编标注擅长领域,这个信息从哪来?主编 profile?主编写自己的擅长领域?还是系统根据历史审核记录学习?分派之后主编能主动退回稿件吗?退回的稿件重新进队列还是分派给别人?这些是下一轮抛回。

第二轮抛回可能长这样。

"主编的擅长领域信息从哪来?

选项 A:主编在 profile 里手动标注,从预设的 20 个类别中选 3 到 5 个。管理清晰,但主编需要一次性配置,覆盖不到长尾话题。

选项 B:系统根据主编历史通过的稿件学习。适应性好,能覆盖长尾,但需要一定的历史积累才生效。新入职主编没有历史数据。

选项 C:混合。手动标注为主,学习作为补充。灵活但复杂度高。"

"主编能主动退回稿件吗?

选项 A:能。主编看了觉得不擅长可以退回,退回后重新分派给别人。灵活,但可能出现踢皮球。

选项 B:不能。分派就是分派,主编必须处理。责任明确,但可能勉强审核。

选项 C:能,但每人每天的退回次数有限(比如 3 次)。有灵活性也有约束。"

产品经理的回答:混合方案 C 用于领域标注,因为新入职主编能立刻工作,学习模块作为长期优化。退回选 C,每天限次数,理由是我们的团队规模不大,几个人踢皮球影响很大。

大模型固化这些决策,同时检查前后一致性。发现一个潜在冲突:如果新入职主编只有 3 个手动标签,而稿件分类可能超过 3 个方向,某些方向可能没人可派。这是覆盖检查抓到的一致性问题。抛回下一轮。

"新入职主编只有 3 个手动标签的情况下,某些主题的稿件可能没有匹配的主编。这时候的分派策略是什么?

选项 A:分派给最活跃的主编,让他处理。

选项 B:进入未分派队列,通知所有主编,抢占式认领。

选项 C:管理员介入分配。"

这类由一致性检查发现的抛回,比第一轮的直接抛回质量更高。因为它是从"你的决策会导致这个具体场景"出发的,具体场景更容易判定。产品经理选了 B,理由是未分派队列是一个安全网机制,能覆盖任何我们没预想到的分派缺口。

每一轮结束,载体的信息密度上升一个台阶。前几轮的载体像一个不断填充的产品设计文档。大方向定下来,细节逐层展开。经过几轮之后,产品层的决策基本定型。载体开始长出结构。

中期:架构决策浮现

到中间几轮,载体已经长到审核工作流成型、架构层决策浮现的程度。产品层的关键选择基本定下来,抛回的决策开始出现架构成分。数据存到哪,接口怎么设计,前后端怎么切分,通知走什么渠道。这些决策的抛回对象可能不是同一个人,产品经理判定不了架构问题。这时候需要抛给工程师或者架构师。

同时,载体的规模开始变得有压力。你打开这份文档发现它已经三四十页。你翻到中间看某一段,看完之后感觉描述得不太清楚,翻回去查前面的定义,走神了几分钟才找回来。同一个概念在不同页出现,感觉描述得不太一样,翻回去对比,发现前后其实是一致的,是自己读的时候记忆漂移。

这是分块的触发信号。载体本身还是一致的,是消费者(你、其他人、Agent)读不下来了。这个信号越来越明显的时候,就要开始分块。

分块沿决策边界画开。哪里是决策边界?哪里的决策已经被产品层定完,下面的展开彼此独立,切开来两边可以自足工作,哪里就是决策边界。

对于这个审核队列,分块可能是这样。

产品交互块。 承载主编的操作流程、UI 状态、反馈路径、错误显示、快捷键、批量操作界面。这一块的读者是前端 Agent。上层决策里跟前端相关的部分(分派式、分类标签加自由文字、拒稿后作者的修改流程)都装在这一块里。前端 Agent 不需要读其他块也能干活。这一块的自足边界是:前端能实现一个可运行的界面。

API 契约块。 承载前后端交互的接口定义、请求响应结构、错误码、状态机。这一块的读者是负责集成的 Agent。它把产品交互和后端逻辑绑定起来。这一块的自足边界是:能生成一份完整的 API 文档,包括每个端点的输入输出格式和状态转移。

数据 schema 块。 承载数据库表结构、字段类型、约束、索引、迁移策略。这一块的读者是数据库 Agent。上层决策里跟存储相关的部分(审核历史保留多久、如何追溯、支持哪些查询、并发写入的处理)都装进来。这一块的自足边界是:能写出建表 SQL 和相应的迁移脚本。

通知机制块。 承载事件触发条件、通知渠道、模板、送达失败重试、频率限制、静默期设置。这一块的读者是通知子系统 Agent。这一块的自足边界是:能实现一个从事件到用户接收通知的完整通道。

垃圾投稿处理块。 承载识别规则、隔离策略、误伤纠正流程、白名单机制。这一块的读者是反垃圾 Agent。这一块的自足边界是:能实现从投稿到判定的全流程,包括误判的纠错。

拿数据 schema 块举个具体例子看看这一块里装了什么。开头是这一块的意图和边界。

"本块面向数据库 Agent。目标产出:审核队列相关的建表 SQL、迁移脚本、索引定义。范围:审核队列涉及的所有持久化数据。不包括:反垃圾内部的判定日志(由反垃圾块承载)、通知模板存储(由通知块承载)。"

接下来是核心决策及其依据。

"主表:articles_reviews。承载稿件审核记录。字段包括审核 ID、稿件 ID、主编 ID、状态、提交时间、处理时间、决策类型、反馈类别、反馈备注。理由:状态跟主编 ID 分开存,因为要支持一稿多次审核(初审、复审)。"

再往下是边界和边缘策略。

"审核历史保留三年。理由:内容团队合规要求。实现方式:articles_reviews 按年分区,超过三年的分区归档到冷存储。归档时保留稿件 ID 和最终状态,不保留详细审核记录。"

"并发写入:两个主编同时决策的兜底。数据库层用乐观锁,version 字段控制。冲突时后提交的返回错误,交给应用层按产品规则处理(应用层规则见产品交互块)。"

这一块的写法有几个特点。第一,一开头就明确边界,读者知道自己该关心什么、不该关心什么。第二,每条决策带理由。理由不是装饰,是给遇到边界情况的 Agent 用的推理依据。第三,边界处理策略明确到具体机制(乐观锁 + version 字段)。第四,涉及其他块的部分(应用层规则)明确指出去别处看,但同时给出足够的钩子("按产品规则处理")让本块的 Agent 不需要跳过去看也能干活。

这些块之间的关键决策已经在产品层定完,块内部相当独立。每一块开始独立扩展。前几轮扩展是全文档一起做的,现在扩展分块进行。每块内部再多轮迭代,把这块的意图外化到自足。

分块的时候有一个容易犯的错误。按代码模块切,比如按前端、后端、数据库切。这个切法看起来跟按决策边界切类似,但两者不一样。按代码模块切,跨模块的决策(比如 API 契约的具体格式)落在两个模块中间,两个 Agent 各自的 spec 里都没有完整信息。按决策边界切,API 契约是一个独立的决策块,专门有一份 spec 承载。区别在具体的分块列表里就能看出来。

后期:自足性验证

到后几轮,重点转向每块的自足性验证。方法是把每块喂给一个 Agent,看它能否不看其他块就完成任务。

拿数据 schema 这一块作为例子。你把这一块的 spec 喂给一个 Agent,让它写建表 SQL。它写出来了。假设它写了主表 articles_reviews,字段包含 id、article_id、status、reviewer_id、reviewed_at。它还写了一个附表 review_comments 存主编的评语。你检查 SQL 有没有覆盖需求。

回头看这块 spec 里的意图。有没有针对审核历史保留时间的策略?spec 里写了要保留三年。SQL 里有没有对应的机制?没看到。articles_reviews 只是一张单表,没有分区,没有归档,也没有触发器把老数据搬到别的地方。这说明 Agent 漏了保留策略。

为什么漏?可能有两种情况。第一种是 spec 里"保留三年"这条决策没写在这一块里,写在了产品层的"审核历史追溯"相关决策里,还没被拉进来。这种情况是自足性漏了:这一块少了它需要的信息。补上,把保留策略写进 schema 块。

第二种是 spec 里写了保留策略,但写在一个不显眼的地方,Agent 读的时候在跳读里错过了。这种情况是表达漏了:信息在但没被 Agent 读到。补的方式是提高显著性——把这条策略放到 schema 块的开头显眼位置,或者做一个专门的"存储策略"小节。

区分这两种情况的方法是把 spec 里跟保留相关的所有内容找出来,看它在什么位置、多显眼、跟别的内容混不混。如果找不到,是自足性漏。如果找到但埋在长段落中间,是表达漏。

回填之后再喂给 Agent 一次,它这次考虑了保留期,SQL 里加了分区。检查通过。

对每一块重复这个验证。反垃圾块可能第一次喂给 Agent 的时候,Agent 只写了识别规则,忘了误伤纠正流程。回头看反垃圾块的 spec,误伤纠正的描述是这样一句:"识别到疑似垃圾时先隔离,等待主编确认。"Agent 读的时候可能觉得这句话是关于识别的,没意识到"主编确认"是一整个交互流程需要设计。

这是一个表达没到位的例子。意图在(spec 明确说了要主编确认),但表达没让 Agent 抓到它是一个独立的交互流程。补的方式是把"主编确认"展开成一个小节,明确定义主编看到什么、能做什么操作、这些操作有什么后果。补完再喂一次,Agent 能完成任务。

再举一个通知块的例子。通知块喂给 Agent,它写了完整的通知发送逻辑:什么事件触发什么模板,通过什么渠道发送,失败怎么重试。你 review 它的产出,发现它没考虑一个情况——同一个作者同时投了十篇稿件,主编逐一处理,每处理一篇就触发一条通知。结果作者一分钟内收到十条相似的通知,等于骚扰。

回头看通知块的 spec。里面有"送达失败重试"这条决策,也有"通知模板"这类内容。但没有关于"频率控制"或者"合并通知"的决策。这是意图缺失,不是表达问题。产品层的循环里,主编批量处理场景没有被想到,通知块继承下来的意图里就没有对应的决策。

补的方式是回到产品层的循环。这个具体的场景(十篇稿件、十条通知、骚扰)作为一个新的抛回问题:一次性处理多篇同一作者的稿件,通知策略是什么?选项 A:每篇一条通知,作者按篇看结果。选项 B:合并成一条通知,列出所有稿件的结果。选项 C:给一个阈值(比如超过 3 条),超过阈值的合并,不超过的分开发。产品经理选 C,理由是既保留个别稿件的独立性,也避免大规模投稿带来的骚扰。

新决策进入通知块,Agent 再次尝试,产出满足。

终态与失败模式

终态载体的验收标准就是原则的操作性检验。拿任意一块喂给 Agent,Agent 能独立完成本块任务,就说明自足性和单元大小联合成立。Agent 完不成的时候,两种失败模式要区分。

缺依据。 Agent 完成任务需要的某条决策不在这块里。可能这条决策还没做(意图不完整),也可能做了但装在别块(分块问题)。前者要回到产品层的循环,补上决策。后者要把决策从别块拉过来,或者提到公共层。

诊断方法:把 Agent 卡住的具体点问它一句"你在这里遇到什么信息缺口"。它会告诉你它需要知道什么但不知道。拿这个"需要知道的东西"去 spec 里找。找不到就是意图缺失。找到但在别块就是分块问题。

过载。 Agent 拿到的块太大,中间的关键决策被跳读了,导致产出漏项。这时候 Agent 不会说"我不知道",它会自己发挥一个答案。跟意图对不上但看起来自洽。

诊断方法:把 Agent 产出的东西跟 spec 里的关键决策一条一条对。如果 spec 里有但产出里漏了或者做反了,检查 spec 里那条决策的位置。如果它落在这块的中间段落,可能就是被跳读。

区分两种失败模式是必要的,因为补的方向不同。缺依据是补内容。过载是重新切分或者压缩内容。

载体做好之后

走完这一遍,载体的每一块都能被独立消费。你把这份载体分发出去。数据库 Agent 拿 schema 块,前端 Agent 拿产品交互块,API 层 Agent 拿契约块,通知 Agent 拿通知机制块,反垃圾 Agent 拿垃圾处理块。五个 Agent 并行开始工作。

每个 Agent 在自己的子空间里独立执行。它遇到边界情况沿着 spec 里的推理判断,遇到边缘情况按照 spec 里写的默认策略处理。它不需要跨空间同步,因为 spec 里的自足性已经保证它拿到了所有需要的信息。它不需要跟你实时对话,因为你不在场也无所谓,一切原本在场会补的东西已经预先编码进去。

产出从五个子空间陆续出来。合起来是一个完整的功能。

回顾整个过程

从起点到可用载体,走过了几个关键节点。

起点是一句话,二三十个字。缺一切细节。

前几轮把大方向的产品决策定下来。文章级审核、分类标签加自由文字、分派式协作、退回次数限制、混合领域标注。这些决策的杠杆最高,改一次牵动一大片,所以放在最前面。定完之后载体规模从零膨胀到十几页。

中间几轮把架构层的决策浮现出来。数据存到哪、接口怎么设计、通知走什么渠道、并发怎么处理。载体规模膨胀到三四十页。到这里,一个人一次读完开始困难,触发分块信号。

分块把载体拆成五块。每一块对应一个决策边界,块内部相当独立,块之间的关键决策已经在产品层定完。

后几轮针对每一块做自足性验证。挨个把块喂给 Agent,看 Agent 能否独立完成本块任务。完不成的时候诊断是缺依据还是过载,回填或者重切。反复几轮之后,每一块都能通过验证。

终态的载体分发出去,多个 Agent 并行执行,产出合起来。

整个过程有几个特点值得强调。

第一,载体不是设计出来的,是通过多轮共同产出逐步收敛出来的。你没有在某一时刻坐下来说"我要设计一份载体",然后一次画完整个结构。你是在多轮循环里逐步长出来的。前几轮的决策为后几轮的决策打基础,中间某一轮出现的信号(读不完)触发结构性调整(分块)。收敛过程遵循原则,但具体节奏跟意图本身的复杂度和你判定能力的分布相关。

第二,你在循环里的负担是可控的。每一轮你要做的判定是五到八个决策,都是产品行为层面的选择,跟你的日常工作强度差不多。你不需要理解 attention 承载力的物理机制,不需要设计分块结构,不需要维护跨块一致性。这些是大模型承担的。你专注在意图判断上。

第三,元原则始终在起作用。你在每一轮看到的抛回都是可判定的。判定不了的问题你没看到(大模型自己处理了,或者转成了可判定的形式)。这个过滤是共同产出跑通的关键。没有这个过滤,你会疲于奔命判定不了的问题,而载体的对齐也会因为凑合出来的判定而失败。

第四,失败模式有明确的诊断方法。缺依据和过载两种失败模式对应不同的补救动作。你在验证阶段发现 Agent 完不成任务的时候,不是笼统地"补 spec",是先诊断属于哪种模式,再针对性补。

这就是原则加方法确实能产出可用载体的完整论证。载体不是设计出来的,是通过多轮共同产出逐步收敛出来的。逐步收敛的每一步都严格遵守元原则。终态的载体在原则的操作性检验下能通过。多个 Agent 并行执行时的产出可以合起来。

载体做出来了。多个 Agent 并行工作,各个子空间陆续有产出。这些产出要怎么验证是接下来的问题。卷一里最后一道人肉审已经不成立。验证机制要能自己兜住。这是下一章的话题。


Harness Engineering Playbook · AgentsZone Community

results matching ""

    No results matching ""