Lab 008:本地模型能不能胜任日常 Agent 编码?
本地模型(Llama 3、Qwen 2.5、DeepSeek-Coder)最大的卖点是"数据不出云"。但很多团队试过之后发现:速度不够快、质量不够好、上下文窗口太小。本地模型到底适合什么场景?在哪些任务上会翻车?本文用 Ollama + LM Studio 做了系统性测试,给出了本地模型的适用边界和 fallback 策略。
一、实验目标
| 问题 | 实验方法 |
|---|---|
| 本地模型的速度够不够快? | 测试不同模型大小在常见任务上的响应时间 |
| 代码质量够用吗? | 与 Sonnet 做对比评测 |
| 什么任务本地模型做不了? | 逐步增加任务复杂度,找到失败边界 |
| 隐私收益到底有多大? | 量化分析哪些代码真的不能出云 |
| 什么硬件配置是最低要求? | 测试不同 GPU 对模型表现的影响 |
二、实验环境
2.1 硬件配置
| 配置 | GPU | 显存 | RAM | 适合模型 |
|---|---|---|---|---|
| 低配 | RTX 3060 | 12GB | 32GB | 7B-13B(Q4 量化) |
| 中配 | RTX 4090 | 24GB | 64GB | 34B(Q4)/ 70B(Q2) |
| 高配 | A100 80GB | 80GB | 128GB | 70B(Q8)/ 混合专家 |
2.2 测试模型
# local-models.yaml
models:
- name: "qwen2.5-coder-7b"
size: "7B"
quantization: "Q4_K_M"
vram_required: "5GB"
provider: "ollama"
- name: "qwen2.5-coder-32b"
size: "32B"
quantization: "Q4_K_M"
vram_required: "20GB"
provider: "ollama"
- name: "llama3-70b"
size: "70B"
quantization: "Q4_K_M"
vram_required: "42GB"
provider: "ollama"
- name: "deepseek-coder-v2"
size: "16B (MoE)"
quantization: "Q4_K_M"
vram_required: "12GB"
provider: "ollama"
- name: "codestral-22b"
size: "22B"
quantization: "Q4_K_M"
vram_required: "14GB"
provider: "lm-studio"
# 对比基线
baseline:
- name: "claude-sonnet"
provider: "anthropic"
- name: "gpt-4o-mini"
provider: "openai"2.3 调用配置
# local_model_config.py
"""
本地模型调用配置(Ollama / LM Studio)。
"""
# Ollama 配置
OLLAMA_CONFIG = {
"base_url": "http://localhost:11434",
"model": "qwen2.5-coder:32b",
"options": {
"temperature": 0.2,
"top_p": 0.9,
"num_ctx": 8192, # 上下文窗口
"num_predict": 2048, # 最大生成长度
"num_gpu": -1, # 全部层放到 GPU
"stop": ["</s>", "\n\n\n"],
}
}
# LM Studio 配置(兼容 OpenAI API)
LM_STUDIO_CONFIG = {
"base_url": "http://localhost:1234/v1",
"api_key": "not-needed",
"model": "local-model",
"temperature": 0.2,
"max_tokens": 2048,
}
# 模型预热(首次加载需要时间)
def warmup_model(model_name: str):
"""预加载模型到显存"""
import requests
response = requests.post(f"{OLLAMA_CONFIG['base_url']}/api/generate", json={
"model": model_name,
"prompt": "Hello",
"stream": False,
"options": {"num_predict": 1}
})
return response.status_code == 200三、速度测试
3.1 生成速度(Tokens/秒)
| 模型 | RTX 3060 (12GB) | RTX 4090 (24GB) | A100 (80GB) | 对比 Sonnet |
|---|---|---|---|---|
| qwen2.5-coder-7b Q4 | 45 tok/s | 72 tok/s | 95 tok/s | 60 tok/s |
| qwen2.5-coder-32b Q4 | 12 tok/s | 35 tok/s | 55 tok/s | 60 tok/s |
| llama3-70b Q4 | 不可用 | 15 tok/s | 32 tok/s | 60 tok/s |
| deepseek-coder-v2 Q4 | 28 tok/s | 52 tok/s | 78 tok/s | 60 tok/s |
| codestral-22b Q4 | 18 tok/s | 42 tok/s | 65 tok/s | 60 tok/s |
关键发现:
- 7B 模型在 3060 上就能超过 Sonnet 的速度
- 32B+ 模型需要 4090 级别才有可用的速度
- 70B 模型必须用 A100 才不至于太慢
3.2 首次 Token 延迟(TTFT)
| 模型 | 4K 上下文 | 8K 上下文 | 16K 上下文 |
|---|---|---|---|
| 7b Q4 | 0.3s | 0.5s | 1.2s |
| 32b Q4 | 0.8s | 1.5s | 3.5s |
| 70b Q4 | - | 3.2s | 8.0s |
| Sonnet (cloud) | 0.8s | 1.2s | 2.5s |
上下文越长,本地模型的 TTFT 越高(需要处理更多 KV Cache)。
四、质量对比
4.1 编码任务得分
| 任务类型 | 7b | 32b | 70b | Sonnet | 32b/Sonnet |
|---|---|---|---|---|---|
| 简单 Bugfix | 0.62 | 0.78 | 0.81 | 0.82 | 95% |
| 中等 Bugfix | 0.38 | 0.61 | 0.70 | 0.75 | 81% |
| 困难 Bugfix | 0.12 | 0.32 | 0.45 | 0.63 | 51% |
| 代码补全 | 0.71 | 0.85 | 0.88 | 0.90 | 94% |
| 单元测试生成 | 0.55 | 0.72 | 0.78 | 0.78 | 92% |
| Code Review | 0.30 | 0.52 | 0.65 | 0.79 | 66% |
| 代码重构 | 0.25 | 0.48 | 0.60 | 0.80 | 60% |
| 文档生成 | 0.48 | 0.68 | 0.75 | 0.81 | 84% |
本地模型能力边界(32B 模型):
✅ 可做(得分 > 0.7):简单 Bugfix、代码补全、测试生成、文档生成
⚠️ 勉强可做(0.5-0.7):中等 Bugfix、Code Review
❌ 不建议(< 0.5):困难 Bugfix、大型重构、复杂架构设计4.2 上下文窗口实测
| 模型 | 标称窗口 | 有效窗口(质量不下降) | 超过后表现 |
|---|---|---|---|
| 7b | 32K | 4K | 超过 4K 后开始"遗忘"前面的内容 |
| 32b | 32K | 8K | 超过 8K 后代码引用开始混乱 |
| 70b | 8K* | 6K | 标称 8K,超过 6K 质量明显下降 |
| Sonnet | 200K | 100K+ | 长上下文表现稳定 |
*70B 模型受限于显存,实际上下文通常只有 8K
五、适用场景矩阵
隐私要求
高 ┃ 低
┃
任务 ┃
复杂度 ┃
低 ━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━
(补全/格式化) ┃ ✅ 本地模型 ✅ 云端便宜模型
┃ 7B-32B (GPT-4o-mini)
┃
中 ━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━
(简单Bugfix) ┃ ⚠️ 本地大模型 ✅ 云端 Sonnet
┃ 32B+ 性价比更高
┃
高 ━━━━━━━━━━━━━━╋━━━━━━━━━━━━━━
(重构/架构) ┃ ❌ 本地模型 ✅ 云端 Opus
┃ 不推荐 本地模型质量不够
┃推荐配置
# 推荐的混合部署策略
routing:
# 隐私敏感 + 简单任务 → 本地模型
- condition: "data_sensitivity == 'HIGH' AND task.complexity == 'LOW'"
model: "qwen2.5-coder:32b"
reason: "代码不出云,32B 足够处理简单任务"
# 隐私敏感 + 复杂任务 → 本地模型 + 分步处理
- condition: "data_sensitivity == 'HIGH' AND task.complexity == 'HIGH'"
model: "llama3:70b"
fallback: "split_task" # 拆成小任务分步完成
reason: "70B 处理复杂任务,但需要拆分上下文"
# 非隐私 + 简单任务 → 云端便宜模型
- condition: "data_sensitivity == 'LOW' AND task.complexity == 'LOW'"
model: "gpt-4o-mini"
reason: "成本低,速度快,质量够用"
# 非隐私 + 复杂任务 → 云端强模型
- condition: "data_sensitivity == 'LOW' AND task.complexity == 'HIGH'"
model: "claude-opus"
reason: "最强模型处理最复杂的任务"六、真实经验与踩坑
6.1 Ollama 的模型加载时间被低估
场景:CI 流水线中每次调用本地模型,都要等 30 秒加载模型。
问题:CI 环境中 GPU 不常驻模型,每次调用都是"冷启动"。对于短任务(10 秒完成),加载时间比执行时间还长。
解决方案:CI 中使用 ollama serve 作为后台服务,保持模型常驻显存。或者使用专用 GPU 机器作为"模型服务节点",CI 通过 API 调用而不是本地运行。
6.2 量化对代码质量的影响
场景:同一个 70B 模型,Q4 量化和 FP16 的得分差 15%。 问题:Q4 量化在代码任务上损失明显——尤其是需要精确的变量名和缩进的场景。Q4 偶尔会生成语法错误的代码。 解决方案:代码任务优先使用 Q5 或 Q6 量化(多占 20-30% 显存,但质量明显提升)。如果显存不够,用 Q4 但增加 Lint 检查作为"质量守门员"——量化生成的语法错误能被 Lint 捕获并让 Agent 自修复。
6.3 本地模型的 Tool Use 能力有限
场景:用本地模型做 Agent,配置了文件读写和命令执行的 Tool。 问题:7B 模型经常生成格式错误的 Tool 调用(JSON 格式不对、参数缺失)。32B 好一些但仍有 10% 的错误率。 解决方案:对本地模型的 Tool 调用增加"格式修复层"——用正则表达式尝试修复常见的 JSON 格式错误。如果修复不了,重试一次。同时建议在 Prompt 中给出 Tool 调用的完整示例。
七、参数说明表
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
model_name |
string | 必填 | Ollama 模型名 |
quantization |
string | "Q4_K_M" |
量化级别 |
num_ctx |
int | 8192 |
上下文窗口大小 |
num_gpu |
int | -1 |
GPU 层数(-1 = 全部) |
temperature |
float | 0.2 |
采样温度 |
provider |
string | "ollama" |
调用方式 |
warmup |
bool | true |
是否预热模型 |
tool_use |
bool | false |
是否启用 Tool Use |
lint_check |
bool | true |
生成代码后是否 Lint 检查 |
fallback_model |
string | "sonnet" |
失败时的 fallback 模型 |
八、落地检查清单
- 硬件配置能运行目标模型(显存 ≥ 模型大小 × 0.7)
- 模型加载时间可接受(常驻显存 < 冷启动 30 秒)
- 量化级别选择合理(代码任务建议 Q5+)
- 有效上下文窗口已实测(不信任标称值)
- Tool Use 有格式修复层
- 生成代码经过 Lint 检查
- 隐私敏感代码的路由规则已配置
- Fallback 策略已测试(本地失败 → 云端接管)
- 速度与云端模型做过对比
- 成本计算包含了硬件折旧和电费
九、系列导航
上一篇:Lab 007:Claude / GPT / DeepSeek / 本地模型编码任务横评 下一篇:Lab 009:Agent 自动重试几次最合适?成功率与成本曲线