问题

你的 Agent 跟用户聊了 50 轮,每次工具返回几千 Token。你把这些全塞进上下文里,结果窗口爆了——模型开始"失忆":重复问用户已经回答过的问题、违背十分钟前做出的决策。

长对话的历史是 Agent 最宝贵的资产,也是最重的包袱。把几千 Token 的原始对话压缩成几百 Token 的结构化摘要——保留 90% 的语义,消耗 10% 的 Token。

核心模式

语义压缩:把不再活跃的历史压缩成结构化摘要,用 1/10 的 token 保住 9 成语义。

def compress_history(messages, threshold_tokens=4000):
    if total_tokens(messages) < threshold_tokens:
        return messages
    # 保留最近 N 轮原文 + 压缩更早的历史
    recent = messages[-6:]
    old = messages[:-6]
    summary = llm_summarize(old, schema={
        "user_goal": "用户的最终目标",
        "decisions": "已确认的关键决策",
        "constraints": "用户明确提出的约束",
        "done": "已完成的步骤及结果",
        "open_issues": "未解决的问题"
    })
    return [system_note(summary)] + recent

压缩不是简单概括,而是按 schema 抽取:目标、决策、约束、进展、遗留问题——这些才是后续推理真正需要的东西。工具输出的原始 JSON 全文不值得留存,结论值得。

实战要点

  • 压缩 schema 按业务定制:代码 Agent 要保留"改过的文件清单",客服 Agent 要保留"用户情绪变化"
  • 压缩时机:增量压缩(每超阈值压一次)优于一次性大压缩,后者会突然改变模型的语境
  • 被压缩的原文别真删——存到持久层,压缩摘要里留指针("详见记录 #37"),配合渐进发现(第 03 讲)可按需取回
  • 警惕压缩损失:用户对措辞敏感的指令("标题必须包含 XX")应标记为不可压缩