Amux

迁移指南

从 OpenAI 或 Anthropic SDK 迁移到 Amux

为什么要迁移到 Amux?

Amux 相比使用特定提供商的 SDK 具有以下几个优势:

  • 提供商灵活性 - 无需更改代码即可切换提供商
  • 统一 API - 所有提供商的单一接口
  • 模型映射 - 轻松映射和交换模型
  • 双向转换 - 支持任何请求/响应格式
  • 类型安全 - 所有适配器的完整 TypeScript 支持

迁移到 Amux 非常简单。大多数代码更改都是机械替换。

从 OpenAI SDK 迁移

之前(OpenAI SDK)

import OpenAI from 'openai'

const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
})

const response = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [
    { role: 'system', content: '你是一个有帮助的助手。' },
    { role: 'user', content: '你好!' }
  ],
  temperature: 0.7,
  max_tokens: 100
})

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

之后(Amux)

import { createBridge } from '@amux.ai/llm-bridge'
import { openaiAdapter } from '@amux.ai/adapter-openai'

const bridge = createBridge({
  inbound: openaiAdapter,
  outbound: openaiAdapter,
  config: {
    apiKey: process.env.OPENAI_API_KEY
  }
})

const response = await bridge.chat({
  model: 'gpt-4',
  messages: [
    { role: 'system', content: '你是一个有帮助的助手。' },
    { role: 'user', content: '你好!' }
  ],
  temperature: 0.7,
  max_tokens: 100
})

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

关键变化:

  1. 用 Amux 导入替换 import OpenAI
  2. createBridge() 替换 new OpenAI()
  3. bridge.chat() 替换 openai.chat.completions.create()
  4. 请求/响应格式保持不变!

流式响应

之前(OpenAI SDK):

const stream = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [{ role: 'user', content: '给我讲个故事' }],
  stream: true
})

for await (const chunk of stream) {
  const content = chunk.choices[0]?.delta?.content
  if (content) {
    process.stdout.write(content)
  }
}

之后(Amux):

const stream = await bridge.chat({
  model: 'gpt-4',
  messages: [{ role: 'user', content: '给我讲个故事' }],
  stream: true
})

for await (const event of stream) {
  if (event.type === 'content') {
    process.stdout.write(event.content.delta)
  }
}

关键变化:

  • 使用 bridge.chat() 并设置 stream: true
  • 事件通过 type 字段规范化
  • 内容在 event.content.delta

函数调用

之前(OpenAI SDK):

const response = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [{ role: 'user', content: '天气怎么样?' }],
  tools: [
    {
      type: 'function',
      function: {
        name: 'get_weather',
        description: '获取天气',
        parameters: {
          type: 'object',
          properties: {
            location: { type: 'string' }
          }
        }
      }
    }
  ]
})

if (response.choices[0].message.tool_calls) {
  // 处理工具调用
}

之后(Amux):

const response = await bridge.chat({
  model: 'gpt-4',
  messages: [{ role: 'user', content: '天气怎么样?' }],
  tools: [
    {
      type: 'function',
      function: {
        name: 'get_weather',
        description: '获取天气',
        parameters: {
          type: 'object',
          properties: {
            location: { type: 'string' }
          }
        }
      }
    }
  ]
})

if (response.choices[0].message.tool_calls) {
  // 处理工具调用 - 与之前相同!
}

无需更改! 工具调用 API 完全相同。

从 Anthropic SDK 迁移

之前(Anthropic SDK)

import Anthropic from '@anthropic-ai/sdk'

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

const response = await anthropic.messages.create({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [
    { role: 'user', content: '你好!' }
  ]
})

console.log(response.content[0].text)

之后(Amux)

import { createBridge } from '@amux.ai/llm-bridge'
import { anthropicAdapter } from '@amux.ai/adapter-anthropic'

const bridge = createBridge({
  inbound: anthropicAdapter,
  outbound: anthropicAdapter,
  config: {
    apiKey: process.env.ANTHROPIC_API_KEY
  }
})

const response = await bridge.chat({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [
    { role: 'user', content: '你好!' }
  ]
})

console.log(response.content[0].text)

关键变化:

  1. 用 Amux 导入替换 import Anthropic
  2. createBridge() 替换 new Anthropic()
  3. bridge.chat() 替换 anthropic.messages.create()
  4. 请求/响应格式保持不变!

流式响应

之前(Anthropic SDK):

const stream = await anthropic.messages.create({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [{ role: 'user', content: '给我讲个故事' }],
  stream: true
})

for await (const event of stream) {
  if (event.type === 'content_block_delta') {
    process.stdout.write(event.delta.text)
  }
}

之后(Amux):

const stream = await bridge.chat({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [{ role: 'user', content: '给我讲个故事' }],
  stream: true
})

for await (const event of stream) {
  if (event.type === 'content') {
    process.stdout.write(event.content.delta)
  }
}

关键变化:

  • 事件规范化为 type: 'content'
  • 文本在 event.content.delta 中(而不是 event.delta.text

工具使用

之前(Anthropic SDK):

const response = await anthropic.messages.create({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [{ role: 'user', content: '天气怎么样?' }],
  tools: [
    {
      name: 'get_weather',
      description: '获取天气',
      input_schema: {
        type: 'object',
        properties: {
          location: { type: 'string' }
        }
      }
    }
  ]
})

之后(Amux):

const response = await bridge.chat({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [{ role: 'user', content: '天气怎么样?' }],
  tools: [
    {
      type: 'function',
      function: {
        name: 'get_weather',
        description: '获取天气',
        parameters: {
          type: 'object',
          properties: {
            location: { type: 'string' }
          }
        }
      }
    }
  ]
})

关键变化:

  • 工具使用 OpenAI 风格格式(可由适配器规范化)
  • input_schema 变为 parameters
  • 包装在 function 对象中

跨提供商迁移

Amux 的关键优势之一是轻松实现跨提供商迁移。

OpenAI 到 Anthropic

// 之前:使用 OpenAI SDK
import OpenAI from 'openai'
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })

const response = await openai.chat.completions.create({
  model: 'gpt-4',
  messages: [{ role: 'user', content: '你好!' }]
})

// 之后:相同代码,不同提供商
import { createBridge } from '@amux.ai/llm-bridge'
import { openaiAdapter } from '@amux.ai/adapter-openai'
import { anthropicAdapter } from '@amux.ai/adapter-anthropic'

const bridge = createBridge({
  inbound: openaiAdapter,
  outbound: anthropicAdapter,
  config: { apiKey: process.env.ANTHROPIC_API_KEY },
  modelMapping: {
    'gpt-4': 'claude-3-5-sonnet-20241022'
  }
})

// 相同的请求格式!
const response = await bridge.chat({
  model: 'gpt-4',
  messages: [{ role: 'user', content: '你好!' }]
})

Anthropic 到 DeepSeek

import { createBridge } from '@amux.ai/llm-bridge'
import { anthropicAdapter } from '@amux.ai/adapter-anthropic'
import { deepseekAdapter } from '@amux.ai/adapter-deepseek'

const bridge = createBridge({
  inbound: anthropicAdapter,
  outbound: deepseekAdapter,
  config: { apiKey: process.env.DEEPSEEK_API_KEY },
  modelMapping: {
    'claude-3-5-sonnet-20241022': 'deepseek-chat'
  }
})

// 使用 Anthropic 格式,调用 DeepSeek
const response = await bridge.chat({
  model: 'claude-3-5-sonnet-20241022',
  max_tokens: 1024,
  messages: [{ role: 'user', content: '你好!' }]
})

常见迁移模式

1. 渐进式迁移

逐步迁移而不破坏现有代码:

// 步骤 1:继续使用 OpenAI SDK
import OpenAI from 'openai'
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })

// 步骤 2:同时添加 Amux
import { createBridge } from '@amux.ai/llm-bridge'
import { openaiAdapter } from '@amux.ai/adapter-openai'

const bridge = createBridge({
  inbound: openaiAdapter,
  outbound: openaiAdapter,
  config: { apiKey: process.env.OPENAI_API_KEY }
})

// 步骤 3:逐个迁移路由
async function chat(request) {
  // 旧代码
  // return await openai.chat.completions.create(request)

  // 新代码
  return await bridge.chat(request)
}

// 步骤 4:完成后删除 OpenAI SDK

2. 功能标志迁移

使用功能标志控制发布:

const useAmux = process.env.USE_AMUX === 'true'

async function chat(request) {
  if (useAmux) {
    return await bridge.chat(request)
  } else {
    return await openai.chat.completions.create(request)
  }
}

3. A/B 测试

并排比较提供商:

async function chatWithComparison(request) {
  const [openaiResponse, claudeResponse] = await Promise.all([
    bridgeOpenAI.chat(request),
    bridgeClaude.chat(request)
  ])

  // 记录以进行比较
  console.log('OpenAI:', openaiResponse.choices[0].message.content)
  console.log('Claude:', claudeResponse.content[0].text)

  // 返回首选提供商
  return openaiResponse
}

关键差异和注意事项

系统消息

OpenAI SDK:

messages: [
  { role: 'system', content: '你很有帮助。' },
  { role: 'user', content: '你好!' }
]

Anthropic SDK:

system: '你很有帮助。',
messages: [
  { role: 'user', content: '你好!' }
]

Amux: 两种格式都可以!适配器处理转换。

// OpenAI 格式适用于 Anthropic 适配器
const bridge = createBridge({
  inbound: openaiAdapter,
  outbound: anthropicAdapter,
  config: { apiKey: process.env.ANTHROPIC_API_KEY }
})

await bridge.chat({
  model: 'gpt-4',
  messages: [
    { role: 'system', content: '你很有帮助。' },  // 自动转换
    { role: 'user', content: '你好!' }
  ]
})

响应格式

OpenAI SDK:

response.choices[0].message.content

Anthropic SDK:

response.content[0].text

Amux: 格式匹配入站适配器!

// 使用 OpenAI 入站适配器
const response = await bridge.chat({ ... })
console.log(response.choices[0].message.content)  // OpenAI 格式

// 使用 Anthropic 入站适配器
const response = await bridge.chat({ ... })
console.log(response.content[0].text)  // Anthropic 格式

错误处理

错误在提供商之间规范化:

import { APIError, NetworkError } from '@amux.ai/llm-bridge'

try {
  const response = await bridge.chat(request)
} catch (error) {
  if (error instanceof APIError) {
    console.error('API 错误:', error.status, error.provider)
  } else if (error instanceof NetworkError) {
    console.error('网络错误:', error.message)
  }
}

迁移检查清单

  • 安装 Amux 包:@amux.ai/llm-bridge@amux.ai/adapter-*
  • 用 Amux 导入替换 SDK 导入
  • createBridge() 替换客户端初始化
  • bridge.chat() 替换 API 调用
  • 更新流式事件处理(如果使用流)
  • 更新错误处理(使用 Amux 错误类型)
  • 使用现有请求进行测试
  • 更新 TypeScript 类型(如果使用)
  • 删除旧的 SDK 依赖项
  • 更新文档

最佳实践

1. 保持请求格式

迁移期间不要更改请求格式:

// ✅ 好:保持现有格式
const bridge = createBridge({
  inbound: openaiAdapter,  // 使用你当前的格式
  outbound: anthropicAdapter,
  config: { apiKey: process.env.ANTHROPIC_API_KEY }
})

// 你现有的请求按原样工作
await bridge.chat({ model: 'gpt-4', messages: [...] })

2. 彻底测试

为你的迁移创建测试用例:

import { describe, it, expect } from 'vitest'

describe('迁移测试', () => {
  it('应返回相同格式', async () => {
    const request = {
      model: 'gpt-4',
      messages: [{ role: 'user', content: '你好!' }]
    }

    const response = await bridge.chat(request)

    expect(response.choices).toBeDefined()
    expect(response.choices[0].message.content).toBeTruthy()
  })
})

3. 使用类型安全

利用 TypeScript 实现更安全的迁移:

import type { LLMBridge } from '@amux.ai/llm-bridge'

// 为你的桥接添加类型
const bridge: LLMBridge = createBridge({
  inbound: openaiAdapter,
  outbound: anthropicAdapter,
  config: { apiKey: process.env.ANTHROPIC_API_KEY }
})

// TypeScript 确保正确使用
const response = await bridge.chat({
  model: 'gpt-4',
  messages: [{ role: 'user', content: '你好!' }]
})

下一步

On this page