feat: add plan mode (enter/exit/completion check/verification gate/periodic hints)
This commit is contained in:
@@ -1,13 +1,8 @@
|
|||||||
"""Desktop Pet with Skin System — Cross-platform with True Transparency"""
|
"""Desktop Pet with Skin System — Cross-platform with True Transparency"""
|
||||||
import os
|
import os, re, sys, json, threading, io
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import json
|
|
||||||
import threading
|
|
||||||
from http.server import HTTPServer, BaseHTTPRequestHandler
|
from http.server import HTTPServer, BaseHTTPRequestHandler
|
||||||
from urllib.parse import urlparse, parse_qs
|
from urllib.parse import urlparse, parse_qs
|
||||||
from PIL import Image, ImageDraw, ImageFont, ImageOps
|
from PIL import Image, ImageDraw, ImageFont, ImageOps
|
||||||
import io
|
|
||||||
|
|
||||||
PORT = 51983
|
PORT = 51983
|
||||||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
@@ -784,7 +779,7 @@ if __name__ == '__main__':
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
if sys.platform == 'darwin':
|
if sys.platform == 'darwin':
|
||||||
pet = MacPet()
|
pet = MacPet('vita')
|
||||||
pet.run()
|
pet.run()
|
||||||
else:
|
else:
|
||||||
pet = WinPet('vita')
|
pet = WinPet('vita')
|
||||||
|
|||||||
@@ -56,9 +56,9 @@ def render_sidebar():
|
|||||||
agent._pet_req = _pet_req
|
agent._pet_req = _pet_req
|
||||||
if not hasattr(agent, '_turn_end_hooks'): agent._turn_end_hooks = {}
|
if not hasattr(agent, '_turn_end_hooks'): agent._turn_end_hooks = {}
|
||||||
def _pet_hook(ctx):
|
def _pet_hook(ctx):
|
||||||
parts = [f"🔄 Turn {ctx.get('turn','?')}"]
|
parts = [f"Turn {ctx.get('turn','?')}"]
|
||||||
if ctx.get('summary'): parts.append(ctx['summary'])
|
if ctx.get('summary'): parts.append(ctx['summary'])
|
||||||
if ctx.get('exit_reason'): parts.append('✅ 任务已完成')
|
if ctx.get('exit_reason'): parts.append('任务已完成')
|
||||||
_pet_req(f'msg={quote(chr(10).join(parts))}')
|
_pet_req(f'msg={quote(chr(10).join(parts))}')
|
||||||
if ctx.get('exit_reason'): _pet_req('state=idle')
|
if ctx.get('exit_reason'): _pet_req('state=idle')
|
||||||
agent._turn_end_hooks['pet'] = _pet_hook
|
agent._turn_end_hooks['pet'] = _pet_hook
|
||||||
|
|||||||
28
ga.py
28
ga.py
@@ -415,6 +415,16 @@ class GenericAgentHandler(BaseHandler):
|
|||||||
next_prompt += "\n[SYSTEM TIPS] 正在读取记忆或SOP文件,若决定按sop执行请提取sop中的关键点(特别是靠后的)update working memory."
|
next_prompt += "\n[SYSTEM TIPS] 正在读取记忆或SOP文件,若决定按sop执行请提取sop中的关键点(特别是靠后的)update working memory."
|
||||||
return StepOutcome(result, next_prompt=next_prompt)
|
return StepOutcome(result, next_prompt=next_prompt)
|
||||||
|
|
||||||
|
def _in_plan_mode(self): return self.working.get('in_plan_mode')
|
||||||
|
def _exit_plan_mode(self): self.working.pop('in_plan_mode', None)
|
||||||
|
def enter_plan_mode(self, plan_path):
|
||||||
|
self.working['in_plan_mode'] = plan_path; self.max_turns = 80
|
||||||
|
print(f"[Info] Entered plan mode with plan file: {plan_path}"); return plan_path
|
||||||
|
def _check_plan_completion(self):
|
||||||
|
if not os.path.isfile(p:=self._in_plan_mode() or ''): return None
|
||||||
|
try: return len(re.findall(r'\[ \]', open(p, encoding='utf-8', errors='replace').read()))
|
||||||
|
except: return None
|
||||||
|
|
||||||
def do_update_working_checkpoint(self, args, response):
|
def do_update_working_checkpoint(self, args, response):
|
||||||
'''为整个任务设定后续需要临时记忆的重点。'''
|
'''为整个任务设定后续需要临时记忆的重点。'''
|
||||||
key_info = args.get("key_info", "")
|
key_info = args.get("key_info", "")
|
||||||
@@ -439,6 +449,12 @@ class GenericAgentHandler(BaseHandler):
|
|||||||
return StepOutcome({}, next_prompt="[System] Incomplete response. Regenerate and tooluse.")
|
return StepOutcome({}, next_prompt="[System] Incomplete response. Regenerate and tooluse.")
|
||||||
if 'max_tokens !!!]' in content[-100:]:
|
if 'max_tokens !!!]' in content[-100:]:
|
||||||
return StepOutcome({}, next_prompt="[System] max_tokens limit reached. Use multi small steps to do it.")
|
return StepOutcome({}, next_prompt="[System] max_tokens limit reached. Use multi small steps to do it.")
|
||||||
|
|
||||||
|
if self._in_plan_mode() and any(kw in content for kw in ['任务完成', '全部完成', '已完成所有', '🏁']):
|
||||||
|
if 'VERDICT' not in content and '[VERIFY]' not in content and '验证subagent' not in content:
|
||||||
|
yield "[Warn] Plan模式完成声明拦截。\n"
|
||||||
|
return StepOutcome({}, next_prompt="⛔ [验证拦截] 检测到你在plan模式下声称完成,但未执行[VERIFY]验证步骤。请先按plan_sop §四启动验证subagent,获得VERDICT后才能声称完成。")
|
||||||
|
|
||||||
# 2. 检测"包含较大代码块但未调用工具"的情况
|
# 2. 检测"包含较大代码块但未调用工具"的情况
|
||||||
# 关键特征:恰好1个大代码块 + 代码块直接结尾(后面只有空白)
|
# 关键特征:恰好1个大代码块 + 代码块直接结尾(后面只有空白)
|
||||||
code_block_pattern = r"```[a-zA-Z0-9_]*\n[\s\S]{50,}?```"
|
code_block_pattern = r"```[a-zA-Z0-9_]*\n[\s\S]{50,}?```"
|
||||||
@@ -461,7 +477,12 @@ class GenericAgentHandler(BaseHandler):
|
|||||||
"并明确是否还需要额外的实际操作。"
|
"并明确是否还需要额外的实际操作。"
|
||||||
)
|
)
|
||||||
return StepOutcome({}, next_prompt=next_prompt)
|
return StepOutcome({}, next_prompt=next_prompt)
|
||||||
# 3. 正常情况:直接将回复返回给用户并结束循环
|
|
||||||
|
if self._in_plan_mode():
|
||||||
|
remaining = self._check_plan_completion()
|
||||||
|
if remaining == 0:
|
||||||
|
self._exit_plan_mode(); yield "[Info] Plan完成:plan.md中0个[ ]残留,退出plan模式。\n"
|
||||||
|
|
||||||
yield "[Info] Final response to user.\n"
|
yield "[Info] Final response to user.\n"
|
||||||
return StepOutcome(response, next_prompt=None)
|
return StepOutcome(response, next_prompt=None)
|
||||||
|
|
||||||
@@ -510,6 +531,11 @@ class GenericAgentHandler(BaseHandler):
|
|||||||
elif turn % 7 == 0:
|
elif turn % 7 == 0:
|
||||||
next_prompt += f"\n\n[DANGER] 已连续执行第 {turn} 轮。禁止无效重试。若无有效进展,必须切换策略:1. 探测物理边界 2. 请求用户协助。如有需要,可调用 update_working_checkpoint 保存关键上下文。"
|
next_prompt += f"\n\n[DANGER] 已连续执行第 {turn} 轮。禁止无效重试。若无有效进展,必须切换策略:1. 探测物理边界 2. 请求用户协助。如有需要,可调用 update_working_checkpoint 保存关键上下文。"
|
||||||
elif turn % 10 == 0: next_prompt += get_global_memory()
|
elif turn % 10 == 0: next_prompt += get_global_memory()
|
||||||
|
|
||||||
|
if (_plan := self._in_plan_mode()) and turn >= 10 and turn % 5 == 0:
|
||||||
|
next_prompt = f"[Plan Hint] 你正在计划模式。必须 file_read({_plan}) 确认当前步骤,回复开头引用:📌 当前步骤:...\n\n" + next_prompt
|
||||||
|
if _plan and turn >= 70: next_prompt += f"\n\n[DANGER] Plan模式已运行 {turn} 轮,已达上限。必须 ask_user 汇报进度并确认是否继续。"
|
||||||
|
|
||||||
injkeyinfo = consume_file(self.parent.task_dir, '_keyinfo')
|
injkeyinfo = consume_file(self.parent.task_dir, '_keyinfo')
|
||||||
injprompt = consume_file(self.parent.task_dir, '_intervene')
|
injprompt = consume_file(self.parent.task_dir, '_intervene')
|
||||||
if injkeyinfo: self.working['key_info'] = self.working.get('key_info', '') + f"\n[MASTER] {injkeyinfo}"
|
if injkeyinfo: self.working['key_info'] = self.working.get('key_info', '') + f"\n[MASTER] {injkeyinfo}"
|
||||||
|
|||||||
@@ -1,69 +1,261 @@
|
|||||||
# Plan Mode SOP
|
# Plan Mode SOP
|
||||||
|
|
||||||
**触发**:3步以上有依赖/多文件协同/条件分支/需并行 | **禁用**:1-2步简单任务直接做
|
**触发**:3步以上有依赖/多文件协同/条件分支/需并行 | **禁用**:1-2步简单任务直接做
|
||||||
**工作目录**:`./plan_XXX/`(XXX=任务英文短名)
|
任务开始前必须先创建工作目录 `./plan_XXX/`(XXX=任务英文短名)
|
||||||
## 规划态(按序执行)
|
使用code_run({'_inline_eval':True, 'script':'handler.enter_plan_mode("./plan_XXX/plan.md")'})进入plan模式(使用未在schema中描述的秘密参数_inline_eval)
|
||||||
**步骤1:创建文件夹 + 存checkpoint**
|
|
||||||
```
|
---
|
||||||
[任务] 产出 ./plan_XXX/plan.md | [需求] 一句话 | [约束] 关键限制
|
|
||||||
[进度] 即将读领域SOP | ⚡写完plan后必须重读本SOP步骤3切换执行态
|
## 一、探索态(规划前置,必须执行)
|
||||||
```
|
|
||||||
**步骤2:读领域SOP → 写plan骨架**
|
⛔ **硬性规则(先读再做)**:
|
||||||
先读相关SOP,立即写骨架。允许"⚠待确认",禁止以"没调研清楚"推迟。
|
|
||||||
**骨架格式**:
|
- **主agent禁止直接执行环境探测**(必须委托subagent,无例外)
|
||||||
```
|
- 主agent只做:创建目录、读SOP索引、启动subagent、读取结论
|
||||||
|
- subagent只读探测,禁止修改任何文件、执行有副作用的操作
|
||||||
|
- **探索subagent启动失败时:排查原因→重试,最多2次。禁止主agent回退为自己探测**
|
||||||
|
|
||||||
|
**目标**:在写任何计划之前,搞清3件事:
|
||||||
|
① 环境现状(有什么、缺什么) ② 可用SOP ③ 关键不确定点
|
||||||
|
|
||||||
|
**为什么必须用subagent**:主agent上下文是最稀缺资源,探测长输出会挤占规划执行空间。
|
||||||
|
|
||||||
|
### 步骤1:创建目录(必做) + SOP匹配 + 设置plan标志(主agent直接做)
|
||||||
|
|
||||||
|
1. 创建工作目录 `mkdir plan_XXX/`
|
||||||
|
2. 读 `sop_index.md` 匹配可用领域SOP
|
||||||
|
3. 更新checkpoint:`[任务] XXX | [需求] 一句话 | [约束] 关键限制 | [匹配SOP] ... | [进度] 探索态`
|
||||||
|
|
||||||
|
### 步骤2:启动探索subagent(监察模式)
|
||||||
|
|
||||||
|
按 subagent.md 启动探索subagent,**加 `--verbose`** 开启监察模式,input要点:
|
||||||
|
|
||||||
|
- **任务**:探测环境信息,写入 `plan_XXX/exploration_findings.md`
|
||||||
|
- **探测项**(按任务类型选做,不是全做):
|
||||||
|
- 代码类 → 关键文件结构、依赖、入口点
|
||||||
|
- 浏览器类 → 目标页面当前状态、可交互元素
|
||||||
|
- 自动化类 → 环境检查(which/pip/路径/权限)
|
||||||
|
- 数据类 → 抽样数据(首5行+尾5行+总量)
|
||||||
|
- **输出格式**:`## 环境现状` / `## 关键发现` / `## 风险/不确定点`
|
||||||
|
- **约束**:只读探测,禁止修改文件,≤10次工具调用
|
||||||
|
- **复杂度评估**:探测时注意记录数据规模(文件数、行数、页面数),写入findings供规划时判断委托
|
||||||
|
|
||||||
|
### 步骤3:监察等待 + 读取结论
|
||||||
|
|
||||||
|
主agent主动观察output.txt进度(`--verbose`输出含原始工具结果),而非无脑sleep轮询:
|
||||||
|
|
||||||
|
1. **观察**:读output.txt,审查subagent的探测方向和原始数据
|
||||||
|
2. **纠偏**(按需):
|
||||||
|
- 方向偏了 → 写 `_intervene` 追加指令纠正
|
||||||
|
- 缺少关键上下文 → 写 `_keyinfo` 注入信息
|
||||||
|
- 已获取足够信息 → 写 `_stop` 提前终止,节省轮次
|
||||||
|
3. **收取**:等待 `[ROUND END]`,读取 `exploration_findings.md`
|
||||||
|
|
||||||
|
**产出**:`exploration_findings.md`(结构化发现报告),主agent基于此进入规划态,写入plan.md头部的「探索发现」段。主agent在监察过程中获得的一手认知也可直接用于规划。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 二、规划态(含审查门)
|
||||||
|
|
||||||
|
### 步骤4:读领域SOP → 写plan.md
|
||||||
|
|
||||||
|
先读探索态匹配到的SOP,然后写plan骨架。允许"⚠待确认",禁止以"没调研清楚"推迟。
|
||||||
|
|
||||||
|
**[D] 委托标注规则**:写每个步骤时,结合探索发现评估操作量,符合以下任一条件则标 `[D]`:
|
||||||
|
|
||||||
|
- 需要读取大量代码/文件(预估 >3个文件或 >100行)
|
||||||
|
- 需要浏览网页并提取信息
|
||||||
|
- 需要执行 3 次以上重复性操作
|
||||||
|
- 需要运行测试/构建并分析输出
|
||||||
|
|
||||||
|
不标 `[D]` 的情况:读/更新 plan.md、单文件小幅修改、ask_user、简单一次性命令
|
||||||
|
|
||||||
|
**plan.md格式**:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
<!-- EXECUTION PROTOCOL (每轮必读,这是你的执行指南)
|
||||||
|
1. file_read(plan.md),找到第一个 [ ] 项
|
||||||
|
2. 该步标注了SOP → file_read 该SOP的🔑速查段
|
||||||
|
3. 执行该步骤 + Mini验证产出
|
||||||
|
4. file_patch 标记 [ ] → [✓]+简要结果,然后回到步骤1继续下一个[ ]
|
||||||
|
5. 所有步骤(包括验证步骤)标记完成后 → 终止检查:file_read(plan.md)确认0个[ ]残留
|
||||||
|
⚠ 禁止凭记忆执行 | 禁止跳过验证步骤 | 禁止未经终止检查就结束 | 禁止停下来输出纯文字汇报
|
||||||
|
💡 搬砖活(读大量代码/文件/网页/重复操作)优先委托subagent,保持主agent上下文干净
|
||||||
|
-->
|
||||||
# 任务标题
|
# 任务标题
|
||||||
需求:一句话 | 约束:关键限制
|
需求:一句话 | 约束:关键限制
|
||||||
1. [ ] 步骤1简述
|
|
||||||
2. [P] 步骤2简述(并行,读subagent_sop.md执行Map模式)
|
|
||||||
依赖:1
|
|
||||||
3. [?] 步骤3(条件分支)
|
|
||||||
条件:X成功→3.1,否则→3.2
|
|
||||||
```
|
|
||||||
**标记**:`[ ]`待做 | `[✓]`完成 | `[✗]`失败 | `[P]`并行 | `[?]`条件分支
|
|
||||||
**[P]标记条件**(全YES才可标):
|
|
||||||
□ 2+步骤可同时? □ 无数据依赖? □ 产出不同文件? □ 节省>20%时间?
|
|
||||||
**子任务目录**:subagent产出放 `./plan_XXX/subtask_name/`
|
|
||||||
**探索规则**:有⚠项→逐项探索,每轮更新plan+checkpoint | 连续3轮无进展→用当前最佳方案
|
|
||||||
**⛔ 写完骨架后禁止执行。必须先完成步骤3。**
|
|
||||||
|
|
||||||
**步骤3:转入执行态**
|
## 探索发现
|
||||||
|
- 发现1:XXX(来源:file_read/web_scan/code_run)
|
||||||
|
- 发现2:YYY
|
||||||
|
- 不确定点:ZZZ
|
||||||
|
|
||||||
|
## 执行计划
|
||||||
|
1. [ ] 步骤1简述
|
||||||
|
SOP: xxx_sop.md
|
||||||
|
2. [D] 步骤2简述(委托subagent执行)
|
||||||
|
SOP: yyy_sop.md
|
||||||
|
依赖:1
|
||||||
|
3. [P] 步骤3简述(并行,读subagent.md执行Map模式)
|
||||||
|
SOP: yyy_sop.md
|
||||||
|
4. [?] 步骤4(条件分支)
|
||||||
|
SOP: (无) ← 高风险
|
||||||
|
条件:X成功→4.1,否则→4.2
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 验证检查点
|
||||||
|
N+1. [ ] **[VERIFY] 启动独立验证subagent**
|
||||||
|
SOP: verify_sop.md
|
||||||
|
操作:准备verify_context.json → 启动验证subagent → 读取VERDICT → 按结果处理
|
||||||
|
⚠ 不可跳过,不可在未启动subagent的情况下标记[✓]
|
||||||
|
|
||||||
|
---
|
||||||
```
|
```
|
||||||
CALL update_working_checkpoint(
|
|
||||||
key_info='[执行] plan.md | 当前:1.1 | ⚡有[P]标记必须读subagent_sop.md执行Map模式'
|
### 步骤5:自检清单(主agent逐项检查)
|
||||||
)
|
|
||||||
```
|
- □ 探索发现是否都反映在plan中?(没遗漏关键约束)
|
||||||
## 执行态循环
|
- □ 每步的SOP标注是否合理?(SOP真的能解决该步?)
|
||||||
1. 读plan.md → 定位当前`[ ]`项
|
- □ 步骤间依赖是否正确?(有没有隐含依赖没写出来)
|
||||||
2. **检查并行**:
|
- □ 高风险步骤(SOP:无/不可逆)有没有清晰的执行思路?
|
||||||
```
|
- □ 步骤粒度是否合适?(禁止"处理所有文件",必须展开具体条目)
|
||||||
IF has_mark('[P]'):
|
- □ **复杂/繁琐步骤是否标注了[D]?**(读大量代码/网页/重复操作必须委托subagent)
|
||||||
CALL file_read('subagent_sop.md')
|
- □ **是否包含"验证检查点"section,且有[VERIFY]步骤?(必须有,这是强制步骤)**
|
||||||
# 按SOP创建context.json(含绝对路径)+ input.txt
|
|
||||||
# ⚠ subagent必须从context.json读取绝对路径写入文件
|
### 步骤6:用户确认
|
||||||
ELSE:
|
|
||||||
执行当前步骤
|
ask_user 确认plan后才能转入执行态。**⛔ 用户未确认不得执行。**
|
||||||
```
|
|
||||||
3. 执行该项
|
### 步骤7:转入执行态
|
||||||
4. **收尾(必须执行,不可跳过)**:
|
|
||||||
```
|
更新checkpoint:`[执行] plan.md | 当前:步骤1 | ⚡有[P]标记必须读subagent.md执行Map模式`
|
||||||
# ⚠ 进度标记更新是强制要求,每步完成后必须执行
|
|
||||||
file_patch(plan, '[ ] 当前步骤' → '[✓] 当前步骤')
|
---
|
||||||
file_read(plan) # 验证标记已更新 + 找下一步
|
|
||||||
update_working_checkpoint('[进度] 步骤N已完成 | 下一步:...')
|
## 三、执行态循环
|
||||||
```
|
|
||||||
5. **Checkpoint验证(每3步或关键节点)**:
|
> **核心原则:连续执行,不停顿汇报。** 做完一步立即 file_read(plan.md) 找下一个 `[ ]`,直到全部完成。
|
||||||
```
|
|
||||||
file_read(plan) # 检查:所有已执行步骤是否标[✓]
|
### 每轮流程
|
||||||
IF 有遗漏标记:
|
|
||||||
立即补标 file_patch(...)
|
1. **读plan** — `file_read(plan.md)` 定位第一个 `[ ]` 项
|
||||||
```
|
2. **读SOP** — 该步标注了SOP → 先 file_read 该SOP
|
||||||
6. 全部完成 → 汇总结果 → 清理checkpoint
|
3. **检查标记** — `[D]`标记 → 必须委托subagent执行,主agent只收结果摘要;`[P]`标记 → 读 subagent_sop.md 执行Map模式;`[?]`条件 → 评估条件选分支,未选标[SKIP]
|
||||||
## 失败处理
|
4. **执行** — 无特殊标记的步骤由主agent自己执行
|
||||||
|
5. **Mini验证** — 快速确认产出存在且合理(file_read确认非空、检查exit code等)
|
||||||
|
6. **标记完成** — `file_patch` 标记 `[ ]` → `[✓ 简要结果]`(进度写入plan.md)
|
||||||
|
7. **继续** — 立即回到步骤1,file_read(plan.md) 执行下一个 `[ ]`
|
||||||
|
|
||||||
|
### 终止检查(最后一步标记后,不可跳过)
|
||||||
|
|
||||||
|
file_read(plan.md) 全文扫描,确认所有步骤(含[VERIFY])均为 `[✓]`/`[✗]`,0个 `[ ]` 残留。
|
||||||
|
输出:`🏁 终止检查:[总步数]步全部完成,0个[ ]残留 → 任务结束`
|
||||||
|
若发现遗漏 → 继续执行,禁止声称完成。
|
||||||
|
|
||||||
|
### ⚠ 执行态禁令
|
||||||
|
|
||||||
|
- **禁止凭记忆执行**:每次做新步骤前必须 `file_read(plan.md)`,不可"我记得下一步是..."
|
||||||
|
- **禁止跳过验证步骤**:[VERIFY]步骤是强制的,不可以"任务都做完了"为由跳过
|
||||||
|
- **禁止未经终止检查就结束**:最后一步标记后必须 file_read 全文扫描确认0个[ ]残留,输出🏁终止确认行
|
||||||
|
- **禁止停下来输出纯文字汇报**:做完一步后必须立即 file_read(plan.md) 继续,不要输出进度总结
|
||||||
|
|
||||||
|
### 💡 动态委托原则
|
||||||
|
|
||||||
|
即使步骤未标 `[D]`,执行中发现以下情况时,主动委托 subagent 处理:
|
||||||
|
|
||||||
|
- 需要读取大量代码/文件才能理解上下文(>3个文件或预估 >100行)
|
||||||
|
- 需要反复试错调试
|
||||||
|
- 需要浏览网页提取信息
|
||||||
|
|
||||||
|
做法:起 subagent 完成具体操作,要求返回精简摘要,主 agent 基于摘要继续决策。保持主 agent 上下文干净是第一优先级。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 四、验证态(subagent独立验证)
|
||||||
|
|
||||||
|
> 全部步骤[✓]后进入。**强制**启动独立subagent做对抗性验证,避免上下文污染。
|
||||||
|
|
||||||
|
### 触发条件
|
||||||
|
|
||||||
|
- 所有执行步骤标记为 `[✓]`
|
||||||
|
- **所有plan模式任务必须经subagent验证**(主agent有确认偏误,易被表面成功迷惑)
|
||||||
|
|
||||||
|
### 步骤8:准备验证上下文
|
||||||
|
|
||||||
|
在 `./plan_XXX/` 下创建 `verify_context.json`,包含:
|
||||||
|
|
||||||
|
- task_description:原始任务描述(用户原话)
|
||||||
|
- plan_file:plan.md绝对路径
|
||||||
|
- task_type:code|data|browser|file|system
|
||||||
|
- deliverables:交付物列表(type/path/expected)
|
||||||
|
- required_checks:必做检查列表(check/tool)
|
||||||
|
|
||||||
|
**传什么**:任务描述、plan路径、交付物清单、必做检查。**不传**:执行过程、调试记录。
|
||||||
|
|
||||||
|
### 步骤9:启动验证subagent
|
||||||
|
|
||||||
|
按 subagent.md 标准流程启动验证subagent,input要点:
|
||||||
|
|
||||||
|
- **角色**:你是独立验证者,工作是对抗性验证(证明交付物不能用)
|
||||||
|
- **第一步强制**:file_read verify_sop.md 完整阅读验证SOP
|
||||||
|
- **按 verify_sop.md 第3节**选择对应task_type的验证策略执行
|
||||||
|
- **每个检查必须有工具调用证据**(实际执行,不是叙述)
|
||||||
|
- **任务描述**:(填入原始任务描述)
|
||||||
|
- **交付物清单**:(填入deliverables列表)
|
||||||
|
- **输出**:在 result.md 中按 verify_sop.md 第6节格式输出,最后一行 `VERDICT: PASS / FAIL / PARTIAL`
|
||||||
|
- **约束**:3轮内完成,每轮至少1个实际工具调用
|
||||||
|
|
||||||
|
同时传入 verify_context.json 的路径,让subagent自行读取详细上下文。
|
||||||
|
|
||||||
|
### 步骤10:收集验证结果
|
||||||
|
|
||||||
|
轮询 output.txt 等待 `[ROUND END]`,然后读取 result.md:
|
||||||
|
|
||||||
|
1. **找VERDICT行**:读取result.md最后几行,提取 `VERDICT: PASS/FAIL/PARTIAL`
|
||||||
|
2. **检查有效性**:如果所有PASS项都没有工具调用输出(只有叙述),视为验证无效,按FAIL处理
|
||||||
|
3. **按结果处理**:
|
||||||
|
- **PASS** → 进入任务完成收尾
|
||||||
|
- **FAIL** → 进入修复循环
|
||||||
|
- **PARTIAL** → 主agent判断可接受则完成,否则修复
|
||||||
|
- **无VERDICT行** → 从output.txt提取关键信息,主agent自行判断PASS/FAIL
|
||||||
|
|
||||||
|
**任务完成收尾**(验证PASS后执行):
|
||||||
|
|
||||||
|
1. 标记plan.md中 `[VERIFY]` 步骤为 `[✓]`
|
||||||
|
2. 更新checkpoint:`[完成] XXX任务 | [产出] ... | [经验] ...`
|
||||||
|
3. 向用户确认任务完成
|
||||||
|
|
||||||
|
**重要**:只有在验证PASS后,才能标记[VERIFY]为[✓]并声称任务完成。如果验证FAIL,需要进入修复循环。
|
||||||
|
|
||||||
|
**Fallback**:若subagent未产出result.md(turn耗尽),从output.txt提取VERDICT关键信息。
|
||||||
|
|
||||||
|
### 修复循环(FAIL后)
|
||||||
|
|
||||||
|
FAIL → 提取具体失败项 → 回执行态修复(不重新规划) → 修复完成 → 再次启动验证subagent → 最多2轮FAIL-重试,超过 ask_user 介入
|
||||||
|
|
||||||
|
修复时:
|
||||||
|
|
||||||
|
1. 将FAIL项作为新步骤追加到plan.md(标记为 `[FIX]`)
|
||||||
|
2. 只修复失败项,不重做已PASS的部分
|
||||||
|
3. 修复完成后重新准备verify_context.json(只含失败项)
|
||||||
|
|
||||||
|
### 特殊场景处理
|
||||||
|
|
||||||
|
浏览器/键鼠/定时任务等场景:主agent执行操作并导出证据(截图/录屏/日志)→ subagent验证证据文件。**禁止主agent自行判断PASS/FAIL**。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 五、失败处理
|
||||||
|
|
||||||
1. **记录**:checkpoint中 `step_X: [FAILED] 原因 (retry: N/3)`
|
1. **记录**:checkpoint中 `step_X: [FAILED] 原因 (retry: N/3)`
|
||||||
2. **重试**:网络超时→自动重试3次(2s/4s/8s) | 配置错误→询问用户 | 其他→标[✗]跳过
|
2. **重试**:网络超时→自动重试3次(2s/4s/8s) | 配置错误→询问用户 | 其他→标[✗]跳过
|
||||||
3. **subagent失败**:查stderr.log→明确错误主agent修正重启 | 未知错误重试1次 | 最多重启2次
|
3. **subagent失败**:查stderr.log→明确错误主agent修正重启 | 未知错误重试1次 | 最多重启2次
|
||||||
4. **依赖传播**:步骤失败后,后续依赖项标[SKIP]
|
4. **依赖传播**:步骤失败后,后续依赖项标[SKIP]
|
||||||
|
5. **plan有误**:回退到规划态修正plan.md,重新过审查门
|
||||||
|
|
||||||
## 强制约束
|
## 强制约束
|
||||||
|
|
||||||
- 每项必须有独立完成判据
|
- 每项必须有独立完成判据
|
||||||
- 禁止"处理所有文件",必须展开具体条目
|
- 禁止"处理所有文件",必须展开具体条目
|
||||||
- 一次只做一项;计划有误回规划态修正
|
- 一次只做一项;计划有误回规划态修正
|
||||||
|
|||||||
Reference in New Issue
Block a user