在多 Agent 系统里,让几个角色看到同一段聊天记录,并不意味着它们已经共享了同一个任务状态。

用户最初要求蓝色主题,后来改成绿色;UI Agent 写了风格指南,前端 Agent 说已经完成,但构建失败了。下一位接手者真正需要知道的,是现在以哪条要求为准、该读取哪份设计稿、上次改了哪些文件,以及还有哪些验收没有通过。

这是我在 AgentMeld 里处理上下文时一直关心的问题。项目是一个基于 Pi 的本地多 Agent 群聊工作空间,支持讨论、同伴咨询与按需任务编排。对需要委派执行的任务,我希望提供一份有来源、有状态、能连接到执行证据的材料包,而不是让接手者重新阅读整段群聊。

下面沿着 Task Context Compiler、事实记录、产物绑定和验证链路展开。实现细节以文末链接的源码快照为参照;其中的 Todo 场景与材料包示例用于说明设计,并非一次实际运行的测量报告。

摘要之外,需要保留当前状态

把历史变短,和把当前状态说清楚,是两种工作。

摘要可以减少重复讨论,但它不会天然表达“绿色已经替代蓝色”,也不会自动证明“修复完成”之后确实有一次成功的构建。产物被口头转述时,还容易丢掉它的身份与版本;失败被压成一句“之前有问题”时,下一次执行也失去了定位入口。

因此,我把上下文选择与文本压缩分开:先判断哪些材料对这次任务有效,再决定带正文、结构化状态还是读取引用。摘要仍然有用,但只是可能的材料来源之一。

一次任务尝试,对应一份材料包

编译器从当前任务和执行身份出发。taskId 表示正在做什么,attemptId 区分第几次尝试,contextSnapshotId 标识这次组织出的上下文;计划修订与执行者也属于这份身份。

这样才能区分“同一个任务的上次失败”与“另一个任务里的相似问题”。失败证据、产物读取和验证结果,都需要落回对应的尝试,而不能只按消息出现的先后关联。

材料需要回答的问题
当前任务与验收契约这次必须完成什么、怎样报告结果?
当前有效事实哪些要求与约束仍然生效?
上游输入和输出绑定依赖谁的哪项产出,具体是哪份产物?
工作区快照与目标路径去哪里找文件,本次改动涉及哪里?
上次失败与工具证据上次执行了什么,为什么没有通过?
消息、摘要与历史检索哪些沟通背景值得补充?

候选材料带有 sourceType、sourceId、trustLevel、关联任务、路径引用和 Token 估算等字段。它们让“为什么把这项内容交给这个 Agent”成为可检查的数据问题。

编译结果也不只是一个字符串。TaskContextEnvelope 同时承载任务身份、要求、上游输入、纳入材料、失败背景、预算与 manifest,之后再由 renderer 生成模型输入。

text
task + active facts + upstream bindings + prior attempt
    -> collect candidates
    -> qualify -> classify -> rank
    -> preserve metadata / externalize references
    -> pack within budget
    -> envelope + manifest -> rendered prompt

先检查资格,再计算相关性

一条消息很像当前问题,不代表它仍然有效。一份 Agent 自称完成的产物,也不能因为标题匹配就直接成为可信输入。

资格检查考虑会话与任务依赖范围、事实生命周期以及上游输入的可信状态。这些检查依赖调用方提供正确的作用域和元数据,不能被理解为系统自动识别所有自然语言冲突。

有效状态与来源可信度,是两条轴

Fact Registry 对事实保留 canonical key、来源与替代关系。新的值通过相应检查后,可以把旧记录标为 superseded,再成为当前 active 的值。

但 active 描述的是生命周期,authoritative、verified、reported 等描述来源可信度。一个仍然有效的记录,也可能只是模型提取出的声明;不能因为它进入事实表,就把它升级成用户确认或工具证明的事实。

绿色替代蓝色的例子,依赖事实更新被正确识别并记录。相关历史仍可能保留在消息中,但不应该凭检索相似度覆盖当前已确认的约束。

分数表达优先级,不表达正确率

合格候选再进入确定性排序。排序器 中的部分加分规则如下:

条件加分
任务明确要求的材料+1000
当前任务本身+900
来自直接依赖的上游输入+800
失败背景+780
与目标路径匹配+650

这些分数可以叠加,也受后续分层规则约束。失败材料还是必需层,不能简单理解成“只比路径匹配多 130 分”。它们没有概率含义,也不是一次额外模型判断给出的置信度。

预算打包,需要保留任务契约

材料分为必需、高优先、可选和禁止几类。任务目标、明确要求的材料与失败重试背景优先保留;事实、上游输入和工作区信息再按规则进入其余预算。

当前 packer 先装必需项,再为高优先组分配剩余预算的 60%,可选材料利用后续余量。这是可解释的分组打包规则,并不保证找到全局最优的材料组合。

如果必需内容本身超出预算,编译器返回 blocked,执行路径报告 task_context_overflow,而不是删掉关键要求后继续调用模型。预算也需要为系统提示、工具 schema、输出和协议留出空间。

这里有一个容易被名字掩盖的边界:context-compressor 目前大量保留原有结构化内容或轻量元数据,并没有普遍调用模型生成新的语义摘要。另一个边界是 Token 数主要依赖估算,任务预算模块仍使用固定默认窗口,不能当作针对每个模型精确计算后的实际输入长度。

这套设计现阶段的收益,更多来自选择、分层、引用和按需读取。

从产物引用,到真正读到材料

上游风格指南不必在每次调用中重复全文。材料包可以先携带真实的产物 ID、版本、生产任务与输出键,执行者需要正文时,再使用 read_artifact 读取。

输出键与产物 ID 承担不同职责:前者说明任务承诺交付哪类输出,后者定位实际产物。不能把任务名或 style_guide 这样的键,猜成一个已经存在的 artifact ID。

同样重要的是,下面几个状态并不等价:

text
source exists
    -> candidate qualified
    -> item packed
    -> text or reference rendered
    -> model receives input
    -> artifact body read through a tool

manifest 中的 included 记录打包选择;Context Trace 的产物读取记录提供另一层观察。两者都不是“模型已经理解并采用该内容”的证明。

这也影响对历史检索能力的描述:当前 FTS5 命中可以进入 retrieved_history 候选和打包结果,但所核对的 renderer 没有专门输出这一类别的正文段落。因此,不能仅凭检索命中数或纳入清单,就声称这些历史片段已经到达模型。渲染和传递仍需沿实际调用路径检查。

验收要求,要同时到达模型与验证器

证据驱动的上下文不能只告诉 Agent “你要实现页面”,然后在结束时用它从未见过的要求判断失败。

buildRequirements 将目标路径、预期输出、必需命令、证据说明和验收条目带进 envelope;renderer 再输出对应的 evidence contract。可以自动核验的契约项与需要报告的人工验收项,也要与验证端的处理方式对应。

渲染器回归测试 专门检查这些字段是否真正出现在 Prompt 中。这类测试验证的是整条数据路径,而不是只检查数据库里存在几个字段。

执行后,模型通过 report_task_result 提交声明,运行时结合持久化证据验证。不同材料支持的结论必须分别看待:

材料可以支持什么不能直接推出什么
Agent 说“已经完成”有一份完成声明要求全部满足
命令退出码为 0该次命令成功退出所有功能正确
文件或产物创建记录对应内容被创建或修改内容符合业务要求
浏览器验收结果指定页面和交互通过检查未覆盖路径也正确

验证器从产物证据构造输出绑定,并检查类型、内容及契约要求。绑定将上游的输出键连接到实际产物,供后续任务解析输入;它不应来自报告里随手写下的一个 ID。

失败与交接,延续的是任务状态

失败后的上下文应保留上次 attempt、失败命令及错误摘录、关联证据、未通过的验收与已改文件。这样,“重试”才有明确的起点。

回到 Todo 场景,一份面向接手者的材料可以概括为下面这样。它是阅读示意,不是 envelope 的完整序列化格式:

text
目标:完成分类筛选,并修复上次构建失败。
有效约束:绿色主题,保留现有任务数据。
上游:当前绑定的 PRD 与风格指南产物引用。
失败:上一尝试的构建命令、错误摘录和证据 ID。
验收:构建通过、分类切换正常、原有数据仍可使用。
继续:先读取相关产物与文件,再验证当前状态。

前一次检查通过的部分值得保留,但文件变动后,相关证据可能需要重新取得。“曾经通过”并不等于当前版本仍然通过。

这套思路也用于任务交接。交接包包含实际执行过的任务契约、证据引用、上游产物版本、有效事实指纹和相关文件指纹。人工确认接手时会再次检查这些引用是否过期,并由运行时协调原执行者退出与新尝试启动。

同伴咨询与交接则有不同语义:咨询返回建议,责任仍在原 Agent;交接转移未完成任务的执行责任,接手者仍要提交结果并经过验证。交接成功也不等于整个失败计划中的所有下游任务自动恢复。

Context Trace,把排错落到具体环节

当结果偏离预期时,我希望先回答几个可以查证的问题:材料有没有进入本次快照,是否因为预算被省略,上游引用是否有效,正文有没有读取,以及任务究竟在哪项验证上失败。

Context Trace 把快照、manifest、上游输入、工具证据、verdict 和输出绑定组织到同一个尝试视图中。unread_verified_input、output_binding_missing 等提示,可以把“Agent 没理解设计稿”拆成更具体的排查方向。

同时,Trace 只能展示已经采集和持久化的数据。当前 manifest 主要来自打包阶段,不能假定所有资格初筛的拒绝理由、排序得分与最终模型输入都已经完整记录。观察链路也需要持续补齐,而不是只增加一个漂亮的统计面板。

Pi 与平台,各自维护不同范围的上下文

Pi 负责一次执行内部的模型交互、工具循环与会话历史;AgentMeld 负责团队身份、任务契约、跨任务材料和工作区协作。Task Context Compiler 主要服务于委派任务的启动与新尝试,不意味着普通讨论也必须先建一张 DAG。

上下文也不会随每个生成的 Token 重编译。执行中的补充要求由平台跟踪;需要替换调用时,先完成原执行的清理,再以更新后的要求组织新尝试。这让“需求发生变化”与“旧执行还在继续”成为需要显式协调的状态。

如何判断设计是否有用

仓库提供了最近消息、摘要加最近消息、证据感知,以及叠加角色契约的策略配置,也有编译器、渲染器、验证器和交接相关测试。这些可以检查机制是否按预期连接,却不能直接给出哪种策略更优的结论。

真正的比较需要控制模型、任务、工具、预算与验收方式,并进行重复试验。我会同时看任务完成率、过期约束被采用的情况、上游产物读取率、无证据声明、重试次数、Token 开销与耗时,而不只看材料包更短了多少。

当前边界也应该进入评价:FTS5 是全文检索,事实替代依赖正确记录,Token 估算和渲染覆盖仍需改进,验证只能支持实际检查过的范围。

我希望这套上下文工程最终带来的,是让每次执行更明确:当前要做什么,哪些要求仍然有效,依据哪些材料继续,以及失败后应当带着什么交给下一次尝试。