Files
ocp/PLAN-v4.md
T
taodengandClaude Opus 4.6 1f1b3871da feat: Phase 1 — modular backend architecture (v4.0-alpha)
Internal refactor: extract BackendAdapter, ModelRegistry, AgentRouter,
SessionManager, and StatsCollector as standalone modules. Claude CLI
logic encapsulated in ClaudeCliAdapter.

External API completely unchanged — all existing endpoints behave
identically. Legacy request path (callClaude/callClaudeStreaming)
untouched. v4 modules load in parallel for validation.

New endpoints:
  GET /backends  — backend health and status
  GET /routing   — agent routing table

Architecture:
  unified-chunk.mjs    — streaming protocol (delta/done/error)
  backends/base.mjs    — BackendAdapter interface
  backends/claude-cli.mjs — Claude CLI adapter (core)
  model-registry.mjs   — model → backend mapping (Layer 1)
  agent-router.mjs     — agent policy routing (Layer 2)
  session-manager.mjs  — conversation session management
  stats-collector.mjs  — per-model/backend/agent metrics

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 08:02:53 +10:00

14 KiB
Raw Blame History

OCP v4.0 开发计划 — Agent 成本控制器

背景

OCP 当前架构:Tool → OCP (localhost:3456) → Claude CLI → Anthropic

核心风险:Claude CLI proxy 属于灰色地带,Anthropic 随时可能封堵。

核心资产(不依赖 CLI 的部分):

  • OpenAI 兼容 API 层
  • Session 管理(会话隔离、TTL、复用)
  • Usage 监控(plan limits、per-model stats、实时查询)
  • 运行时调参(timeout、并发、prompt 限制)
  • /ocp 命令集(Telegram/Discord/CLI
  • 多实例并发控制

定位

OCP is a cost-control and model-routing layer for AI agents, optimized for subscription-based usage.

不是 proxy,不是 gateway,不是 LiteLLM clone。 是:让 Agent 用模型这件事变得可控 — 尤其是成本。

核心差异点:OCP 有 agent 上下文,知道是谁在请求、在做什么任务、已经花了多少。LiteLLM 只看到 HTTP 请求。

目标

将 OCP 从 "Claude CLI proxy" 重构为 "Agent 成本控制器",支持可扩展的多后端,保留全部管理能力。


⚠️ 第零原则:不动现有功能

OCP 作为 Claude CLI proxy 是当前的核心价值和用户吸引力。所有 v4 重构必须遵守:

  • 外部 API 不变/v1/chat/completions/usage/health/settings 签名不变
  • 行为不变 — 现有用户升级后零感知,所有 session/timeout/并发逻辑保持原样
  • 逐步替换 — 先抽模块,跑稳了再切;任何时候回归测试不过就回滚
  • 新 backend 是增量 — 加 OpenAI/Ollama 是新能力,不改动 Claude CLI 路径

Phase 1 的定义就是:拆完之后跟没拆一样。 拆出问题就说明拆法有误。


架构关键决策(三轮 Design Review 定稿)

决策 1: 路由分两层 — Model Registry + Agent Policy

三轮讨论结论:

  • 第一轮建议"删掉 model routing" → 错误,非 agent 客户端(Cline/Aider)只带 model 名
  • 反驳:model-to-backend mapping 是基础设施,不是 routing rule
  • 校准:物理拆成两个模块,不要混在一起

最终设计 — 两层分离:

🧱 Layer 1: Model Registry(基础设施层)
   model-registry.mjs
   静态映射,无条件,必须存在
   "claude-sonnet-4-6" → claude-cli backend
   "gpt-4o" → openai backend
   "qwen3" → ollama backend

🧠 Layer 2: Agent Policy(策略层)
   agent-router.mjs
   动态决策,可覆盖,可选
   agent "coder" → override to claude-cli
   agent "interpreter" → override to ollama

路由决策顺序(写死):

1. Agent policy override  → 有 agent identity 且有配置?用它
2. Model registry         → 模型属于哪个 backend?路由过去
3. Default backend        → 都没匹配?全局默认
4. Fallback chain         → 上面选的挂了?降级

决策 2: 统一 Streaming 协议

所有 adapter 必须输出统一的内部 chunk 格式:

{
  type: "delta" | "done" | "error",
  content?: string,
  model: string,
  backend: string,
  usage?: { promptTokens: number, completionTokens: number }
}

server.mjs 只处理统一协议 → 转换为 OpenAI SSE 输出。

决策 3: 成本标记 — actual / estimated / free

{
  cost: {
    value: 0.23,
    type: "actual" | "estimated" | "free"
  }
}
Backend cost type 来源
OpenAI API actual API 返回 usage
Claude CLI estimated prompt chars × 估价
Ollama free 本地运行

/ocp cost 输出明确标注类型,不误导用户。

决策 4: Fallback — 只在 First-Byte 前触发

const allowFallback = !hasStartedStreaming;

Phase 3 严格限制:已输出 ≥1 个 delta → 不 fallback,直接报错。 flag 预留,未来扩展 streaming fallback 只改判断条件。

决策 5: Agent Identity — 结构预留,实现从简

优先级:

1. x-ocp-agent header       → OpenClaw 自动附加
2. Session metadata          → 首次请求绑定,后续复用
3. (future) Inferred         → 按使用模式推断(预留接口)
4. default                   → 兜底

现在只实现 1 + 2 + 4。 但接口预留 inferred 扩展点。

为什么重要:未来 Cline coding mode 和 chat mode 可能需要不同路由,如果没有 identity hook 以后很难加。


Backend Adapter 设计

接口

class BackendAdapter {
  get id()            // "claude-cli" | "openai-api" | "ollama"
  get displayName()
  get models()
  get costType()      // "actual" | "estimated" | "free"
  get tier()          // "core" | "community"

  async healthCheck()  { ok, message, latencyMs }
  async *chatCompletion(request)  AsyncGenerator<UnifiedChunk>
  async initialize(config)
  async shutdown()
}

Backend Tier 体系

OCP provides a pluggable backend adapter interface. Core adapters are maintained officially; community adapters are contributed by users.

/ocp backends 输出示例:

claude-cli   ✓ healthy  12ms   (core)
openai       ✓ healthy  89ms   (core)
ollama       ✓ healthy   5ms   (core)
deepseek     ✓ healthy 120ms   (community)

架构不限制 backend 数量。我们主动维护 3 个 core adapterClaude CLI、OpenAI 兼容、Ollama),接口开放,社区可贡献更多。

OpenAI 兼容的服务(DeepSeek、Groq、Together 等)直接复用 OpenAiApiAdapter,只需换 baseUrl + apiKey,不算新 adapter。


分阶段实施

Phase 1: 后端抽象 + Model Registryv4.0-alpha

目标: 不改变外部行为,内部重构

  • 定义 BackendAdapter 接口 + UnifiedChunk 类型
  • model-registry.mjs — 模型到 backend 的静态映射
    • getBackendForModel(model) → backendId
  • agent-router.mjs — 路由决策引擎
    • resolveBackend({ agent, model }) → backendId
    • 实现决策顺序:agent override → model registry → default → fallback
  • 将 Claude CLI 逻辑封装为 ClaudeCliAdapter
    • stdout → UnifiedChunk 转换
    • costType = "estimated"
  • 抽取 SessionManager(从 server.mjs
  • 抽取 StatsCollectorper-agent, per-backend
  • Config v4 格式(带 version + validation):
{
  "version": "4.0",
  "backends": {
    "claude-cli": {
      "type": "claude-cli",
      "tier": "core",
      "enabled": true,
      "models": ["claude-sonnet-4-6", "claude-opus-4-6", "claude-haiku-4-5"],
      "maxConcurrent": 4,
      "timeout": { "firstByte": 120000, "overall": 300000 },
      "estimatedCostPerMTok": { "input": 3.0, "output": 15.0 }
    }
  },
  "agents": {
    "default": { "preferred": "claude-cli", "fallback": null }
  }
}
  • 启动时 config validation
  • /ocp backends 命令
  • 所有现有测试通过,行为不变

验收标准: 现有用户升级后零感知变化

Phase 2: OpenAI API 后端(v4.0-beta

目标: 第二个 backend,验证 adapter 抽象

  • OpenAiApiAdapter
    • SSE → UnifiedChunk
    • costType = "actual"
    • 支持任何 OpenAI 兼容端点(baseUrl + apiKey
  • Model registry 自动注册新 backend 的 models
  • Agent routing 生效:
{
  "agents": {
    "default": { "preferred": "claude-cli", "fallback": "openai" },
    "interpreter": { "preferred": "openai/gpt-4o-mini", "fallback": null }
  }
}
  • Non-streaming fallbackallowFallback = !hasStartedStreaming
  • Stats 按 backend + agent 分组

验收标准: claude-cli 挂了 → default agent 自动 fallback 到 openai

Phase 3: Ollama + Agent Routing 稳定化(v4.0-rc

目标: 摆脱付费依赖,agent routing 跑稳

  • OllamaAdapter
    • 自动发现模型
    • costType = "free"
  • Agent routing 完整覆盖所有 agent
{
  "agents": {
    "main":        { "preferred": "claude-cli/opus", "fallback": "openai" },
    "tech_geek":   { "preferred": "claude-cli/sonnet", "fallback": "ollama/qwen3" },
    "interpreter": { "preferred": "ollama/qwen3", "fallback": null }
  }
}
  • /ocp routing — 显示每个 agent 当前走哪个 backend
  • 端到端测试:Claude CLI 下线 → agent 自动 fallback → 恢复后自动回切

验收标准: 三个 backend 同时运行,每个 agent 走不同路径,稳定无错

Phase 4: Budget + Cost Controlv4.1

目标: 核心差异化 — agent-aware 成本控制

前置条件: Phase 3 routing 稳定(先确定流量怎么走 → 再控制花多少钱)

安全原则: 没有显式配置 budget 的 agent → 行为等同于 v3(不限制、不降级、不告警)。Budget 是 opt-in,不是 opt-out。

  • Per-agent 预算:
{
  "agents": {
    "main": {
      "preferred": "claude-cli/opus",
      "fallback": "openai",
      "dailyBudget": { "limit": 3.00, "onExhausted": "downgrade" }
    }
  },
  "budget": {
    "global": { "daily": 10.00, "onExhausted": "warn" }
  }
}
  • 超预算行为:downgrade | block | warn
  • /ocp cost — per-agent 成本(标注 actual/estimated/free
  • Telegram 告警(预算 80%、backend 连续失败)

Phase 5: Anthropic 官方 APIv4.2,等时机)

  • AnthropicApiAdapter(官方 SDK
  • 迁移指南:一行配置切换
  • costType = "actual"

文件结构(目标)

claude-proxy/
├── server.mjs              → HTTP 层(统一 chunk → SSE 输出)
├── model-registry.mjs      → 模型注册表(model → backend 映射)
├── agent-router.mjs        → Agent 路由引擎(策略层)
├── session-manager.mjs     → 会话管理
├── stats-collector.mjs     → 统计 + 成本追踪
├── config.mjs              → 配置加载 + 版本验证
├── unified-chunk.mjs       → UnifiedChunk 类型定义
├── backends/
│   ├── base.mjs            → BackendAdapter 接口
│   ├── claude-cli.mjs      → Claude CLIcore
│   ├── openai-api.mjs      → OpenAI 兼容(core
│   └── ollama.mjs          → Ollama 本地(core
├── setup.mjs               → 安装向导
└── ocp-plugin/             → Gateway 命令插件

配置完整示例(目标状态)

{
  "version": "4.0",
  "port": 3456,

  "backends": {
    "claude-cli": {
      "type": "claude-cli",
      "tier": "core",
      "enabled": true,
      "models": ["claude-sonnet-4-6", "claude-opus-4-6"],
      "maxConcurrent": 4,
      "timeout": { "firstByte": 120000, "overall": 300000 },
      "estimatedCostPerMTok": { "input": 3.0, "output": 15.0 }
    },
    "openai": {
      "type": "openai-api",
      "tier": "core",
      "enabled": true,
      "baseUrl": "https://openrouter.ai/api/v1",
      "apiKey": "${OPENROUTER_API_KEY}",
      "models": ["anthropic/claude-3.5-sonnet", "google/gemini-2.0-flash"],
      "maxConcurrent": 10,
      "timeout": { "firstByte": 30000, "overall": 120000 }
    },
    "ollama": {
      "type": "ollama",
      "tier": "core",
      "enabled": true,
      "baseUrl": "http://localhost:11434",
      "models": "auto"
    }
  },

  "agents": {
    "default": {
      "preferred": "claude-cli",
      "fallback": "openai"
    },
    "main": {
      "preferred": "claude-cli/claude-opus-4-6",
      "fallback": "openai",
      "dailyBudget": { "limit": 3.00, "onExhausted": "downgrade" }
    },
    "tech_geek": {
      "preferred": "claude-cli/claude-sonnet-4-6",
      "fallback": "ollama/qwen3",
      "dailyBudget": { "limit": 2.00, "onExhausted": "fallback" }
    },
    "interpreter": {
      "preferred": "ollama/qwen3",
      "fallback": null
    }
  },

  "fallback": {
    "onlyBeforeFirstByte": true,
    "triggers": ["timeout", "rate-limit", "connection-error"],
    "maxRetries": 1
  },

  "budget": {
    "global": { "daily": 10.00, "onExhausted": "warn" },
    "alerts": { "threshold": 0.8, "channel": "telegram" }
  },

  "sessions": { "ttl": 3600000, "maxPromptChars": 150000 },
  "monitoring": { "retainHours": 72 }
}

风险与应对

风险 应对
Claude CLI 被封 切换 backend,上层不变
Anthropic 出订阅 API 实现 anthropic-api adapter,成本控制层继续有价值
LiteLLM 竞争 不竞争。OCP 做 agent-aware 成本控制,赛道不同
成本数据不准 cost type 标记 actual/estimated/free
Streaming fallback 拼接 Phase 3 只做 non-streaming fallback
过度工程 只维护 3 个 core backendphase 严格拆分

优先级

Phase 时间 内容 交付物
1 本周 重构:adapter 接口 + model registry + agent router 行为不变,架构就位
2 1-2 周 OpenAI backend 两个 backend 跑通
3 2-3 周 Ollama + Agent routing 稳定化 三 backend + per-agent 路由
4 按需 Budget + Cost control 成本可控
5 等时机 Anthropic 官方 API 逃生通道

成功标准

  1. Claude CLI 被封的那天,改一行配置,所有 agent 继续运行
  2. /ocp cost 每个 agent 花了多少(actual/estimated/free
  3. 翻译 agent 自动用 Ollama$0),coding agent 用 Claude
  4. 超预算自动降级,不需人工干预
  5. 新 backend 只需实现 BackendAdapter 接口 + 一个文件

设计审核记录

轮次 审核方 关键结论
第一轮 AI-A 定位从 proxy 转向成本控制器;识别 5 个 P0 问题
第二轮 Claude(本项目开发者) 反驳:不能删 model routing(基础设施层);backend 数量是运营决策不是架构约束;budget 拆到 Phase 4
第三轮 AI-A 校准:model registry 与 routing 物理拆开两个模块;agent identity 结构预留 inferred 扩展点;backend 加 tier 标记

一句话总结

短期靠套利活(Claude CLI proxy),长期靠控制力活(Agent 成本控制器)。两条腿走路,CLI 死了上层不死。