跳到主要内容

ADR-008 — LLM Provider 接口抽象

决策

FinBayes Provider Adapter Pool 内部对所有 LLM Provider 采用 统一 OpenAI-compatible 接口,不直接调用各家 SDK。

M0 阶段最小实施

  1. 统一接口:Provider Adapter Pool 内部所有 LLM 调用走 OpenAI Chat Completions API + Function Calling 协议(含 streaming / tool_calls / usage 字段)
  2. 客户端实现:基于 httpx.AsyncClient 自实现最小客户端(不强依赖 LiteLLM / LangChain);接口签名见 m0-walking-skeleton §2 call_llm
  3. M0 仅 L1 implement:仅实现 L1 用户配置 Provider 的调用路径(OpenAI-compatible 端点 + API key 从 OS Keychain 读取,详见 m0-walking-skeleton §13 Provider key 加载顺序);L1' / L2 / L3 / L4 全部 stub(详见 m0-walking-skeleton §1 表)
  4. 统一响应类型LLMResponse Pydantic 模型(详见 m0-walking-skeleton §3)含 content / tool_calls / finish_reason / usage 四字段,与 OpenAI 响应字段 1:1
  5. Provider 配置格式providers.yaml 内 Provider 条目最小字段:provider_id(格式 <provider_type>:<model_id>)/ endpoint_url / api_key_ref(指向 Keychain 中的 key 名)/ model / enabled

M1+ 演化空间

  • L1' 系统默认 Provider(FinBayes 团队代付小流量兜底)
  • L2 本地嵌入式 LLM(Ollama / vLLM 集成,仍走 OpenAI-compatible 端点)
  • L3 缓存 + 规则兜底(BM25 + 关键词词典,详见 CHAP-09)
  • L4 受限菜单 UI
  • 跨 Provider 路由(task_routing.yaml 配置任务类型 → Provider 偏好)

上下文

业界 LLM Provider 接口现状:

Provider接口
OpenAIOpenAI Chat Completions + Function Calling(原生)
Anthropic自有 Messages API + tool use,也提供 OpenAI-compatible endpoint
DeepSeek / Qwen / Moonshot / Mistral / 等自有 + OpenAI-compatible endpoint
Ollama / vLLM / LM Studio自有 + OpenAI-compatible endpoint
Google Gemini自有 Vertex AI + GenAI SDK;第三方代理可转 OpenAI-compatible

OpenAI-compatible 是事实标准。第三方库(LiteLLM 等)做了同类抽象但增加依赖与版本管理风险。

FinBayes 工程范式(ADR-001 + ADR-003)要求接口抽象不依赖外部库的稳定性 —— 自实现最小客户端比依赖 LiteLLM 风险低(M1+ 视情况再评估是否引入)。

后果

收益

  • 新增 Provider 不动 runtime 业务代码(仅在 providers.yaml 加条目 + Provider Adapter Pool 内部测试 fixture)
  • 与 ADR-004 Function Calling 主导一致(OpenAI 协议是 Function Calling 的事实标准)
  • LLMResponse 模型固定让综合层 / 审计 / 评估 闭环不受 Provider 变化影响
  • 多 Provider 在统一接口下做评估对比变得简单(详见 CHAP-21)

成本

  • 各 Provider 端实现的 OpenAI-compatible 兼容度参差不齐(如 finish_reason 枚举值不一致 / tool_calls 字段位置差异)→ Provider Adapter 内部做最小归一化
  • 个别 Provider 独有能力(如 Anthropic prompt caching / Gemini 多模态)需要绕过统一接口直接调原生 → M0 不支持,M2+ 可在 Provider Adapter 内做"扩展点"承接

残余风险

  • OpenAI 端 API 变化(如 GPT-5 引入新字段)→ fixture 版本检测 + Provider Adapter 内部适配
  • Provider 端突然废弃 OpenAI-compatible 端点 → fallback 到 L1' 系统默认(M1+)

备选方案

考虑过未采用:

  • 直接调各家原生 SDK:M0 工作量翻倍 / 跨 Provider 测试复杂 / 评估对比难
  • 依赖 LiteLLM:增加外部库依赖管理风险 / LiteLLM 自身 API 变化频繁 / 调试链路加长
  • 直接抽象到自定义 Protocol:抽象层更高但脱离业界标准 / 新 Provider 接入时仍要做映射

关联

  • 触发章节:CHAP-09 Provider Adapter Pool 子系统
  • 影响章节:CHAP-09 / CHAP-13 故障与降级路径 / CHAP-15 数据存储划分(Credential Store)
  • M0 实施承接:m0-walking-skeleton.md §2 Provider Adapter Pool 接口子集 + §3 LLMResponse 模型 + §13 Bootstrap 模板(httpx 客户端配置)
  • 关联 ADR:ADR-004(任务识别策略)/ ADR-010(输出端过滤)
  • 后续:M1+ 起新增 L1' / L2 / L3 / L4 实现时本 ADR 不变;任何 OpenAI-compatible 协议层变更走新 ADR 替代或 patch