Files
smartmate/docs/功能决策记录/Execute_Context_Compaction_决策记录.md
LoveLosita 8bde981592 Version: 0.9.20.dev.260415
后端:
1. 修复 query_available_slots section_from/section_to 错误覆盖 duration 并使用精确匹配而非范围包含
- 更新backend/newAgent/tools/schedule/read_filter_tools.go:移除 span = exactTo - exactFrom + 1 对 duration 的覆盖;matchSectionRange
  从精确匹配改为范围包含语义(slotStart < exactFrom || slotEnd > exactTo)
2. Execute 上下文窗口从硬编码裁剪改造为 80k token 动态预算 + LLM滚动压缩
- 基础设施层:AgentChat 新增 compaction 三个持久化字段,dao 新增 CRUD,Redis 新增缓存;pkg 新增 ExecuteTokenBudget常量、ExecuteTokenBreakdown 结构体、CheckExecuteTokenBudget 预算检查函数
- prompt 层:新建 compact_msg1.go / compact_msg2.go 分别实现msg1(历史对话)和 msg2(ReAct Loop)的 LLM 压缩;execute_context.go 移除 msg1 的 1400 字符/30 轮/120 字符三重裁剪和 msg2 的 8 条窗口限制,改为全量加载
- node 层:新建 execute_compact.go(compactExecuteMessagesIfNeeded:预算检查 → msg1 优先压缩 → msg2 兜底 → SSE 通知 → token 分布持久化);execute.go ReAct 循环插入 compact 调用 - 服务/API 层:AgentGraphDeps / AgentService 新增 CompactionStore 注入链路;新增 GET /api/v1/agent/context-stats 查询接口
- 启动层:cmd/start.go 注入 agentRepo 为 CompactionStore
3. 新增 Execute Context Compaction 决策报告
- 新建docs/功能决策记录/Execute_Context_Compaction_决策记录.md

前端:无 仓库:无
2026-04-15 22:01:37 +08:00

7.2 KiB
Raw Permalink Blame History

功能决策记录Execute Context Compaction

1. 基本信息

  • 记录编号FDR-2026-003
  • 功能名称Execute 节点上下文窗口动态管理与 LLM 压缩
  • 记录日期2026-04-15
  • 决策状态:已采纳
  • 负责人LoveLosita
  • 关联需求 / IssueExecute 节点 msg1/msg2 硬编码裁剪导致 LLM 上下文不完整

2. 背景与问题

  • 业务背景Execute 节点通过 4 条消息msg0=系统规则, msg1=历史对话, msg2=ReAct Loop, msg3=当前状态)构建 LLM prompt指导 ReAct 循环决策。
  • 现状问题:
    1. msg1 使用 1400 字符总上限 + 30 轮对话上限 + 单条 120 字符截断,三重硬编码限制叠加导致长对话中 LLM 看不到完整的用户诉求和约束条件。
    2. msg2 仅保留最近 8 条 ReAct Loop 记录复杂任务中早期工具调用结果丢失LLM 无法理解执行全貌。
    3. 四条消息之间没有统一的 token 预算管理,各维度独立裁剪,无法保证总 prompt 不超模型上下文窗口。
  • 不做此决策的后果随着任务复杂度和对话轮数增长LLM 因上下文裁剪频繁丢失关键信息,导致决策质量下降(漏掉用户约束、重复执行已完成的操作、无法回溯错误路径)。

3. 决策目标

  • 目标 1移除所有硬编码裁剪限制改为全量加载 msg1/msg2 数据。
  • 目标 2基于 80k token 总预算统一管理四条消息的 token 分配,超限时通过 LLM 压缩保留语义信息。
  • 目标 3提供上下文窗口实时查询接口便于调试和监控。
  • 非目标:不改造 Chat/Plan/Deliver 节点的上下文管理(各节点 token 策略独立),不引入流式压缩(压缩在 ReAct 循环内同步完成)。

4. 备选方案

方案 A维持硬编码裁剪 + 调参

  • 描述:保持现有架构,仅上调 1400 字符、30 轮、8 条等阈值。
  • 优点:零开发成本,改动最小。
  • 缺点:治标不治本,调参后仍有上限;不同任务的最优阈值不同,无法一劳永逸。
  • 复杂度 / 成本:极低。

方案 B动态 Token 预算 + LLM 滚动压缩(采纳)

  • 描述:全量加载后统一计算 token超 80k 预算时按 msg1 → msg2 优先级调用 LLM 生成压缩摘要,替代原始文本。压缩结果持久化到 DB后续轮次复用摘要 + 新增量。
  • 优点:
    1. 无硬编码上限,短对话全量放行,长对话按语义压缩。
    2. watermark 机制保证跨轮增量压缩,不重复处理已压缩内容。
    3. 独立压缩 msg1历史对话和 msg2ReAct Loop互不干扰。
  • 缺点:首次触发压缩时需额外调用一次 LLM增加约 2-5 秒延迟和 token 开销。
  • 复杂度 / 成本:中等(新增 ~200 行核心逻辑,涉及 prompt/node/service/dao/api 五层)。

方案 C滑动窗口 + 向量检索

  • 描述:将历史上下文存入向量数据库,每轮按相关性检索 top-k 片段注入 prompt。
  • 优点:理论上最精确的上下文选择。
  • 缺点引入向量数据库依赖架构复杂度剧增Execute 阶段对时序连续性敏感,检索结果可能打乱因果链。
  • 复杂度 / 成本:高。

5. 最终决策

  • 采纳方案:方案 B
  • 关键理由:
    1. 方案 A 无法根治问题,每次阈值调整都是临时修补。
    2. 方案 C 过度设计,引入的依赖和复杂度不适合当前阶段。
    3. 方案 B 在可控复杂度内解决了核心问题:无硬编码上限 + 语义保留 + 持久化复用。
    4. LLM 压缩的额外延迟仅在首次超限时触发,后续轮次复用缓存结果。

6. 影响范围

  • 涉及模块:
    • newAgent/node/execute.go — ReAct 循环中新增 token 预算检查和压缩调用
    • newAgent/node/execute_compact.go — 新增压缩逻辑(独立文件)
    • newAgent/prompt/compact_msg1.go — msg1 压缩 prompt
    • newAgent/prompt/compact_msg2.go — msg2 压缩 prompt
    • newAgent/prompt/execute_context.go — 移除硬编码裁剪
    • newAgent/model/state_store.go — 新增 CompactionStore 接口
    • newAgent/model/graph_run_state.go — AgentGraphDeps 新增字段
    • pkg/token_budget.go — 新增预算常量和检查函数
    • dao/agent.go — 新增 compaction CRUD
    • dao/agent-cache.go — 新增 Redis 缓存
    • model/agent.go — AgentChat 新增字段
    • service/agentsvc/agent.go — 新增 compactionStore 字段和注入
    • service/agentsvc/agent_meta.go — 新增 GetContextStats 方法
    • api/agent.go — 新增 GetContextStats handler
    • routers/routers.go — 注册 /context-stats 路由
    • cmd/start.go — 注入 CompactionStore
  • 数据与存储影响:
    • agent_chats 表新增 3 列:compaction_summary TEXTcompaction_watermark INT DEFAULT 0context_token_stats JSON
    • Redis 新增 smartflow:compaction:{chatID} 缓存 key
  • 接口 / 协议影响:
    • 新增 SSE 状态码 context_compact_start / context_compact_donestage 为 compact_msg1compact_msg2
    • 新增 HTTP API GET /api/v1/agent/context-stats?conversation_id=xxx
  • 监控与日志影响:
    • ReAct 循环中新增 [COMPACT] 前缀日志,记录 token 分布和压缩决策
    • 每轮 execute 结束后持久化 token 分布到 context_token_stats 字段

7. 风险与应对

  • 风险 1LLM 压缩摘要丢失关键信息,导致后续决策质量下降。
    • 应对策略:压缩 prompt 明确要求保留用户诉求、约束条件、操作结果、偏好信息;前端可通过 SSE 通知感知压缩发生,提醒用户关键约束可能被折叠。
  • 风险 2首次触发压缩时的额外延迟影响用户体验。
    • 应对策略:通过 SSE context_compact_start 推送前端展示"正在压缩上下文..."提示watermark 机制保证后续轮次复用缓存,不重复触发。
  • 风险 3Token 估算不精确CJK 1:1, ASCII 4:1 是粗略估算),导致实际 token 超出模型限制。
    • 应对策略:预算常量 ExecuteTokenBudget=80000 留有充足余量(模型实际支持 128k+);后续可接入模型 tokenizer 精确计数作为优化项。

8. 验证与回滚

  • 验证方式:
    1. go build ./... 全量编译通过
    2. 短对话场景不触发压缩msg1/msg2 全量放行
    3. 长对话场景:触发 msg1 压缩验证摘要质量、SSE 通知、token 降幅
    4. GET /context-stats 接口返回正确的 token 分布 JSON
  • 成功判定标准:
    1. 编译零错误
    2. 短对话功能不受影响(回归)
    3. 长对话中压缩后 LLM 决策质量不低于压缩前
    4. SSE 通知正确推送
  • 回滚方案:将 compactExecuteMessagesIfNeeded 函数改为直接 return messages 即可跳过压缩逻辑,所有其他改动均为增量添加,不影响原有功能。

9. 里程碑与后续计划

  • 里程碑 1编译通过 + 短对话回归验证(已完成)
  • 里程碑 2集成测试 — 模拟长对话触发压缩场景(待做)
  • 后续优化项:
    1. 接入模型 tokenizer 替换粗略估算
    2. 压缩摘要质量自动化评估(对比压缩前后 LLM 决策准确率)
    3. Redis 缓存 compaction 结果的 TTL 策略优化
    4. 前端 UI 展示上下文窗口使用情况和压缩状态

10. 复盘结论(上线后补充)

  • 实际效果:
  • 与预期偏差:
  • 后续是否需要二次决策: