Ollama Lifecycle Manager

Workflows

Ollama local model lifecycle management — pull, benchmark, alias, cleanup, and fallback strategies.

Install

openclaw skills install ollama-lifecycle

Ollama 模型生命周期管理技能(安全增强版)

语言:中文(简体) | English version: SKILL.en.md

用途

本 skill 是 Ollama 本地模型生命周期管理的操作指南与检查清单,用于帮助用户安全地完成:

  • 拉取新模型
  • 记录模型台账
  • 进行可复盘 Benchmark
  • 创建模型别名
  • 创建 no-think / low-think 使用方式
  • 扫描脚本中的模型引用
  • 清理旧模型
  • 处理国内镜像回退和常见故障

触发词:Ollama、拉模型、下载模型、测速、Benchmark、模型对比、模型别名、清理模型、ModelScope、GGUF、no-think、think false、模型台账、模型生命周期。


0. 安全边界

本 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
  • 覆盖已有 Modelfile
  • 修改 ~/.zshrc~/.bashrc~/.profile
  • 修改系统级环境变量
  • 改动 OLLAMA_CONTEXT_LENGTHOLLAMA_NUM_PARALLELOLLAMA_MAX_LOADED_MODELS
  • 批量下载多个大模型

删除模型前必须输出确认信息

删除任何模型前,必须先输出:

  1. 当前 ollama list 摘要
  2. 待删除模型名称
  3. 模型用途判断
  4. 是否发现脚本引用
  5. 是否存在替代模型
  6. 删除后能否重新拉取
  7. 用户确认语句

推荐确认语句:

请确认是否删除模型:<model_name>。删除后如需恢复,需要重新下载或重新 create。

1. 适用场景与不适用场景

适用场景

  • 本地模型越来越多,需要建立台账
  • 想比较多个模型在同一设备上的速度和质量
  • 想创建简短别名,方便命令行调用
  • 想判断某个模型是否可以安全删除
  • 想处理 Ollama 官方 registry 下载慢、卡住、失败
  • 想为不同工作流选择不同模型
  • 想规范 no-think / think false 使用方式

不适用场景

  • 自动替用户决定删除哪些模型
  • 自动替用户选择"最强模型"
  • 自动修改生产脚本中的模型名称
  • 自动处理涉及隐私材料的 Benchmark 输入
  • 代替模型质量评估或专业任务评审

2. 环境检查

在做任何模型管理前,先检查环境。

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 服务后再测试。


3. 模型台账

生命周期管理的核心不是"模型多就删",而是知道每个模型为什么存在。

建议维护一个 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 | 速度慢 |

状态分层

建议把模型分为五类:

  1. 核心模型:默认工作流正在使用,不能删除。
  2. 任务模型:embedding、vision、coding、long-context 等特殊用途模型。
  3. 备用模型:核心模型失效或质量不足时备用。
  4. 测试模型:新模型观察期,建议 7—30 天后复盘。
  5. 废弃模型:无明确用途、无脚本引用、已有替代,可考虑删除。

4. 脚本引用扫描

清理模型前,先扫描当前项目是否有脚本引用模型名称。

在项目根目录执行:

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 | 深度问答 | 是 |

删除模型前必须回答:

  1. 是否被脚本硬编码引用?
  2. 是否是 alias 的源模型?
  3. 是否用于 embedding / RAG / 视觉 / 代码 / 长上下文?
  4. 是否已有质量和速度都更好的替代模型?
  5. 删除后是否容易恢复?

5. 拉取新模型流程

5.1 官方 registry 优先

ollama pull <model_name>:<tag>

拉取前先确认:

  • 模型来源
  • 模型尺寸
  • 量化等级
  • 预计磁盘占用
  • 本机内存是否足够
  • 是否已有同类模型
  • 是否有明确测试任务

5.2 下载失败后的回退流程

如果官方 registry 卡住或超时:

  1. 先等待一段合理时间,确认不是短暂网络波动。
  2. 终止卡住的下载。
  3. 到 ModelScope 或 Hugging Face 查找对应模型。
  4. 核对发布者、文件名、量化格式、更新时间、license。
  5. 使用完整路径重新拉取或手动导入。

ModelScope 示例:

ollama pull modelscope.cn/<org>/<model_name>:<tag>

5.3 ModelScope 风险提示

使用镜像源时必须注意:

  • 路径和 tag 以模型页面为准。
  • 同名模型可能不是官方发布者上传。
  • template、chat format、license、量化格式可能与官方版本不同。
  • 拉取后必须用固定测试集验证输出格式、速度和质量。
  • 工作流模型不要只因下载成功就直接替换生产模型。

6. Benchmark 标准流程

不要只用 ollama run + subprocess 统计总耗时。总耗时会混入模型加载、命令行包装和输出渲染,不适合严肃对比。

优先调用 Ollama API,读取:

  • total_duration
  • load_duration
  • prompt_eval_count
  • prompt_eval_duration
  • eval_count
  • eval_duration

核心速度指标:

tokens_per_second = eval_count / (eval_duration / 1e9)

6.1 Benchmark 场景

建议至少分四类测试:

  1. 短问答:100—300 字输出,测试日常响应。
  2. 长文写作:800—1500 字输出,测试持续生成。
  3. 长文档摘要:输入 5000—15000 字,测试上下文处理。
  4. 结构化输出:要求 JSON 或固定 Markdown,测试工作流稳定性。

6.2 冷启动与热启动

  • 冷启动:包含模型加载时间,用于判断首次响应体验。
  • 热启动:先预热一次,再测试,用于判断真实连续使用速度。

6.3 API Benchmark 脚本

保存为 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

6.4 质量评估必须用真实任务

速度测试不能代替质量测试。模型用于生产工作流前,必须用真实材料或脱敏材料测试:

  • 是否漏事实
  • 是否编造
  • 是否能按固定格式输出
  • 是否能处理长文本
  • 是否容易过度推断
  • 是否会输出思考过程
  • 是否符合任务角色定位

7. 创建模型别名

7.1 Ollama 模型别名

ollama cp <source_model> <alias_name>

示例:

ollama cp qwen3.6:35b-a3b-q4_k_m qq36

注意:

  • ollama cp 创建的别名通常共享底层模型存储。
  • 删除 alias 不等于删除源模型。
  • 删除源模型前要确认 alias 是否仍可用。
  • alias 名称应短、稳定、能反映模型家族或任务用途。

7.2 Shell 命令别名

只建议输出命令,不自动写入 shell 配置。

alias qq36='ollama run qq36'
alias g26='ollama run gemma4:26b'

如需写入:

echo "alias qq36='ollama run qq36'" >> ~/.zshrc
source ~/.zshrc

写入前必须提醒用户:这会修改 shell 配置文件。


8. no-think / thinking 控制规范

8.1 关键原则

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 支持情况为准。

8.2 Modelfile 方式只是弱约束

对不支持 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


9. 清理旧模型

9.1 查看模型与占用

ollama list
du -sh ~/.ollama/models/

9.2 清理判断标准

不要机械执行"只保留 3—5 个模型"。更合理的判断是:

  • 无明确用途
  • 无脚本引用
  • 非 embedding / vision / coding / RAG 等特殊任务模型
  • 最近 30 天未使用或已确认不再使用
  • benchmark 明显落后
  • 已有同类替代模型
  • 删除后可重新下载或重建

9.3 删除前检查模板

## 删除模型前检查

- 待删除模型:
- 当前用途:
- 是否在台账中:是 / 否
- 是否发现脚本引用:是 / 否
- 是否是 alias:是 / 否
- 是否有替代模型:
- 删除风险:低 / 中 / 高
- 恢复方式:重新 pull / 重新 create / 无法恢复
- 建议:删除 / 暂缓 / 保留

删除命令:

ollama rm <model_name>

删除后确认:

ollama list
du -sh ~/.ollama/models/

10. 量化级别选择指南

量化体积质量速度/内存适用场景
Q3_K_M一般压力小内存紧张、粗略任务
Q4_K_M良好平衡日常首选
Q5_K_M较大较好压力略高对质量更敏感
Q8_0接近原始压力大质量优先且内存充足

选择原则:

  • 普通聊天、摘要、轻量工作流:优先 Q4_K_M。
  • 高质量长文、复杂分析:可测试 Q5_K_M 或 Q8_0。
  • 小内存设备:先试 Q3_K_M 或更小模型。
  • 不同量化版本必须用同一测试集比较,不要凭感觉判断。

11. 常见故障

11.1 Ollama 版本过旧导致模型加载失败

症状:

unable to load model

可能原因:

  • Ollama 版本不支持新版 GGUF
  • CLI 和 server 版本不一致
  • server 未重启

处理:

ollama --version
curl http://localhost:11434/api/version

然后根据安装方式升级或重启 Ollama。

11.2 模型下载卡住

处理顺序:

  1. 确认网络是否正常。
  2. 重新执行 ollama pull,Ollama 通常可断点续传。
  3. 官方源长期卡住时,考虑 ModelScope 或 Hugging Face。
  4. 换源后必须重新验证模型质量和格式。

11.3 模型加载慢或内存不足

检查:

ollama list
du -sh ~/.ollama/models/

建议:

  • 降低模型尺寸或量化等级。
  • 减少并发。
  • 避免同时驻留多个大模型。
  • 不要盲目提高 OLLAMA_CONTEXT_LENGTH
  • 长上下文只在任务确实需要时开启。

11.4 输出格式不稳定

可能原因:

  • 模型不适合结构化输出
  • temperature 过高
  • prompt 太松
  • 上下文过长导致指令稀释

处理:

  • 降低 temperature。
  • 增加固定模板。
  • 用短样本测试格式遵循能力。
  • 必要时更换模型。

12. 推荐工作流

新模型进入流程

发现模型 → 检查来源 → 判断用途 → 拉取/导入 → 环境记录 → Benchmark → 真实任务测试 → 写入台账 → 决定是否绑定脚本

模型替换流程

候选模型测试 → 与现有模型对比 → 检查输出质量 → 小范围替换 → 保留旧模型一段观察期 → 稳定后更新台账 → 再决定是否删除旧模型

模型清理流程

ollama list → 台账核对 → 脚本引用扫描 → 判断替代关系 → 输出删除建议 → 用户确认 → 删除 → 复查空间 → 更新台账

13. 最小可复制命令清单

# 环境
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
}'

14. 输出要求

当用户请求"帮我管理 Ollama 模型"时,应优先输出:

  1. 当前判断
  2. 安全风险
  3. 建议执行的只读检查
  4. 是否需要用户确认
  5. 下一步命令

当用户请求"清理模型"时,应输出:

  1. 模型分层
  2. 不可删模型
  3. 可观察模型
  4. 可删除候选
  5. 删除前引用扫描命令
  6. 删除确认提示

当用户请求"测试模型"时,应输出:

  1. 测试目标
  2. 测试场景
  3. Benchmark 命令
  4. 质量评估维度
  5. 是否建议进入生产工作流