Context Gateway架构深度解析:Pipes管道、Adapter适配器与多Provider路由设计

【免费下载链接】Context-Gateway

Context Gateway is an agentic proxy that enhances any AI agent workflow with instant history compaction and context optimization tools

项目地址: https://gitcode.com/gh_mirrors/co/Context-Gateway
点击查看 免费下载

Context Gateway 是一个开源的 AI Agent 上下文压缩代理(LLM Proxy),部署在 AI 编程助手(Claude Code、Cursor 等)与大模型 API 之间,自动完成历史压缩(history compaction)与上下文优化。本文将带你拆解它的三大核心架构:Pipes 压缩管道、Adapter 适配器 与 多 Provider 路由设计,帮你快速理解一个生产级 LLM 网关是如何设计的。

一、整体架构:四层协作的上下文压缩网关

Context Gateway 的架构可以概括为四个层次,每一层职责单一、边界清晰:

层次核心模块职责
路由层internal/gateway/接收请求、识别 Provider、安全校验
适配层internal/adapters/抹平各厂商 API 协议差异
管道层internal/pipes/工具输出压缩、工具发现、任务输出处理
存储层internal/store/影子上下文存储,支持按需"还原"

Context Gateway 上下文压缩网关

一个请求的完整生命周期如下:

AI Agent (Claude Code / Cursor)
        │
        ▼
  ① 路由层:识别 Provider(OpenAI / Anthropic / Bedrock / Ollama ...)
        ▼
  ② 适配层:Adapter 从请求中提取工具输出 / 工具定义 / 用户意图
        ▼
  ③ 管道层:task_output → tool_output ∥ tool_discovery 并行压缩
        ▼
  ④ 转发给 LLM API,影子内容存入 Store 供 expand_context 还原

这种"路由 → 适配 → 管道 → 存储"的单向数据流,是整个架构最优雅的地方:任何一层都可以独立替换,互不污染。

二、多 Provider 路由:一次识别,自动适配

2.1 六级优先级的 Provider 识别策略

网关面对的第一个问题是:这个请求到底是发给哪家的?不同厂商的 API 格式(消息结构、认证头、路径)各不相同,但 Context Gateway 用一个集中式入口 IdentifyAndGetAdapter 一次解决,它按六级优先级逐步探测:

优先级识别信号判定结果
1X-Provider 请求头(显式声明)7 种 Provider 之一
2Bedrock URL 路径特征(/model/.../invoke)Bedrock
3anthropic-version 请求头Anthropic
4API Key 前缀(sk-ant- vs sk-)Anthropic / OpenAI
5路径特征(/v1/messages、/v1/chat/completions 等)对应厂商
6兜底默认OpenAI(最通用格式)

这里有一个精妙的细节:Bedrock 路径检测被刻意放在 anthropic-version 头检测之前,因为 AWS SDK 客户端常常在 Bedrock 请求中同时携带 anthropic-version 头,如果头检测先触发会导致误判(见 provider_identification.go 中的注释说明)。

识别失败时不会报错,而是优雅降级到 OpenAI 适配器——因为 OpenAI Chat Completions 是最通用的事实标准格式。

2.2 内置七个适配器,注册表统一管理

所有适配器在启动时通过 Registry 统一注册,内置 7 个:

  • Anthropic / OpenAI(含 Responses API)
  • Bedrock / Gemini / MiniMax
  • Ollama(本地模型)/ LiteLLM(网关套网关)

注册表基于 map[string]Adapter + 读写锁实现,支持热插拔——新增一个 Provider 只需实现接口并调用 Register,路由层代码零改动。

2.3 SSRF 防护:请求白名单机制

作为代理,网关还承担安全责任。gateway.go 维护了一份目标域名白名单(allowedHosts),只放行 api.openai.com、api.anthropic.com、bedrock-runtime.amazonaws.com 等受信任的 LLM 域名,防止恶意配置把请求转发到内网地址。本地开发可通过环境变量 GATEWAY_ALLOW_LOCAL=true 显式开启 localhost 访问。

三、Adapter 适配器:用一个接口抹平所有协议差异

3.1 核心设计:2×2 的 Extract / Apply 方法对

Adapter 接口 是整个系统的"协议翻译官"。它定义了成对的方法,每对方法对应一类管道:

方法对服务管道示例差异
ExtractToolOutput / ApplyToolOutputtool_outputOpenAI 是 role="tool" 消息;Anthropic 是 type="tool_result" 内容块
ExtractToolDiscovery / ApplyToolDiscoverytool_discovery各家 tools 定义结构不同
ExtractUserQuery / ExtractAssistantIntent压缩上下文提取用户原话和 LLM 调用工具的"意图"
ExtractUsage / ExtractModel计费统计OpenAI 用 prompt_tokens,Anthropic 用 input_tokens

除了压缩相关方法,Adapter 还负责响应侧的工作:从 LLM 响应中提取工具调用、过滤"幽灵工具"调用、构建下一轮请求消息、归一化停止原因信号(ExtractTurnSignal)等。

关键约束:适配器必须无状态、线程安全,因为管道池会并发复用它们。

3.2 管道与适配器分离:为什么这样设计?

Pipe 接口 的注释明确写着:"Pipes 中不得包含 Provider 特定逻辑——那由 Adapter 负责"。这意味着:

  • Pipes 只写一遍压缩算法(如"压缩工具输出并打引用标记"),通过调用 adapter.Extract*() 取数据、adapter.Apply*() 写回结果;
  • 新增 Provider 时不需要改任何管道代码,只要新 Adapter 正确实现接口即可。

这是典型的策略模式 + 依赖倒置:压缩策略(管道)与协议实现(适配器)双向解耦,是理解整个项目的架构钥匙。

四、Pipes 管道:三条压缩流水线与并行调度

4.1 三条管道各管一摊

Context Gateway 内置三条独立的压缩管道,配置集中在 pipes/config.go:

管道目录作用
task_outputpipes/task_output/识别子 Agent / 任务工具的结果,按客户端 Schema 单独处理
tool_outputpipes/tool_output/压缩冗长的工具输出(如超长文件内容),注入 expand_context 还原入口
tool_discoverypipes/tool_discovery/动态过滤不相关工具定义,节省 tools[] 占用的 token

每条管道通过 Strategy() 方法声明执行策略,常见策略有:

  • passthrough:完全透传,不做处理
  • api(compresr):调用 Compresr 压缩 API
  • external_provider:直连你自己的 OpenAI/Anthropic 兼容模型
  • relevance / trimming:本地相关性过滤 / 尾部保留裁剪

4.2 Router 调度:先串行、后并行的两阶段执行

调度核心在 Router.ProcessAll,它实现了非常有讲究的两阶段执行模型:

阶段一(串行):task_output
    └── 认领子 Agent 的工具结果 ID,写入 TaskOutputHandledIDs
阶段二(并行):tool_output ∥ tool_discovery
    ├── tool_output 修改 messages[] 路径
    └── tool_discovery 修改 tools[] 路径
最终:sjson 合并两个结果(不重叠的 JSON 路径,可安全合并)

并行设计有三个保障:

  1. 路径不重叠:两条管道分别改写 messages[] 和 tools[],互不干扰;
  2. 上下文隔离:router.go 为并行分支深拷贝 PipeContext,并将只属于对方的字段置空,避免数据竞争;
  3. 故障隔离:每个 worker 都用 recover() 兜住 panic,单条管道失败时回退到原始请求体,绝不让网关把正常请求搞挂。

4.3 智能跳过:便宜模型不压缩

tool_output 管道 内置了一个反直觉但非常实用的机制:如果目标模型是廉价模型(如 gpt-4o-mini),自动跳过压缩——因为压缩 API 本身的成本可能超过省下的 token 费用。压缩还有 token 阈值(默认 min_tokens: 512,max_tokens: 50000),太小不值得压,太大可能压不动。

五、影子存储与 expand_context:压缩了还能"还原"

这是 Context Gateway 区别于简单截断方案的核心能力。压缩后的工具输出以 [REF:shadow_id] 引用标记的形式留在对话中,原文存入 store 模块 的"影子存储",并采用双 TTL 策略:

  • 原文 5 小时 TTL:会话期间 LLM 发现信息不够时,可调用注入的 expand_context 工具按 ID 取回原文;
  • 压缩内容 24 小时 TTL:保证跨会话 KV-Cache 前缀稳定——已压缩的历史轮次不会被再次改写,避免缓存全部失效。

存储层用 LRU 上限控制内存(原文 1000 条 ≈ 5MB,压缩缓存 2000 条 ≈ 4MB),当前是内存实现,接口预留了 Redis 等多实例扩展点。

六、预压缩:让历史压缩"零等待"

preemptive 模块 实现了 README 中宣传的"即时历史压缩":一个后台 Worker 持续监控各会话的 token 使用量,当接近触发阈值(默认 75%)时提前调用摘要模型生成历史摘要。等会话真的触及上下文上限时,摘要已经就绪,压缩动作瞬时完成——用户永远不会卡在一次漫长的摘要生成上。

七、热更新与配置驱动

所有管道都支持配置热加载:Router.UpdateConfig 在收到新配置时先构建全新的 worker 池,再原子替换引用,进行中的请求继续使用旧池完成,做到无中断热更新。每个管道池默认 10 个 worker,通过 channel 实现获取/归还,天然限流。

八、总结:值得借鉴的五个架构模式

回顾整个 Context Gateway 的设计,有五个模式尤其值得做 LLM 基础设施的同学参考:

  1. 集中式识别入口:Provider 检测只有一个入口(IdentifyAndGetAdapter),规则集中、优先级显式,杜绝散落各处的 if-else;
  2. 无状态适配器 + 注册表:新增 Provider 是"加文件"而非"改代码";
  3. 管道/适配器解耦:压缩算法只写一遍,协议差异全部下沉到适配器;
  4. 路径不重叠的并行管道 + 故障隔离:性能与稳定性兼得;
  5. 压缩可逆:影子存储 + expand_context,让"省 token"和"保信息"不再二选一。

如果你想动手验证,可以通过 make 或脚本 scripts/start_gateway.sh 启动网关,再运行 tests/anthropic/ 下的端到端测试观察压缩效果;压缩明细会写入 logs/history_compaction.jsonl,方便逐请求审计。

📌 关键源码地图:internal/pipes/pipe.go(管道接口)、internal/adapters/adapter.go(适配器接口)、internal/gateway/router.go(调度核心)、internal/store/store.go(影子存储)。

【免费下载链接】Context-Gateway

Context Gateway is an agentic proxy that enhances any AI agent workflow with instant history compaction and context optimization tools

项目地址: https://gitcode.com/gh_mirrors/co/Context-Gateway
点击查看 免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值