Skip to content

上下文管理与压缩 ​

本文引用的源码文件

本文引用的文件

目录 ​

  1. 引言
  2. 项目结构
  3. 核心组件
  4. 架构总览
  5. 详细组件分析
  6. 依赖关系分析
  7. 性能与容量规划
  8. 故障排查指南
  9. 结论
  10. 附录:指标与评估

引言 ​

本文件聚焦“对话上下文管理与压缩”的完整实现,覆盖以下关键主题:

  • 对话上下文的构建、维护与优化策略
  • Token 估算与校准算法、上下文窗口管理
  • 自动压缩触发条件、历史消息裁剪与结构化摘要生成
  • 长对话场景下的内存优化、上下文恢复与会话状态持久化
  • 不同模型上下文窗口的适配策略与性能调优方法
  • 上下文生命周期图、Token 使用统计与压缩效果评估

本项目采用双进程架构:Chrome 扩展端(Manifest V3)与独立本地代理端 Agent。上下文压缩既包含扩展端的轻量估算与 UI 决策,也包含后台调用 LLM 生成结构化摘要的能力;会话状态(含压缩记录)通过 IndexedDB 持久化,支持切换、归档、分叉与恢复。

项目结构 ​

围绕上下文管理的代码主要分布在以下模块:

  • 共享层:Token 估算、上下文预算、模型窗口映射、内容截断等
  • 背景层:手动压缩摘要生成、批量 ReAct 轮次压缩
  • 侧边栏:自动压缩决策、上下文指示器、Token 统计面板
  • 存储层:会话持久化、压缩记录恢复
  • 代理端:记忆与 RAG 中的 Token 统计(用于跨进程对齐)
graph TB
subgraph "扩展端"
A["侧边栏<br/>auto-compaction.js"]
B["上下文指示器<br/>context-indicator.js"]
C["Token 统计面板<br/>token-stats-panel.js"]
D["共享工具<br/>token-counter.js"]
E["共享上下文用量<br/>context-usage.js"]
F["背景服务<br/>context-compactor.js / context-summarizer.js"]
G["会话存储<br/>session-store.js"]
end
subgraph "代理端"
H["记忆 Token 统计<br/>memory/tokens.js"]
end
A --> B
B --> F
B --> G
C --> D
E --> D
F --> D
F --> H

图表来源

章节来源

核心组件 ​

  • Token 估算与上下文预算:提供字符到 Token 的估算、图片 Token 估算、EWMA 校准、上下文压力评估、按预算裁剪历史消息、引用内容压缩等。
  • 手动压缩摘要生成:将用户选定的素材交给当前模型生成结构化摘要,失败不静默降级。
  • 批量 ReAct 轮次压缩:从消息中识别完整轮次(assistant(tool_calls)+tool),一次 LLM 调用压缩多轮旧对话为结构化摘要,并带输入封顶与快速失败降级。
  • 自动压缩决策:纯函数判定是否触发阈值驱动的半自动压缩,发送前钩子保证失败不阻断用户发送,具备连续失败退避。
  • 会话持久化:保存/恢复会话级上下文压缩记录,支持切换、归档、分叉与定时任务宿主会话。

章节来源

架构总览 ​

上下文管理贯穿“估算—决策—压缩—持久化—恢复”全链路:

sequenceDiagram
participant UI as "侧边栏界面"
participant Auto as "自动压缩决策<br/>auto-compaction.js"
participant Indicator as "上下文指示器<br/>context-indicator.js"
participant BG as "背景服务<br/>context-compactor.js / context-summarizer.js"
participant Store as "会话存储<br/>session-store.js"
participant Stats as "Token 统计<br/>token-stats-panel.js"
UI->>Auto : 发送前检查
Auto->>Indicator : runCompaction({silent})
Indicator->>BG : COMPACT_CONTEXT_SUMMARY
BG-->>Indicator : {success, summary, memoryId}
Indicator->>Store : saveCurrentSession()
Store-->>UI : 会话已持久化
BG->>Stats : recordTokenUsage(...)
Stats-->>UI : 更新 Token 统计

图表来源

详细组件分析 ​

Token 估算与上下文预算 ​

  • 估算策略:中文约 1.5 字符/token,英文约 4 字符/token;图片按分辨率 tiles 公式估算,避免 Base64 字符串高估。
  • EWMA 校准:基于 API 返回的实际 prompt_tokens 修正估算偏差,样本不足时不生效。
  • 上下文预算:上下文窗口 - 系统提示词预留 - 工具定义预留 - 输出预留 = 消息历史可用预算。
  • 压力等级:ratio < 0.7 安全,0.7~0.9 警告,≥0.9 临界。
  • 历史裁剪:按预算从旧到新移除消息,保持 assistant(tool_calls)/tool 配对一致性,并可生成规则式摘要。
  • 引用压缩:超过阈值的引用/选中内容自动压缩,防止长期占用上下文。
flowchart TD
Start(["开始"]) --> Calc["计算消息 Token 估算"]
Calc --> Calib{"是否需要 EWMA 校准?"}
Calib --> |是| ApplyCalib["应用校准因子"]
Calib --> |否| KeepRaw["保留原始估算"]
ApplyCalib --> Budget["计算消息历史预算"]
KeepRaw --> Budget
Budget --> Pressure["评估上下文压力等级"]
Pressure --> Trim{"是否超预算?"}
Trim --> |否| End(["结束"])
Trim --> |是| Cut["按预算裁剪历史消息"]
Cut --> Summary["生成被裁剪消息的规则摘要"]
Summary --> End

图表来源

章节来源

手动压缩摘要生成 ​

  • 入口:由侧边栏收集清洗后的素材后调用 background 接口。
  • 行为:构造结构化摘要 Prompt,限制最大输出 Token,低温度稳定输出,失败明确报错。
  • 统计:成功后记录 Token 使用,便于统计面板展示。
sequenceDiagram
participant UI as "上下文指示器"
participant Compactor as "手动压缩摘要生成"
participant API as "LLM 接口"
participant Recorder as "Token 记录器"
UI->>Compactor : generateCompactionSummary(material, model, sessionId)
Compactor->>API : POST /chat/completions (非流式)
API-->>Compactor : {choices[0].message.content}
Compactor->>Recorder : recordTokenUsage(sessionId, model, usage)
Compactor-->>UI : {success, summary}

图表来源

章节来源

批量 ReAct 轮次压缩 ​

  • 轮次识别:从 assistant(tool_calls) 开始,收集其后连续的 tool 消息作为一轮。
  • 转写构建:提取工具名称、关键参数与结果片段,拼接成紧凑 transcript。
  • 输入封顶:transcript 超过上限时保留头部 70% + 尾部 30%,避免压缩请求自身膨胀。
  • 结构化摘要:要求输出“任务目标/已完成事项/关键事实/未决问题”,温度更低以保证稳定性。
  • 失败降级:异常或空响应直接返回 null,调用方回退到权重裁剪。
flowchart TD
S(["进入 summarizeRoundsBatch"]) --> Extract["extractAllRounds 提取轮次"]
Extract --> Transcript["buildBatchTranscript 构建转写"]
Transcript --> Cap{"是否超过 transcriptMaxTokens?"}
Cap --> |是| Trunc["truncateByTokens 头尾保留"]
Cap --> |否| Prompt["组装结构化摘要 Prompt"]
Trunc --> Prompt
Prompt --> Call["POST /chat/completions (低温度)"]
Call --> Check{"是否成功且非空?"}
Check --> |是| Return["返回结构化摘要"]
Check --> |否| Fail["返回 null调用方降级"]

图表来源

章节来源

自动压缩决策与发送前置钩子 ​

  • 决策函数:shouldAutoCompact 为纯函数,依据开关、阈值比、待压缩条数、是否生成中、是否开启记忆等判断。
  • 发送前置钩子:runAutoCompactionBeforeSend 在发送前尝试自动压缩;任何失败均放行本次发送,不阻断用户。
  • 退避机制:连续失败达到上限后进入退避,手动压缩成功后重置计数。
flowchart TD
Start(["发送前钩子"]) --> ReadCfg["读取 chatConfig.autoCompaction"]
ReadCfg --> Backoff{"连续失败是否达上限?"}
Backoff --> |是| Skip["跳过自动压缩"]
Backoff --> |否| Ratio["getRatio() 获取占用比"]
Ratio --> Pending["countPendingSinceCompaction 计算新消息数"]
Pending --> Decide{"shouldAutoCompact 判定"}
Decide --> |否| SendContinue["继续发送"]
Decide --> |是| Compact["compact({silent:true})"]
Compact --> Result{"是否成功?"}
Result --> |是| Reset["重置退避计数"]
Result --> |否| IncFail["增加失败计数"]
Reset --> SendContinue
IncFail --> SendContinue

图表来源

章节来源

上下文指示器与手动压缩流程 ​

  • 入口封装:triggerCompaction 转为薄壳,内核 runCompaction 复用手动与自动两条路径。
  • 素材组装:assembleCompactionMaterial 根据 maxMemoryMessages 与已有压缩记录选择可压缩素材。
  • 结果处理:更新 activeCompaction(摘要、锚点消息 ID、压缩数量、节省 Token、模型、时间戳、版本号、记忆锚点),持久化会话并刷新 UI。
sequenceDiagram
participant Panel as "上下文指示器"
participant Material as "素材组装"
participant BG as "背景压缩摘要"
participant Store as "会话存储"
Panel->>Material : assembleCompactionMaterial(history, config)
Material-->>Panel : {material, includedCount, hasOldSummary}
Panel->>BG : COMPACT_CONTEXT_SUMMARY
BG-->>Panel : {summary, memoryId}
Panel->>Store : saveCurrentSession()
Store-->>Panel : 完成
Panel-->>Panel : 渲染分隔条/更新指示器

图表来源

章节来源

会话状态持久化与上下文恢复 ​

  • 压缩记录:会话对象中包含 contextCompaction 字段,保存 activeCompaction 快照。
  • 切换恢复:switchToSession 恢复 messageHistory、activeCompaction、model/temperature/topP 等。
  • 归档与分叉:archiveCurrentSession/duplicateSession 支持归档与消息级分叉,分叉元数据记录来源与分叉点。
  • 定时任务宿主会话:createScheduledSession 创建专属宿主会话,便于任务绑定与清理。
classDiagram
class Session {
+string id
+string title
+string model
+boolean useTools
+Array enabledTools
+string agentId
+number temperature
+number topP
+Array messageHistory
+object contextCompaction
+boolean isGenerating
+string createdAt
+string updatedAt
}
class ActiveCompaction {
+string summary
+string upToMessageId
+number compressedCount
+number summaryTokens
+number savedTokens
+string model
+number createdAt
+number revision
+string memoryId
}
Session --> ActiveCompaction : "包含"

图表来源

章节来源

依赖关系分析 ​

  • 共享层 token-counter.js 被多个模块依赖:自动压缩决策、批量压缩、手动压缩、上下文指示器等。
  • 背景层 context-compactor.js 与 context-summarizer.js 依赖 fetchWithRetry、i18n、logger、token-counter。
  • 侧边栏 auto-compaction.js 依赖 state、logger,并通过注入的 compact 函数复用上下文指示器的内核。
  • 会话存储 session-store.js 依赖 IndexedDB 适配器与 side_panel/state,负责持久化与恢复。
graph LR
TC["token-counter.js"] --> AC["auto-compaction.js"]
TC --> CS["context-summarizer.js"]
TC --> CC["context-compactor.js"]
CC --> TR["token-recorder.js"]
CI["context-indicator.js"] --> CC
CI --> SS["session-store.js"]
AC --> CI

图表来源

章节来源

性能与容量规划 ​

  • Token 估算开销:estimateMessagesTokens 对每条消息做一次估算,配合 contributions 增量扣减,避免 O(n²) 全量重估。
  • 图片 Token 估算:优先使用 width/height 按 tiles 计算,避免 Base64 字符串导致的高估。
  • 批量压缩输入封顶:transcriptMaxTokens 默认 30000,超出时头尾保留,降低单次压缩请求成本。
  • 模型上下文窗口:内置映射 + 自定义模型配置 + 全局覆盖,优先级清晰,避免误判窗口大小。
  • 自动压缩退避:连续失败达到上限后暂停自动压缩,减少额外 LLM 调用。
  • 会话持久化:saveCurrentSession 仅写入必要字段,避免冗余数据;切换时并行发起保存与读取,提升交互流畅度。

[本节为通用性能建议,不直接分析具体文件]

故障排查指南 ​

  • 压缩失败无摘要:检查 background 接口返回 success 与 summary 是否为空;确认 apiBase/apiKey 配置有效。
  • 自动压缩未触发:确认 chatConfig.autoCompaction 为 true,ratio 达到 thresholdRatio,pendingCount ≥ minPending,且不在生成中。
  • 连续失败退避:查看 consecutiveFailures 是否达到 maxFailures;手动压缩成功后会重置。
  • 会话恢复异常:检查 switchToSession 是否正确恢复 activeCompaction 与 messageHistory;确认 IndexedDB 迁移与读写正常。
  • Token 统计不一致:核对 recordTokenUsage 是否被调用;对比 estimateMessagesTokens 与 API 实际 prompt_tokens 的校准情况。

章节来源

结论 ​

该项目的上下文管理与压缩体系以“估算—决策—压缩—持久化—恢复”为主线,兼顾准确性与鲁棒性:

  • Token 估算结合 EWMA 校准,贴近真实 API 行为;
  • 自动压缩以纯函数决策,失败不阻断用户发送;
  • 批量 ReAct 轮次压缩结构化输出,提高信息密度;
  • 会话持久化确保压缩记录可恢复,支持复杂工作流(切换、归档、分叉、定时任务)。

在实际使用中,建议:

  • 合理设置 autoCompactionThreshold 与 minPending,平衡额外调用与上下文节省;
  • 关注 Token 统计面板,结合校准信息调整估算偏差;
  • 针对大模型窗口差异,使用自定义模型配置精确控制上下文窗口。

[本节为总结性内容,不直接分析具体文件]

附录:指标与评估 ​

  • 上下文生命周期图:从消息产生、估算、压力评估、压缩触发、摘要沉淀到会话恢复的全链路。
  • Token 使用统计:每次 LLM 调用后记录 usage,侧边栏面板展示会话累计、平均每轮、每日统计与近 7 天历史。
  • 压缩效果评估:比较 materialTokens 与 summaryTokens,计算 savedTokens;观察 ratio 变化与压力等级改善。
stateDiagram-v2
[*] --> 空闲
空闲 --> 估算中 : "新增消息"
估算中 --> 安全 : "ratio < 0.7"
估算中 --> 警告 : "0.7 ≤ ratio < 0.9"
估算中 --> 临界 : "ratio ≥ 0.9"
警告 --> 压缩中 : "手动/自动触发"
临界 --> 压缩中 : "自动触发"
压缩中 --> 已压缩 : "摘要生成成功"
压缩中 --> 裁剪降级 : "摘要失败"
已压缩 --> 恢复中 : "切换会话"
恢复中 --> 空闲 : "恢复完成"
裁剪降级 --> 空闲 : "继续发送"

图表来源

章节来源