使用 vLLM 和 LiteLLM 在本地 LLM 上运行 Claude Code
Source: Dev.to
(请提供您希望翻译的正文内容,我将为您翻译成简体中文并保持原有的格式。)
在本地运行 Claude Code 与 vLLM + LiteLLM
目标: 将专有源代码保留在本地,同时仍使用 Claude Code 的工作流。
解决方案: 通过 LiteLLM 代理 Claude Code 的 Anthropic Messages API 调用,将其转换为本地 vLLM 推理服务器使用的兼容 OpenAI 的 API。
Claude Code → LiteLLM (port 4000) → vLLM (port 8000) → Local GPU
1. 一行环境变量
export ANTHROPIC_BASE_URL="http://localhost:4000"
Claude Code 现在指向 LiteLLM 代理,而不是 Anthropic 的云端端点。
2. 模型与硬件
- 模型:
Qwen3‑Coder‑30B‑A3B‑Instruct‑AWQ(混合专家,30 B 总参数,前向时激活 3 B) - GPU: 双 AMD MI60(ROCm)使用张量并行(size = 2)
- 量化: AWQ → 能够舒适地装入 GPU 显存
2.1 vLLM Docker 服务(docker‑compose 片段)
services:
vllm:
image: nalanzeyu/vllm-gfx906:v0.11.2-rocm6.3
container_name: vllm
devices:
- /dev/kfd:/dev/kfd
- /dev/dri/card1:/dev/dri/card1
- /dev/dri/card2:/dev/dri/card2
- /dev/dri/renderD128:/dev/dri/renderD128
- /dev/dri/renderD129:/dev/dri/renderD129
shm_size: 16g
environment:
- HIP_VISIBLE_DEVICES=0,1
command:
- python
- -m
- vllm.entrypoints.openai.api_server
- --model
- QuantTrio/Qwen3-Coder-30B-A3B-Instruct-AWQ
- --tensor-parallel-size
- "2"
- --max-model-len
- "65536"
- --gpu-memory-utilization
- "0.9"
- --enable-auto-tool-choice
- --tool-call-parser
- qwen3_coder
为什么要加最后两个标志?
--enable-auto-tool-choice– 让模型自行决定何时发出工具调用。--tool-call-parser qwen3_coder– 将 Qwen 的 XML 风格工具调用转换为 LiteLLM(以及最终的 Claude Code)所期望的 OpenAI 工具调用格式。
3. LiteLLM 配置
model_list:
- model_name: claude-*
litellm_params:
model: hosted_vllm/QuantTrio/Qwen3-Coder-30B-A3B-Instruct-AWQ
api_base: http://vllm:8000/v1
api_key: "not-needed"
model_info:
max_tokens: 65536
max_input_tokens: 57344
max_output_tokens: 8192
litellm_settings:
drop_params: true # ignore Anthropic‑only params
request_timeout: 600
modify_params: true # adapt params for OpenAI API
general_settings:
disable_key_check: true # no API key needed locally
设置说明
| Setting | Effect |
|---|---|
drop_params: true | 静默丢弃没有 OpenAI 对应字段的 Anthropic‑specific 参数。 |
modify_params: true | 允许 LiteLLM 重写参数(例如 max_tokens),以匹配目标 API 的期望。 |
disable_key_check: true | 跳过 API‑key 验证——在服务器本地运行且无需身份验证时很有用。 |
4. 在本地堆栈上运行 Claude Code
export ANTHROPIC_BASE_URL="http://localhost:4000"
cd my-project
claude # launches Claude Code as usual
Result: 用户体验与托管的 Anthropic API 完全相同,但所有推理都在本地进行。
Performance & Limits
| 指标 | 观察结果 |
|---|---|
| Throughput | ~25‑30 tokens / s on dual MI60, ~175 ms time‑to‑first‑token |
| Context window | Capped at 64 K tokens (Claude Opus can go to 200 K) |
| Model capability | Qwen3‑Coder excels at coding; Claude has broader general knowledge and instruction following. |
Upsides
- Zero API cost
- Full data sovereignty (code never leaves your network)
- Works on air‑gapped environments
5. 端到端测试:构建 Flask 待办事项应用
export ANTHROPIC_BASE_URL="http://localhost:4000"
cd /tmp && mkdir flask-test && cd flask-test
claude --dangerously-skip-permissions -p \
"Build a Flask todo app with SQLite persistence, \
modern UI with gradients and animations, \
mobile responsive design, and full CRUD operations."
生成的项目结构
flask_todo_app/
├── app.py # Flask routes + SQLite setup
├── requirements.txt # Dependencies
├── run_app.sh # Launch script
├── static/
│ ├── css/
│ │ └── style.css # Gradients, animations, hover effects
│ └── js/
│ └── script.js # Client‑side interactions
└── templates/
└── index.html # Jinja2 template (responsive layout)
示例 app.py
from flask import Flask, render_template, request, redirect, url_for
import sqlite3
app = Flask(__name__)
def init_db():
conn = sqlite3.connect('todos.db')
c = conn.cursor()
c.execute('''CREATE TABLE IF NOT EXISTS todos
(id INTEGER PRIMARY KEY AUTOINCREMENT,
task TEXT NOT NULL,
completed BOOLEAN DEFAULT FALSE)''')
conn.commit()
conn.close()
init_db()
@app.route('/')
def index():
conn = sqlite3.connect('todos.db')
c = conn.cursor()
c.execute('SELECT id, task, completed FROM todos ORDER BY id DESC')
todos = c.fetchall()
conn.close()
return render_template('index.html', todos=todos)
示例 CSS (static/css/style.css)
body {
font-family: 'Poppins', sans-serif;
background: linear-gradient(135deg, #667eea, #764ba2);
min-height: 100vh;
padding: 20px;
}
.container {
max-width: 800px;
margin: 0 auto;
}
.header {
text-align: center;
padding: 40px 0;
color: white;
text-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
运行应用
cd flask_todo_app
python -m venv venv
source venv/bin/activate
pip install -r requirements.txt
python app.py # starts Flask on http://localhost:5000
现在您可以添加、切换和删除任务;SQLite 数据库在重启后仍会保留。
6. TL;DR
- 将
ANTHROPIC_BASE_URL设置为指向 LiteLLM 代理 (http://localhost:4000)。 - 运行 vLLM(Docker)并使用 Qwen3‑Coder 模型,添加
--enable-auto-tool-choice+--tool-call-parser qwen3_coder参数。 - 配置 LiteLLM,将所有
claude-*模型名称映射到本地 vLLM 端点。 - 像往常一样启动 Claude Code——它现在会调用您本地的 GPU,实现零成本、主权化的推理,同时保留完整的 Claude Code 工作流(包括工具调用)。
享受安全、高性能的编码助手,无需将专有代码发送到外部!
生成概览
- 整个生成过程大约用了五分钟,经历了多轮 agentic 迭代。
- 每个文件都是一次独立的工具调用:模型生成代码,Claude Code 执行,返回结果,模型再规划下一步。
- 91 % 的前缀缓存命中率表明 vLLM 在多轮循环中高效复用上下文。
这验证了 agentic 工作流能够正常运行。模型读取提示,规划文件结构,发出创建目录和写文件的工具调用,并生成可运行的应用。所有推理都在本地的 MI60 上完成——没有代码离开我的网络。
限制与未来工作
- 规模 – 未在更大的代码库上测试。一个小的 Flask 应用算是一个案例,几千行的重构则是另一回事。
- 上下文窗口 – 64 K token 的限制最终会成为约束,模型在处理复杂架构决策时可能不如真实的 Claude 那样游刃有余。
- 当前适用性 – 适合聚焦、范围明确的任务。
Claude Code 兼容性检查表
| 要求 | 细节 |
|---|---|
| 强大的工具使用 | 模型必须可靠地发出结构化的工具调用 |
| 代码聚焦 | Qwen3‑Coder 表现良好;DeepSeek Coder 和 CodeLlama 系列也应可行 |
| 足够的上下文 | 我使用了 64 K;更小的窗口可能可用,但未经过测试 |
观察
- Qwen3‑Coder‑30B‑A3B 能很好地处理直接的编码任务。
- 对于复杂的重构或架构决策,真实的 Claude API 仍是更好的选择。
硬件建议
- 如果没有 64 GB 显存,可以使用 Qwen2.5‑Coder‑7B 或 Qwen3‑8B,它们可以在单块 16 GB 或 24 GB 显卡上运行。
- 这些配置我尚未测试,无法评论它们的上下文限制或在 Claude Code 的 agentic 工作流中的表现。
工作流建议
- 与其使用宽泛的 “重构此模块” 提示,不如将工作拆分为更紧凑、聚焦的请求。
- 更细粒度的提示更能发挥小模型的优势。
完整的 Docker‑Compose 配置
services:
vllm:
image: nalanzeyu/vllm-gfx906:v0.11.2-rocm6.3
container_name: vllm
restart: unless-stopped
ports:
- "8000:8000"
devices:
- /dev/kfd:/dev/kfd
- /dev/dri/card1:/dev/dri/card1
- /dev/dri/card2:/dev/dri/card2
- /dev/dri/renderD128:/dev/dri/renderD128
- /dev/dri/renderD129:/dev/dri/renderD129
group_add:
- "44"
- "992"
shm_size: 16g
volumes:
- /mnt/cache/huggingface:/root/.cache/huggingface:rw
environment:
- HIP_VISIBLE_DEVICES=0,1
command:
- python
- -m
- vllm.entrypoints.openai.api_server
- --model
- QuantTrio/Qwen3-Coder-30B-A3B-Instruct-AWQ
- --tensor-parallel-size
- "2"
- --max-model-len
- "65536"
- --gpu-memory-utilization
- "0.9"
- --host
- "0.0.0.0"
- --port
- "8000"
- --enable-auto-tool-choice
- --tool-call-parser
- qwen3_coder
litellm:
image: litellm/litellm:v1.80.15-stable
container_name: litellm
restart: unless-stopped
ports:
- "4000:4000"
volumes:
- ./litellm-config.yaml:/app/config.yaml:ro
command:
- --config
- /app/config.yaml
- --port
- "4000"
- --host
- "0.0.0.0"
depends_on:
- vllm
运行堆栈
# 启动(使用 nerdctl 或 Docker)
nerdctl compose -f coder.yaml up -d
在网络中的任意机器上,将 Claude Code 指向 Feynman(GPU 工作站),即可进行本地推理。
# 完成后,关闭并清理
nerdctl compose -f coder.yaml down
最后思考
- 该方案并不能取代所有人的 Claude API。
- 如果需要最大化的能力,Anthropic 的托管模型仍是最佳选择。
- 对于在乎数据主权的用户,本地推理意味着专有代码永远不会离开网络。
- 每次向 Claude Code 提问时看到自己的 GPU 亮起,也是一件令人满足的事。