上下文退化问题
随着 AI 对话变得越来越长,它们面临一个基本挑战:上下文退化。这表现为:
- 性能退化: Token 限制、注意力稀释、处理延迟、成本上升
- 信息过载: 信号与噪声、近期偏差、上下文切换、记忆碎片化
AG-Kit 解决方案
AG-Kit 实现了一个三层上下文管理策略,灵感来自 Manus 的研究:
上下文大小
│
│ ┌─────────────┐
│ │ 硬限制 │ (1M tokens)
│ └─────────────┘
│ ┌─────────────┐
│ │ Pre-rot │ (150K tokens)
│ │ 阈值 │
│ └─────────────┘
│ ┌──────────┐
│ │ 摘要 │ (142.5K = 95%)
│ │ 触发器 │
│ └──────────┘
│ ┌──────────┐
│ │ 压缩 │ (120K = 80%)
│ │ 触发器 │
│ └──────────┘
│ ┌──────────┐
│ │ 正常 │
│ │ 操作 │
└────────────┴──────────┴──────────────────────────────────────>
时间
三层策略
- 🟢 正常操作 (0-80%): 以完整细节存储所有消息
- 🟡 可逆压缩 (80-95%): 压缩旧消息,同时保留重建能力
- 🔴 结构化摘要 (95%+): 创建结构化摘要以大幅减少 token
工作原理
可逆压缩 (🟡 第 2 层)
压缩将完整的原始内容存储在 event.state.__compaction__ 中,同时用紧凑的引用替换消息内容:
// 原始事件
{
"message": {
"id": "msg-1",
"content": "我需要帮助实现一个用户认证系统,包含 JWT tokens、密码哈希和基于角色的访问控制...",
"role": "user"
},
"state": { "userGoal": "implement auth", "complexity": "medium" }
}
// 压缩后
{
"message": {
"id": "msg-1",
"content": "[COMPACTED: 用户认证实现请求]",
"role": "user"
},
"state": {
"userGoal": "implement auth",
"complexity": "medium",
"__compaction__": {
"originalContent": "我需要帮助实现一个用户认证系统,包含 JWT tokens、密码哈希和基于角色的访问控制...",
"tokensSaved": 45,
}
}
}
结构化摘要 (🔴 第 3 层)
系统不是创建自由格式的文本摘要,而是创建具有特定字段的结构化摘要:
interface StructuredSummary {
count: number;
timeRange: { start?: Date; end?: Date };
timestamp: Date;
}
{
count: 1200,
timeRange: {
start: new Date('2024-01-15T10:00:00Z'),
end: new Date('2024-01-15T14:30:00Z')
},
timestamp: new Date('2024-01-15T14:30:00Z')
}
基本设置
import { InMemoryMemory, TDAIMemory } from '@ag-kit/agents/storage';
// 默认上下文工程 (推荐)
const memory = new InMemoryMemory();
// 禁用自动上下文管理
const manualMemory = new InMemoryMemory({
enableContextManagement: false // 禁用自动上下文管理
});
// 带上下文工程的自定义配置
const memoryWithConfig = new InMemoryMemory({
enableContextManagement: true, // 启用自动上下文管理 (默认)
thresholds: {
preRotThreshold: 150_000, // 性能退化点
compactionTrigger: 0.8, // 在 80% 时压缩 (120K tokens)
summarizationTrigger: 0.95, // 在 95% 时摘要 (142.5K tokens)
recentToKeep: 10, // 始终保留最后 10 条消息
}
});
手动上下文管理
当 enableContextManagement 被禁用时,您可以手动触发上下文管理:
const memory = new InMemoryMemory({
enableContextManagement: false // 禁用自动管理
});
// 添加事件而不进行自动上下文管理
await memory.add(event1, { sessionId: 'session-123' });
await memory.add(event2, { sessionId: 'session-123' });
await memory.add(event3, { sessionId: 'session-123' });
// 在需要时手动触发上下文管理
await memory.manageContext('session-123');
自定义记忆实现
要实现自定义上下文工程逻辑,扩展 BaseMemory 并覆盖压缩和摘要方法:
import { BaseMemory, IMemoryEvent, StructuredSummary } from '@ag-kit/agents/storage';
// 方法 1: 在配置中传递摘要器
const customMemory = new BaseMemory({
summarizer: async (events: IMemoryEvent[]): Promise<StructuredSummary> => {
// 自定义摘要逻辑
return {
modifiedFiles: extractFiles(events),
userGoal: extractUserGoal(events),
lastStep: getLastStep(events),
keyDecisions: extractDecisions(events),
criticalContext: { /* 自定义上下文 */ },
timestamp: new Date()
};
},
thresholds: {
preRotThreshold: 100_000,
compactionTrigger: 0.8,
summarizationTrigger: 0.95
}
});
// 方法 2: 扩展 BaseMemory 以进行高级自定义
class CustomMemory extends BaseMemory {
constructor(config?: any) {
super({
...config
});
}
// 覆盖单个事件的压缩逻辑
protected async compactEvent(event: IMemoryEvent): Promise<IMemoryEvent> {
// 自定义压缩逻辑 - 示例: 压缩代码块
if (event.message.content.includes('```')) {
event.state.__compaction__ = {
originalContent: event.message.content,
compactedAt: new Date().toISOString(),
tokensSaved: /* 计算节省的 tokens */,
strategy: 'code_compression'
};
event.message.content = '[COMPACTED: 代码讨论]';
return event
} else {
return super.compactEvent(event);
}
}
// 自定义摘要函数
private async summarizer(events: IMemoryEvent[]): Promise<StructuredSummary> {
return {
count: events.length,
timeRange: {
start: events[0].message.timestamp,
end: events[events.length - 1].message.timestamp
},
timestamp: new Date()
};
}
// 覆盖存储方法 (可选)
protected async storeSummary(sessionId: string, summary: StructuredSummary): Promise<void> {
// 自定义存储逻辑
console.log(`为 ${sessionId} 存储摘要`);
}
protected async clearSummarizedEvents(sessionId: string, recentToKeep: number): Promise<void> {
// 自定义清理逻辑
console.log(`为 ${sessionId} 清理事件`);
await super.clearSummarizedEvents(sessionId, recentToKeep);
}
// 添加事件后触发上下文管理
async add(event: IMemoryEvent): Promise<void> {
await super.add(event);
const sessionId = event.state.sessionId || 'default';
await this.manageContext(sessionId);
}
}
关键实现要点
-
上下文管理控制:
- 自动 (默认): 设置
enableContextManagement: true 以在每次添加后自动进行上下文管理
- 手动: 设置
enableContextManagement: false 并手动调用 manageContext(sessionId)
-
两种自定义方法:
- 简单: 在创建 BaseMemory 时在配置中传递
summarizer 函数
- 高级: 扩展 BaseMemory 类以进行完全自定义
-
自定义摘要器: 提供
config.summarizer 函数,该函数接收事件并返回 StructuredSummary
-
覆盖
compactEvent(): 为单个事件的可逆压缩实现自定义逻辑
-
覆盖存储方法 (可选): 定义
storeSummary() 和 clearSummarizedEvents() 以进行自定义存储
-
保留元数据: 将压缩元数据存储在
event.state.__compaction__ 中
自动 vs 手动: 默认情况下,InMemoryMemory 和 TDAIMemory 都会在添加事件后自动触发上下文管理。如果您希望控制上下文管理发生的时间,请设置 enableContextManagement: false,然后在需要时手动调用 manageContext(sessionId)。
实际示例: 长时间调试会话
以下是上下文工程在跨越 200+ 条消息的实际调试会话中的工作方式:
// 初始问题 (正常操作 - 第 1 层)
await memory.add({
message: {
role: 'user',
content: '我们的生产数据库在 30 秒后超时,影响了 1200 个用户'
},
state: {
issue: 'db_timeout',
severity: 'critical',
environment: 'production'
}
});
// 50 条消息后,上下文达到 120K tokens
// 🟡 系统自动触发第 2 层 (压缩)
// 早期消息被压缩但仍可恢复:
const compactedEvent = {
message: { content: '[COMPACTED: 数据库超时问题报告]' },
state: {
issue: 'db_timeout',
severity: 'critical',
__compaction__: {
originalContent: '我们的生产数据库在 30 秒后超时...',
tokensSaved: 23,
compactedAt: '2024-01-15T10:30:00Z'
}
}
};
// 200 条消息后,上下文达到 142.5K tokens
// 🔴 系统触发第 3 层 (结构化摘要)
const summary = {
modifiedFiles: ['database.ts', 'user-service.ts', 'auth-middleware.ts'],
userGoal: '修复生产环境中的数据库连接超时',
lastStep: '更新了连接池配置',
keyDecisions: [
'将池大小从 10 增加到 50',
'添加了连接重试逻辑',
'实现了断路器模式'
],
criticalContext: {
errorPattern: '30 秒后连接超时',
environment: 'production',
affectedUsers: 1200,
urgency: 'critical'
}
};
// 最近的消息 (最后 5 条) 保持完整细节以保持上下文连续性
结果: 对话可以无限期地继续,同时保持:
- ✅ 性能: 响应时间保持快速
- ✅ 上下文: 关键调试信息得以保留
- ✅ 成本: Token 使用量减少 70-80%
- ✅ 质量: 最近的上下文保持对话流畅
主要优势
上下文工程解决了随着上下文增长而保持对话质量的基本挑战:
🚀 无限对话长度
- 对话持续时间没有实际限制
- 对话可以跨越数百或数千条消息
- 系统自动管理上下文,无需手动干预
📈 保持性能
- 即使在长对话中响应时间也保持快速
- 质量不会随着上下文填满而退化
- 注意力保持集中在相关信息上
🧠 信息保留
- 可逆压缩: 完全恢复压缩内容
- 结构化摘要: 关键见解以有组织的格式保留
- 最近上下文: 始终保持对话流畅
💰 成本效益
- Token 使用量大幅减少 (通常节省 70-80%)
- 降低长对话的 API 成本
- 高效的资源利用
🔧 零配置
- 开箱即用,具有合理的默认值
- 基于可配置阈值的自动触发器
- 渐进策略优化信息保留
Manus 研究的关键见解: 并非所有上下文退化都是平等的。通过在正确的时间应用正确的策略(在不可逆摘要之前进行可逆压缩),我们可以在有效管理资源约束的同时保持对话连贯性。