Skip to main content

上下文退化问题

随着 AI 对话变得越来越长,它们面临一个基本挑战:上下文退化。这表现为:
  • 性能退化: Token 限制、注意力稀释、处理延迟、成本上升
  • 信息过载: 信号与噪声、近期偏差、上下文切换、记忆碎片化

AG-Kit 解决方案

AG-Kit 实现了一个三层上下文管理策略,灵感来自 Manus 的研究:
上下文大小

    │                                    ┌─────────────┐
    │                                    │ 硬限制      │ (1M tokens)
    │                                    └─────────────┘
    │                              ┌─────────────┐
    │                              │ Pre-rot     │ (150K tokens)
    │                              │ 阈值        │
    │                              └─────────────┘
    │                        ┌──────────┐
    │                        │ 摘要     │ (142.5K = 95%)
    │                        │ 触发器   │
    │                        └──────────┘
    │                  ┌──────────┐
    │                  │ 压缩     │ (120K = 80%)
    │                  │ 触发器   │
    │                  └──────────┘
    │            ┌──────────┐
    │            │ 正常     │
    │            │ 操作     │
    └────────────┴──────────┴──────────────────────────────────────>
                                                                时间

三层策略

  1. 🟢 正常操作 (0-80%): 以完整细节存储所有消息
  2. 🟡 可逆压缩 (80-95%): 压缩旧消息,同时保留重建能力
  3. 🔴 结构化摘要 (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 层)

系统不是创建自由格式的文本摘要,而是创建具有特定字段的结构化摘要:
StructuredSummary 接口
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')
}

基本设置

from agkit.agents.storage import InMemoryMemory, TDAIMemory

# 默认上下文工程 (推荐)
memory = InMemoryMemory()

# 禁用自动上下文管理
manual_memory = InMemoryMemory(
    enable_context_management=False  # 禁用自动上下文管理
)

# 带上下文工程的自定义配置
memory = InMemoryMemory(
    enable_context_management=True,  # 启用自动上下文管理 (默认)
    thresholds={
        'pre_rot_threshold': 150_000,
        'compaction_trigger': 0.8,
        'summarization_trigger': 0.95,
        'keep_recent_count': 10,
    }
)

手动上下文管理

enableContextManagement 被禁用时,您可以手动触发上下文管理:
memory = InMemoryMemory(
    enable_context_management=False  # 禁用自动管理
)

# 添加事件而不进行自动上下文管理
await memory.add(event1, session_id='session-123')
await memory.add(event2, session_id='session-123')
await memory.add(event3, session_id='session-123')

# 在需要时手动触发上下文管理
await memory.manage_context('session-123')

自定义记忆实现

要实现自定义上下文工程逻辑,扩展 BaseMemory 并覆盖压缩和摘要方法:
from agkit.agents.storage import BaseMemory, IMemoryEvent, StructuredSummary
from datetime import datetime
from typing import List

# 方法 1: 在配置中传递摘要器
async def custom_summarizer(events: List[IMemoryEvent]) -> StructuredSummary:
    # 自定义摘要逻辑
    return {
        'count': len(events),
        'time_range': {
            'start': events[0]['message']['timestamp'],
            'end': events[-1]['message']['timestamp']
        },
        'timestamp': datetime.now()
    }

custom_memory = BaseMemory(
    summarizer=custom_summarizer,
    thresholds={
        'pre_rot_threshold': 100_000,
        'compaction_trigger': 0.8,
        'summarization_trigger': 0.95
    }
)

# 方法 2: 扩展 BaseMemory 以进行高级自定义
class CustomMemory(BaseMemory):
    def __init__(self, config=None):
        super().__init__({
            **(config or {}),
            'summarizer': self._custom_summarizer
        })

    # 覆盖单个事件的压缩逻辑
    async def _compact_event(self, event: IMemoryEvent) -> None:
        # 自定义压缩逻辑 - 示例: 压缩代码块
        if '```' in event['message']['content']:
            event['state']['__compaction__'] = {
                'original_content': event['message']['content'],
                'compacted_at': datetime.now().isoformat(),
                'tokens_saved': /* 计算节省的 tokens */,
                'strategy': 'code_compression'
            }
            event['message']['content'] = '[COMPACTED: 代码讨论]'
        else:
            await super()._compact_event(event)

    # 自定义摘要函数
    async def _custom_summarizer(self, events: List[IMemoryEvent]) -> StructuredSummary:
        return {
             'count': len(events),
              'time_range': {
                  'start': events[0]['message']['timestamp'],
                  'end': events[-1]['message']['timestamp']
              },
              'timestamp': datetime.now()
        }

    # 覆盖存储方法 (可选)
    async def _store_summary(self, session_id: str, summary: StructuredSummary) -> None:
        # 自定义存储逻辑
        print(f'为 {session_id} 存储摘要')

    async def _clear_summarized_events(self, session_id: str, keep_recent_count: int) -> None:
        # 自定义清理逻辑
        print(f'为 {session_id} 清理事件')
        await super()._clear_summarized_events(session_id, keep_recent_count)

    # 添加事件后触发上下文管理
    async def add(self, event: IMemoryEvent) -> None:
        await super().add(event)
        session_id = event['state'].get('session_id', 'default')
        await self._manage_context(session_id)

关键实现要点

  1. 上下文管理控制:
    • 自动 (默认): 设置 enableContextManagement: true 以在每次添加后自动进行上下文管理
    • 手动: 设置 enableContextManagement: false 并手动调用 manageContext(sessionId)
  2. 两种自定义方法:
    • 简单: 在创建 BaseMemory 时在配置中传递 summarizer 函数
    • 高级: 扩展 BaseMemory 类以进行完全自定义
  3. 自定义摘要器: 提供 config.summarizer 函数,该函数接收事件并返回 StructuredSummary
  4. 覆盖 compactEvent(): 为单个事件的可逆压缩实现自定义逻辑
  5. 覆盖存储方法 (可选): 定义 storeSummary()clearSummarizedEvents() 以进行自定义存储
  6. 保留元数据: 将压缩元数据存储在 event.state.__compaction__
自动 vs 手动: 默认情况下,InMemoryMemoryTDAIMemory 都会在添加事件后自动触发上下文管理。如果您希望控制上下文管理发生的时间,请设置 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 层 (压缩)
compacted_event = {
    'message': {'content': '[COMPACTED: 数据库超时问题报告]'},
    'state': {
        'issue': 'db_timeout',
        'severity': 'critical',
        '__compaction__': {
            'original_content': '我们的生产数据库在 30 秒后超时...',
            'tokens_saved': 23,
            'compacted_at': '2024-01-15T10:30:00Z'
        }
    }
}

# 200 条消息后,上下文达到 142.5K tokens
# 🔴 系统触发第 3 层 (结构化摘要)
summary = {
    'modified_files': ['database.py', 'user_service.py', 'auth_middleware.py'],
    'user_goal': '修复生产环境中的数据库连接超时',
    'last_step': '更新了连接池配置',
    'key_decisions': [
        '将池大小从 10 增加到 50',
        '添加了连接重试逻辑',
        '实现了断路器模式'
    ],
    'critical_context': {
        'error_pattern': '30 秒后连接超时',
        'environment': 'production',
        'affected_users': 1200,
        'urgency': 'critical'
    }
}
结果: 对话可以无限期地继续,同时保持:
  • 性能: 响应时间保持快速
  • 上下文: 关键调试信息得以保留
  • 成本: Token 使用量减少 70-80%
  • 质量: 最近的上下文保持对话流畅

主要优势

上下文工程解决了随着上下文增长而保持对话质量的基本挑战:

🚀 无限对话长度

  • 对话持续时间没有实际限制
  • 对话可以跨越数百或数千条消息
  • 系统自动管理上下文,无需手动干预

📈 保持性能

  • 即使在长对话中响应时间也保持快速
  • 质量不会随着上下文填满而退化
  • 注意力保持集中在相关信息上

🧠 信息保留

  • 可逆压缩: 完全恢复压缩内容
  • 结构化摘要: 关键见解以有组织的格式保留
  • 最近上下文: 始终保持对话流畅

💰 成本效益

  • Token 使用量大幅减少 (通常节省 70-80%)
  • 降低长对话的 API 成本
  • 高效的资源利用

🔧 零配置

  • 开箱即用,具有合理的默认值
  • 基于可配置阈值的自动触发器
  • 渐进策略优化信息保留
Manus 研究的关键见解: 并非所有上下文退化都是平等的。通过在正确的时间应用正确的策略(在不可逆摘要之前进行可逆压缩),我们可以在有效管理资源约束的同时保持对话连贯性。