我的开源大模型网关: github.com/boonya-hrgk...
通过统一网关
http://127.0.0.1:9000,一个CLI同时调用OpenAI和Anthropic协议的模型
目录
- 前置准备
- 安装与配置
- 三种模式详解
- 快速上手
- 常见问题
- 进阶技巧
1. 前置准备
1.1 环境要求
- Node.js ≥ 18.0.0(下载地址)
- 本地网关 :
http://127.0.0.1:9000已启动并运行
1.2 验证网关状态
bash
json
curl http://127.0.0.1:9000/health
# 预期返回: {"status":"ok"}
1.3 准备API密钥
bash
ini
# 设置环境变量(替换为你的实际密钥)
export GATEWAY_API_KEY="your-gateway-key-here"
💡 说明:你的网关已兼容OpenAI和Anthropic两大协议,只需一个统一密钥即可访问所有模型。
2. 安装与配置
2.1 创建项目
bash
perl
# 创建目录
mkdir my-cli && cd my-cli
# 初始化项目
npm init -y
# 安装依赖
npm install openai @anthropic-ai/sdk
2.2 配置文件结构
text
perl
my-cli/
├── package.json
├── cli-openai.js # 模式一:OpenAI协议
├── cli-anthropic.js # 模式二:Anthropic协议
└── cli-claude-code.js # 模式三:Claude Code风格(推荐)
2.3 设置网关地址(重要!)
所有模式都通过环境变量读取网关地址:
bash
ini
# 添加到 ~/.bashrc 或 ~/.zshrc 永久生效
export OPENAI_BASE_URL="http://127.0.0.1:9000/v1"
export OPENAI_API_KEY="your-gateway-key"
export ANTHROPIC_BASE_URL="http://127.0.0.1:9000"
export ANTHROPIC_API_KEY="your-gateway-key"
3. 三种模式详解
模式一:OpenAI协议模式(最轻量)
适用场景:只使用OpenAI兼容模型(如DeepSeek、Qwen、GPT系列)
核心代码 (cli-openai.js):
javascript
javascript
import OpenAI from 'openai';
import readline from 'readline';
const client = new OpenAI({
baseURL: 'http://127.0.0.1:9000/v1',
apiKey: process.env.OPENAI_API_KEY,
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
async function chat(prompt) {
const response = await client.chat.completions.create({
model: 'deepseek-chat', // 可替换为任意模型
messages: [{ role: 'user', content: prompt }],
});
console.log('🤖:', response.choices[0].message.content);
ask();
}
function ask() {
rl.question('👤 你: ', (input) => {
if (input === 'exit') { rl.close(); return; }
chat(input);
});
}
console.log('💬 OpenAI协议CLI已启动 (输入exit退出)');
ask();
运行:
bash
node cli-openai.js
模式二:Anthropic协议模式(原生Claude)
适用场景:使用Claude系列模型,需要原生的Anthropic协议支持
核心代码 (cli-anthropic.js):
javascript
javascript
import Anthropic from '@anthropic-ai/sdk';
import readline from 'readline';
const client = new Anthropic({
baseURL: 'http://127.0.0.1:9000',
apiKey: process.env.ANTHROPIC_API_KEY,
});
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
async function chat(prompt) {
const response = await client.messages.create({
model: 'claude-3-sonnet-20240229',
max_tokens: 1024,
messages: [{ role: 'user', content: prompt }],
});
console.log('🤖:', response.content[0].text);
ask();
}
function ask() {
rl.question('👤 你: ', (input) => {
if (input === 'exit') { rl.close(); return; }
chat(input);
});
}
console.log('💬 Anthropic协议CLI已启动 (输入exit退出)');
ask();
运行:
bash
node cli-anthropic.js
模式三:Claude Code风格(推荐✨)
适用场景:日常开发,需要灵活切换模型/Provider,交互式体验最佳
核心特性:
- ✅ 会话内切换Provider(OpenAI ↔ Anthropic)
- ✅ 会话内切换模型
- ✅ 实时状态查看
- ✅ 统一的对话历史
完整代码 (cli-claude-code.js):
javascript
javascript
import OpenAI from 'openai';
import Anthropic from '@anthropic-ai/sdk';
import readline from 'readline';
// ---- 配置 ----
const config = {
gateway: 'http://127.0.0.1:9000',
apiKey: process.env.GATEWAY_API_KEY || 'your-key',
providers: {
openai: {
type: 'openai',
baseURL: 'http://127.0.0.1:9000/v1',
models: ['deepseek-chat', 'gpt-4', 'qwen-turbo'],
},
anthropic: {
type: 'anthropic',
baseURL: 'http://127.0.0.1:9000',
models: ['claude-3-sonnet-20240229', 'claude-3-haiku-20240307'],
}
}
};
// ---- 状态 ----
let currentProvider = 'openai';
let currentModel = 'deepseek-chat';
let history = [];
// ---- 客户端工厂 ----
function getClient(provider) {
const p = config.providers[provider];
if (p.type === 'openai') {
return new OpenAI({ baseURL: p.baseURL, apiKey: config.apiKey });
}
return new Anthropic({ baseURL: p.baseURL, apiKey: config.apiKey });
}
// ---- 对话 ----
async function chat(prompt) {
const client = getClient(currentProvider);
const providerConfig = config.providers[currentProvider];
// 保存历史
history.push({ role: 'user', content: prompt });
try {
let response;
if (providerConfig.type === 'openai') {
response = await client.chat.completions.create({
model: currentModel,
messages: history,
});
const reply = response.choices[0].message.content;
history.push({ role: 'assistant', content: reply });
console.log('\n🤖:', reply);
} else {
response = await client.messages.create({
model: currentModel,
max_tokens: 1024,
messages: history,
});
const reply = response.content[0].text;
history.push({ role: 'assistant', content: reply });
console.log('\n🤖:', reply);
}
} catch (error) {
console.error('❌ 错误:', error.message);
}
ask();
}
// ---- 命令处理 ----
function handleCommand(input) {
if (['exit', 'quit'].includes(input)) {
console.log('👋 再见!');
rl.close();
return true;
}
if (input === '/status') {
console.log(`📊 Provider: ${currentProvider}, 模型: ${currentModel}, 对话轮次: ${history.length/2}`);
return false;
}
if (input.startsWith('/provider ')) {
const name = input.split(' ')[1];
if (config.providers[name]) {
currentProvider = name;
currentModel = config.providers[name].models[0];
history = []; // 切换时清空历史(可选)
console.log(`✅ 切换到 ${name}, 模型: ${currentModel}`);
} else {
console.log(`❌ 可用: ${Object.keys(config.providers).join(', ')}`);
}
return false;
}
if (input.startsWith('/model ')) {
const model = input.split(' ')[1];
const p = config.providers[currentProvider];
if (p.models.includes(model)) {
currentModel = model;
console.log(`✅ 切换到模型: ${model}`);
} else {
console.log(`❌ 可用: ${p.models.join(', ')}`);
}
return false;
}
if (input === '/clear') {
history = [];
console.log('🧹 对话历史已清空');
return false;
}
chat(input);
return false;
}
// ---- REPL ----
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
function ask() {
rl.question(`\n[${currentProvider}/${currentModel}] 👤 你: `, (input) => {
const exited = handleCommand(input);
if (!exited) ask();
});
}
console.log(`
╔═══════════════════════════════════════╗
║ 🤖 Claude Code 风格 CLI 已启动 ║
╠═══════════════════════════════════════╣
║ 命令: ║
║ /status 查看当前状态 ║
║ /provider <name> 切换Provider ║
║ /model <name> 切换模型 ║
║ /clear 清空对话历史 ║
║ exit/quit 退出 ║
╚═══════════════════════════════════════╝
`);
ask();
运行:
bash
css
node cli-claude-code.js
交互演示:
text
bash
[openai/deepseek-chat] 👤 你: 你好,介绍一下自己
🤖: 你好!我是DeepSeek助手...
[openai/deepseek-chat] 👤 你: /provider anthropic
✅ 切换到 anthropic, 模型: claude-3-sonnet-20240229
[anthropic/claude-3-sonnet-20240229] 👤 你: 刚才我们聊了什么?
🤖: 你刚才让我介绍自己...
[anthropic/claude-3-sonnet-20240229] 👤 你: /status
📊 Provider: anthropic, 模型: claude-3-sonnet-20240229, 对话轮次: 3
4. 快速上手
4.1 选择适合你的模式
| 你的需求 | 推荐模式 | 命令 |
|---|---|---|
| 只用DeepSeek/Qwen等模型 | 模式一 | node cli-openai.js |
| 只用Claude系列 | 模式二 | node cli-anthropic.js |
| 需要来回切换测试 | 模式三 | node cli-claude-code.js |
4.2 修改默认模型
在对应CLI文件中找到 model 字段,替换为你网关支持的模型名:
javascript
arduino
// OpenAI模式
model: 'deepseek-chat' // 改为 'qwen-turbo' 或 'gpt-4'
// Anthropic模式
model: 'claude-3-sonnet-20240229' // 改为 'claude-3-opus-20240229'
// Claude Code风格
models: ['deepseek-chat', 'gpt-4'] // 添加或删除模型
4.3 添加新Provider(模式三)
在 config.providers 中添加:
javascript
css
providers: {
// ... 已有配置
custom: {
type: 'openai', // 或 'anthropic'
baseURL: 'http://127.0.0.1:9000/v1',
models: ['custom-model-1', 'custom-model-2'],
}
}
5. 常见问题
Q1: 连接网关失败
bash
bash
# 检查网关是否运行
curl http://127.0.0.1:9000/health
# 检查环境变量是否设置
echo $OPENAI_BASE_URL
echo $ANTHROPIC_BASE_URL
Q2: 认证失败
bash
bash
# 确认密钥正确
export GATEWAY_API_KEY="your-actual-key"
# 或在代码中硬编码(仅测试用)
apiKey: 'your-actual-key'
Q3: 模型不存在
bash
bash
# 查看网关支持的模型列表
curl http://127.0.0.1:9000/models
# 在CLI中切换存在的模型
/model deepseek-chat
Q4: 对话历史混乱(模式三)
使用 /clear 命令清空历史,或重启CLI。
6. 进阶技巧
6.1 保存对话记录
在CLI中添加文件写入功能:
javascript
javascript
import fs from 'fs';
// 在每次回复后追加到文件
fs.appendFileSync('chat.log', `User: ${prompt}\nAI: ${reply}\n\n`);
6.2 支持流式输出
OpenAI模式添加流式响应:
javascript
php
const stream = await client.chat.completions.create({
model: currentModel,
messages: history,
stream: true,
});
for await (const chunk of stream) {
process.stdout.write(chunk.choices[0]?.delta?.content || '');
}
6.3 创建快捷命令
bash
ini
# 添加别名到 ~/.bashrc
alias ai='node ~/my-cli/cli-claude-code.js'
# 直接运行
ai
6.4 多轮对话优化
模式三已内置历史管理,如需限制上下文长度:
javascript
ini
// 只保留最近10轮对话
if (history.length > 20) {
history = history.slice(-20);
}
总结
| 模式 | 协议 | 交互方式 | 适用场景 | 代码量 |
|---|---|---|---|---|
| 模式一 | OpenAI | 简单对话 | 单一模型测试 | ~30行 |
| 模式二 | Anthropic | 简单对话 | Claude专用 | ~30行 |
| 模式三 | 双协议 | 命令交互 | 日常开发调试 | ~100行 |
推荐新手从模式三开始,功能完整,体验最佳。
相关资源
📝 遇到问题? 检查步骤:
node -v确保版本 ≥ 18curl http://127.0.0.1:9000/health确保网关正常- 环境变量
GATEWAY_API_KEY正确设置- 模型名称与网关支持列表匹配
Happy Coding!