Context 系统
Context 系统概述
Context 系统概述
什么是 Context 系统?
Context 系统是 Vibecape 中 Hero/Agent 对话的上下文管理核心。它负责整合各种信息源,构建最优的消息列表发送给 LLM,确保 AI 能够:
- 理解对话历史:通过滑动窗口和会话摘要
- 记住用户偏好:通过长期记忆的语义检索
- 有效利用工具:通过工具结果压缩和工作记忆卸载
- 保持任务专注:通过活动任务追踪和指令钉选
- 控制 Token 使用:通过智能预算分配和截断策略
核心挑战
在使用 LLM 构建复杂应用时,Context Window 的管理是关键挑战:
- Token 限制:模型有固定的上下文窗口(如 128K、200K tokens)
- 信息密度:需要确保发送的信息最有价值,避免"噪音"
- 记忆持久性:重要信息不能因为滑动窗口而丢失
- 响应延迟:过长的上下文会增加推理延迟和成本
- 工具调用开销:工具结果可能非常大,需要智能压缩
系统架构
Context 系统采用模块化架构,各组件职责清晰:
┌─────────────────────────────────────────────────────────┐
│ ContextBuilder │
│ (上下文构建协调器) │
└────────────────────┬────────────────────────────────────┘
│
┌────────────┼────────────┐
│ │ │
┌───────▼──────┐ ┌──▼──────────┐ ┌▼──────────────┐
│ SlidingWindow│ │ThreadSummary│ │LongTermMemory │
│ (滑动窗口) │ │ (会话摘要) │ │ (长期记忆) │
└───────┬──────┘ └──┬──────────┘ └▼──────────────┘
│ │ │
┌───────▼──────┐ ┌──▼──────────┐ ┌▼──────────────┐
│TokenCounter │ │ ToolResult │ │ActiveTask │
│ (Token计数) │ │ Compressor │ │ Service │
└──────────────┘ │ (工具压缩) │ │ (任务追踪) │
└─────────────┘ └───────────────┘核心组件
1. ContextBuilder(上下文构建器)
- 统一协调所有上下文来源
- 智能分配 Token 预算
- 构建最终的消息列表
2. TokenCounter(Token 计数器)
- 估算文本的 Token 数量
- 跟踪预算使用情况
- 支持文本截断
3. SlidingWindow(滑动窗口)
- 保留最近的 N 轮对话
- 支持 Tool Call 格式
- 按 Token 预算动态调整
4. ThreadSummary(会话摘要)
- 增量生成对话摘要
- 压缩历史对话
- 支持消息数和 Token 双阈值触发
5. LongTermMemory(长期记忆)
- 存储跨会话的重要信息
- 基于语义相似度的检索(RAG)
- 自动向量嵌入和更新
6. ToolResultCompressor(工具结果压缩)
- 针对不同工具的压缩策略
- 大型内容卸载到工作记忆
- 保留关键信息结构
7. ActiveTaskService(活动任务服务)
- 追踪当前任务目标
- 记录完成的步骤和发现
- 生成状态摘要注入上下文
8. MemoryExtractionService(记忆提取)
- 自动从对话中提取有价值信息
- 智能合并重复记忆
- 持久化到长期记忆
上下文构建流程
当用户发送消息时,Context 系统按以下顺序构建上下文:
Token 预算分配策略
默认配置(总预算 48000 tokens):
{
systemPrompt: 9600, // 20% - Hero 系统提示词
summary: 4800, // 10% - 会话摘要
retrieved: 4800, // 10% - 长期记忆检索
recentMessages: 26400, // 55% - 近期消息(滑动窗口)
currentInput: 2400, // 5% - 当前输入
reserved: 0 // 0% - 预留(通过安全网处理)
}核心概念
1. 滑动窗口(Sliding Window)
保留最近的 N 轮对话,旧消息被摘要压缩:
[原始消息]
User: Hello
Assistant: Hi
User: How are you?
Assistant: I'm good
User: Tell me about X
Assistant: [关于 X 的详细解释]
... (100+ messages)
[滑动窗口后]
[对话背景摘要]
用户询问了关于 X、Y、Z 的话题...
User: Tell me about W
Assistant: [关于 W 的回答]2. 会话摘要(Thread Summary)
当消息超过阈值时,自动生成摘要:
- 触发条件:消息数阈值(默认 10 条)或 Token 阈值(默认 3000)
- 摘要内容:主要话题、重要决策、用户偏好、技术细节
- 增量更新:新摘要与旧摘要合并
3. 长期记忆(Long-term Memory)
跨会话的持久化记忆,使用向量检索:
- 分类:用户偏好、项目上下文、技能、事实
- 检索:基于语义相似度(Cosine Similarity)
- 自动提取:每轮对话后自动分析并保存有价值的信息
4. 工具结果压缩(Tool Result Compression)
工具返回的结果可能很大,需要智能压缩:
- 列表截断:只保留前 N 项
- 大文本卸载:存入工作记忆,返回 Pointer
- 结构保留:保留元数据和结构信息
5. 指令钉选(Instruction Pinning)
在上下文末尾再次附加当前指令,防止被中间内容冲刷:
[前面的上下文...]
[对话历史...]
[CRITICAL INSTRUCTION]
User's Current Goal: "解释 Context 系统"
Status: ACTIVE
Guide:
1. If you have just received tool outputs, briefly ANALYZE them first.
2. If the goal is complex, form a concise PLAN before executing.
3. Prioritize answering the User's Goal immediately.数据流
完整对话流程
摘要更新流程
配置选项
ContextBuilder 配置
interface ContextBuilderConfig {
totalBudget: number; // 总 Token 预算
slidingWindowSize: number; // 滑动窗口大小
enableSummary: boolean; // 是否启用摘要
enableMemoryRetrieval: boolean; // 是否启用记忆检索
enableToolResultCompression: boolean; // 是否启用工具压缩
enableInstructionPinning: boolean; // 是否启用指令钉选
}ThreadSummary 配置
interface SummaryConfig {
messageThreshold: number; // 消息数阈值
maxSummaryTokens: number; // 最大摘要 Token 数
modelSlot: 'fast' | 'primary'; // 使用的模型
tokenCompactionThreshold: number; // Token 压缩阈值
enableTokenBasedCompaction: boolean; // 是否启用 Token 阈值
}SlidingWindow 配置
interface SlidingWindowConfig {
windowSize: number; // 窗口大小(消息对数)
maxMessageTokens: number; // 单条消息最大 Token 数
messagesBudget: number; // 消息区域 Token 预算
}设计决策
为什么使用两层摘要?
参考 Goose 的两层压缩策略:
- 消息数阈值:定期触发,确保历史不会过长
- Token 阈值:动态触发,处理大内容场景
为什么使用指令钉选?
参考 Manus 的 Active Instruction Slot 模式:
- LLM 存在"近因效应",更关注上下文末尾
- 工具调用结果可能在中间,冲刷原始指令
- 在末尾重复指令,确保 AI 保持专注
为什么自动提取记忆?
- 用户不会手动维护记忆库
- 每轮对话都可能包含有价值信息
- 自动化降低认知负担
性能考虑
异步非阻塞
- 记忆检索设置 500ms 超时
- 摘要更新异步执行,不阻塞主流程
- 记忆提取在后台排队执行
Token 估算
- 使用简化的字符计数策略
- 中文约 1.8 字符/token,英文约 4 字符/token
- 避免调用 tokenizer API,减少延迟
缓存策略
- 滑动窗口保留最近消息
- 长期记忆使用向量索引
- 摘要增量更新,避免重新生成