Skip to content

API 与本地部署

🎯 学习目标

  • 理解远程 API 与本地推理(Ollama / vLLM)的适用场景与权衡
  • 使用 Node.js 或 Python 完成一次 OpenAI 兼容的 Chat Completions 调用
  • 掌握 API Key、baseURL、环境变量与错误处理的基本模式
  • 设计可切换 Provider 的配置结构

引言

动手写代码之前,先定部署形态:远程 API(OpenAI、DeepSeek、通义、Anthropic 等)让你分钟级接入最强模型,按 Token 付费,运维由云厂商承担;本地部署(Ollama、vLLM、llama.cpp)把权重跑在自己的 GPU/CPU 上,数据不出内网,长期高 QPS 可能更省,但要自己负责显卡、扩容与版本升级。

对大多数团队,路径是 开发期远程 API 快速验证 → 生产按合规与成本选 VPC API 或私有化。本节用 OpenAI 兼容接口 演示——国内多数厂商支持同一套 /v1/chat/completions 路径,换 baseURL 即可迁移。你会完成从环境变量读取 Key、发起请求、打印回复与 usage 的全流程,并看到 Ollama 本地调用的等价写法。

章节正文

第 1 步:远程 API:环境与第一次请求(Node.js)

创建项目目录,安装官方 SDK:

bash
npm init -y
npm install openai dotenv

根目录新建 .env(勿提交 Git):

OPENAI_API_KEY=sk-...
# 若用 DeepSeek 等兼容厂商,再设:
# OPENAI_BASE_URL=https://api.deepseek.com
# OPENAI_MODEL=deepseek-chat

chat.mjs 示例:

javascript
import OpenAI from 'openai'
import 'dotenv/config'

const client = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY,
  baseURL: process.env.OPENAI_BASE_URL, // 可选,默认 OpenAI 官方
})

const response = await client.chat.completions.create({
  model: process.env.OPENAI_MODEL ?? 'gpt-4o-mini',
  messages: [
    { role: 'system', content: '你是简洁的中文技术助手。' },
    { role: 'user', content: '用一句话解释什么是 Token。' },
  ],
  max_tokens: 200,
})

console.log(response.choices[0].message.content)
console.log('usage:', response.usage)

运行 node chat.mjs。成功时你会看到模型回复及 prompt_tokenscompletion_tokens。生产代码务必 不要硬编码 Key,并捕获 401(Key 无效)、429(限流)、5xx(上游故障) 做重试或降级(见 1.5 备用模型)。

第 2 步:Python 等价实现与 httpx 裸调用

Python 同样推荐官方 SDK:

bash
pip install openai python-dotenv

chat.py

python
import os
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()

client = OpenAI(
    api_key=os.environ["OPENAI_API_KEY"],
    base_url=os.environ.get("OPENAI_BASE_URL"),
)

resp = client.chat.completions.create(
    model=os.getenv("OPENAI_MODEL", "gpt-4o-mini"),
    messages=[
        {"role": "system", "content": "你是简洁的中文技术助手。"},
        {"role": "user", "content": "用一句话解释什么是 Token。"},
    ],
    max_tokens=200,
)

print(resp.choices[0].message.content)
print("usage:", resp.usage)

若不想依赖 SDK,可用 httpx 理解 HTTP 形态(便于调试 curl 转代码):

python
import os, httpx

r = httpx.post(
    f"{os.environ.get('OPENAI_BASE_URL', 'https://api.openai.com/v1')}/chat/completions",
    headers={"Authorization": f"Bearer {os.environ['OPENAI_API_KEY']}"},
    json={
        "model": "gpt-4o-mini",
        "messages": [{"role": "user", "content": "hello"}],
    },
    timeout=60.0,
)
r.raise_for_status()
data = r.json()
print(data["choices"][0]["message"]["content"])

timeout 必须设置:LLM 响应可能数十秒,默认过短会导致客户端先断开。

第 3 步:Ollama 本地部署:零 Key 开发循环

安装 Ollama 后拉取模型并启动服务(默认 http://localhost:11434):

bash
ollama pull qwen2.5:7b
ollama run qwen2.5:7b

Ollama 提供 OpenAI 兼容 端点,Node 侧只需改 baseURL 与 model:

javascript
const client = new OpenAI({
  apiKey: 'ollama', // 任意非空字符串
  baseURL: 'http://localhost:11434/v1',
})

const response = await client.chat.completions.create({
  model: 'qwen2.5:7b',
  messages: [{ role: 'user', content: '本地模型是否正常?' }],
})

适用场景:离线开发、敏感原型、演示无外网环境。局限:模型能力弱于顶级 API、并发与长上下文受本机 GPU/内存限制;生产高 QPS 常用 vLLM 而非 Ollama。

对比记忆:

维度远程 APIOllama 本地
数据出境视厂商协议不出机器
运维自备 GPU/驱动
能力旗舰模型取决于所拉权重
计费按 Token电费 + 硬件

第 4 步:抽象 Provider:一套代码切换云与本地

避免业务层散落 if (deepseek) ... else ...。推荐 配置驱动

javascript
// config/models.mjs
export const providers = {
  openai: {
    baseURL: 'https://api.openai.com/v1',
    apiKey: process.env.OPENAI_API_KEY,
    defaultModel: 'gpt-4o-mini',
  },
  deepseek: {
    baseURL: 'https://api.deepseek.com',
    apiKey: process.env.DEEPSEEK_API_KEY,
    defaultModel: 'deepseek-chat',
  },
  ollama: {
    baseURL: 'http://localhost:11434/v1',
    apiKey: 'ollama',
    defaultModel: 'qwen2.5:7b',
  },
}

export function createClient(name = 'openai') {
  const p = providers[name]
  if (!p?.apiKey) throw new Error(`Missing config for provider: ${name}`)
  return new OpenAI({ apiKey: p.apiKey, baseURL: p.baseURL })
}

业务只调用:

javascript
const client = createClient(process.env.LLM_PROVIDER ?? 'openai')
const model = providers[process.env.LLM_PROVIDER].defaultModel

配合 1.5 节 fallback:捕获 429/5xx 时换 createClient('fallback') 重试一次,并记录 metrics。

第 5 步:安全、观测与上线检查清单

安全

  • Key 仅存环境变量或密钥管理服务(Vault、云 KMS)
  • 后端代理 API,禁止前端浏览器直连 Key
  • 企业 VPC / 私有化 endpoint 走专线,日志脱敏

观测

  • 每次请求记录:providermodelusage、latency、HTTP status
  • 对 429 做 指数退避;对重复相同 system+context 探索 Prompt Cache

上线前自测

bash
# 连通性
curl "$OPENAI_BASE_URL/models" -H "Authorization: Bearer $OPENAI_API_KEY"

# 最小 completion
node chat.mjs

确认 模型 ID 字符串 与控制台一致(大小写、后缀 -instruct 等),避免 404 model not found。

动手练习

  1. 用 Node 或 Python 跑通一家远程 API,打印 content 与 usage;再改用 Ollama 跑同一 prompt 对比质量与延迟。
  2. 实现 createClient(providerName),通过环境变量 LLM_PROVIDER 切换 deepseek 与 ollama,业务代码零改动。
  3. 为 chat 函数添加 try/catch:401 抛明确错误,429 等待 2s 重试一次,5xx 记录日志并抛给上层降级。
  4. .env.example(无真实 Key)与 .gitignore 规则,说明团队如何分发密钥。

常见问题

Q:baseURL 末尾要不要加 /v1?

OpenAI SDK 期望 baseURL 含 /v1(如 https://api.deepseek.comhttps://api.deepseek.com/v1,视厂商文档而定)。以厂商示例为准,404 时先检查这一路径。

Q:本地 Ollama 能在团队 CI 里跑吗?

可以但慢且 GPU runner 稀缺。CI 更适合 mock 响应或调用固定 stub;集成测试可夜间跑小模型冒烟。

Q:同一项目能混用 OpenAI 和国产 Embedding 吗?

可以,但 Chat 与 Embedding 建议分别抽象 Provider。RAG 检索链路对 Embedding 模型切换更敏感,需重建向量库。

本节小结

远程 API 适合快速迭代与旗舰能力;Ollama 适合本地开发与数据隔离。OpenAI 兼容 SDK + baseURL 切换是国内多厂商接入的通用模式。通过 Provider 抽象、环境变量管理 Key、timeout 与重试,可为第 2 章后续参数、流式与结构化输出打下基础。