Files
smartmate/backend/newAgent/阶段3_上下文瘦身设计.md
LoveLosita 4195e65cba Version: 0.9.8.dev.260408
后端:
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 调试日志快照

前端:无
仓库:无
2026-04-08 21:35:05 +08:00

466 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 阶段 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 阶段还没有真正完成。