最新n1n v2.0.1 正式上线!企业级大模型接口聚合平台 (LLM API Gateway),为您接入 500+ AI Models,价格低至 1 折, 立即尝试

使用 TypeScript 构建轻量级 AI 代理上下文压缩器

作者
  • avatar
    姓名
    Nino
    职业
    Senior Tech Editor

自主 AI 代理(Agent)在运行循环中存在一个隐蔽且昂贵的习惯:每次向大语言模型(LLM)发起 API 请求时,它都会重新发送完整的历史对话记录。从系统提示词(System Prompt)、用户任务,到历史上的每一次工具调用和原始日志,全部会被重复传输。

一段包含 20,000个 Token 的测试输出或构建日志,并非只支付一次费用,而是在后续的每一个 Turn 中被持续计费。

2026年关于 Agent 架构的多项研究均指出了这一瓶颈。2026年9月发布的论文《An Empirical Study of Harness Design for Coding Agents》在 176个对比实验中表明,随着上下文窗口吃紧,上下文管理策略直接决定了 Agent 的任务成败;其中“基于规则的文本裁切(Elision)”相比单纯的 LLM 摘要总结展现出了更高的性价比与准确率。

同时,Strands Agents 团队发布的评测数据显示,在针对 Claude 3.5 Sonnet 和 GPT-4 系列模型的测试中,通过对超过 1,500 Token 的工具结果实施截断并配合 85% 上下文阈值压缩,Token 成本降低了 28%。CliffCompaction 等技术方案也证明,采用只截断、不重述的严格规则,能在限制上下文大小的同时降低 50% 的 API 开销。无论使用 DeepSeek-V3 还是 OpenAI o3,如何在减少 Token 消耗的同时避免丢失关键错误日志,是构建生产级 Agent Harness 的核心工程课题。

本文将带领大家使用 TypeScript 从零构建一个轻量级、确定性的上下文压缩器。无需任何第三方依赖,无需模型 API Key,纯代码实现。


核心架构:真相日志与模型视图分离

高效 Agent Harness 的核心设计原则是:解耦不可变日志与动态模型视图。

  1. 完整日志(Full Log):追加式记录所有原始工具输出和系统对话,作为不可篡改的“唯一真实来源”。
  2. 截断层(Cap):将超大工具输出转换为预览摘要(Preview),并附加持久化引用 ID(Ref)。
  3. 关键行保留(Keep/Pin):确保测试失败(如 FAIL 或 ERROR)等核心诊断信息不被截断算法丢弃。
  4. 长尾清除(Elision):当工具输出超出配置的历史轮数后,将其收缩为单行存根(Stub)。
  5. 超限丢弃(Drop):当整体视图超过模型窗口容量的 85% 时,按时间顺序丢弃最旧的非锁定消息。
  6. 模型视图(Model View):在当期 Turn 实际提交给 LLM 的切片数据。
完整历史日志 (未篡改真相)
  ↓
Cap 截断: 超大输出转为 Preview + Ref
  ↓
Keep 锁定: 匹配 FAIL/ERROR 的行强行保留在 Preview 中
  ↓
Elide 消除: 超过 N 轮的工具结果转换为单行存根
  ↓
Drop 丢弃: 上下文占用 > 85% 窗口时,丢弃最旧非锁定消息
  ↓
模型视图 (当期 Turn 实际读取的 Payload)

TypeScript 实战代码:compact.ts

首先创建项目目录并安装基础开发依赖:

mkdir tiny-context-compactor && cd tiny-context-compactor
npm init -y
npm install -D tsx typescript @types/node

将以下代码按顺序保存至 compact.ts 文件中。

步骤 1:基础类型定义与模拟运行数据

首先定义消息结构、基于字符数的 Token 简易估算函数(约 4 字符/Token),以及一个模拟的 9 步代码修复 Agent 运行轨迹。

// compact.ts: 轻量级 Agent 上下文压缩器

type Msg = { 
  turn: number; 
  role: "system" | "user" | "assistant" | "tool"; 
  tool?: string; 
  text: string 
};

// 简易 Token 估算函数(约为每 4个字符 1个 Token)
const tokens = (s: string): number => Math.ceil(s.length / 4);

const lines = (n: number, f: (i: number) => string) => 
  Array.from({ length: n }, (_, i) => f(i)).join("
");

const FAIL_LINE = "FAIL src/checkout.test.ts > applies 10% coupon: expected 90, received 100";

const testLog = (failAt: number | null) =>
  lines(1800, (i) => (i === failAt ? FAIL_LINE : `PASS src/suite-${i % 97}.test.ts > case $\{i\} ($\{(i * 37) % 90 + 3\} ms)`));

const sourceCode = (name: string, n: number) =>
  lines(n, (i) => `  const ${name}$\{i\} = applyRule(cart.items[${i % 12}], rules.$\{name\}); // line $\{i + 1\}`);

// 模拟 Agent 修复 Bug 的 9次工具调用历史
const RUN: [tool: string, call: string, output: string][] = [
  ["list_files