# 本地大模型落地实战教程：从 0 搭一个私有 AI 工作台

> 来源文章：KDnuggets《5 Cool Things I Did with Local Language Models》  
> 原文链接：https://www.kdnuggets.com/5-cool-things-i-did-with-local-language-models  
> 本文定位：基于原文 5 个案例，重写成可照做的落地教程。重点不是“本地模型很好”，而是给出具体场景、目录、命令、Prompt、验收标准和失败处理。

## 0. 你最终会得到什么

完成本文后，你会得到一个本地 AI 工作台，包含 4 个可用场景：

1. **私有文档问答库**：把合同、PDF、项目笔记放进本地 RAG，问问题时引用来源。
2. **本地代码审查助手**：用 Qwen2.5-Coder 审查敏感代码，不上传到云端。
3. **固定风格个人助手**：用 Modelfile 固化你的输出偏好和工作背景。
4. **最小只读 Agent**：读取本地日志或文本，生成报告，默认不改原文件、不碰生产系统。

建议按顺序做，不要一上来做 Agent。

```text
Ollama 跑通
  ↓
文档问答库
  ↓
代码审查助手
  ↓
个人助手 Modelfile
  ↓
只读 Agent 原型
```

## 1. 前置准备

### 1.1 推荐机器配置

最低可试：

- 内存：8GB
- 模型：`llama3.2:3b`
- 适合：短文本、简单问答、流程验证

更舒服：

- 内存：16GB 或以上
- 模型：`mistral:7b`、`qwen2.5-coder:7b`
- 适合：文档综合、代码审查、较长上下文

### 1.2 安装 Ollama

去官网下载并安装：

```text
https://ollama.com
```

验证：

```bash
ollama --version
```

启动服务：

```bash
ollama serve
```

如果提示端口已占用，通常说明 Ollama 已经在后台运行。

### 1.3 拉取基础模型

```bash
ollama pull llama3.2:3b
ollama pull mistral:7b
ollama pull qwen2.5-coder:7b
```

验证模型可用：

```bash
ollama run llama3.2:3b
```

输入：

```text
请用一句话解释什么是本地大模型。
```

验收：能正常返回中文回答即可。

## 2. 案例一：搭一个私有文档问答库

### 2.1 目标

把本地文档放进一个私有知识库，能回答：

- 某份合同里有没有数据保留条款？
- 两份制度哪里冲突？
- 某几篇论文对同一个问题的观点是否一致？
- 项目历史记录里某个决策为什么做？

关键要求：**文档不上传云端，回答必须引用来源。**

### 2.2 建一个测试资料目录

先不要导入所有真实文档。先建一个小样本，方便验证系统是否靠谱。

```bash
mkdir -p ~/local-ai-workbench/docs-sample
cd ~/local-ai-workbench/docs-sample
```

创建两份示例制度：

```bash
cat > policy-2023.md <<'EOF'
# 客户数据保留政策 2023

客户订单数据保留 3 年。
客户聊天记录保留 180 天。
超过保留周期后，应在 30 天内删除或匿名化。
EOF

cat > policy-2025.md <<'EOF'
# 客户数据保留政策 2025

客户订单数据保留 5 年。
客户聊天记录保留 90 天。
高风险客户数据需要单独加密存储。
超过保留周期后，应在 15 天内删除或匿名化。
EOF
```

这两份文件故意设计了冲突点：订单数据从 3 年变 5 年，聊天记录从 180 天变 90 天，删除窗口从 30 天变 15 天。

### 2.3 启动 AnythingLLM

```bash
docker run -d \
  --name anythingllm \
  -p 3001:3001 \
  -v anythingllm_storage:/app/server/storage \
  mintplexlabs/anythingllm
```

打开：

```text
http://localhost:3001
```

在 AnythingLLM 中：

1. 新建 Workspace：`private-docs-test`
2. LLM Provider 选择 Ollama
3. Ollama 地址填：`http://localhost:11434`
4. 模型选择：`llama3.2:3b` 或 `mistral:7b`
5. 上传 `policy-2023.md` 和 `policy-2025.md`

### 2.4 用具体问题验收，不要泛泛聊天

不要问：

```text
帮我总结这些文档。
```

要问这种能验证检索质量的问题：

```text
请对比 policy-2023.md 和 policy-2025.md 的客户数据保留政策。
必须输出：
1. 两份文件一致的地方
2. 两份文件冲突的地方
3. 每个结论引用来源文件名
4. 如果文档没有提到，不要猜
```

理想回答应包含类似内容：

```text
冲突点：
- 订单数据保留周期：2023 文件为 3 年，2025 文件为 5 年。
- 聊天记录保留周期：2023 文件为 180 天，2025 文件为 90 天。
- 删除/匿名化窗口：2023 文件为 30 天内，2025 文件为 15 天内。

新增要求：
- 2025 文件新增“高风险客户数据需要单独加密存储”。
```

### 2.5 判断是否可以导入真实文档

通过这 5 条再导入真实资料：

- [ ] 回答能引用具体来源文件
- [ ] 能识别两份文件冲突
- [ ] 不会把 2025 的新要求说成 2023 也有
- [ ] 不知道时会明确说不知道
- [ ] 回答速度可以接受

如果做不到，先换 `mistral:7b`，再检查文档切块和 embedding 配置，不要急着导入几百份文档。

## 3. 案例二：本地代码审查助手

### 3.1 目标

用本地模型审查公司代码或个人项目代码，避免把代码粘到云端 AI。

适合审查：

- SQL 拼接
- 鉴权判断
- 文件上传
- 日志脱敏
- 异常处理
- 边界条件

不适合第一轮审查：

- 整个仓库
- 自动大规模重构
- 生产事故根因分析
- 需要运行完整业务环境的复杂链路

### 3.2 准备一个故意有问题的函数

```bash
mkdir -p ~/local-ai-workbench/code-review-demo
cd ~/local-ai-workbench/code-review-demo

cat > user_api.py <<'EOF'
def get_user_data(user_id):
    query = f"SELECT * FROM users WHERE id = {user_id}"
    result = db.execute(query)
    return result.fetchone()
EOF
```

这个函数有 3 个典型问题：

1. SQL 注入风险
2. `SELECT *` 可能暴露多余字段
3. 用户不存在时返回 `None`，调用方可能在更远处报错

### 3.3 用 Qwen2.5-Coder 审查

启动模型：

```bash
ollama run qwen2.5-coder:7b
```

输入下面这个审查 Prompt：

```text
你是一名资深软件工程师，正在做代码审查。
你的任务是找问题，不要鼓励我。

审查重点：
1. 安全漏洞：SQL 注入、鉴权、数据泄露
2. 边界条件：空值、异常、不存在的数据
3. 复杂度：是否有不必要的写法
4. 真实环境会失败的假设

输出格式：
- 问题：
- 风险：
- 为什么是问题：
- 建议修改：

不要复述代码功能，直接输出发现的问题。

代码如下：

def get_user_data(user_id):
    query = f"SELECT * FROM users WHERE id = {user_id}"
    result = db.execute(query)
    return result.fetchone()
```

### 3.4 你应该期待什么结果

合格的模型输出应该指出：

```text
问题 1：SQL 注入
风险：user_id 直接拼进 SQL，攻击者可构造输入改变查询语义。
建议：使用参数化查询。

问题 2：SELECT * 数据暴露
风险：返回不需要的敏感字段，例如 password_hash、token、internal_note。
建议：只选择必要字段。

问题 3：空结果未处理
风险：用户不存在时返回 None，调用方可能出现 NoneType 错误。
建议：显式处理未找到场景，返回错误或抛出业务异常。
```

### 3.5 给它一个修复目标

继续输入：

```text
请基于上面的审查结果，给出一个更安全的 Python 版本。
约束：
1. 使用参数化查询
2. 不要 SELECT *
3. 用户不存在时显式返回 None，并在注释里提醒调用方处理
4. 不要引入新依赖
```

参考修复：

```python
def get_user_data(db, user_id: int):
    query = """
    SELECT id, name, email
    FROM users
    WHERE id = ?
    """
    result = db.execute(query, (user_id,))
    row = result.fetchone()
    if row is None:
        return None
    return row
```

注意：不同数据库驱动的占位符不一样。SQLite 常用 `?`，PostgreSQL 常见 `%s` 或 `$1`，SQLAlchemy 又是另一套写法。模型给的修复必须按你的实际技术栈二次确认。

### 3.6 接入 IDE 的最小配置

如果使用 Continue，配置本地模型：

```json
{
  "models": [
    {
      "title": "Qwen2.5-Coder Local",
      "provider": "ollama",
      "model": "qwen2.5-coder:7b",
      "apiBase": "http://localhost:11434"
    }
  ]
}
```

第一周只让它审查单文件或选中代码块，不要让它自动改整个项目。

### 3.7 代码审查验收标准

- [ ] 至少能发现一个真实风险
- [ ] 能说明为什么是风险
- [ ] 建议能按你的技术栈落地
- [ ] 不会虚构不存在的框架或文件
- [ ] 不要求你上传代码到外部服务

## 4. 案例三：离线个人助手

### 4.1 目标

提前把模型下载到本地，在断网场景下处理写作、计划、复盘、草稿等任务。

### 4.2 出差/飞行前准备

```bash
ollama pull mistral:7b
ollama list
```

确认列表里有 `mistral:7b`。

断网测试：

1. 关闭 Wi-Fi
2. 运行：

```bash
ollama run mistral:7b
```

3. 输入：

```text
我现在离线。请只基于我提供的信息回答。
我要写一封邮件，目标是把项目延期 3 天的原因说清楚，但不要甩锅。背景如下：
- 接口联调比预期多花 2 天
- 测试环境昨天不可用半天
- 我们已经补了回归测试
请给我一版简洁邮件草稿。
```

### 4.3 离线助手的正确用法

适合：

- 邮件草稿
- 方案提纲
- 会议纪要整理
- 本地代码解释
- 对你提供的材料做归纳

不适合：

- 最新政策
- 实时新闻
- 当前市场价格
- 新版本依赖信息
- 任何需要联网核验的事实

### 4.4 离线 Prompt 模板

```text
我现在处于离线环境。
你只能基于我提供的材料回答。
如果材料不足，请明确说“材料不足，无法判断”。
不要补充外部事实。

任务：
[写清楚你要它做什么]

材料：
[粘贴本地材料]

输出格式：
1. 结论
2. 草稿/步骤
3. 需要联网后再核验的点
```

### 4.5 验收标准

- [ ] 断网后仍能启动模型
- [ ] 能基于材料生成可编辑草稿
- [ ] 会标注需要联网核验的点
- [ ] 不会把猜测包装成事实

## 5. 案例四：用 Modelfile 固化你的工作偏好

### 5.1 目标

把每次都要重复说的背景写进本地模型：语言、风格、工作角色、输出格式、禁忌。

### 5.2 创建个人助手

```bash
mkdir -p ~/local-ai-workbench/my-assistant
cd ~/local-ai-workbench/my-assistant
```

写入 `Modelfile`：

```bash
cat > Modelfile <<'EOF'
FROM llama3.2:3b

SYSTEM """
你是我的本地工作助手。

关于我：
- 我主要做工程实践、自动化脚本、技术文章整理。
- 我偏好中文回答。
- 我不喜欢空泛建议。

工作方式：
- 先给结论，再给步骤。
- 如果请求含糊，先改写成更清楚的问题，再回答。
- 优先给最简单够用的方案，不要过度工程化。
- 不确定就说不确定，不要编造。

输出格式：
1. 结论
2. 具体步骤
3. 验证方式
4. 风险或限制
"""

PARAMETER temperature 0.4
PARAMETER num_ctx 4096
EOF
```

创建模型：

```bash
ollama create my-work-assistant -f Modelfile
ollama run my-work-assistant
```

### 5.3 对比测试

输入：

```text
我想把一篇技术文章转成内部分享稿，请给我一个 30 分钟内能完成的流程。
```

合格输出应该类似：

```text
结论：30 分钟内不要追求完整复刻原文，应提炼成“问题-方案-演示-边界”的分享结构。

具体步骤：
1. 5 分钟：提取文章一句话结论和 3 个关键案例。
2. 10 分钟：改成内部听众关心的落地场景。
3. 10 分钟：补一个可运行 Demo 或截图。
4. 5 分钟：写风险边界和下一步试点。

验证方式：让一个同事只看标题和步骤，判断是否知道怎么试。
```

如果模型仍然输出很多泛泛建议，就回到 `Modelfile` 里继续收紧要求。

## 6. 案例五：做一个只读本地 Agent

### 6.1 目标

让模型读取本地文件，生成报告。第一版不联网、不删除文件、不覆盖原始数据。

这个案例比原文的“搜索 + 写文件 Agent”更保守，适合作为第一版落地。

### 6.2 准备目录和样本日志

```bash
mkdir -p ~/local-ai-workbench/read-only-agent/{input,output}
cd ~/local-ai-workbench/read-only-agent

cat > input/app.log <<'EOF'
2026-05-19 09:00:01 INFO service started
2026-05-19 09:02:11 WARN retry payment callback order_id=1001
2026-05-19 09:03:42 ERROR database timeout query=get_user order_id=1002
2026-05-19 09:05:10 INFO payment callback success order_id=1001
2026-05-19 09:06:55 ERROR failed to send webhook order_id=1003
EOF
```

### 6.3 写一个只读分析脚本

这个脚本使用 Ollama 原生 HTTP API，只依赖 Python 标准库。

```bash
cat > local_log_agent.py <<'EOF'
import json
from pathlib import Path
from urllib.request import Request, urlopen

ROOT = Path(__file__).parent.resolve()
INPUT = ROOT / "input" / "app.log"
OUTPUT_DIR = ROOT / "output"
OUTPUT = OUTPUT_DIR / "log_report.md"
MODEL = "llama3.2:3b"

SYSTEM_PROMPT = """
你是一个只读日志分析助手。
约束：
1. 只能基于用户提供的日志内容分析。
2. 不要编造日志里没有的信息。
3. 输出中文 Markdown。
4. 必须包含：错误摘要、告警摘要、可能影响、建议排查顺序。
"""


def call_ollama(prompt: str) -> str:
    payload = {
        "model": MODEL,
        "messages": [
            {"role": "system", "content": SYSTEM_PROMPT},
            {"role": "user", "content": prompt},
        ],
        "stream": False,
    }
    req = Request(
        "http://localhost:11434/api/chat",
        data=json.dumps(payload).encode("utf-8"),
        headers={"Content-Type": "application/json"},
        method="POST",
    )
    with urlopen(req, timeout=120) as response:
        data = json.loads(response.read().decode("utf-8"))
    return data["message"]["content"]


def main() -> None:
    if not INPUT.exists():
        raise SystemExit(f"missing input file: {INPUT}")

    log_text = INPUT.read_text(encoding="utf-8")
    prompt = f"请分析以下日志：\n\n{log_text}"
    report = call_ollama(prompt)

    OUTPUT_DIR.mkdir(parents=True, exist_ok=True)
    OUTPUT.write_text(report + "\n", encoding="utf-8")
    print(f"written: {OUTPUT}")


if __name__ == "__main__":
    main()
EOF
```

### 6.4 运行

确保 Ollama 服务在运行：

```bash
ollama serve
```

另一个终端运行：

```bash
python3 local_log_agent.py
```

查看输出：

```bash
cat output/log_report.md
```

### 6.5 你应该看到什么

合格报告应包含：

```text
错误摘要：
- database timeout 出现在 get_user 查询，关联 order_id=1002。
- failed to send webhook，关联 order_id=1003。

告警摘要：
- payment callback 对 order_id=1001 出现 retry，随后成功。

建议排查顺序：
1. 先查数据库超时是否影响 get_user 查询链路。
2. 再查 webhook 发送失败的目标服务和重试机制。
3. 最后确认 order_id=1001 是否已最终一致。
```

### 6.6 为什么这是 Agent，而不是普通总结

因为它已经具备最小闭环：

```text
读取本地输入 → 调用本地模型 → 生成本地报告 → 保留可审计文件
```

但它还不是全自动运维 Agent。它没有权限删除、重启、部署、发消息。这是有意为之。

### 6.7 第一版安全边界

必须保留：

- 输入目录：`input/`
- 输出目录：`output/`
- 不覆盖原始日志
- 不执行 shell 命令
- 不连接生产数据库
- 不自动发送外部消息

如果后续要加“搜索目录”“读取多个文件”，也只扩大读取范围，不扩大写入或执行权限。

## 7. 一周落地计划

### 第 1 天：跑通模型

任务：

```bash
ollama pull llama3.2:3b
ollama run llama3.2:3b
```

验收：模型能稳定中文回答。

### 第 2 天：文档问答小样本

任务：用 `policy-2023.md` 和 `policy-2025.md` 验证 AnythingLLM。

验收：能指出 3 个冲突点，并引用来源。

### 第 3 天：代码审查小样本

任务：审查 `get_user_data()` 示例函数，再换成你自己的一个低风险函数。

验收：能发现真实问题，建议不脱离你的技术栈。

### 第 4 天：个人助手

任务：创建 `my-work-assistant`。

验收：默认中文、直接、能先改写含糊问题。

### 第 5 天：只读 Agent

任务：跑通 `local_log_agent.py`。

验收：生成 `output/log_report.md`，且不改动 `input/app.log`。

### 第 6 天：换成真实低风险材料

任务：

- 文档问答：导入 5 份真实但低敏文档
- 代码审查：选择一个非核心模块
- 日志 Agent：换成一小段脱敏日志

验收：每个场景都能产生一个可检查的输出。

### 第 7 天：决定是否继续投入

只问 4 个问题：

1. 它是否减少了重复劳动？
2. 它是否保护了不能上传云端的数据？
3. 它是否能被验证，而不是只靠感觉？
4. 它是否没有扩大权限风险？

如果答案不明确，继续小样本，不要急着接入生产流程。

## 8. 三个可直接分享的演示脚本

### 演示 1：隐私文档不会离开本机

演示流程：

1. 展示两份本地 Markdown 政策文件。
2. 上传到 AnythingLLM。
3. 提问“找出冲突点并引用来源”。
4. 关闭网络后再次提问简单问题。
5. 强调：文档在本地，模型在本地，回答可追溯。

### 演示 2：代码审查发现 SQL 注入

演示流程：

1. 展示 `get_user_data()`。
2. 用 Qwen2.5-Coder 审查。
3. 让模型指出 SQL 注入、`SELECT *`、空结果处理。
4. 展示修复版。
5. 强调：不要让模型直接改全仓库，先审小片段。

### 演示 3：只读日志 Agent 生成报告

演示流程：

1. 展示 `input/app.log`。
2. 运行 `python3 local_log_agent.py`。
3. 展示 `output/log_report.md`。
4. 强调：第一版只读、固定输出目录、可审计。

## 9. 常见失败和处理方法

### 9.1 模型太慢

处理：

- 换小模型：`llama3.2:3b`
- 缩短输入材料
- 先做单文件/小样本
- 不要一开始就导入全部资料

### 9.2 文档问答乱引用

处理：

- 减少一次导入的文件数量
- 文件名写清楚，例如 `policy-2023.md`
- Prompt 要求“必须引用来源文件名”
- 换更强的模型，如 `mistral:7b`

### 9.3 代码审查建议不适配项目

处理：

- 在 Prompt 里写明技术栈
- 只给相关函数和上下文
- 要求“不引入新依赖”
- 要求“给出最小修改”

### 9.4 Agent 想做危险操作

处理：

- 工具层不要提供危险函数
- 程序层限制写入目录
- 所有外部动作先人工确认
- 第一版不要接生产数据库、部署系统、消息机器人

## 10. 最小落地检查表

### 环境

- [ ] `ollama --version` 正常
- [ ] `ollama run llama3.2:3b` 正常
- [ ] 至少知道本机能跑多大的模型

### 文档问答

- [ ] AnythingLLM 能连接 Ollama
- [ ] 能上传小样本文档
- [ ] 能引用来源文件
- [ ] 能指出文档冲突

### 代码审查

- [ ] `qwen2.5-coder:7b` 可运行
- [ ] 能审查单个函数
- [ ] 能发现真实风险
- [ ] 修复建议经过人工确认

### 个人助手

- [ ] Modelfile 已创建
- [ ] 自定义模型能运行
- [ ] 输出风格符合你的偏好

### 只读 Agent

- [ ] 输入和输出目录分离
- [ ] 不覆盖原文件
- [ ] 不执行危险动作
- [ ] 输出报告可复查

## 11. 分享时的主线

开场可以这样说：

> 本地大模型不是为了替代最强云模型，而是为了解决云模型天然不适合的场景：隐私、离线、低成本、高频试错和本地工具接入。

中间用 3 个案例支撑：

1. 私有文档问答：文档不动，AI 来读。
2. 本地代码审查：代码不上传，先发现低级风险。
3. 只读 Agent：先做可审计的小闭环，再谈自动化。

收尾可以这样说：

> 本地 AI 落地的关键不是模型参数，而是边界：输入是什么、允许做什么、输出在哪里、怎么验证。边界清楚，小模型也能产生实际价值；边界不清楚，大模型也会放大风险。

## 12. 本文和原文的关系

原文提供了 5 个实践灵感：私有文档脑、代码审查、离线助手、个人思考伙伴、本地 Agent。本文把它改造成可执行教程，并额外补充了样本文件、审查代码、只读 Agent 脚本、一周计划和验收清单。

原文里的能力边界仍然成立：本地 3B/7B 模型不适合替代前沿云模型做复杂推理。它更适合在边界清楚、风险可控、数据需要留在本地的场景里先落地。
