后端:
1.execute 上下文瘦身第一版落地(固定 4 消息骨架 + ReAct 窗口压缩 + JSON 输出约束)
- 新建 prompt/execute_context.go:
execute 阶段改为 message[0..3] 固定结构;
加入历史摘要、当轮 ReAct 绑定展示、同工具 observation 压缩(保留最新)与工具简表返回示例提示
- 更新 prompt/execute.go:
重写 plan/ReAct 执行提示词;
补齐“可做/不可做”约束;
统一严格 JSON 指令;
补充 tool_call.arguments/abort/speak 非空等格式护栏
- 更新 model/execute_contract.go:
新增 ExecuteDecision/ToolCallIntent 自定义 Unmarshal;
兼容空字符串占位与 tool_call.parameters→arguments 回退解析
- 更新 node/correction.go:
为 correction 注入 history kind 标记,避免被当作真实用户输入污染摘要
- 更新 node/execute.go:
补齐 continue/ask_user/confirm 的 speak 兜底;
移除工具结果写入前 3000 字截断
2.工具层微调语义重构(任务视角概览 + 首个空位查询 + 移动权限收紧)
- 更新 tools/read_tools.go:
get_overview 改为任务视角全量输出(课程仅占位统计);
新增 find_first_free(首个命中位 + 当日负载明细);
find_free 保留兼容别名;
list_tasks 增加 status/category 校验与空结果纠偏文案
- 更新 tools/registry.go:
注册 find_first_free;
find_free 改兼容别名;
同步 get_overview/list_tasks/move/batch_move 描述语义
- 更新 tools/write_tools.go:
move/batch_move 仅允许 suggested,existing/pending 明确拒绝并返回可读错误
- 更新 tools/SCHEDULE_TOOLS.md:
同步 get_overview/find_first_free/list_tasks/move/batch_move 的最新入参与返回示例
- 更新 prompt/plan.go:
读工具示例由 find_free 调整为 find_first_free
3.交接文档与阶段说明同步
- 更新 newAgent/HANDOFF_粗排修复与Prompt重构.md:
更新为 2026-04-08;
补充“最新增量交接”章节(当前主矛盾、P0/P1、验证清单)
- 更新 newAgent/阶段3_上下文瘦身设计.md:
同步 existing/suggested 的 move/batch_move 约束口径
- 更新 newAgent/Log.txt:
追加本轮 execute 调试日志快照
前端:无
仓库:无
466 lines
12 KiB
Markdown
466 lines
12 KiB
Markdown
# 阶段 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 阶段还没有真正完成。
|