本地大模型网关 CLI 使用教程

16 阅读5分钟

我的开源大模型网关: github.com/boonya-hrgk…

通过统一网关 http://127.0.0.1:9000,一个CLI同时调用OpenAI和Anthropic协议的模型


目录

  1. 前置准备
  2. 安装与配置
  3. 三种模式详解
  4. 快速上手
  5. 常见问题
  6. 进阶技巧

1. 前置准备

1.1 环境要求

  • Node.js ≥ 18.0.0(下载地址
  • 本地网关http://127.0.0.1:9000 已启动并运行

1.2 验证网关状态

bash

curl http://127.0.0.1:9000/health
# 预期返回: {"status":"ok"}

1.3 准备API密钥

bash

# 设置环境变量(替换为你的实际密钥)
export GATEWAY_API_KEY="your-gateway-key-here"

💡 说明:你的网关已兼容OpenAI和Anthropic两大协议,只需一个统一密钥即可访问所有模型。


2. 安装与配置

2.1 创建项目

bash

# 创建目录
mkdir my-cli && cd my-cli

# 初始化项目
npm init -y

# 安装依赖
npm install openai @anthropic-ai/sdk

2.2 配置文件结构

text

my-cli/
├── package.json
├── cli-openai.js       # 模式一:OpenAI协议
├── cli-anthropic.js    # 模式二:Anthropic协议
└── cli-claude-code.js  # 模式三:Claude Code风格(推荐)

2.3 设置网关地址(重要!)

所有模式都通过环境变量读取网关地址:

bash

# 添加到 ~/.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

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

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

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

node cli-claude-code.js

交互演示

text

[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

// 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

providers: {
  // ... 已有配置
  custom: {
    type: 'openai',  // 或 'anthropic'
    baseURL: 'http://127.0.0.1:9000/v1',
    models: ['custom-model-1', 'custom-model-2'],
  }
}

5. 常见问题

Q1: 连接网关失败

bash

# 检查网关是否运行
curl http://127.0.0.1:9000/health

# 检查环境变量是否设置
echo $OPENAI_BASE_URL
echo $ANTHROPIC_BASE_URL

Q2: 认证失败

bash

# 确认密钥正确
export GATEWAY_API_KEY="your-actual-key"

# 或在代码中硬编码(仅测试用)
apiKey: 'your-actual-key'

Q3: 模型不存在

bash

# 查看网关支持的模型列表
curl http://127.0.0.1:9000/models

# 在CLI中切换存在的模型
/model deepseek-chat

Q4: 对话历史混乱(模式三)

使用 /clear 命令清空历史,或重启CLI。


6. 进阶技巧

6.1 保存对话记录

在CLI中添加文件写入功能:

javascript

import fs from 'fs';

// 在每次回复后追加到文件
fs.appendFileSync('chat.log', `User: ${prompt}\nAI: ${reply}\n\n`);

6.2 支持流式输出

OpenAI模式添加流式响应:

javascript

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

# 添加别名到 ~/.bashrc
alias ai='node ~/my-cli/cli-claude-code.js'

# 直接运行
ai

6.4 多轮对话优化

模式三已内置历史管理,如需限制上下文长度:

javascript

// 只保留最近10轮对话
if (history.length > 20) {
  history = history.slice(-20);
}

总结

模式协议交互方式适用场景代码量
模式一OpenAI简单对话单一模型测试~30行
模式二Anthropic简单对话Claude专用~30行
模式三双协议命令交互日常开发调试~100行

推荐新手从模式三开始,功能完整,体验最佳。


相关资源


📝 遇到问题?  检查步骤:

  1. node -v 确保版本 ≥ 18
  2. curl http://127.0.0.1:9000/health 确保网关正常
  3. 环境变量 GATEWAY_API_KEY 正确设置
  4. 模型名称与网关支持列表匹配

Happy Coding!