🧠 LLM 集成

Provider 选型 / Failover / Routing / 成本控制 — 造 AI 产品最核心的基础设施层
📑 目录

§1 为什么 LLM 集成是基础设施层

在 AI 产品中,LLM 调用不像"发一个 HTTP 请求"那么简单。它是产品的核心引擎——调用质量决定了产品质量,调用成本决定了商业模型,调用稳定性决定了用户体验。

当你只有 1 个用户、1 个模型时,直接 openai.chat.completions.create() 就够了。但当你有 1000 个用户、多个模型、需要 99.9% 可用性时,你需要一套LLM 基础设施层

用户请求 │ ▼ ┌─────────────────────────────────────────────┐ LLM 基础设施层 ┌──────────┐ ┌──────────┐ ┌──────────┐ Routing │ │ Failover │ │ Cost │ 智能路由 │ │ 故障切换 │ │ 成本控制 │ └──────────┘ └──────────┘ └──────────┘ ┌──────────┐ ┌──────────┐ ┌──────────┐ Cache │ │ Stream │ │ Observ │ 语义缓存 │ │ 流式输出 │ │ 可观测性 │ └──────────┘ └──────────┘ └──────────┘ └─────────────────────────────────────────────┘ │ ▼ OpenAI Anthropic Google DeepSeek 本地...
🎯 LLM 集成要解决的核心问题

§2 Provider 全景:2026 主流选项

2.1 OpenAI

OpenAI — 行业标杆

生态最全 Function Calling 价格中高

模型矩阵 (2025-2026)

模型上下文输入/输出价格 (per 1M tokens)最佳场景
GPT-4o128K$2.50 / $10通用复杂推理
GPT-4o mini128K$0.15 / $0.60分类/提取/简单任务
o3200K$2.00 / $8.00深度推理 (thinking)
o4-mini200K$1.10 / $4.40推理 + 性价比
GPT-4.11M$2.00 / $8.00超长上下文 + 指令遵循
GPT-4.1 mini1M$0.40 / $1.60长上下文 + 性价比
GPT-4.1 nano1M$0.10 / $0.40分类/路由/轻量任务

代码示例:基础调用

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
});

const response = await client.chat.completions.create({
  model: 'gpt-4o',
  messages: [
    { role: 'system', content: '你是一个专业的代码审查助手。' },
    { role: 'user', content: '审查这段代码:...' },
  ],
  temperature: 0.3,
  // 结构化输出 — 确保返回 JSON
  response_format: { type: 'json_object' },
});

console.log(response.choices[0].message.content);

代码示例:Function Calling (工具调用)

const tools = [{
  type: 'function',
  function: {
    name: 'search_docs',
    description: '搜索内部文档库',
    parameters: {
      type: 'object',
      properties: {
        query: { type: 'string', description: '搜索关键词' },
        limit: { type: 'number', description: '返回结果数量' },
      },
      required: ['query'],
    },
  },
}];

const response = await client.chat.completions.create({
  model: 'gpt-4o',
  messages: [{ role: 'user', content: '查找关于缓存的文档' }],
  tools,
  tool_choice: 'auto', // auto | required | none | { type: 'function', function: { name: '...' } }
});

// 处理工具调用
if (response.choices[0].message.tool_calls) {
  for (const call of response.choices[0].message.tool_calls) {
    const args = JSON.parse(call.function.arguments);
    const result = await searchDocs(args.query, args.limit);
    // 将结果返回给模型继续对话
  }
}

优势与劣势

✅ 生态最成熟,SDK / 社区 / 教程最多

✅ Function Calling 稳定可靠

✅ Structured Outputs (JSON Schema 强制)

✅ Vision / Audio 多模态齐全

✅ Batch API 半价,适合离线处理

❌ 价格偏高,尤其输出 token

❌ 国内直连不稳定,需要代理

❌ 速率限制严格 (Tier 制度)

❌ 数据政策:默认不训练,但需主动 opt-out

❌ Vendor lock-in 风险

2.2 Anthropic (Claude)

Anthropic — 安全优先,编码之王

编码最强 长上下文 价格高 Thinking

模型矩阵

模型上下文输入/输出价格 (per 1M tokens)最佳场景
Claude Sonnet 4200K$3.00 / $15.00通用 + 编码 + 推理
Claude Opus 4200K$15.00 / $75.00最复杂推理任务
Claude Haiku 3.5200K$0.80 / $4.00分类/提取/轻量任务

代码示例:Extended Thinking

import Anthropic from '@anthropic-ai/sdk';

const client = new Anthropic({ apiKey: process.env.ANTHROPIC_API_KEY });

const response = await client.messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 16000,
  thinking: {
    type: 'enabled',
    budget_tokens: 10000, // 分配给思考的 token 预算
  },
  messages: [{
    role: 'user',
    content: '设计一个分布式任务调度系统的架构',
  }],
});

// thinking 内容在 content 数组的第一个块
const thinkingBlock = response.content.find(b => b.type === 'thinking');
const textBlock = response.content.find(b => b.type === 'text');

console.log('思考过程:', thinkingBlock?.thinking);
console.log('最终回答:', textBlock?.text);

代码示例:Tool Use

const response = await client.messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 4096,
  tools: [{
    name: 'get_weather',
    description: '获取指定城市的天气',
    input_schema: {
      type: 'object',
      properties: {
        city: { type: 'string', description: '城市名' },
      },
      required: ['city'],
    },
  }],
  messages: [{ role: 'user', content: '北京今天天气怎么样?' }],
});

// 检查是否有工具调用
const toolUse = response.content.find(b => b.type === 'tool_use');
if (toolUse) {
  console.log(`调用工具: ${toolUse.name}`);
  console.log(`参数: ${JSON.stringify(toolUse.input)}`);
}

优势与劣势

✅ 编码能力业界最强

✅ 200K 超长上下文,丢书进去能总结

✅ Extended Thinking 透明推理链

✅ 安全对齐最好,幻觉率低

✅ Prompt Caching 节省 90% 输入成本

❌ 价格最高 (Opus 输出 $75/M tokens)

❌ 速率限制极严,需要爬 Tier

❌ 国内无直连,代理更不稳定

❌ 不支持 JSON Schema 强制输出 (需 prompt 约束)

❌ 生态比 OpenAI 小

2.3 Google Gemini

Google Gemini — 长上下文之王,免费额度大

1M 上下文 免费额度 多模态原生

模型矩阵

模型上下文输入/输出价格 (per 1M tokens)最佳场景
Gemini 2.5 Pro1M$1.25 / $10.00 (≤128K) | $2.50 / $15.00 (>128K)长文档/视频/复杂推理
Gemini 2.5 Flash1M$0.15 / $0.60 (≤128K) | $0.40 / $1.50 (>128K)高速/高性价比
Gemini 2.0 Flash1M$0.10 / $0.40简单任务/分类

代码示例

import { GoogleGenerativeAI } from '@google/generative-ai';

const genAI = new GoogleGenerativeAI(process.env.GOOGLE_API_KEY);

const model = genAI.getGenerativeModel({
  model: 'gemini-2.5-flash',
  generationConfig: {
    temperature: 0.7,
    maxOutputTokens: 4096,
  },
});

// 支持多模态输入
const result = await model.generateContent([
  { text: '描述这张图片的内容' },
  { inlineData: { mimeType: 'image/png', data: imageBase64 } },
]);

console.log(result.response.text());

// Function Calling
const modelWithTools = genAI.getGenerativeModel({
  model: 'gemini-2.5-flash',
  tools: [{
    functionDeclarations: [{
      name: 'query_database',
      description: '查询数据库',
      parameters: {
        type: 'object',
        properties: {
          sql: { type: 'string', description: 'SQL 查询语句' },
        },
        required: ['sql'],
      },
    }],
  }],
});

优势与劣势

✅ 1M token 上下文窗口,业界最长

✅ 免费额度慷慨 (Flash 免费)

✅ 多模态原生 (图片/视频/音频)

✅ Grounding (Google 搜索) 能力

✅ Context Caching 节省成本

❌ 指令遵循弱于 OpenAI/Anthropic

❌ SDK 文档质量参差不齐

❌ 国内同样需要代理

❌ JSON 输出不如 OpenAI 可靠

2.4 DeepSeek

DeepSeek — 性价比之王,开源标杆

极低成本 开源可部署 国内直连

模型矩阵

模型上下文输入/输出价格 (per 1M tokens)最佳场景
DeepSeek-V3128K¥1 / ¥2 (缓存命中 ¥0.1)通用对话/编码
DeepSeek-R1128K¥4 / ¥16深度推理 (thinking)
DeepSeek-R1-Distill128K¥1 / ¥4推理 + 性价比
💡 缓存命中价:DeepSeek 对重复前缀(system prompt + 历史消息)有缓存机制,命中后输入价格降 90%。对于多轮对话场景,实际成本远低于标价。

代码示例

// DeepSeek API 兼容 OpenAI 格式!
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.DEEPSEEK_API_KEY,
  baseURL: 'https://api.deepseek.com', // 只改这一个!
});

// 代码完全一样
const response = await client.chat.completions.create({
  model: 'deepseek-chat', // V3
  messages: [{ role: 'user', content: '解释量子计算' }],
  temperature: 0.3,
});

// R1 推理模型
const r1Response = await client.chat.completions.create({
  model: 'deepseek-reasoner', // R1
  messages: [{ role: 'user', content: '证明 √2 是无理数' }],
});

优势与劣势

✅ 价格极低,V3 输出仅 ¥2/M tokens

✅ API 兼容 OpenAI SDK,零迁移成本

✅ 国内直连,延迟低

✅ 开源模型可自部署

✅ R1 推理链透明可审查

❌ 编码能力弱于 Claude/GPT-4o

❌ Function Calling 格式偶有不稳定

❌ 高峰期偶尔排队

❌ 英文场景弱于 OpenAI/Anthropic

❌ 社区生态较新,坑多文档少

2.5 通义千问 (Qwen)

通义千问 — 国内最强开源模型,阿里云生态

国内最强 阿里云集成 开源

模型矩阵

模型上下文输入/输出价格 (per 1M tokens)最佳场景
Qwen-Max128K¥2 / ¥6复杂推理/编码
Qwen-Plus128K¥0.8 / ¥2通用/性价比
Qwen-Turbo128K¥0.3 / ¥0.6简单任务/分类
Qwen3-Coder128K按量编码专用

代码示例

// 通义千问同样兼容 OpenAI 格式
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.DASHSCOPE_API_KEY,
  baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
});

const response = await client.chat.completions.create({
  model: 'qwen-max',
  messages: [{ role: 'user', content: '帮我写一个 React Hook' }],
  // 启用思考模式
  extra_body: { enable_thinking: true },
});

优势与劣势

✅ 中文能力国内最强

✅ 阿里云生态无缝集成

✅ 国内合规无忧

✅ 开源 Qwen 系列可自部署

❌ 英文/编码弱于国际模型

❌ Function Calling 可靠性一般

❌ 文档质量参差

2.6 智谱 GLM

智谱 GLM — 国内老牌,性价比高

免费额度大 学术出身 国内合规

模型矩阵

模型上下文输入/输出价格 (per 1M tokens)最佳场景
GLM-4-Plus128K¥5 / ¥5通用复杂任务
GLM-4-Flash128K免费轻量任务/开发测试
GLM-4-FlashX128K免费高速场景
GLM-Z1-Air128K¥1 / ¥1推理场景

代码示例

import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.ZHIPU_API_KEY,
  baseURL: 'https://open.bigmodel.cn/api/paas/v4',
});

const response = await client.chat.completions.create({
  model: 'glm-4-plus',
  messages: [{ role: 'user', content: '分析这段代码的性能瓶颈' }],
  tools: [{
    type: 'function',
    function: {
      name: 'run_benchmark',
      description: '运行性能基准测试',
      parameters: {
        type: 'object',
        properties: { test_name: { type: 'string' } },
        required: ['test_name'],
      },
    },
  }],
});
💡 GLM-4-Flash 完全免费!非常适合做开发测试、低流量产品的默认模型。很多 Agent 框架用它做路由预判。

2.7 Mistral

Mistral — 欧洲之光,开源先锋

开源 欧洲数据合规 小而精

模型矩阵

模型上下文价格 (per 1M tokens)最佳场景
Mistral Large128K$2.00 / $6.00复杂推理
Mistral Medium128K$0.70 / $2.10通用
Codestral256K$0.30 / $0.90编码专用
Mistral Small128K$0.20 / $0.60轻量任务

优势与劣势

✅ 开源模型可自部署

✅ 欧洲数据主权合规 (GDPR)

✅ Codestral 编码性价比高

✅ API 简洁高效

❌ 顶级推理弱于 GPT-4o/Claude

❌ 中文能力一般

❌ 生态规模小于 OpenAI/Google

2.8 本地模型 (Ollama / vLLM)

本地部署 — 数据不出服务器

零 API 成本 数据主权 需要 GPU

部署方案对比

方案适合场景GPU 需求并发能力
Ollama开发/个人/小团队1 张消费级 GPU低 (串行)
vLLM生产环境1-8 张 A100/H100高 (PagedAttention)
llama.cppCPU 推理/嵌入式可选 GPU
TensorRT-LLMNVIDIA 优化部署NVIDIA GPU最高

代码示例:Ollama + OpenAI 兼容

// Ollama 也兼容 OpenAI 格式!
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: 'ollama', // 任意值
  baseURL: 'http://localhost:11434/v1',
});

const response = await client.chat.completions.create({
  model: 'qwen3:8b', // 或 llama3, mistral, deepseek-r1:7b
  messages: [{ role: 'user', content: '写一个快排' }],
});

代码示例:vLLM 部署

# 启动 vLLM 服务 (兼容 OpenAI API)
python -m vllm.entrypoints.openai.api_server \
  --model Qwen/Qwen3-72B \
  --tensor-parallel-size 4 \   # 4 GPU 并行
  --max-model-len 32768 \
  --gpu-memory-utilization 0.9 \
  --port 8000

# 然后就可以用 OpenAI SDK 调用了
# baseURL: http://localhost:8000/v1
⚠️ 本地模型看似"免费",但 GPU 成本不低:一张 A100 约 ¥15,000/月(云厂商租用),电费 + 运维也需考虑。算总账后,小规模 (<1M req/月) 用云 API 通常更便宜。

§3 Provider 横向对比

维度OpenAIAnthropicGoogleDeepSeekQwenGLMMistral
编码能力 ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
中文能力 ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
推理深度 ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
性价比 ⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
国内直连
Function Calling 最稳稳定较稳一般一般较稳较稳
开源可部署 部分部分
长上下文 1M (4.1)200K1M128K128K128K128K
💡 选型建议:面向国内用户 → DeepSeek/Qwen/GLM 为主,海外 API 做备选。面向海外用户 → OpenAI/Anthropic 为主。编码场景 → Claude Sonnet 4 无悬念。需要超长上下文 → Gemini 2.5 Pro。追求性价比 → DeepSeek V3 或本地 Ollama。

§4 抽象层:统一 API 的设计

为什么需要抽象层?直接调 openai.chat.completions.create() 有什么问题?

🚫 不做抽象的后果

4.1 抽象层设计模式

业务代码 │ ▼ ┌────────────────────────────────────────────┐ LLM 抽象层 (统一接口) interface LLMProvider { chat(messages, options) → Response chatStream(messages, options) → Stream embed(text) → number[] } ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐ OpenAI│ │Claude│ │Gemini│ │DeepSeek └──────┘ └──────┘ └──────┘ └──────┘ └────────────────────────────────────────────┘

4.2 TypeScript 实现

// types.ts — 统一类型定义
interface ChatMessage {
  role: 'system' | 'user' | 'assistant' | 'tool';
  content: string;
  toolCallId?: string;
  toolCalls?: ToolCall[];
}

interface ToolCall {
  id: string;
  name: string;
  arguments: Record<string, unknown>;
}

interface ChatOptions {
  model?: string;
  temperature?: number;
  maxTokens?: number;
  tools?: ToolDefinition[];
  responseFormat?: { type: 'text' | 'json' };
  stream?: boolean;
  // 高级选项
  timeout?: number;
  retries?: number;
  cacheKey?: string;       // 语义缓存键
  costLimit?: number;      // 单次调用成本上限
  metadata?: Record<string, string>; // 可观测性标签
}

interface ChatResponse {
  content: string;
  toolCalls?: ToolCall[];
  usage: {
    inputTokens: number;
    outputTokens: number;
    cachedTokens?: number;  // 缓存命中的 token 数
  };
  model: string;
  provider: string;
  latencyMs: number;
  cost: number;             // 预估成本 (USD)
}

interface LLMProvider {
  readonly name: string;
  chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse>;
  chatStream(messages: ChatMessage[], options?: ChatOptions): AsyncIterable<ChatStreamChunk>;
  embed?(texts: string[]): Promise<number[][]>;
  isAvailable(): Promise<boolean>;
}

4.3 Provider 适配器示例

// providers/deepseek.ts
class DeepSeekProvider implements LLMProvider {
  readonly name = 'deepseek';
  private client: OpenAI;

  constructor(apiKey: string) {
    this.client = new OpenAI({
      apiKey,
      baseURL: 'https://api.deepseek.com',
    });
  }

  async chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse> {
    const start = Date.now();
    const model = options?.model || 'deepseek-chat';

    const response = await this.client.chat.completions.create({
      model,
      messages: messages.map(m => ({
        role: m.role,
        content: m.content,
        ...(m.toolCalls ? { tool_calls: m.toolCalls } : {}),
      })),
      temperature: options?.temperature,
      max_tokens: options?.maxTokens,
      tools: options?.tools?.map(t => ({
        type: 'function' as const,
        function: { name: t.name, description: t.description, parameters: t.parameters },
      })),
      response_format: options?.responseFormat?.type === 'json'
        ? { type: 'json_object' } : undefined,
    }, { timeout: options?.timeout || 30000 });

    const choice = response.choices[0];
    return {
      content: choice.message.content || '',
      toolCalls: choice.message.tool_calls?.map(tc => ({
        id: tc.id,
        name: tc.function.name,
        arguments: JSON.parse(tc.function.arguments),
      })),
      usage: {
        inputTokens: response.usage?.prompt_tokens || 0,
        outputTokens: response.usage?.completion_tokens || 0,
      },
      model,
      provider: this.name,
      latencyMs: Date.now() - start,
      cost: this.calculateCost(model, response.usage),
    };
  }

  async isAvailable(): Promise<boolean> {
    try {
      await this.client.models.list();
      return true;
    } catch { return false; }
  }

  private calculateCost(model: string, usage: any): number {
    // DeepSeek V3: ¥1/¥2 per 1M tokens → ~$0.00014/$0.00028
    const rates: Record<string, [number, number]> = {
      'deepseek-chat': [0.14, 0.28],
      'deepseek-reasoner': [0.55, 2.2],
    };
    const [inputRate, outputRate] = rates[model] || [0.14, 0.28];
    return (usage?.prompt_tokens || 0) * inputRate / 1_000_000
         + (usage?.completion_tokens || 0) * outputRate / 1_000_000;
  }
}

4.4 OpenAI 兼容的妙用

💡 关键发现:DeepSeek、Qwen、GLM、Ollama、vLLM 都兼容 OpenAI API 格式!这意味着你可以一个 OpenAI SDK 打天下,只需换 baseURLapiKey。这大大简化了 Provider 适配器的实现——大部分 Provider 共享同一个适配器类,只是配置不同。
// 用一个工厂创建所有 OpenAI 兼容的 Provider
function createOpenAICompatibleProvider(config: {
  name: string;
  baseURL: string;
  apiKey: string;
  defaultModel: string;
  pricing: Record<string, [number, number]>;
}): LLMProvider {
  const client = new OpenAI({ apiKey: config.apiKey, baseURL: config.baseURL });
  // ... 复用同一套 chat/embed 实现
}

// 配置一览
const providers = {
  deepseek: createOpenAICompatibleProvider({
    name: 'deepseek', baseURL: 'https://api.deepseek.com',
    apiKey: process.env.DEEPSEEK_API_KEY, defaultModel: 'deepseek-chat',
    pricing: { 'deepseek-chat': [0.14, 0.28], 'deepseek-reasoner': [0.55, 2.2] },
  }),
  qwen: createOpenAICompatibleProvider({
    name: 'qwen', baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1',
    apiKey: process.env.DASHSCOPE_API_KEY, defaultModel: 'qwen-plus',
    pricing: { 'qwen-max': [0.28, 0.83], 'qwen-plus': [0.11, 0.28] },
  }),
  glm: createOpenAICompatibleProvider({
    name: 'glm', baseURL: 'https://open.bigmodel.cn/api/paas/v4',
    apiKey: process.env.ZHIPU_API_KEY, defaultModel: 'glm-4-plus',
    pricing: { 'glm-4-plus': [0.69, 0.69], 'glm-4-flash': [0, 0] },
  }),
  ollama: createOpenAICompatibleProvider({
    name: 'ollama', baseURL: 'http://localhost:11434/v1',
    apiKey: 'ollama', defaultModel: 'qwen3:8b',
    pricing: {}, // 本地免费
  }),
};

§5 Failover 与高可用

LLM API 不是传统 Web 服务——它们的可用性显著更低:

ProviderSLA实际可用性常见故障
OpenAI99.9%~99.5%限流、模型过载、响应超时
Anthropic99.9%~99.3%限流严苛、偶发 529
DeepSeek无 SLA~98%高峰排队、偶发宕机
本地 Ollama~99%OOM、GPU 故障
⚠️ 血泪教训:如果你的产品只有 1 个 Provider,OpenAI 挂了 = 你的产品挂了。这不是理论风险,2024 年 OpenAI 多次大规模宕机,每次持续 1-6 小时。多 Provider Failover 不是锦上添花,是必须品。

5.1 Failover 策略

🔄 顺序 Failover

定义 Provider 优先级,主 Provider 失败自动切到备选。

// 简单顺序 Failover
const failoverChain = [
  { provider: 'openai', model: 'gpt-4o' },
  { provider: 'deepseek', model: 'deepseek-chat' },
  { provider: 'qwen', model: 'qwen-max' },
];

async function chatWithFailover(messages, options) {
  for (const { provider, model } of failoverChain) {
    try {
      return await providers[provider].chat(messages, {
        ...options, model,
        timeout: 15000, // 快速超时
      });
    } catch (err) {
      console.warn(`${provider} failed: ${err.message}`);
      continue; // 尝试下一个
    }
  }
  throw new Error('All providers failed');
}

✅ 简单可靠

❌ 主 Provider 失败时延迟翻倍

⚡ 竞速 Failover

同时请求多个 Provider,谁先回用谁。

// 竞速 Failover — 快者胜
async function chatRacing(messages, options) {
  const candidates = [
    { provider: 'openai', model: 'gpt-4o' },
    { provider: 'deepseek', model: 'deepseek-chat' },
  ];

  return Promise.any(
    candidates.map(({ provider, model }) =>
      providers[provider].chat(messages, { ...options, model })
        .then(res => { res.provider = provider; return res; })
    )
  );
}

✅ 延迟最优

❌ 成本翻倍 (多个 Provider 都算 token)

❌ 不适合非幂等操作 (写数据库等)

🛡️ 断路器 Failover

跟踪 Provider 健康状态,自动跳过已知故障的 Provider。

class CircuitBreaker {
  private failures = new Map<string, {
    count: number;
    lastFail: number;
    state: 'closed' | 'open' | 'half-open';
  }>();

  async call(provider: string, fn: () => Promise<any>) {
    const cb = this.failures.get(provider);
    if (cb?.state === 'open') {
      // 断路器打开:检查是否该尝试恢复
      if (Date.now() - cb.lastFail > 60_000) {
        cb.state = 'half-open'; // 半开:允许一次尝试
      } else {
        throw new Error(`Circuit open: ${provider}`);
      }
    }
    try {
      const result = await fn();
      this.recordSuccess(provider);
      return result;
    } catch (err) {
      this.recordFailure(provider);
      throw err;
    }
  }
}

✅ 避免浪费请求到已知故障 Provider

❌ 实现复杂度较高

5.2 生产级 Failover 实现

class LLMFailover {
  private circuitBreaker = new CircuitBreaker();
  private healthChecker = new HealthChecker();

  constructor(
    private providers: Record<string, LLMProvider>,
    private config: FailoverConfig,
  ) {
    // 每 30 秒健康检查
    setInterval(() => this.healthChecker.checkAll(providers), 30_000);
  }

  async chat(messages: ChatMessage[], options?: ChatOptions): Promise<ChatResponse> {
    const startTime = Date.now();
    const orderedProviders = this.getOrderedProviders();

    for (const { provider, model } of orderedProviders) {
      // 跳过断路器打开的 Provider
      if (!this.circuitBreaker.canTry(provider)) continue;

      try {
        const result = await this.circuitBreaker.call(provider, () =>
          this.providers[provider].chat(messages, { ...options, model })
        );

        // 记录成功,用于后续路由决策
        this.healthChecker.recordSuccess(provider, Date.now() - startTime);
        return result;

      } catch (err) {
        this.healthChecker.recordFailure(provider, err);
        console.warn(`[Failover] ${provider} failed: ${err.message}`);

        // 如果是超时,可以竞速尝试下一个
        if (this.config.raceOnTimeout && orderedProviders.length > 1) {
          return this.raceFallback(messages, options, provider);
        }
      }
    }

    // 所有 Provider 都失败了——尝试本地模型
    if (this.providers.ollama) {
      return this.providers.ollama.chat(messages, {
        ...options,
        model: 'qwen3:8b',
      });
    }

    throw new LLMAllProvidersError('All LLM providers are unavailable');
  }

  private getOrderedProviders(): Array<{ provider: string; model: string }> {
    // 根据健康度排序,最健康的排前面
    return this.config.chain
      .filter(p => this.healthChecker.getHealth(p.provider) > 0.3)
      .sort((a, b) =>
        this.healthChecker.getHealth(b.provider) - this.healthChecker.getHealth(a.provider)
      );
  }
}

§6 智能 Routing

不是所有请求都该走最贵的模型。智能路由根据请求特征自动选择最合适的模型。

6.1 路由策略一览

🏷️ 任务类型路由

根据任务类型选择模型:

分类/提取GPT-4o mini / Flash
简单对话DeepSeek V3 / Qwen-Plus
编码Claude Sonnet 4
深度推理o3 / DeepSeek-R1
长文档Gemini 2.5 Pro

💰 成本路由

根据用户等级选择模型:

免费用户DeepSeek V3 / Qwen-Turbo
付费用户GPT-4o / Claude Sonnet
企业用户o3 / Claude Opus
💡 这种路由的ROI最高——80%的请求可以用20%成本的模型处理。

⚡ 延迟路由

根据延迟要求选择:

实时聊天 (<2s)Flash / Haiku
普通 (<10s)GPT-4o / Sonnet
后台任务o3 / R1 (30s+)

🤖 LLM 路由器

用小模型预判,决定用大模型还是小模型:

// 用 Flash 判断任务复杂度
const judge = await flash.chat([{
  role: 'user',
  content: `这个任务需要深度推理吗?
任务: ${userMessage}
回答: simple 或 complex`
}]);

const model = judge.includes('complex')
  ? 'gpt-4o'
  : 'gpt-4o-mini';

✅ 精度最高

❌ 增加一次小模型调用

6.2 实战:智能路由器实现

interface RouteRule {
  condition: (messages: ChatMessage[], options?: ChatOptions) => boolean;
  provider: string;
  model: string;
  priority: number;
}

class SmartRouter {
  private rules: RouteRule[] = [];

  addRule(rule: RouteRule): this {
    this.rules.push(rule);
    this.rules.sort((a, b) => b.priority - a.priority);
    return this;
  }

  resolve(messages: ChatMessage[], options?: ChatOptions): { provider: string; model: string } {
    for (const rule of this.rules) {
      if (rule.condition(messages, options)) {
        return { provider: rule.provider, model: rule.model };
      }
    }
    // 默认:性价比之选
    return { provider: 'deepseek', model: 'deepseek-chat' };
  }
}

// 配置路由规则
const router = new SmartRouter();

// 规则 1:编码任务 → Claude
router.addRule({
  priority: 100,
  provider: 'anthropic',
  model: 'claude-sonnet-4-20250514',
  condition: (msgs, opts) =>
    opts?.metadata?.task === 'code' ||
    msgs.some(m => m.content.includes('```')),
});

// 规则 2:长文档 → Gemini
router.addRule({
  priority: 90,
  provider: 'google',
  model: 'gemini-2.5-pro',
  condition: (msgs) =>
    msgs.reduce((sum, m) => sum + m.content.length, 0) > 100_000,
});

// 规则 3:简单分类 → 小模型
router.addRule({
  priority: 80,
  provider: 'openai',
  model: 'gpt-4o-mini',
  condition: (msgs, opts) =>
    opts?.metadata?.task === 'classify' ||
    opts?.responseFormat?.type === 'json',
});

// 规则 4:深度推理 → o3
router.addRule({
  priority: 70,
  provider: 'openai',
  model: 'o3',
  condition: (msgs, opts) =>
    opts?.metadata?.task === 'reasoning',
});

// 规则 5:付费用户 → 高级模型
router.addRule({
  priority: 50,
  provider: 'openai',
  model: 'gpt-4o',
  condition: (msgs, opts) =>
    opts?.metadata?.tier === 'pro',
});

// 使用
const { provider, model } = router.resolve(messages, options);
const result = await providers[provider].chat(messages, { ...options, model });

§7 成本控制

LLM 成本是 AI 产品最大的运营支出。一个中型 SaaS (1000 DAU),每人每天 50 次调用,GPT-4o 单次均价 $0.01 → $500/天 = $15,000/月。不做成本控制 = 烧钱。

7.1 Token 经济学

💰 真实成本构成
环节占比优化空间
System Prompt (每次重复)20-40%⭐⭐⭐⭐⭐ 缓存
历史消息 (多轮对话)30-50%⭐⭐⭐⭐ 裁剪/摘要
本次输入10-20%⭐⭐ 压缩
输出15-30%⭐⭐ 限制 maxTokens
💡 最大成本黑洞:System Prompt + 历史消息 = 占 50-90% 的 token,但这些大部分是重复的!这就是为什么 Prompt Caching / Context Caching 如此重要。

7.2 成本优化策略

🏷️ Prompt Caching

重复前缀自动缓存,命中后输入价格降 50-90%。

Provider机制折扣
Anthropic自动缓存90% off
OpenAI自动缓存50% off
DeepSeek自动缓存90% off
GoogleContext Caching API75% off
💡 关键技巧:将 system prompt + 工具定义 放在消息最前面,确保它们被缓存。不要在 system prompt 前插入动态内容。

✂️ 上下文裁剪

多轮对话时,不是所有历史都值得保留。

// 策略 1:滑动窗口
const recentMessages = messages.slice(-10);

// 策略 2:摘要压缩
if (messages.length > 20) {
  const summary = await cheapModel.chat([{
    role: 'user',
    content: `压缩以下对话历史为关键信息:
${messages.slice(0, -5).map(m => m.content).join('\n')}`
  }]);
  messages = [
    { role: 'system', content: `历史摘要: ${summary}` },
    ...messages.slice(-5),
  ];
}

// 策略 3:OpenClaw 的 Cache Boundary
// 在 system prompt 末尾标记缓存边界
// 新消息不会使 system prompt 缓存失效
🔗 详见 Agent 提示词工程Agent 记忆系统

🪜 模型降级

简单任务用小模型,复杂任务才用大模型。

// 典型的 3 级模型策略
const MODEL_TIERS = {
  light:  'gpt-4o-mini',    // $0.15/$0.60
  medium: 'deepseek-chat',  // ¥1/¥2
  heavy:  'gpt-4o',         // $2.50/$10
};

// 80% 请求走 light → 成本降 90%
function selectTier(complexity: number) {
  if (complexity < 0.3) return MODEL_TIERS.light;
  if (complexity < 0.7) return MODEL_TIERS.medium;
  return MODEL_TIERS.heavy;
}

✅ ROI 最高 — 80% 请求可走轻量模型

📊 Token 预算

每次调用设 token 上限,防止模型"唠叨"。

// 设置 per-request 预算
const result = await provider.chat(messages, {
  maxTokens: 500,         // 输出上限
  costLimit: 0.05,        // 单次成本上限 $0.05
});

// 设置 per-user 日预算
const dailyBudget = getUserBudget(userId);
const todayCost = getTodayCost(userId);
if (todayCost + estimatedCost > dailyBudget) {
  // 降级到小模型或返回缓存结果
  return cheapModel.chat(messages);
}

❌ 需要精确的 cost 预估

7.3 成本监控仪表盘

class CostTracker {
  private costs = new Map<string, {
    total: number;
    byProvider: Record<string, number>;
    byModel: Record<string, number>;
    byUser: Record<string, number>;
    requestCount: number;
  }>();

  record(userId: string, response: ChatResponse) {
    const day = new Date().toISOString().slice(0, 10);
    const entry = this.costs.get(day) || {
      total: 0, byProvider: {}, byModel: {},
      byUser: {}, requestCount: 0,
    };

    entry.total += response.cost;
    entry.byProvider[response.provider] =
      (entry.byProvider[response.provider] || 0) + response.cost;
    entry.byModel[response.model] =
      (entry.byModel[response.model] || 0) + response.cost;
    entry.byUser[userId] =
      (entry.byUser[userId] || 0) + response.cost;
    entry.requestCount++;

    this.costs.set(day, entry);
  }

  getDailyReport(day: string) {
    const entry = this.costs.get(day);
    if (!entry) return null;
    return {
      total: `$${entry.total.toFixed(2)}`,
      topProvider: Object.entries(entry.byProvider)
        .sort(([,a],[,b]) => b - a)[0],
      topModel: Object.entries(entry.byModel)
        .sort(([,a],[,b]) => b - a)[0],
      avgCostPerRequest: `$${(entry.total / entry.requestCount).toFixed(4)}`,
      topUser: Object.entries(entry.byUser)
        .sort(([,a],[,b]) => b - a)[0],
    };
  }
}

§8 流式输出与用户体验

LLM 响应慢(2-30 秒),如果不做流式输出,用户会以为卡死了。流式不是可选的,是必须的

8.1 流式输出实现

// 统一流式接口
interface ChatStreamChunk {
  content?: string;        // 增量文本
  toolCall?: Partial<ToolCall>;  // 增量工具调用
  usage?: {                // 最后一个 chunk 才有
    inputTokens: number;
    outputTokens: number;
  };
  done: boolean;
}

// 使用
const stream = provider.chatStream(messages, options);
for await (const chunk of stream) {
  if (chunk.content) {
    process.stdout.write(chunk.content); // 逐字输出
  }
  if (chunk.done) {
    console.log('\n[完成]', chunk.usage);
  }
}

8.2 SSE 到前端的完整链路

// 后端:SSE 端点 (FastAPI)
from fastapi import FastAPI
from fastapi.responses import StreamingResponse

@app.post("/api/chat/stream")
async def chat_stream(request: ChatRequest):
    async def generate():
        stream = await llm.chat_stream(
            messages=request.messages,
            model=request.model,
        )
        async for chunk in stream:
            if chunk.content:
                yield f"data: {json.dumps({'content': chunk.content})}\n\n"
            if chunk.done:
                yield f"data: {json.dumps({'done': True, 'usage': chunk.usage})}\n\n"

    return StreamingResponse(generate(), media_type="text/event-stream")
// 前端:消费 SSE
const response = await fetch('/api/chat/stream', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ messages, model }),
});

const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';

while (true) {
  const { done, value } = await reader.read();
  if (done) break;

  buffer += decoder.decode(value, { stream: true });
  const lines = buffer.split('\n');
  buffer = lines.pop() || '';

  for (const line of lines) {
    if (line.startsWith('data: ')) {
      const data = JSON.parse(line.slice(6));
      if (data.content) {
        appendToChat(data.content); // 逐字追加到 UI
      }
      if (data.done) {
        updateUsageStats(data.usage);
      }
    }
  }
}

8.3 流式输出的坑

⚠️ 流式输出的常见问题
// 处理用户取消
async function chatWithAbort(messages, options) {
  const controller = new AbortController();

  // 前端取消时
  window.addEventListener('user-cancel', () => controller.abort());

  const stream = await provider.chatStream(messages, {
    ...options,
    signal: controller.signal,  // 传入 AbortSignal
  });

  try {
    for await (const chunk of stream) {
      if (controller.signal.aborted) break;
      processChunk(chunk);
    }
  } finally {
    // 确保清理
    controller.abort();
  }
}

§9 语义缓存与 Prompt 缓存

缓存是成本控制的杀手锏。两层缓存配合使用:

用户请求 │ ▼ ┌──────────────┐ 命中 → 直接返回,成本 = $0 │ 语义缓存 │ ───────────────────────────── │ (跨会话) │ 未命中 ↓ └──────────────┘ │ ▼ ┌──────────────┐ 命中 → 输入价格降 50-90% │ Prompt 缓存 │ ───────────────────────────── │ (Provider级) │ 未命中 ↓ └──────────────┘ │ ▼ 完整 LLM 调用 → 全价

9.1 语义缓存

相同含义的问题应该返回缓存的答案,即使措辞不同。

import { Redis } from 'ioredis';
import { createHash } from 'crypto';

class SemanticCache {
  private redis: Redis;
  private embedder: LLMProvider; // 用便宜的 embedding 模型

  // 相似度阈值 — 越高越严格
  private similarityThreshold = 0.95;

  async get(query: string): Promise<ChatResponse | null> {
    // 1. 生成 query embedding
    const [embedding] = await this.embedder.embed([query]);

    // 2. 在向量存储中搜索相似 query
    const similar = await this.redis.send_command(
      'FT.SEARCH', 'semantic_cache',
      `(*=>[KNN 1 @embedding $vec])`,
      'PARAMS', 2, 'vec', Buffer.from(Float32Array.from(embedding).buffer),
      'DIALECT', 2,
    );

    if (similar && similar[0] > 0) {
      const score = similar[1]; // 相似度分数
      if (score >= this.similarityThreshold) {
        // 命中!返回缓存的响应
        return JSON.parse(similar[2].response);
      }
    }

    return null; // 未命中
  }

  async set(query: string, response: ChatResponse, ttl = 3600): Promise<void> {
    const [embedding] = await this.embedder.embed([query]);
    const key = `cache:${createHash('sha256').update(query).digest('hex').slice(0, 16)}`;

    await this.redis.send_command(
      'HSET', key,
      'query', query,
      'response', JSON.stringify(response),
      'embedding', Buffer.from(Float32Array.from(embedding).buffer),
      'timestamp', Date.now(),
    );
    await this.redis.expire(key, ttl);
  }
}

// 使用
const cache = new SemanticCache(redis, embedder);

async function chatWithCache(messages, options) {
  const query = messages[messages.length - 1].content;

  // 先查缓存
  const cached = await cache.get(query);
  if (cached) {
    console.log('[Cache Hit] Saved $', cached.cost.toFixed(4));
    return { ...cached, fromCache: true };
  }

  // 缓存未命中,调 LLM
  const result = await provider.chat(messages, options);

  // 缓存结果(只缓存成功的非工具调用响应)
  if (!result.toolCalls && result.content) {
    await cache.set(query, result);
  }

  return result;
}

9.2 Prompt 缓存最佳实践

🎯 Prompt 缓存优化清单
// Anthropic 显式缓存控制
const response = await anthropic.messages.create({
  model: 'claude-sonnet-4-20250514',
  max_tokens: 4096,
  system: [{
    type: 'text',
    text: systemPrompt,       // 这部分会被缓存
    cache_control: { type: 'ephemeral' },  // 标记缓存点
  }],
  tools: toolDefinitions.map(t => ({
    ...t,
    cache_control: { type: 'ephemeral' },  // 工具定义也缓存
  })),
  messages,
});

// response.usage 中会显示缓存命中的 token 数
console.log(`Cache hit: ${response.usage.cache_read_input_tokens} tokens`);
⚠️ 语义缓存 vs Prompt 缓存:语义缓存是"相似问题返回相同答案",适合 FAQ/知识库场景;Prompt 缓存是"相同前缀不重复计费",适合多轮对话场景。两者互补,不要只做一个。

Agent 架构研究中,20 个开源 Agent 项目展示了丰富的 LLM 集成实践。以下是关键发现:

🔑 Agent 研究中的 LLM 集成模式

1. 多模型策略是标配

几乎所有成熟 Agent 都使用多个模型:AutoGPT 支持 7 个 LLM Provider,OpenHands 可配置任意模型,Aider 的 ArchitectCoder 模式用双模型(架构师+编码者)。

AutoGPT 深度分析 | Aider 深度分析

2. 缓存是提示词工程的核心

OpenClaw 的 Cache Boundary 是最佳实践——在 system prompt 末尾标记缓存边界,后续动态消息不会使静态部分缓存失效。Aider 的 ChatChunks 分区缓存和 Hermes 的三层组装也是优秀设计。

提示词工程深度分析

3. 安全 = LLM 调用链的每个环节都要防护

Hermes 的 60+ 威胁模式静态扫描、Codex CLI 的 Guardian LLM 审查、Agent Zero 的 LLM Infection Check——每个 Agent 都在 LLM 集成层做了安全防护。

安全机制深度分析

4. 工具调用是 LLM 集成的核心能力

Function Calling / Tool Use 的可靠性直接决定 Agent 的可靠性。PydanticAI 的类型安全验证、OpenClaw 的 Policy Pipeline、Hermes 的 76 工具体系展示了不同层次的工具调用设计。

工具系统深度分析

5. 记忆系统 = 智能的上下文管理

LLM 的上下文窗口有限,记忆系统决定哪些信息进入上下文。OpenHands 的双 Condenser、Agent Zero 的 3 区域 FAISS、Hermes 的 HRR 全息编码都是优秀实践。

记忆系统深度分析

§11 实施清单

✅ 从 0 到 1:LLM 集成实施清单

Phase 1: 基础 (第 1 周)

Phase 2: 可靠性 (第 2 周)

Phase 3: 优化 (第 3 周)

Phase 4: 生产级 (第 4 周)

🧮 成本速算表

假设:1000 DAU,每用户每天 50 次调用,每次平均 1000 input + 500 output tokens。

模型单次成本日成本月成本年成本
GPT-4o$0.0075$375$11,250$135,000
GPT-4o mini$0.00045$22.5$675$8,100
Claude Sonnet 4$0.0105$525$15,750$189,000
DeepSeek V3$0.00042$21$630$7,560
Qwen-Plus$0.00019$9.5$285$3,420
GLM-4-Flash$0$0$0$0
本地 Ollama$0*$0*GPU ¥3000*¥36,000*

* 本地模型需要 GPU 服务器成本,约 ¥3000-15000/月取决于配置

💡 混合策略成本:80% 请求走 DeepSeek V3 + 20% 走 GPT-4o → 月成本约 $3,000,比纯 GPT-4o 节省 73%。

替代方案与相关工具

🔗 LiteLLM

开源的 LLM Proxy,统一 100+ Provider 的 API。Python 生态,内置成本追踪和 Failover。

开源 100+ Provider

pip install litellm

# 用法 — 自动路由到正确 Provider
from litellm import completion
response = completion(
  model="deepseek/deepseek-chat",
  messages=[{"role": "user", "content": "Hello"}],
)

🔗 OpenRouter

LLM API 聚合商,一个 API Key 访问 200+ 模型。按量计费,内置 Failover。

商业 200+ 模型

// 兼容 OpenAI SDK
const client = new OpenAI({
  baseURL: 'https://openrouter.ai/api/v1',
  apiKey: process.env.OPENROUTER_KEY,
});

// 任意模型
const res = await client.chat.completions.create({
  model: 'anthropic/claude-sonnet-4',
  messages: [...],
});

🔗 Portkey

LLM 网关,提供路由/Failover/缓存/可观测性。SaaS 服务。

商业 网关

  • 自动重试 + Failover
  • 语义缓存
  • 成本分析仪表盘
  • 请求日志和调试

🔗 AI SDK (Vercel)

TypeScript 原生 LLM SDK,统一接口 + 流式 + React 集成。

开源 TypeScript

import { generateText } from 'ai';
import { openai } from '@ai-sdk/openai';

const { text } = await generateText({
  model: openai('gpt-4o'),
  prompt: 'Explain quantum computing',
});

延伸阅读

📚 知识库内相关模块