回应 Fasthei 终审三点: 1) [P1 文档/代码冲突 + 死代码] 删除从不被调用的 *_enabled() helper(autonomous_tasks.proposals_enabled / task_competition.task_competition_enabled / convergence.convergence_report_enabled)及其 import os;模块 docstring 与四份协议文档(autonomous-task-generation / task-competition-protocol / review-loop-protocol / convergence-protocol)从"默认关/未接入/待 PR/cutover 转无条件"全部改为 "无条件接入(无开关)",删除引用死 helper 的过时集成代码样例;同步删除三个模块单测里的 "flag default OFF" 断言。 2) [P1 验收] #6 "Closes" 降为 "Refs":#6 DoD 需 ARB 决策记录链接,当前只有 owner 指示断言、无链接。 product-positioning.md 改为如实记录决策来源(owner 指示 + 本 PR + 文档)并把"补 ARB 记录链接(或 owner 明确接受断言)"列为关闭 #6 的前置;纠正其"flag 门控、默认行为不变"的过时表述(重构已无条件)。 3) [P2 契约卫生] assess_swarm_health 不再 emit_event("swarm.health")(避免向订阅全部的 Manager 回调 投递未注册事件);改为存 run.metadata["health"] + 内部 health_log。test-swarm-guard 相应断言 "无 swarm.health 外发 + 内部 health_log 已记"。 本地受影响 11 套全绿。影响范围:agent_swarm(orchestrator 模块/文档/测试);不改 Manager↔Swarm 契约。 Refs #6 Refs #7 Refs #8 Refs #11 Refs #12 Refs #18 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
133 lines
9.8 KiB
Markdown
133 lines
9.8 KiB
Markdown
# Agent 自主任务生成:提案协议(Issue #7)
|
||
|
||
> 状态:**已接入实时 WS 主循环(去中心化重构 P3)**。`main.py: handle_task_proposal` + WS `task_proposal` 分支:Agent 提案 → 审查(置信度/去重合并/每 run 预算 `AGENT_PROPOSAL_BUDGET`)→ ACCEPT 即入池为真实 PENDING 任务(带 lineage,`source=agent_proposed`,发标准 `task.created`);提案生命周期存 `run.metadata["proposals"]`(内部遥测)。feature flag `ENABLE_AGENT_TASK_PROPOSALS`(构建期;cutover 转无条件)。集成测试 `scripts/test-swarm-autonomous.py`。本文是该机制的唯一入口。
|
||
> 实现:`orchestrator/autonomous_tasks.py`(纯模块,无 Redis / WS / FastAPI 依赖)。
|
||
> 测试:`scripts/test-autonomous-tasks.py`。
|
||
> 配套:任务模型见 `orchestrator/task_queue.py`;事件流 schema 见 [`../integration/event-schema.md`](../integration/event-schema.md);派发回退对照 [`../benchmark/decision-engine.md`](../benchmark/decision-engine.md)。
|
||
|
||
## 1. 问题与边界
|
||
|
||
Issue #7:执行单元(Agent)在工作中会**发现**当前共享状态缺失的工作(例如实现已落地但无测试、缺文档、需要补一个后续步骤),但运行时此前没有任何机制让 Agent **提出**或**补全**任务。本机制补上「自底向上」的任务来源。
|
||
|
||
**关键边界(务必先读)**:
|
||
|
||
- **是 Agent 在提案,不是 Master 在生成任务。** Master/planner 的自顶向下分解路径**已在去中心化重构中删除**;本机制(自底向上提案)是蜂群**唯一**的分解路径。提案恒带 `source="agent_proposed"` 与 `proposed_by_agent_id`;`assert_not_master_origin()` 在运行时拒绝任何 proposer/trigger 名含 `master`/`planner` 的提案,防止 Master 借此路径「洗白」任务来源。
|
||
- **无条件接入(无开关)。** 该机制是蜂群运行时的固有行为,**无 `ENABLE_*` 开关**(本仓即 swarm 运行时,模式选择在仓外);`main.py` 的 WS `task_proposal` 分支与 `handle_task_proposal` 始终生效。
|
||
- **Agent 只提案,编排器才决策。** Agent 给出自评置信度 `proposal_confidence`,但「收 / 拒 / 并」由编排器侧的策略函数 `review_proposal` 依据置信度阈值、提案预算、与现存任务去重来裁决——不调用任何模型。
|
||
|
||
## 2. 数据模型(`orchestrator/autonomous_tasks.py`)
|
||
|
||
### 2.1 `TaskProposal`
|
||
|
||
| 字段 | 说明 |
|
||
|---|---|
|
||
| `proposal_id` | `prop-<hex>`,自动生成 |
|
||
| `proposed_by_agent_id` | **必填**,提案的执行单元;为空抛错 |
|
||
| `source` | 恒为 `"agent_proposed"`(`__post_init__` 硬锁,外部覆盖无效) |
|
||
| `title` / `description` / `agent_role` / `required_capabilities` / `depends_on` | 拟建任务的规格 |
|
||
| `proposal_reason` | Agent 为何提出(人/审计可读) |
|
||
| `proposal_confidence` | Agent 自评 0..1,构造时夹紧到 `[0,1]` |
|
||
| `lineage` | `ProposalLineage`:`origin_task_id` / `trigger_event` / `shared_state_snapshot` |
|
||
| `status` | `ProposalStatus` 枚举 |
|
||
| `merged_into_task_id` | 合并时记录并入的现存任务 id |
|
||
| `decision_reason` | `review_proposal` 写入的裁决理由 |
|
||
|
||
### 2.2 `ProposalStatus`(状态机)
|
||
|
||
```
|
||
proposed ──accept──▶ accepted ──ingest──▶ (新建 PENDING 任务)
|
||
│
|
||
├──reject──▶ rejected
|
||
├──merge───▶ merged(并入现存任务,不新建)
|
||
└──(超时/未处理)──▶ expired # 枚举已定义,过期判定由集成方按预算/时限实现
|
||
```
|
||
|
||
`ProposalLineage` 三要素让被提案任务端到端可审计:来自哪个原始任务(`origin_task_id`)、被什么事件触发(`trigger_event`)、Agent 基于哪份共享状态快照推理(`shared_state_snapshot`,需脱敏)。
|
||
|
||
## 3. 策略与摄取
|
||
|
||
### 3.1 `review_proposal(proposal, policy, existing_tasks) -> ReviewOutcome`
|
||
|
||
纯函数,按序裁决,返回 `ProposalDecision`(`accept`/`reject`/`merge`)并就地更新 `proposal.status` 与 `decision_reason`:
|
||
|
||
1. **置信度下限**:`proposal_confidence < policy.min_confidence` → **REJECT**。
|
||
2. **去重**:与某个**存活**(pending/assigned/in_progress/blocked)现存任务描述相似度 ≥ `dedup_similarity_threshold` → **MERGE** 进该任务(不新建)。相似度用 `description_similarity`(词集 Jaccard,确定性、无模型调用、可复现)。**已完成任务不作为去重目标**——允许 Agent 提后续轮次。
|
||
3. **预算**:`policy.remaining_proposal_budget <= 0` → **REJECT**。
|
||
4. 否则 → **ACCEPT**。
|
||
|
||
`ProposalPolicy` 字段(`min_confidence` / `auto_accept_confidence` / `remaining_proposal_budget` / `dedup_similarity_threshold`)全部显式,集成方应从 run 的 `orchestration_plan.budget` 取值,不从模型读取。
|
||
|
||
### 3.2 `ingest_accepted_proposal(proposal, *, swarm_id, root_task_id) -> dict`
|
||
|
||
仅接受 **ACCEPTED** 提案(否则抛错),再次校验 `assert_not_master_origin`,产出与 `task_queue.create_task` 对齐的 kwargs 形 spec:`description` / `agent_role` / `required_capabilities` / `depends_on` / `parent_task_id` / `root_task_id` / `source="agent_proposed"` / `context`。完整 lineage 写入 `context["proposal"]`(提案人、理由、置信度、origin/trigger、快照),新任务由 `create_task` 落为 `PENDING`。默认以 `origin_task_id` 为 `parent_task_id`,将新任务挂入原 run。
|
||
|
||
> 本函数只**产出 spec**,由集成方调用 `task_queue.create_task(**spec)` 入队——模块本身不碰 Redis/队列,以保持纯净与可测。
|
||
|
||
### 3.3 生命周期事件
|
||
|
||
`build_proposal_event(event_type, proposal, **extra)` 与 `build_lifecycle_events_for_outcome(proposal, outcome)` 产出扁平 payload:恒先 `task.proposal_submitted`(提案这一动作本身可审计),再按裁决追加 `task.proposal_accepted` / `task.proposal_rejected` / `task.proposal_merged`(合并事件带 `merge_target_task_id`)。
|
||
|
||
事件类型常量:`EVENT_SUBMITTED` / `EVENT_ACCEPTED` / `EVENT_REJECTED` / `EVENT_MERGED`。
|
||
|
||
## 4. 接入现状(已无条件接入)
|
||
|
||
**已落地于 `orchestrator/main.py`**(去中心化重构,无开关):WS `task_proposal` 分支 → `handle_task_proposal`:构造 `TaskProposal` → `review_proposal`(置信度/去重合并/每 run 预算 `AGENT_PROPOSAL_BUDGET`)→ ACCEPT 即 `task_queue.create_task` 入队为真实 PENDING 任务(带 lineage、`source=agent_proposed`、发标准 `task.created`);提案生命周期存 `run.metadata["proposals"]`(**内部遥测,非 Manager 事件**)。这是蜂群唯一的分解路径。集成测试 `scripts/test-swarm-autonomous.py`。
|
||
|
||
模块本身(`autonomous_tasks.py`)仍是纯策略/数据层(无 Redis/WS/模型):`TaskProposal`/lineage/状态枚举、`review_proposal` 三路裁决、`ingest_accepted_proposal` 映射、生命周期事件、`assert_not_master_origin` 守卫。
|
||
|
||
**仍为后续**:`expired` 过期判定仅定义枚举未实现;`Task`/`SwarmRun` 未加持久化提案字段(提案存于 `run.metadata`);真实 Agent 执行器基于 LLM 决定「提哪些子任务」为后续(`scripts/stub_agent.py` 已演示种子→提案)。
|
||
|
||
## 5. Agent 端发送(`agent/main.py`)
|
||
|
||
新增一个方法(与 `request_handoff` 同风格),由执行器在发现缺口时调用:
|
||
|
||
```python
|
||
async def propose_task(self, *, description, reason, confidence, origin_task_id,
|
||
trigger_event, shared_state_snapshot, agent_role="general",
|
||
required_capabilities=None, depends_on=None, title=None):
|
||
await self.safe_send({
|
||
"type": "task_proposal", "agent_id": self.agent_id,
|
||
"title": title, "description": description, "proposal_reason": reason,
|
||
"proposal_confidence": confidence, "agent_role": agent_role,
|
||
"required_capabilities": required_capabilities or [], "depends_on": depends_on or [],
|
||
"origin_task_id": origin_task_id, "trigger_event": trigger_event,
|
||
"shared_state_snapshot": shared_state_snapshot, "timestamp": time.time(),
|
||
})
|
||
```
|
||
|
||
并在 `handle_message` 的控制消息集合中加入 `task_proposal_ack`。
|
||
|
||
### 5.3 新增 Task 字段(`orchestrator/task_queue.py`,可选增强)
|
||
|
||
去重与审计已可由 `source="agent_proposed"` + `context["proposal"]` 承载,**无需**新增 Task 字段即可工作。如需一等公民查询,可选增(默认不破坏现有契约):
|
||
|
||
- `Task.proposal_id: Optional[str] = None`
|
||
- `Task.proposed_by_agent_id: Optional[str] = None`
|
||
|
||
### 5.4 新增 SwarmRun 字段(`orchestrator/swarm_runtime.py`)
|
||
|
||
提案预算与提案台账建议落到 run 上(与 `collaboration` / `decisions` 同为内部遥测,**非** Manager 事件):
|
||
|
||
```python
|
||
# 已提案任务台账(内部遥测,不入 HM 事件注册表)。
|
||
proposals: List[Dict[str, Any]] = Field(default_factory=list)
|
||
```
|
||
|
||
预算可暂存于既有 `metadata["proposal_budget"]`(如 §5.1 所示),无需新增字段;若要显式化可加 `proposal_budget: int = 3`。配套可加 `record_proposal(run, proposal_dict)` 方法(仿 `record_decision`)。
|
||
|
||
### 5.5 影响范围声明(PR 模板用)
|
||
|
||
- Client:否(除非同时落 §5.2 Agent 端)。
|
||
- Manager:**接口不变**;提案事件为内部遥测,未改 HM 事件注册表 / 回调 / 审批链 / 计费 / 审计字段语义。
|
||
- agent_swarm:是(新增 WS `task_proposal` 分支、派发入队、SwarmRun 遥测字段)。
|
||
- 密钥 / 计费 / 审计 / 发布链路:不涉及。
|
||
|
||
## 6. 测试
|
||
|
||
```
|
||
pip install -r orchestrator/requirements.txt -r agent/requirements.txt
|
||
..\.venv\Scripts\python.exe scripts/test-autonomous-tasks.py
|
||
```
|
||
|
||
模块级、无需 Redis / WS / 模型密钥:模拟 Agent 基于共享状态快照提案 → 策略 accept/reject/merge → ACCEPTED 提案产出带完整 lineage 的新 PENDING 任务 spec + 状态机转移 + 生命周期事件。当前 47 项断言全部通过。
|