Files
HomeAgent/internal
JianFeeeee e6c1bfa6bf fix(spawn): 子 Agent 报告如实 + 跑满预算不再丢弃成果 + 提示词补执行纪律
三处修复,均来自生产日志实证(本机 systemd 实例,2026-10-08)。

## 1. 报告轮数在说谎(max_turns != 5 时必现)

生产日志:`spawn_child` 声明「最多 10 轮」,子 Agent 实际跑满 10 轮后被判定
「子 Agent 执行超时(超过 5 轮)」——**那个 5 是硬编码的**,与真实轮数无关。
排查时会被这个假数字带偏(我本人就先据此去查「为什么是 5」)。

改法:新增 `completed` / `reachedLimit` 两个标志如实分类收尾原因,
文案用 `maxTurns` 插值。顺带修两个边界:
- 模型返回**空文本**也算「回答完了」,此前会被误报成故障;
- 「跑满预算」不是「超时」,不再如此描述。

## 2. 跑满预算时丢弃全部中间成果

原实现直接回一句「超时」,子 Agent 前几轮已取到的工具结果**全部丢弃**。
父 Agent 拿到不可操作的信号只能重 spawn —— 生产日志里 `child_5→6→7` 正是
同一任务连试三次,每次重烧一整个上下文(也是实例内存偏高的成因之一)。

改法:新增 `salvageChildSummary()`,在**失败路径**上多做一次不带工具的调用
(`ToolChoice: "none"`),把已有成果落成文本并标注「可能不完整」。
成本权衡:多一次 LLM 调用 ≪ 父重 spawn 烧掉整个上下文。
正常完成的子任务**不会**触发它(有判据钉住,避免白花调用)。

## 3. 提示词缺「执行纪律」与「工具执行顺序」

子 Agent 的提示词原先只有 3 行,而父有 7 个章节。缺失的直接后果(生产日志):

    child_1 done: I'll start by searching for each school's admissions catalog information.
    child_3 done: 我将逐校用官方渠道核实。先并行检索四校的招生专业目录信息。

**它把「宣告计划」当成任务完成了**——因为退出判据只看模型有没有返回 tool_calls,
而「I'll start by…」之后就不再调工具。父的提示词里早有同类先例
(【记忆清理指令】:「必须实际调用…不能只回复文本」「不要只描述计划而不执行」),
子这里一句都没有。

另缺【工具执行顺序】:同轮多个 tool_call 默认**并行**,而子不知道
「依赖前一步结果的调用必须分两轮」,多步任务因此被塞进一轮。

★ 循环判据**未改动**(它是对的:模型确实不再要求工具了)——
靠提示词让模型不要过早停止调用,而不是放宽判据。

## 验证

- 新增 `spawn_replenish_test.go`:4 组判据覆盖 max_turns ∈ {1,5,10,14}、
  成果保留、正常完成不触发收尾、日志含轮次/预算/工具名
- **变异测试**:把轮数改回硬编码 5 / 去掉收尾提炼 / 删掉子日志 → 三个变异全部被杀
- `go test ./internal/agent/core/ -count=1` 绿;`-race` 绿

注:本提交含一行随 module 迁移的 import 路径更新(spawn.go 的 agentAPI 导入)。
2026-10-08 10:40:53 +08:00
..