第二十章 任务内进化:搜索、反思与验证—修复
证据地位:本章综合公开研究与作者工程推导;近期演化研究以预印本为主,结论不等同于长期生产复现。控制流和费用表是教学示例。
任务内进化是在一次任务中根据新观察调整计划、候选和资源,通常不改变长期发布版本。只要候选能隔离、反馈足够快,它就适合做有界试验;但真实副作用未必容易回滚,不能仅因属于 L1 就认定风险较低。当前任务结束后,若没有另行验证并发布经验,下一次独立任务不会自动继承本次改进。
1. 本层的证据模板实例
| 字段 | 任务内实例 |
|---|---|
| 可变对象 | 当前计划、候选分支、临时反思、检索范围、分配预算 |
| 观测信号 | 工具错误、测试差异、环境状态、复核诊断、成本增量 |
| 归因方法 | 错误分类、假设—动作—结果链、固定环境下的候选比较 |
| 候选生成 | best-of-N、树搜索、独立工作单元、最小修复 |
| 评价隔离方式 | 开发诊断可回传;封存终测不进入修复上下文 |
| 门禁判据 | 必需检查通过、预算和副作用上限;失败集合只作诊断 |
| 发布方式 | 选定当前任务产物,不改全局配置 |
| 回滚粒度 | 分支、工作树和可恢复检查点 |
| 失败模式 | 无限重试、自我确认、错误反思、重复副作用、测试泄漏 |
2. 反思要绑定观察,采样也可以构成搜索
Reflexion 将环境反馈写成语言反思,在后续尝试中复用而不更新模型权重。它展示了文本反馈改变后续策略的路线,但反思是否正确仍依赖外部反馈。Reflexion 同一模型可能把权限拒绝解释为命令写法错误,然后反复换命令。有效的反思应绑定动作编号、错误类别、产物和仍未排除的解释,写成“观察—贡献假设—下一试验”。
best-of-N 可以从相同提示随机采样,再由外部选择器筛选;显式写出不同假设不是搜索成立的必要条件。不过,候选高度相关或选择器不可靠时,增加 N 未必值得。仓库修复可以比较“恢复 API”“补兼容层”“改调用方”,并记录每条路线的适用证据,使有限预算覆盖不同解释。
有三类选择器可串联使用:编译、测试和约束校验先筛明确错误;评分准则下的复核者判断难以形式化的质量;责任人处理业务取舍。模型复核应盲化候选顺序并保留分歧,其总分不能覆盖硬检查失败。通过硬门后再比较成本、改动范围和风险,选择规则应在看到候选前确定。
3. 一个会推进、会扣费、会停止的搜索
下面是控制流示意,宿主负责预算、隔离和事件记录,候选不能修改这些对象。paid 包装每一个生成、执行和验证动作:调用前预留该动作的费用、时间及调用数上限,宿主在上限处停止,调用结束后结算实耗;异常也结算,拿不到可靠计量时保守扣留预留额并登记待对账。未获得预算就不能启动动作。
代码里的propose、run_in_fresh_branch和development_checks只构造延迟执行的Operation描述,不调用模型或工具。获得ticket后,host.run_with_limits才执行该描述。若实现使用普通立即执行的函数,应把闭包交给paid,例如paid("execute", lambda: run_branch(c)),不能在求值参数时就先花费预算。本书运行测试采用前一种显式描述对象的约定。
paid(kind, operation):
ticket = budget.reserve_upper_bound(kind) # 不足则抛 BudgetExhausted
try:
return host.run_with_limits(operation, ticket)
finally:
budget.settle(ticket, measured_usage_or_reserved_upper_bound)
frontier = queue([(baseline_state, depth=0)])
visited = set()
verified = []
expansions = 0
stalled = 0
reason = "frontier_empty"
try:
while frontier and expansions < max_expansions and stalled < max_stalled:
state, depth = frontier.pop() # 取出并移除
key = hash(state.artifact, state.environment, state.hypothesis)
if key in visited or depth >= max_depth:
continue
visited.add(key)
expansions += 1
progressed = false
candidates = paid("generate", propose(state, max_children))
for c in candidates: # 结果数由宿主截在 max_children
result = paid("execute", run_in_fresh_branch(c))
verdict = paid("verify", development_checks(result))
record(c, result, verdict)
if verdict.integrity_alarm:
raise IntegrityAlarm
if verdict.all_required_pass:
verified.append(seal(c, verdict))
if verdict.comparable_progress and c.state_key not in visited:
frontier.push((c.state, depth + 1))
progressed = true
stalled = 0 if progressed else stalled + 1
reason = stop_reason(frontier, expansions, stalled)
except BudgetExhausted:
reason = "budget_exhausted"
except (IntegrityAlarm, UnknownEffect):
quarantine_and_reconcile()
return incomplete("integrity_or_effect_unresolved")
except HostActionError as error:
reason = record_error_and_stop(error)
if verified:
return best_by_preregistered_rule(verified), reason
return incomplete(reason) # 空候选、全失败均不可宣称成功验证不通过但有可比较进展的分支可以继续搜索;验证通过的产物要封存,后续改动不能继承旧结论。达到深度、展开数、无进展或总预算上限,就返回已有合格候选或明确未完成。生成器返回空集合也会消耗一次展开机会和实际费用,不能无成本无限重试。用于防止重复展开的状态键应包含环境与假设,不能只用聊天摘要。
开发检查通过只产生待确认产物。合同要求封存终测或外部提交时,控制器还须完成对应门禁,才可宣称业务完成。终测费用应预先保留,不得把预算全部花在搜索后再临时省略验收。
以下虚构轨迹用“费用单位”说明账目,不代表任何 API 价格。总预算 15,预留最终确认 2,开发搜索可用 13;共同生成三条路线花费 3,每条执行与开发验证分别为 2 和 1:
| 路线 | 隔离执行 | 开发验证 | 本路线实耗 | 阶段结果 |
|---|---|---|---|---|
| A:恢复旧 API | 执行完成 | 兼容检查失败 | 3 | 不入已验证集合 |
| B:增加兼容层 | 执行完成 | 新增高严重度失败 | 3 | 拒绝继续扩展 |
| C:修正调用方 | 执行完成 | 必需检查全部通过 | 3 | 封存待确认 |
共同生成 3 加三条路线 9,开发实耗为 12;最终确认再花 2,总计 14,剩余 1。三条候选都应进搜索记录,但这是一个任务的三条分支,不是三个独立实验单位。如果最后 2 单位未获预留或确认失败,任务仍未完成。
4. 验证反馈与环境重试
固定版本和输入下稳定复现的失败,可称为确定性失败;根因仍可能未知。结果忽好忽坏是稳定性问题,也不自动等于外部环境故障。开发检查可以返回定位诊断,封存终测则只按第二十四章的协议回传结果。不能把终测失败全文交给代理修复,再称重测仍是独立确认。
候选 → 干净环境中的检查
├─ 必需检查通过 → 封存待确认
├─ 开发诊断失败 → 有界修复
├─ 不稳定或疑似环境失败 → 独立归类、按统一限额重试并保留账目
├─ 完整性告警 → 隔离并停止
└─ 无进展或预算耗尽 → 未完成、合法升级或人工接管实验主分析按事先分配的全部合格任务或运行计分。标记为 invalid_environment 的运行、未激活机制和没有成功返回的运行,都不能事后从这个分母筛掉。独立控制面确认的外部故障可以按两组相同的限额重试,保留原失败、关联尝试、最终结果和全部费用;重试没有增加一个新的实验单位。候选自己造成的内存耗尽、超时或进程破坏也不能由候选改标为外部故障。
全局环境事故可以按预注册规则暂停整批并作废结论,另建新批次;原批次的暴露和费用仍需报告。机制分析可以另看激活或环境有效的子集,但它回答的是条件性问题,不能替代部署策略的端到端效果。
进展也不能只数失败减少了多少。ΔF = |失败_before| − |失败_after| 仅适用于同一套检查。应一起列出已解决、新增、未运行的检查及严重度;跳过测试、改测试版本或用许多轻微修复掩盖一项严重失败,都不构成晋级。连续无进展时换假设或停止,阈值按任务成本预设。
5. 修计划、修状态与真实副作用
计划错误可从同一检查点换路线;状态已经被破坏则要恢复环境或新建分支。例如先升级依赖再修代码,回退时必须一起处理锁文件、缓存和后台进程,否则下一候选仍运行在混合状态。检查点应记录代码版本、依赖镜像、环境引用、待确认外部动作和事件位置。
工作树可以分支,邮件、工单、部署和数据写入却不能随候选任意复制。搜索阶段使用模拟、只读或受控预演;真实提交由选定候选在最新授权和幂等控制下执行。结果未知的调用先对账,不能借“再试一个分支”重复提交。回滚环境也不能把已经消耗的费用退回搜索预算。
不同错误需不同权限。INVALID_ARGUMENT 可在限额内修参数;TEST_FAILURE 需要新证据或假设;POLICY_DENIED 只能合法变更授权或停止;INFRASTRUCTURE 由控制面按统一规则重试并计费;UNKNOWN_EFFECT 暂停可能重复的动作直到对账完成。重试次数是配置,不是所有任务通用的常数。
6. 长项目靠产物和证据延续
Harness-of-Harness 在固定模型、基础 Harness、角色和运行策略下,组织规划、开发与 QA 循环。开发者修改产物,QA 检查冻结候选,后续规划使用项目产物和执行证据;隐藏基准评价不回传开发循环。这是同一项目的有界迭代,不是固定基础 Harness 在运行中改写自己,项目内状态也不自动成为跨独立任务的学习。Harness-of-Harness v1
这项工作提供了匹配开发轮数的对照,但轮数相同不代表模型调用、token 或总费用相同。其长期案例仍有未解决和重新打开的问题,因此进度要同时报告新增、关闭、重开和未决项。多个角色调用同一模型,可以分开权限,却不会自动消除相关判断错误。
Stellar Colosseum 把长证明组织为相互依赖的子问题,先探索路线,再以针对性反证和验证发现驱动局部修复,聚合时保留批评。它提醒我们:并行生成的段落不能仅凭各自看似合理就直接合并;改掉一个前提,还要重查依赖它的结论。这是作者报告的研究机制,本书没有独立复现其数学成果。Stellar Colosseum v2
7. 将预算用在可区分的解释上
平均分配 token 可能把资源耗在已被否定的路线。若测试失败可能来自代码、测试数据或环境,先复现最小失败并校验镜像与数据摘要,往往比直接生成三个补丁更有信息。记录预测与实际观察能提高诊断质量;随机采样仍是合法搜索方式,只需按候选相关性和选择收益证明它值得付费。
停止行为本身也应测量。组件实证研究中的计划机制在部分模型上帮助完成任务,在另一些设置中主要减少重复验证;计划与动作接口的比较仅发生在指定上下文配置,不能泛化为“多计划必然更好”。Harness 组件实证研究 v1
本层指标包括可信完成率、每任务候选数、全费用下的单位可信完成成本、重复副作用、无进展停止和人工接管。可确定执行的流程、弱验证器下的高损失任务,不一定适合开放搜索。更多思考轮数不是独立目标。
8. 如何结束当前任务
任务结束时可以提出经验候选,附原任务、证据、适用条件、反例、暴露标签与归因不确定性,再进入第二十一章的写入门。来自封存测试的诊断不能直接变成技能或训练样本;若经授权转作开发材料,派生产物也继承暴露标签,并更换后续终测数据。
失败也可产出有价值的发现,例如工具错误不可诊断、合同缺字段或检查不稳定,不必强行写成“以后都应该怎样做”。本层交付是产物、检查记录、完整费用和停止原因;跨任务复用需要另一次验证与发布决定。