# 阶段 3:上下文瘦身设计 本文档更新时间:2026-04-08 ## 0. 文档目的 这份文档只服务第 3 阶段“上下文瘦身”。 职责边界: 1. 记录当前已经和用户对齐的“瘦身后 execute 上下文骨架”。 2. 记录第 3 阶段的落地顺序、非目标和完成标准。 3. 作为后续上下文被裁剪后的继续施工依据。 明确不负责: 1. 不展开第 4 阶段 prompt 三层拆分的最终结构。 2. 不在这里继续讨论粗排和 abort 协议本身。 --- ## 1. 当前已经确认的收敛结论 以下结论已经对齐,后续不要再回摆: 1. 第 3 阶段先解决“上下文过胖、重复、噪音多”,不是先做 prompt 三层重构。 2. 工具参数定义和 JSON 调用示例,应该放在工具块里,不应该散落在别的 message。 3. 上下文结构应尽量通用化,后端只填“已有事实”,不要引入大量需要主观概括的分类字段。 4. `msg3` 和 `msg4` 必须是一一对应的一组: - `msg3` 是最近一次工具调用记录; - `msg4` 是与 `msg3` 对应的工具结果; - 如果当前没有最近工具调用,则 `msg3` / `msg4` 应一起缺省。 5. `msg4` 已经承载“最近一次工具结果”,`msg5` 不应再重复这部分内容。 6. `msg5` 只保留“有唯一来源的运行态事实”,不能放没有明确 owner 的解释性字段。 7. `当前步骤` 可以保留,唯一来源应是 `CommonState.CurrentPlanStep()`。 8. `当前目标` 当前不保留,因为没有稳定 owner,容易变成后端替模型总结下一步动作。 9. `最近观察` 当前不保留,因为没有稳定结构化来源;如果需要相关信息,应直接通过 `msg4` 表达最近一次工具结果。 10. `已确认语义` 这类过宽、难填、边界不清的字段不要进入第 3 阶段方案。 --- ## 2. 瘦身后的目标上下文骨架 这里记录的是第 3 阶段完成后,`execute` 阶段理想的 messages 骨架。 注意: 1. 这是“上下文瘦身后的骨架”,不是第 4 阶段 prompt 三层重构的最终形态。 2. 重点是减量、去重、压缩,而不是新增更多层次和字段。 ### 2.1 目标 message 列表 ```text message[0] role=system 执行规则: - 只围绕当前步骤行动 - 只输出严格 JSON - 不要伪造工具结果 - 读操作使用 action=continue + tool_call - 写操作使用 action=confirm + tool_call - 缺少关键信息时用 action=ask_user - 当前流程应终止时用 action=abort - next_plan / done 时 goal_check 必填 message[1] role=system 可用工具: - 工具名 - 工具说明 - 参数定义 - 最小 JSON 调用示例 message[2] role=assistant 历史摘要: - 用户目标 - 更早但仍有效的事实 - 最近失败摘要 - 已折叠说明(重复查询、过程话术、旧修正链已省略) message[3] role=assistant 最近一次工具调用记录(与 message[4] 成对) message[4] role=tool 最近一次工具结果 message[5] role=system 当前执行状态: - 当前轮次 - 当前步骤 - 当前步骤完成判定 message[6] role=user 请继续当前任务的执行阶段,严格输出 JSON。 ``` ### 2.2 各 message 的职责边界 #### message[0]:执行规则 只保留 execute 的稳定规则,不在这里重复工具参数,也不在这里放运行态数据。 #### message[1]:工具块 必须包含: 1. 工具名 2. 工具说明 3. 参数定义 4. 最小 JSON 调用示例 原因: 1. 这是 LLM 真实调用工具时最直接依赖的材料。 2. 如果只给工具名不给参数,模型很容易继续出现缺参调用。 3. 第 3 阶段里,工具块比“更长的执行 prompt”更重要。 #### message[2]:历史摘要 只保留“更早但仍有效”的摘要,不保留全量流水账。 允许保留的内容: 1. 用户原始目标 2. 当前会话中仍然有效的约束 3. 最近失败摘要 4. 历史折叠说明 不应保留的内容: 1. assistant 的过程话术,例如“我先看一下”“我接下来准备……” 2. 同工具同参数的多份原始重复结果 3. 整段 correction 往返原文 #### message[3] + message[4]:最近一组工具观察 这是 execute 在当前轮之前最关键、最新鲜的一组观察。 约束: 1. `message[3]` 和 `message[4]` 必须成对出现。 2. `message[3]` 是调用记录,`message[4]` 是与之对应的工具结果。 3. 若当前没有最近工具调用,则这两条一起省略。 4. 不能凭空生成“最近结果摘要”。 #### message[5]:当前执行状态 这里只允许放“有唯一来源的运行态事实”。 当前允许的字段: 1. 当前轮次 2. 当前步骤 3. 当前步骤完成判定 当前不允许的字段: 1. 当前目标 2. 最近观察 3. 已确认语义 4. 任何需要后端主观解释才能生成的字段 #### message[6]:本轮触发指令 作用很单一: 1. 明确“现在继续 execute” 2. 强化“严格输出 JSON” 不要在这里重复整份计划、工具说明或历史摘要。 --- ## 3. 一个更接近真实落地的示例 下面这个例子只用于校准方向,不要求文案逐字一致。 ```text message[0] role=system 你是 SmartFlow NewAgent 的执行器。 执行规则: 1. 只围绕当前步骤行动,不要跳到别的步骤。 2. 只输出严格 JSON,不要输出 markdown,不要输出 JSON 之外的解释。 3. 不要伪造工具结果。 4. 读操作用 action=continue + tool_call。 5. 写操作用 action=confirm + tool_call。 6. 缺少关键上下文且无法补齐时,输出 action=ask_user。 7. 当前流程应正式终止时,输出 action=abort。 8. 输出 action=next_plan 或 action=done 时,goal_check 必填。 message[1] role=system 可用工具: 1. get_overview 说明:查看当前窗口内整体分布。 参数: {} 调用示例: { "name": "get_overview", "arguments": {} } 2. find_free 说明:查找满足指定连续时长的空位。 参数: { "duration": "int, 必填", "day": "int, 可选" } 调用示例: { "name": "find_free", "arguments": { "duration": 2, "day": 5 } } 3. list_tasks 说明:列出任务,可按类别和状态过滤。 参数: { "category": "string, 可选", "status": "string, 可选, 可取 all/existing/suggested/pending" } 调用示例: { "name": "list_tasks", "arguments": { "status": "suggested" } } 4. move 说明:移动一个已预排任务(仅 suggested)。 参数: { "task_id": "int, 必填", "new_day": "int, 必填", "new_slot_start": "int, 必填" } 调用示例: { "name": "move", "arguments": { "task_id": 128, "new_day": 5, "new_slot_start": 1 } } 5. swap 说明:交换两个已落位任务。 参数: { "task_a": "int, 必填", "task_b": "int, 必填" } 调用示例: { "name": "swap", "arguments": { "task_a": 128, "task_b": 136 } } 6. batch_move 说明:批量原子移动多个任务。 参数: { "moves": [ { "task_id": "int, 必填", "new_day": "int, 必填", "new_slot_start": "int, 必填" } ] } 调用示例: { "name": "batch_move", "arguments": { "moves": [ { "task_id": 128, "new_day": 5, "new_slot_start": 1 }, { "task_id": 129, "new_day": 5, "new_slot_start": 3 } ] } } 7. unplace 说明:取消一个已落位任务。 参数: { "task_id": "int, 必填" } 调用示例: { "name": "unplace", "arguments": { "task_id": 128 } } 补充约束: - suggested 可以 move / swap / unplace - existing 不能 move / batch_move(仅作已安排事实层) - pending 不能 move / swap / unplace - 如果当前任务已经是 suggested,不要再把它当 pending 去 place message[2] role=assistant 历史摘要: - 用户目标:把任务类 [101,102] 调整到本周,尽量分布更均匀,周五不要太满。 - 当前已知事实: 1. 当前阶段是 execute 2. task_class_ids=[101,102] 3. 当前状态统计:existing=9, suggested=18, pending=0 - 最近一次失败摘要:find_free 缺少 duration 参数 - 更早的重复查询、过程话术、旧修正链已折叠 message[3] role=assistant tool_call: { "name": "get_overview", "arguments": {} } message[4] role=tool 规划窗口概览: - existing=9 - suggested=18 - pending=0 - 周三第5-8节 suggested 偏密 - 周五第1-2节有空位 - 周五第3-4节有空位 message[5] role=system 当前执行状态: - 当前轮次:2/8 - 当前步骤:先识别最值得调整的 suggested 任务和候选空位 - 当前步骤完成判定:能明确指出哪些任务值得调整,以及候选目标时段 message[6] role=user 请继续当前任务的执行阶段,严格输出 JSON。 ``` --- ## 4. 第 3 阶段的具体落地计划 ### 4.1 第一件事:先抓真实输入样本 目标: 1. 先拿到 `BuildExecuteMessages()` 真正送给模型的样本。 2. 不先拍脑袋改结构,先确认“胖点”究竟在 history、pinned,还是 runtime prompt。 当前可复用入口: 1. `backend/newAgent/prompt/execute.go` 2. `backend/newAgent/prompt/base.go` 3. `backend/newAgent/node/execute.go` 中已有 execute 上下文调试日志 产出: 1. 至少 2 到 3 份真实样本 2. 标出每个 message 的长度、重复点和噪音来源 ### 4.2 第二件事:补 execute 专用的历史压缩层 目标: 1. 不再把 `ConversationContext.History` 原样全量喂给 execute。 2. 形成“更早历史摘要 + 最近一组工具观察”的结构。 必须做的事: 1. 同工具同参数的重复查询,不保留多份原始结果。 2. 更早结果改成摘要,只保留最近一条原始结果。 3. assistant 过程话术不再进入后续模型历史。 4. correction / 工具失败链改成“最近失败摘要”,不要保留整段往返原文。 5. 保留合法的 assistant tool_call + tool result 成对消息,不能破坏 OpenAI 兼容格式。 ### 4.3 第三件事:压缩 pinned / runtime 的重复信息 目标: 1. 避免 `state summary + pinned + runtime user prompt` 三处重复抄同一份信息。 2. 保留最新、必要、唯一来源的信息。 原则: 1. 当前计划/当前步骤只保留最新版本,不做历史累积。 2. `msg5` 只保留“当前轮次 + 当前步骤 + 当前步骤完成判定”。 3. 工具结果只出现在 `msg4`,不在 `msg5` 再复述。 4. 粗排语义只保留一处,不要在多条 message 重复提醒。 ### 4.4 第四件事:最后再接 token budget 目标: 1. 在完成摘要化和去重后,再做按预算裁剪。 2. 避免一上来直接砍历史,把真正有价值的信息也一起砍掉。 可复用思路: 1. 参考旧链路 `agent.go` 的历史预算计算和裁剪流程。 2. 参考 `backend/pkg/token_budget.go` 中的预算估算与窗口裁剪函数。 要求: 1. 不一定照搬旧链路。 2. 但应复用“先估算、再裁剪、最后收敛会话窗口”的思路。 --- ## 5. 第 3 阶段明确不做什么 为了避免和第 4 阶段混淆,这一轮明确不做: 1. 不把 execute prompt 直接拆成三层正式文件结构。 2. 不在通用执行 prompt 里重写完整排程领域模块。 3. 不额外新增没有稳定 owner 的字段,例如: - 当前目标 - 最近观察 - 已确认语义 4. 不继续围绕粗排补边角语义。 5. 不继续围绕 abort 协议扩展描述文案。 --- ## 6. 第 3 阶段完成标准 至少要满足: 1. execute 首轮 messages 明显变短。 2. 同工具同参数的重复查询不会继续堆多份原始结果。 3. assistant 过程话术不再进入后续执行历史。 4. 最近一次失败模式仍能被模型感知。 5. 最近一次工具调用与结果仍以合法配对形式保留。 6. `msg5` 不再重复 `msg4` 的内容。 7. 不破坏第 1-2 阶段已经打通的粗排 / abort 语义。 --- ## 7. 供下一轮继续时快速判断的检查清单 如果下一轮接手时要快速判断是否做对,可以先问这几个问题: 1. execute 现在是否还是“全量 history + 全量 pinned + 全量 runtime prompt”直接拼接? 2. 工具参数和 JSON 示例是否已经进入单独工具块? 3. `msg3` / `msg4` 是否仍保持一一对应? 4. `msg5` 是否只保留运行态事实,而没有重复工具结果? 5. assistant 的过程话术是否还在继续污染后续历史? 6. correction 失败链是否还在整段保留? 如果以上问题仍然大多回答“是”,说明第 3 阶段还没有真正完成。