Skip to content

共享状态与黑板协作 ​

共享状态是一份供多个 Agent 或执行节点读取、更新的任务数据。它记录当前目标、已收到的证据、各子任务的进度和产物版本,使后续执行者能够知道任务已经推进到哪里。

黑板协作在共享状态之上增加了调度机制:各执行者把发现写入“黑板”,控制器检查哪些工作的前提已经满足,再选择下一项工作。例如两份资料核实结果通过验收后启动比较,发现价格过期后重新查价,草稿就绪后启动审查。黑板可以用数据库或内存对象实现,不要求模型之间轮流聊天。

哪些数据需要共享 ​

以多个 Agent 共同生成选型报告为例,可以把信息分成三种范围。

数据范围保存内容谁需要读取
Agent 私有上下文自己的指令、工作中的工具交互、尚未提交的草稿当前 Agent 的下一次调用
共享任务状态当前选型条件、候选证据、子任务状态、报告版本、审查意见参与这项任务的相关执行者
长期记忆允许跨任务复用的偏好、经过整理的历史经验后续有权限且确实需要这些信息的任务

共享状态保存到数据库后可以跨进程恢复,但它仍然属于这一项任务。数据库的持久化方式不会把一次采购的预算变成用户永久偏好。关于记忆的范围划分,见记忆机制。

“共享”也不要求每个 Agent 每轮读取全部字段。研究 Agent 需要选型条件和待查对象,审查 Agent 需要草稿、证据和验收要求。应用应按角色和当前步骤组装输入;共享存储中的数据只有经过读取,才会进入模型的上下文。

先约定字段由谁更新 ​

下面是一份报告任务的状态布局:

json
{
  "task_id": "selection-report",
  "revision": 0,
  "requirements_revision": 1,
  "requirements": {"max_price_cny": 6000, "max_weight_kg": 1.5},
  "subtasks": {
    "verify-a": {"status": "running", "acceptance": "pending"},
    "verify-c": {"status": "running", "acceptance": "pending"}
  },
  "evidence_by_id": {},
  "draft": null,
  "review_notes_by_id": {},
  "status": "researching"
}

字段所有权决定谁可以提出哪些更新。它可以由一个 Agent 持有,也可以由运行时或确定性的处理函数负责。

字段更新方式
requirements协调者根据用户的新要求更新,同时增加条件版本
subtasks执行程序更新运行状态,验收流程另行记录交付结果是否可用;两者都关联对应子任务
evidence_by_id研究 Agent 提交证据,合并函数按稳定 ID 去重追加
draft写作 Agent 提交新产物引用及版本,审查 Agent 对指定版本提意见
review_notes_by_id审查结果按意见 ID 合并,解决状态由约定的处理者更新
整体 status控制器根据就绪条件和验收结果推进

Agent 在提示词里看到“只改自己的字段”,有助于减少误操作;共享服务仍需校验实际写入。否则任何能调用通用写入工具的执行者,都可能覆盖其他字段。

跟着两次并发完成,看更新怎样合并 ​

研究 Agent A 和 C 都读到了上面的 revision: 0。A 查完自己的资料时,C 还在执行。如果它们各自把整份状态写回,后写入的一方就可能把另一方的新结果覆盖成旧值。

让执行者提交局部更新,可以缩小冲突范围。本次两个子任务都要求核实指定配置的总价与重量,证据需保留型号、配置、来源定位和查询时间。每次更新带有提交 ID 和所属子任务,数据交由状态服务处理:

text
更新 U-A
  submission_id = result-a-1
  task_id = selection-report
  subtask_id = verify-a
  requirements_revision = 1
  新增证据 = {a-price-01: A 的价格记录, a-weight-01: A 的重量记录}
  执行方报告状态 = completed

更新 U-C
  submission_id = result-c-1
  task_id = selection-report
  subtask_id = verify-c
  requirements_revision = 1
  新增证据 = {c-price-01: C 的价格记录, c-weight-01: C 的重量记录}
  执行方报告状态 = completed

状态服务收到结果后,先检查归属与条件版本,再按任务契约检查交付字段,核对价格、重量对应的配置及其来源。执行方报告 completed 只表示本次执行已经结束;验收通过后,服务才记录 acceptance: accepted,供下游判断是否就绪。核实到价格超出预算也是有效结果,验收检查的是资料能否支持比较。

两份交付都满足要求时,状态服务按以下顺序更新:

步骤状态变化控制器的决定
验收 U-A保存 A 的证据,记录 verify-a 已完成且验收通过,整体版本变为 1C 尚未通过验收,继续等待
验收 U-C在当前状态上合并 C 的证据,记录 verify-c 已完成且验收通过,整体版本变为 2两份结果均可用,创建比较任务
再次收到 U-A发现相同提交已经处理,不再写入或重复触发比较任务继续原来的执行

若 U-C 缺少重量来源,就记录验收未通过并要求补查,比较任务继续等待。通过验收的证据、验收状态和提交 ID 应在一个原子更新中保存。否则可能先出现“验收通过”,证据却还没写入,控制器据此启动比较时仍会读到不完整材料。

两次新增证据可以合并,是因为它们写入不同的证据 ID。对这类字段,可以定义 reducer,即根据旧值与局部更新计算新值的函数:

python
def merge_evidence(current, incoming):
    merged = dict(current)
    for evidence_id, record in incoming.items():
        if evidence_id in merged and merged[evidence_id] != record:
            raise ValueError(f"同一证据 ID 对应不同内容: {evidence_id}")
        merged[evidence_id] = record
    return merged

这段函数将重复的相同记录视为同一次数据,而对相同 ID、不同内容报错。它只负责数据合并;并发事务、权限和持久化仍由存储层负责。若先读后写之间缺少事务或版本检查,使用 reducer 也可能发生覆盖。

当输入合法且证据不可变时,这种合并满足重复提交不改变结果,也不依赖两份更新的到达顺序。简单的列表拼接则会留下重复项,而且排列顺序可能随调度变化。若后续要按时间或优先级读取,应保存相应字段,再显式排序。

哪些更新不能直接相加 ​

证据追加容易合并,修改同一个草稿或改变任务状态需要更严格的规则。

假设两个写作 Agent 都读到 draft_version: 3,分别生成新版。如果系统无条件接受两次写入,后一次就会覆盖前一次。可以要求提交带 expected_draft_version: 3,由存储层原子比较:第一次成功后版本变为 4,第二次因版本不符被拒绝,再由执行者读取版本 4,决定重新生成或交给合并步骤。

这称为乐观并发控制。版本比较与写入必须是一个原子操作;在应用中先查版本、隔一会儿再写,仍然留有竞争窗口。也可以使用短事务或锁串行更新某些字段,不需要每个字段都采用同一种策略。

任务状态还应限制允许的转移。例如收到重复完成事件不应再次启动写作,已取消任务的迟到结果不能把任务重新改成运行中。具体状态转移放在生命周期篇讨论。

数据合并也不能代替内容判断。两份证据使用不同 ID,分别记着同一配置价格为 5999 和 6299,reducer 可以同时保留;当前报告采用哪条,还需要比较来源、查询时间和价格口径。将它们取平均值或随意保留后到的一条,都会改变证据含义。

如果用户此时将预算改为 5500 元,requirements_revision 应增加。依据旧条件生成的“符合预算”判断需要重算,已经核实的型号和重量则可能继续使用。把事实记录与派生结论分开,才能有选择地更新结果。

黑板怎样启动下一项工作 ​

有了可靠的共享状态,控制器可以把调度条件写成规则,也可以让模型从当前符合条件的任务中选择。无论谁选择,运行时都需要记录任务是否已经派发,防止同一状态反复触发。

text
收到子任务结果
    ↓
校验归属、条件版本与提交 ID
    ↓
按任务契约检查交付字段、配置和来源
    ↓
原子保存证据、执行状态及验收结果
    ↓
检查就绪条件
    ├─ A、C 的结果均通过验收,且比较任务尚未创建 → 创建比较任务
    ├─ 验收发现缺少来源或同配置报价 → 创建补查任务
    └─ 草稿已提交,且该版本尚未审查 → 创建审查任务

创建任务时,可以用“任务类型 + 输入版本”生成稳定的调度键,并通过唯一约束防止重复创建。例如草稿版本 4 已经有审查任务,重复到达的通知就不应再启动一遍审查。通知负责促使控制器检查状态;当前状态和调度记录决定实际执行什么。

黑板与群聊的区别也在这里。群聊围绕共享消息记录,由调度器选择下一位发言者;黑板围绕可更新的问题状态,由控制器选择当前能推进任务的工作。两者可以结合:群聊产生一条修改建议,程序将其转换为待办;黑板任务完成后,再把结果发给参与讨论的 Agent。聊天记录本身不会自动提供字段所有权、版本检查或任务就绪条件。

对于步骤固定的研究、写作、审查,用明确的依赖图通常更容易调试。黑板适合线索逐渐出现、后续任务需要随状态增补的工作,同时也需要限制待办数量和重复调度。不同任务的执行依赖见流水线与任务依赖图。

参考资料 ​

持续学习,持续实践。