S10 团队协议详解笔记

基于 s10_team_protocols.py 源码逐行分析,配合 s10-team-protocols.md 设计思路。


一、问题:队友之间需要结构化的握手

s09 的队友可以发消息了,但所有消息都是 msg_type: "message"——非结构化的自由文本。这在实际协作中不够。

想象这个场景:Lead 想让 Alice 停下来(她的任务已经被 Bob 完成了),Lead 发了一条 “请停止工作”。Alice 的 LLM 怎么理解这条消息?

  • 它可能当成闲聊忽略掉
  • 它可能理解成"检查一下工作质量"
  • 它可能直接继续干活

自由文本不适合传递指令。指令需要结构、确认、追踪。

s10 引入了两个结构化握手协议:Shutdown(关闭)和 Plan Approval(计划审批)。两者共享同一个 request_id 关联模式。


二、解决方案:请求-响应 + request_id 关联

两个协议都遵循同样的模式:

发起方                            接收方
+---------------------+          +---------------------+
| 发送 request         |          |                     |
| {request_id: abc}    | -------> | 收到 request        |
+---------------------+          | 决定: approve?      |
                                 +---------------------+
                                          |
+---------------------+          +-------v-------------+
| 收到 response        | <------- | 发送 response       |
| 匹配 request_id      |          | {request_id: abc}   |
| 状态: approved       |          | {approve: true}     |
+---------------------+          +---------------------+

request_id 是桥接请求和响应的关键:发起方保存 {request_id: status},接收方在响应中带回同一个 request_id,发起方据此更新状态。


三、和 s09 相比,多了什么?

组件 s09 s10
消息类型 message, broadcast + shutdown_request, shutdown_response, plan_approval_response
握手协议 Shutdown + Plan Approval
请求追踪 shutdown_requests / plan_requests 字典
队友工具 6 个 8 个(+ shutdown_response, plan_approval
Lead 工具 9 个 12 个(+ shutdown_request, shutdown_response[查询], plan_approval

四、协议一:Shutdown — 优雅关闭

4.1 状态机

pending → approved | rejected

Lead 发起关闭请求,teammate 可以同意或拒绝。

4.2 Lead 侧:发起请求

def handle_shutdown_request(teammate: str) -> str:
    req_id = str(uuid.uuid4())[:8]       # 生成唯一请求 ID
    with _tracker_lock:
        shutdown_requests[req_id] = {"target": teammate, "status": "pending"}

    BUS.send(
        "lead", teammate,
        "Please shut down gracefully.",
        "shutdown_request",               # 消息类型
        {"request_id": req_id},           # extra 字段
    )
    return f"Shutdown request {req_id} sent to '{teammate}'"

发送的消息结构:

{
  "type": "shutdown_request",
  "from": "lead",
  "content": "Please shut down gracefully.",
  "request_id": "a1b2c3d4"
}

4.3 Teammate 侧:响应请求

Teammate 在自己的 agent_loop 中读到 inbox,看到 shutdown_request。它调用 shutdown_response 工具:

# TeammateManager._exec 中的处理
if tool_name == "shutdown_response":
    req_id = args["request_id"]
    approve = args["approve"]
    with _tracker_lock:
        if req_id in shutdown_requests:
            shutdown_requests[req_id]["status"] = "approved" if approve else "rejected"
    BUS.send(sender, "lead", args.get("reason", ""),
             "shutdown_response",
             {"request_id": req_id, "approve": approve})
    return f"Shutdown {'approved' if approve else 'rejected'}"

如果 approve: true,队友循环中的 should_exit 标志被设为 True,循环退出,状态切为 shutdown

4.4 Lead 侧:查询状态

# Lead 工具:
"shutdown_response": lambda **kw: _check_shutdown_status(kw.get("request_id", "")),

Lead 可以传 request_id 查询请求状态,看 teammate 是否同意了关闭。

注意语义上的微妙:Lead 的 shutdown_response 和 teammate 的 shutdown_response不同的工具,虽然同名。Lead 侧是"查询请求状态",teammate 侧是"同意/拒绝关闭请求"。在 dispatch map 中它们映射到不同的 handler。


五、协议二:Plan Approval — 执行前审批

5.1 动机

Teammate 在做一个高风险操作前(如"删除 production 数据库"),先提交计划给 Lead 审批。只有获批后才执行。这是 “human-in-the-loop” 或 “lead-in-the-loop” 的简化实现

5.2 Teammate 侧:提交计划

if tool_name == "plan_approval":
    plan_text = args.get("plan", "")
    req_id = str(uuid.uuid4())[:8]
    with _tracker_lock:
        plan_requests[req_id] = {"from": sender, "plan": plan_text, "status": "pending"}
    BUS.send(sender, "lead", plan_text, "plan_approval_response",
             {"request_id": req_id, "plan": plan_text})
    return f"Plan submitted (request_id={req_id}). Waiting for lead approval."

Teammate 调用 plan_approval(plan="删除 production 数据库的所有记录") → 计划发给 lead,状态 pending。此时 teammate 暂停执行(等待响应)。

5.3 Lead 侧:审批计划

Lead 在 inbox 中看到计划,调用 plan_approval 工具:

def handle_plan_review(request_id: str, approve: bool, feedback: str = ""):
    with _tracker_lock:
        req = plan_requests.get(request_id)
    if not req:
        return f"Error: Unknown plan request_id '{request_id}'"

    with _tracker_lock:
        req["status"] = "approved" if approve else "rejected"

    BUS.send("lead", req["from"], feedback, "plan_approval_response",
             {"request_id": request_id, "approve": approve, "feedback": feedback})
    return f"Plan {req['status']} for '{req['from']}'"

如果 approve: false,Lead 可以附带 feedback: "分批删除,每次不超过 1000 条"。Teammate 收到反馈后修改计划,重新提交。


六、Teammate 循环中的协议集成

def _teammate_loop(self, name: str, role: str, prompt: str):
    sys_prompt = (
        f"You are '{name}', role: {role}. "
        f"Submit plans via plan_approval before major work. "
        f"Respond to shutdown_request with shutdown_response."
    )
    should_exit = False

    for _ in range(50):
        inbox = BUS.read_inbox(name)
        for msg in inbox:
            messages.append(...)

        if should_exit:        # shutdown_response 设置的
            break

        # ...agent loop...

        # 检查是否发了 shutdown_response
        for block in response.content:
            if block.name == "shutdown_response" and block.input.get("approve"):
                should_exit = True

    # 结束时更新状态
    member["status"] = "shutdown" if should_exit else "idle"

七、设计洞察

7.1 request_id 是分布式系统的基石

两个协议共用一个 request_id 关联模式——这个模式在分布式系统中无处不在(HTTP 的 X-Request-Id、消息队列的 correlation_id、OpenTelemetry 的 trace_id)。s10 在 30 行代码里展示了这个模式的核心:生成唯一 ID → 随请求发送 → 在响应中带回 → 匹配并更新状态。

7.2 消息类型的演进

s09: message, broadcast         ← 非结构化
s10: + shutdown_request/response, plan_approval_response  ← 结构化握手

消息类型从"随便说"到"有格式的契约"。这不是随意的添加——每种新消息类型代表一种新的人机/机机交互模式。shutdown_request 是"终止",plan_approval 是"审批"。未来可以扩展更多(code_review_requestdeploy_approval…),模式不变。

7.3 协议是 Harness 的职责

shutdown 和 plan approval 都不是 LLM 发明的——是 Harness 层定义的结构。模型只是"使用"这些协议(调用相应的工具),但协议的存在、状态追踪、超时处理、响应匹配——全是 Harness 代码的责任。这回到了这个系列的核心哲学:Harness 提供结构和约束,模型提供推理和决策。

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐