使用 llama.cpp 和 Claude Code 搭建本地 Agent 编码环境
目前有一张 RTX 4090 24G 显卡。平时编码主要使用 Codex,但有些小任务可以先尝试本地模型,减少调用成本。
这篇文章保留实际执行过的命令,并按执行顺序整理。目前 Qwen3.6-27B 已经可以通过 llama-server 启动编码测试正常
CUDA 环境准备
先安装添加 NVIDIA 软件源需要的工具:
sudo apt install dirmngr ca-certificates software-properties-common apt-transport-https curl -y添加 Debian 12 对应的 NVIDIA GPG 公钥:
# 下载 NVIDIA GPG 公钥
curl -fSsL https://developer.download.nvidia.com/compute/cuda/repos/debian12/x86_64/3bf863cc.pub \
| sudo gpg --dearmor \
| sudo tee /usr/share/keyrings/nvidia-drivers.gpg > /dev/null这台机器需要清理旧环境后重新安装驱动。下面几条命令会卸载已有的 NVIDIA 和 CUDA 软件包,只适合确实需要重装的机器:
# 清理旧环境
sudo apt-get purge -y '^nvidia-.*'
sudo apt-get purge -y '^libnvidia-.*'
sudo apt-get purge -y '^cuda-.*'
sudo apt autoremove --purge -y
apt search nvidia-driver
sudo apt install --reinstall -y nvidia-driver nvidia-driver-cuda
# 重启后确认驱动
nvidia-sminvidia-smi 能正常识别 RTX 4090 后,会输出以下信息
Tue Jul 21 17:35:09 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 610.43.02 KMD Version: 610.43.02 CUDA UMD Version: 13.3 |
+-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 4090 On | 00000000:01:00.0 Off | Off |
| 30% 34C P8 12W / 450W | 1MiB / 24564MiB | 0% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+配置显卡容器支持
这台机器还需要通过 Docker 使用显卡,因此安装 NVIDIA Container Toolkit:
sudo apt install nvidia-container-toolkit
sudo nvidia-ctk runtime configure --runtime=docker
sudo systemctl restart docker如果只准备直接运行 llama.cpp,不使用 Docker,这一步可以跳过。
安装 CUDA 开发工具包
apt search cuda-toolkit
sudo apt install cuda-toolkit-13-3
# 将以下内容添加到 ~/.bashrc
echo 'export CUDA_HOME=/usr/local/cuda' >> ~/.bashrc
echo 'export PATH=$CUDA_HOME/bin:$PATH' >> ~/.bashrc
echo 'export LD_LIBRARY_PATH=$CUDA_HOME/lib64:$LD_LIBRARY_PATH' >> ~/.bashrc
source ~/.bashrc这里安装的是实际使用的 cuda-toolkit-13-3。环境变量生效后,可以用 nvcc --version 再确认一次。
编译 llama.cpp
git clone https://github.com/ggml-org/llama.cpp.git
cd llama.cpp
# 编译前清理旧的构建目录
rm -fr build
# CUDA 构建
cmake -B build -DGGML_CUDA=ON -DGGML_RPC=ON
# 纯 CPU 构建,二选一
# cmake -B build -DGGML_CUDA=OFF -DGGML_RPC=OFF
cmake --build build --config Release -j 32
./build/bin/llama-server --version这次构建同时启用了 CUDA 和 RPC。最后一条命令能够打印 llama-server 版本,说明编译完成。
下载模型文件
本地模型使用 GGUF 格式。这里先通过 ModelScope 下载已经测试可用的 Qwen3.6-27B。
Qwen3.6-27B:完整测试可用
modelscope download --model unsloth/Qwen3.6-27B-GGUF --include "*Q4_K_M*" "*mmproj-F16*"这条命令只下载 Q4_K_M 量化模型和 F16 视觉投影文件,避免把仓库里的其他量化版本全部拉下来。
启动 Qwen3.6-27B
先设置本次服务使用的 API key。实际值只放在当前终端或私有配置中,不写进文章:
# 先设置实际的 llama.cpp API key,不要把 key 写进脚本或文章
export LLAMA_API_KEY='在这里填入你的实际 key'
./build/bin/llama-server --metrics --alias Qwen3.6-27B \
--model /vol1/1000/models/modelscope/models/unsloth/Qwen3.6-27B-GGUF/Qwen3.6-27B-Q4_K_M.gguf \
--mmproj /vol1/1000/models/modelscope/models/unsloth/Qwen3.6-27B-GGUF/mmproj-F16.gguf \
--host 0.0.0.0 --port 30104 --ctx-size 262144 -ngl 100 \
--cache-type-k q4_0 --cache-type-v q4_0 --parallel 1 --swa-full \
--batch-size 4096 --ubatch-size 1024 --flash-attn on --mlock --no-mmap --threads $(nproc)这组参数是实际使用配置,不是通用推荐值。其中:
--ctx-size 262144将上下文设为 262K。-ngl 100尽量把模型层放到 GPU。--cache-type-k q4_0 --cache-type-v q4_0压缩 KV Cache,降低长上下文的显存占用。--parallel 1只保留一个并行槽位。--metrics开启指标接口,便于观察运行状态。--swa-full为使用 Sliding Window Attention 的层启用完整尺寸的 SWA 缓存。长上下文下会占用更多缓存空间,但不会只保留滑动窗口范围内的缓存。--batch-size 4096设置逻辑批次上限。对llama-server来说,它限制连续批处理时每轮最多送入多少个 token;调大后可能加快长提示词的处理,也会增加内存或显存压力。--ubatch-size 1024设置一次实际计算的物理批次上限。batch-size可以再拆成多个ubatch执行,因此这里保持4096 >= 1024。--flash-attn on强制启用 Flash Attention,减少注意力计算的中间数据读写,通常能降低显存占用并提高速度。--mlock尝试把模型占用的内存锁在 RAM 中,避免被系统换出到 swap。进程需要足够的锁页权限,物理内存也必须留有余量。--no-mmap不使用内存映射加载模型,而是直接读入内存。启动通常更慢、常驻内存更明确;这里与--mlock一起使用,目的是减少运行中发生换页的可能。--threads $(nproc)将生成阶段的 CPU 线程数设为当前系统可见的逻辑处理器数量。模型的大部分层已经交给 GPU,但剩余 CPU 计算、采样和调度仍会使用这些线程。
先确认这个模型能够稳定启动,再进行 Claude Code 配置。不要在第一次报错时同时修改上下文、KV Cache、批大小和线程数。
Claude Code 配置
用户级配置文件是 ~/.claude/settings.json。当前 llama-server 的模型别名是 Qwen3.6-27B,所以 Claude Code 也统一使用这个名称:
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"env": {
"ANTHROPIC_AUTH_TOKEN": "与 LLAMA_API_KEY 相同",
"ANTHROPIC_BASE_URL": "http://localhost:30104",
"ANTHROPIC_MODEL": "Qwen3.6-27B",
"ANTHROPIC_DEFAULT_HAIKU_MODEL": "Qwen3.6-27B",
"ANTHROPIC_DEFAULT_SONNET_MODEL": "Qwen3.6-27B",
"ANTHROPIC_DEFAULT_OPUS_MODEL": "Qwen3.6-27B",
"ANTHROPIC_DEFAULT_FABLE_MODEL": "Qwen3.6-27B",
"CLAUDE_CODE_SUBAGENT_MODEL": "Qwen3.6-27B",
"API_TIMEOUT_MS": "3000000",
"CLAUDE_CODE_AUTO_COMPACT_WINDOW": "200000",
"CLAUDE_AUTOCOMPACT_PCT_OVERRIDE": "90"
},
"theme": "auto",
"statusLine": {
"type": "command",
"command": "node -e \"let s='';process.stdin.on('data',d=>s+=d).on('end',()=>{const j=JSON.parse(s),c=j.context_window||{},i=c.total_input_tokens||0,o=c.total_output_tokens||0,m=(j.model&&(j.model.display_name||j.model.id))||'model';console.log(m+' | Claude '+(i+o)+'/'+(c.context_window_size||200000)+' ('+(c.used_percentage||0)+'%) | Server 262144')})\"",
"padding": 1
}
}ANTHROPIC_AUTH_TOKEN 填写 llama-server 使用的 API Key,不要加 Bearer 前缀。ANTHROPIC_BASE_URL 是服务地址,其他模型字段全部指向同一个本地模型。
statusLine 会读取 Claude Code 传入的会话 JSON。Claude Code 对这个本地模型按 200000 token 管理上下文,而 llama-server 实际启动的上下文是 262144,因此状态栏同时显示两个数值。命令使用 Node.js,不依赖 jq:
Qwen3.6-27B | Claude 16700/200000 (8.4%) | Server 262144状态栏需要在第一次模型响应后才会有 token 数据。CLAUDE_CODE_AUTO_COMPACT_WINDOW 明确指定 Claude Code 按 200000 token 计算自动压缩,CLAUDE_AUTOCOMPACT_PCT_OVERRIDE 设为 90,因此大约在 180000 token 时提前压缩,给服务端留出余量。压缩时 Claude Code 会先清理旧的工具输出,再对较早的对话做摘要。
可以随时输入 /context 查看上下文占用,或输入 /compact 手动压缩。状态栏中的 Server 262144 只是显示服务端容量,不会把 Claude Code 的自动压缩上限扩大到 262144。
先测试普通对话:
claude --model Qwen3.6-27B -p --max-turns 1 --no-session-persistence "只回复 OK"实际返回 OK。再测试 Bash 工具调用:
claude --model Qwen3.6-27B -p --max-turns 2 --no-session-persistence "使用 Bash 执行 git rev-parse --short HEAD,只回复命令输出"实际返回 c193f661。Qwen3.6-27B 已经跑通普通对话和工具调用。Qwen-AgentWorld-35B-A3B 的接入状态单独记录在文章最后。
检查 llama-server 接口
启动命令设置了 --api-key,查询时带上 LLAMA_API_KEY:
curl -s http://localhost:30104/health
curl -s -H "Authorization: Bearer $LLAMA_API_KEY" http://localhost:30104/v1/models
curl -s -H "Authorization: Bearer $LLAMA_API_KEY" http://localhost:30104/metrics
curl -s -H "Authorization: Bearer $LLAMA_API_KEY" http://localhost:30104/props
curl -s -H "Authorization: Bearer $LLAMA_API_KEY" http://localhost:30104/slots几个接口的用途很直接:/health 检查服务是否可用,/v1/models 返回已加载的模型,/metrics 查看 token 数、耗时和速度,/props 查看上下文大小等服务参数,/slots 查看当前请求是否正在处理。
本次检查时,/health 返回:
{"status":"ok"}/v1/models 实际返回:
{"models":[{"name":"Qwen3.6-27B","model":"Qwen3.6-27B","modified_at":"","size":"","digest":"","type":"model","description":"","tags":[""],"capabilities":["completion","multimodal"],"parameters":"","details":{"parent_model":"","format":"gguf","family":"","families":[""],"parameter_size":"","quantization_level":""}}],"object":"list","data":[{"id":"Qwen3.6-27B","aliases":["Qwen3.6-27B"],"tags":[],"object":"model","created":1784619582,"owned_by":"llamacpp","meta":{"vocab_type":2,"n_vocab":248320,"n_ctx":262144,"n_ctx_train":262144,"n_embd":5120,"n_params":26895998464,"size":16806250496,"ftype":"Q4_K - Medium"}}]}启动时设置了 --alias Qwen3.6-27B,所以返回的模型名称和 ID 都是 Qwen3.6-27B。
/metrics 返回的主要统计如下:
llamacpp:prompt_tokens_total 70285
llamacpp:prompt_seconds_total 26.391
llamacpp:prompt_tokens_seconds 2663.22
llamacpp:tokens_predicted_total 4021
llamacpp:tokens_predicted_seconds_total 83.936
llamacpp:predicted_tokens_seconds 47.9055
llamacpp:n_decode_total 4051
llamacpp:n_tokens_max 25184
llamacpp:requests_processing 0
llamacpp:requests_deferred 0
llamacpp:n_busy_slots_per_decode 1这次记录的提示词处理速度约为 2663 token/s,生成速度约为 47.9 token/s。/props 显示上下文为 262144,/slots 显示唯一的 slot 处于空闲状态。这些统计会随请求继续增长,不是固定的基准测试结果。
TMUX 工具
sudo apt install tmux
tmux
tmux attach -t 0执行 tmux 进入一个独立的终端会话,然后直接在这个会话中运行 llama-server。模型启动后,需要退出当前终端时,先按 Ctrl+B,松开后再按 D,即可与 tmux 会话分离。分离后模型仍会继续运行,不要在会话中执行 exit。
以后重新登录服务器,执行 tmux attach -t 0 就能回到原来的终端,继续查看模型日志和运行状态。