Install
openclaw skills install modelpilotYour copilot for local LLM management — safely pull, benchmark, alias, and clean up models with confidence.
openclaw skills install modelpilot语言:中文(简体) | English version:
SKILL.en.md
本 skill 是 Ollama 本地模型生命周期管理的操作指南与检查清单,用于帮助用户安全地完成:
触发词:Ollama、拉模型、下载模型、测速、Benchmark、模型对比、模型别名、清理模型、ModelScope、GGUF、no-think、think false、模型台账、模型生命周期。
本 skill 默认遵循"只读优先、确认后修改、破坏性操作单独确认"的原则。
可以直接执行或建议执行:
ollama list
ollama --version
curl http://localhost:11434/api/version
curl http://localhost:11434/api/tags
pwd
ls
rg "ollama run|MODEL_NAME|model_name|\"model\"|ollama\.chat|ollama\.generate" .
du -sh ~/.ollama/models/
以下操作涉及下载、复制、创建、删除或修改配置,必须先说明影响,再等待用户确认:
ollama pull <model>
ollama cp <source_model> <alias>
ollama create <new_model> -f <Modelfile>
ollama rm <model>
brew upgrade ollama
除非用户明确要求,不要自动执行:
ollama rm~/.zshrc、~/.bashrc、~/.profileOLLAMA_CONTEXT_LENGTH、OLLAMA_NUM_PARALLEL、OLLAMA_MAX_LOADED_MODELS删除任何模型前,必须先输出:
ollama list 摘要推荐确认语句:
请确认是否删除模型:<model_name>。删除后如需恢复,需要重新下载或重新 create。
在做任何模型管理前,先检查环境。
ollama --version
curl http://localhost:11434/api/version
ollama list
du -sh ~/.ollama/models/
建议记录:
## Ollama 环境记录
- 日期:YYYY-MM-DD
- 操作系统:
- 芯片/CPU/GPU:
- 内存:
- Ollama CLI 版本:
- Ollama Server 版本:
- 模型目录占用:
- 当前主要用途:聊天 / RAG / 长文分析 / 代码 / 视觉 / 其他
如果 CLI 和 server 版本不一致,优先重启 Ollama 服务后再测试。
生命周期管理的核心不是"模型多就删",而是知道每个模型为什么存在。
建议维护一个 Ollama模型台账.md。
# Ollama 模型台账
| 模型名 | 类型 | 当前用途 | 绑定脚本/应用 | 状态 | 是否可删 | 替代模型 | 最近测试日期 | 备注 |
|---|---|---|---|---|---|---|---|---|
| gemma4:26b | 通用文本 | 长文分析 | batch_xxx.py | 核心 | 否 | - | 2026-xx-xx | 稳定 |
| qwen3-vl | 视觉模型 | 图片理解 | photo_app | 核心 | 否 | - | 2026-xx-xx | 保留 |
| gpt-oss:20b | 通用文本 | 测试 | 无 | 观察 | 可考虑 | xxx | 2026-xx-xx | 速度慢 |
建议把模型分为五类:
清理模型前,先扫描当前项目是否有脚本引用模型名称。
在项目根目录执行:
rg "ollama run|MODEL_NAME|model_name|\"model\"|ollama\.chat|ollama\.generate" .
如果没有 rg,可用:
grep -R "ollama run\|MODEL_NAME\|model_name\|\"model\"" . 2>/dev/null
输出后整理成:
## 模型引用扫描结果
| 模型名 | 文件 | 行号/位置 | 用途 | 是否影响删除 |
|---|---|---|---|---|
| gemma-doc-nothink | batch_qwen_cards.py | MODEL_NAME | 资料抽取 | 是 |
| mistral-qa | qa_ask.py | model_name | 深度问答 | 是 |
删除模型前必须回答:
ollama pull <model_name>:<tag>
拉取前先确认:
如果官方 registry 卡住或超时:
ModelScope 示例:
ollama pull modelscope.cn/<org>/<model_name>:<tag>
使用镜像源时必须注意:
不要只用 ollama run + subprocess 统计总耗时。总耗时会混入模型加载、命令行包装和输出渲染,不适合严肃对比。
优先调用 Ollama API,读取:
total_durationload_durationprompt_eval_countprompt_eval_durationeval_counteval_duration核心速度指标:
tokens_per_second = eval_count / (eval_duration / 1e9)
建议至少分四类测试:
保存为 ollama_benchmark.py:
#!/usr/bin/env python3
import argparse
import json
import statistics
import time
import urllib.request
from typing import Any, Dict, List
OLLAMA_URL = "http://localhost:11434/api/generate"
def call_ollama(model: str, prompt: str, think: str | None = None, timeout: int = 600) -> Dict[str, Any]:
payload: Dict[str, Any] = {
"model": model,
"prompt": prompt,
"stream": False,
}
if think is not None:
if think.lower() == "false":
payload["think"] = False
elif think.lower() == "true":
payload["think"] = True
else:
payload["think"] = think
req = urllib.request.Request(
OLLAMA_URL,
data=json.dumps(payload).encode("utf-8"),
headers={"Content-Type": "application/json"},
method="POST",
)
start = time.time()
with urllib.request.urlopen(req, timeout=timeout) as resp:
data = json.loads(resp.read().decode("utf-8"))
wall_sec = time.time() - start
eval_count = data.get("eval_count") or 0
eval_duration = data.get("eval_duration") or 0
prompt_eval_count = data.get("prompt_eval_count") or 0
prompt_eval_duration = data.get("prompt_eval_duration") or 0
load_duration = data.get("load_duration") or 0
total_duration = data.get("total_duration") or 0
response = data.get("response", "")
tps = None
if eval_count and eval_duration:
tps = eval_count / (eval_duration / 1e9)
prompt_tps = None
if prompt_eval_count and prompt_eval_duration:
prompt_tps = prompt_eval_count / (prompt_eval_duration / 1e9)
return {
"model": model,
"wall_sec": round(wall_sec, 3),
"total_sec_api": round(total_duration / 1e9, 3) if total_duration else None,
"load_sec": round(load_duration / 1e9, 3) if load_duration else None,
"prompt_eval_count": prompt_eval_count,
"prompt_eval_sec": round(prompt_eval_duration / 1e9, 3) if prompt_eval_duration else None,
"prompt_tokens_per_sec": round(prompt_tps, 2) if prompt_tps else None,
"eval_count": eval_count,
"eval_sec": round(eval_duration / 1e9, 3) if eval_duration else None,
"tokens_per_sec": round(tps, 2) if tps else None,
"response_chars": len(response),
"preview": response[:160].replace("\n", " ") + ("..." if len(response) > 160 else ""),
}
def run_benchmark(models: List[str], prompt: str, rounds: int, warmup: bool, think: str | None) -> None:
if warmup:
for model in models:
try:
call_ollama(model, "请用一句话回答:测试。", think=think)
except Exception as e:
print(f"[WARMUP FAIL] {model}: {e}")
for model in models:
results = []
for i in range(rounds):
try:
result = call_ollama(model, prompt, think=think)
results.append(result)
print(json.dumps(result, ensure_ascii=False))
except Exception as e:
print(json.dumps({"model": model, "round": i + 1, "error": str(e)}, ensure_ascii=False))
speeds = [r["tokens_per_sec"] for r in results if r.get("tokens_per_sec") is not None]
if speeds:
summary = {
"model": model,
"rounds": len(speeds),
"tokens_per_sec_avg": round(statistics.mean(speeds), 2),
"tokens_per_sec_min": round(min(speeds), 2),
"tokens_per_sec_max": round(max(speeds), 2),
}
print("[SUMMARY] " + json.dumps(summary, ensure_ascii=False))
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Ollama API benchmark")
parser.add_argument("models", nargs="+", help="Models to benchmark")
parser.add_argument("--prompt", default="请写一段约500字的中文说明,介绍本地大模型的实际用途。")
parser.add_argument("--rounds", type=int, default=1)
parser.add_argument("--warmup", action="store_true")
parser.add_argument("--think", default=None, help="true / false / low / medium / high, if supported by model and Ollama")
args = parser.parse_args()
run_benchmark(args.models, args.prompt, args.rounds, args.warmup, args.think)
使用示例:
python3 ollama_benchmark.py gemma4:26b qq36 --rounds 2 --warmup
python3 ollama_benchmark.py qq36-nothink qq36 --think false --rounds 2 --warmup
速度测试不能代替质量测试。模型用于生产工作流前,必须用真实材料或脱敏材料测试:
ollama cp <source_model> <alias_name>
示例:
ollama cp qwen3.6:35b-a3b-q4_k_m qq36
注意:
ollama cp 创建的别名通常共享底层模型存储。只建议输出命令,不自动写入 shell 配置。
alias qq36='ollama run qq36'
alias g26='ollama run gemma4:26b'
如需写入:
echo "alias qq36='ollama run qq36'" >> ~/.zshrc
source ~/.zshrc
写入前必须提醒用户:这会修改 shell 配置文件。
SYSTEM 提示词只能要求模型"不输出思考过程",不等于底层关闭 thinking。
如果 Ollama 和模型支持 think 参数,应优先用 API 显式设置:
curl http://localhost:11434/api/generate -d '{
"model": "<model>",
"prompt": "请总结这段材料。",
"think": false,
"stream": false
}'
如果模型支持 thinking levels,也可以测试:
"think": "low"
或:
"think": "medium"
具体是否生效,必须以模型实际输出和 Ollama API 支持情况为准。
对不支持 think 参数的模型,可用 Modelfile 提示减少显式思考,但不能保证真正关闭 thinking。
FROM <model_name>:<tag>
SYSTEM "直接输出最终答案。不要输出思考过程、推理草稿或隐藏分析。"
PARAMETER temperature 0.4
创建:
ollama create <model_name>-nothink -f Modelfile.<model_name>-nothink
建议文件命名:
Modelfile.<source_model>.<purpose>.nothink
不要覆盖已有 Modelfile。
ollama list
du -sh ~/.ollama/models/
不要机械执行"只保留 3—5 个模型"。更合理的判断是:
## 删除模型前检查
- 待删除模型:
- 当前用途:
- 是否在台账中:是 / 否
- 是否发现脚本引用:是 / 否
- 是否是 alias:是 / 否
- 是否有替代模型:
- 删除风险:低 / 中 / 高
- 恢复方式:重新 pull / 重新 create / 无法恢复
- 建议:删除 / 暂缓 / 保留
删除命令:
ollama rm <model_name>
删除后确认:
ollama list
du -sh ~/.ollama/models/
| 量化 | 体积 | 质量 | 速度/内存 | 适用场景 |
|---|---|---|---|---|
| Q3_K_M | 小 | 一般 | 压力小 | 内存紧张、粗略任务 |
| Q4_K_M | 中 | 良好 | 平衡 | 日常首选 |
| Q5_K_M | 较大 | 较好 | 压力略高 | 对质量更敏感 |
| Q8_0 | 大 | 接近原始 | 压力大 | 质量优先且内存充足 |
选择原则:
症状:
unable to load model
可能原因:
处理:
ollama --version
curl http://localhost:11434/api/version
然后根据安装方式升级或重启 Ollama。
处理顺序:
ollama pull,Ollama 通常可断点续传。检查:
ollama list
du -sh ~/.ollama/models/
建议:
OLLAMA_CONTEXT_LENGTH。可能原因:
处理:
发现模型 → 检查来源 → 判断用途 → 拉取/导入 → 环境记录 → Benchmark → 真实任务测试 → 写入台账 → 决定是否绑定脚本
候选模型测试 → 与现有模型对比 → 检查输出质量 → 小范围替换 → 保留旧模型一段观察期 → 稳定后更新台账 → 再决定是否删除旧模型
ollama list → 台账核对 → 脚本引用扫描 → 判断替代关系 → 输出删除建议 → 用户确认 → 删除 → 复查空间 → 更新台账
# 环境
ollama --version
curl http://localhost:11434/api/version
ollama list
du -sh ~/.ollama/models/
# 拉模型
ollama pull <model_name>:<tag>
# ModelScope 回退
ollama pull modelscope.cn/<org>/<model_name>:<tag>
# 创建 Ollama alias
ollama cp <source_model> <alias_name>
# 扫描脚本引用
rg "ollama run|MODEL_NAME|model_name|\"model\"|ollama\.chat|ollama\.generate" .
# 删除模型,必须确认后执行
ollama rm <model_name>
# API no-think 测试
curl http://localhost:11434/api/generate -d '{
"model": "<model>",
"prompt": "请用一句话回答:测试。",
"think": false,
"stream": false
}'
当用户请求"帮我管理 Ollama 模型"时,应优先输出:
当用户请求"清理模型"时,应输出:
当用户请求"测试模型"时,应输出: