内容
<div align="center">
# 本地卸载
**将繁琐工作委托给免费的本地模型 — 节省云代币用于关键决策。**
一个优先考虑本地的卸载工具,将短上下文、低判断力的工作(如 **摘要 · 分类 · 提取 · 分类**,以及视觉、OCR、转录和图像/SVG生成)卸载到免费的 **Gemma 家族级联**,由 [llama.cpp](https://github.com/ggml-org/llama.cpp) 提供服务。它作为 Go CLI 和 **MCP 服务器**运行,供 AI 编码代理使用。它 **从不调用云模型**:当无法自信地完成任务时,它会返回一个结构化的 **延期**,让代理处理。
[](LICENSE)
[](https://pkg.go.dev/github.com/dmmdea/offload-harness)
[](../../actions)
[](https://modelcontextprotocol.io)
</div>
---
## 什么是本地卸载及其原因
当代理(或您)需要总结日志、标记票据、从文档中提取字段或回答关于文本的"是/否"问题时,这项工作是 **机械且低判断力** 的 — 但仍然会消耗上下文窗口和云代币。`local-offload` 在 **免费的本地模型** 上运行这些任务,以便大部分低价值代币不会进入昂贵的上下文中。内置的 **记账器** 会准确报告节省了多少代币。
设计规则很简单:**本地模型处理繁琐工作;您的代理保留所有判断力**。每个任务要么返回一个经过验证的、符合模式的结果,要么 **延期** — 一个结构化的 `{"deferred": true, ...}`,告诉调用者"自己处理这个任务"。卸载工具内部没有云备份,它也不持有任何云凭证。
它适用于任何运行 AI 编码代理或管道的人,他们希望在保持数据在本地的同时 **减少批量文本工作的代币消耗**。
## 功能
- **免费且完全本地** — 所有推理都在您的 GPU 上运行,通过 llama.cpp;无需 API 密钥,无需计量,任何数据都不会离开机器。
- **从不调用云,总是延期** — 低置信度返回一个结构化的延期,而不是猜测。核心卸载路径根据设计不具有云凭证。
- **自我学习的级联** — 快速任务进入一个小层级,只有在真正不确定时才会升级到更大模型(logprob 决策边缘 + 自我报告的置信度)。
- **可靠的结构化输出** — 强制执行生成的 **GBNF 语法** + Go 模式验证,解决模型的 JSON 模式崩溃问题。
- **单个静态二进制文件** — 一个 Go 可执行文件;CLI 和 MCP 服务器在同一构建中。
- **MCP 原生** — 通过 stdio 为任何 MCP 客户端(Claude Code 等)暴露 15 种工具。
- **超越文本** — 本地 **视觉**(VQA / OCR / 图像字段提取 / 渲染 QA)、**语音转文本**(whisper.cpp)、**图像/音频/视频生成**(SDXL · Chatterbox TTS · ACE-Step · Hunyuan 通过 ComfyUI)和依赖项无关的 **SVG 数据可视化工具**。
- **可选的远程升级** — 一个明确的选择性 `nim` 工具可以访问任何 OpenAI 兼容的 **NVIDIA NIM** 端点(NVIDIA 的托管 [build.nvidia.com](https://build.nvidia.com) 免费模型目录,或自托管的 NIM),适用于需要本地 GPU 无法运行的前沿模型的罕见任务。密钥仅来自环境变量;不会记账;本地级联不受影响。
- **代币记账器** — 每笔卸载调用和节省的云代币的追加式 JSONL 会计。
## 快速开始
```bash
# 1. 构建(Go 1.26+)
go build -o local-offload .
# 2. 指向本地 llama.cpp 端点(默认为 http://127.0.0.1:11436)
# ./config.json 在从当前目录运行时会自动被读取;
# 对于全局安装,请将其放在 ~/.local-offload/config.json。
cp config.example.json config.json
# 3. 运行任务 — 输入为文件路径或 "-" 表示标准输入
./local-offload summarize notes.md --max-points 5 --json
./local-offload triage log.txt --question "Does this contain an error?" --json
# 4. 查看节省的代币
./local-offload ledger
```
只需五条命令即可获得第一个输出。如果本地模型无法访问或不确定,您将获得 `{"deferred": true, "reason": "..."}` — 这是预期的,而不是失败。
## 安装
**从源代码构建**(推荐):
```bash
git clone https://github.com/dmmdea/offload-harness.git
cd local-offload
go build -o local-offload . # 或:go build -o local-offload.exe . 在 Windows 上
```
**Go 安装:**
```bash
go install github.com/dmmdea/offload-harness@latest
```
需要 **Go 1.26+** 和正在运行的 **llama.cpp 服务器**(参见 [ Serving the models ](#serving-the-models))。
## 用法(CLI)
```bash
# 文本 — 四个核心任务
local-offload summarize <文件|-> [--max-points N] [--json]
local-offload classify <文件|-> --labels bug,feature,question [--json]
local-offload extract <文件|-> --schema fields.json [--json]
local-offload triage <文件|-> --question "Is this a refund request?" [--json]
# 视觉(图像理解)
local-offload vqa image.png --question "What number is shown?" --json
local-offload ocr scan.png --json
local-offload extract-image invoice.png --schema fields.json --json
local-offload assess-image render.png --brief "a red sports car at sunset" --json
# 语音转文本(音频或视频)
local-offload transcribe clip.mp4 --language es --json
local-offload transcribe noisy.m4a --language es --hq # 高质量模型用于困难音频
# 视频理解(采样帧)
local-offload video-describe clip.mp4 --question "What happens here?" --json
# 生成(免费,本地 GPU)
local-offload generate-image "a product photo of a coffee mug on white" --negative "people, text, watermark"
local-offload generate-svg gauge '{"value":72,"max":100,"label":"Score","unit":"%"}'
# 远程升级(明确,选择性 — NVIDIA NIM;需要 NVIDIA_API_KEY 用于免费托管目录)
local-offload nim --list-models # 浏览可用的模型 ID
local-offload nim "Explain MoE routing in 3 bullets" --model nvidia/nemotron-3-ultra-550b-a55b --max-tokens 600
local-offload nim "Summarize this" --model meta/llama-3.3-70b-instruct --base http://127.0.0.1:8000/v1 # 自托管 NIM(无密钥)
# 操作和检查
local-offload mcp # 作为 MCP 服务器运行(stdio)
local-offload ledger [--since DAYS] # 代币节省报告
local-offload doctor # 端点健康 + 配置检查
local-offload models # 显示配置的模型 + 服务标志
local-offload eval [--dir DIR] # 基于代码的质量评估(AURC,延期曲线 AUDC/QNC)
local-offload stats # 每任务记账遥测
```
输入为 **文件路径** 或 `-` 表示标准输入。添加 `--json` 以获取完整的返回对象,`--select a,b,c` 以仅保留某些顶级字段,`--compact` 以压缩。配置从 `--config <path>` 或 `$LOCAL_OFFLOAD_CONFIG` 读取。
<details>
<summary><b>示例:提取结构化字段</b></summary>
`fields.json` 是一个具有 `properties` 映射的 JSON 模式:
```json
{ "properties": { "name": { "type": "string" }, "amount": { "type": "number" }, "date": { "type": "string" } } }
```
```bash
local-offload extract invoice.txt --schema fields.json --json
# -> {"name":"...","amount":1240.50,"date":"2026-01-15"} (值基于输入文本)
```
一个裸露的 `{"field":"string"}` 映射没有可用的属性,因此会被延期。
</details>
<details>
<summary><b>自我学习作业(离线,无推理)</b></summary>
这些作业作为夜间批次运行在记账器上 — 纯 Go 统计数据,**零云代币**:
```bash
local-offload calibrate # 每任务保形升级阈值 -> thresholds.json
local-offload health # 每层 EWMA/Page-Hinkley/CUSUM + P95 超时 -> tier_overrides.json
local-offload train-router # 从输入特征的逻辑入口层路由器 -> router-weights.json
local-offload optimize # 挖掘已验证的良好调用到 few-shot 示例池
local-offload audit-sample --hard # 展示最困难的案例供人工/代理审查
```
参见 [级联如何学习](#how-the-cascade-learns)。
</details>
## 作为 MCP 服务器使用
将二进制文件注册到您的 MCP 客户端。内置的默认值已经编码了完整的级联,因此 `--config` 仅在非默认端点或路径时需要。
```bash
claude mcp add local-offload --scope user -- /path/to/local-offload mcp
```
或将其直接添加到客户端的 MCP 配置中:
```json
{
"mcpServers": {
"local-offload": {
"command": "/path/to/local-offload",
"args": ["mcp"]
}
}
}
```
传输是 **stdio**。每个工具返回完整的返回 JSON — 而延期是一个 *有效* 的返回,指示代理自己处理该任务。
### 暴露的 MCP 工具
| 工具 | 参数 | 功能 |
|---|---|---|
| `offload_summarize` | `text`, `max_points?` | 总结文本 → `{summary, bullets}`,或延期。 |
| `offload_classify` | `text`, `labels[]` | 分类到其中一个标签 → `{label, confidence}`,或延期。 |
| `offload_extract` | `text`, `schema` | 提取模式约束字段 → 对象,或延期。值基于输入。 |
| `offload_triage` | `text`, `question` | 是/否/不确定检查 → `{decision, reason}`,或延期。 |
| `offload_vqa` | `image`, `question` | 本地图像上的视觉 Q&A → `{answer}`,或延期。 |
| `offload_ocr` | `image` | 转录图像中的所有文本 → `{text}`,或延期。 |
| `offload_extract_image` | `image`, `schema` | OCR 然后从图像中提取基础字段 → 对象,或延期。 |
| `offload_assess_image` | `image`, `brief?` | QA 渲染器对抗排除 → `{has_people, has_text, matches_brief, notes}`。 |
| `offload_video_describe` | `video`, `question` | 从本地视频中采样帧并回答 → `{answer}`,或延期。 |
| `offload_transcribe` | `audio`, `language?`, `hq?`, `select?` | 转录本地音频/视频 → `{gist, segments[], srt_path, ...}`,或延期。 |
| `offload_generate_image` | `prompt`, `negative?`, `width?`, `height?`, `steps?`, `seed?`, `out?` | 在本地 GPU 上生成图像(SDXL/ComfyUI)→ `{image_path, ...}`,或延期。 |
| `offload_generate_svg` | `kind`, `spec`, `out?` | 渲染清晰的数据可视化 SVG(`gauge` · `comparison-bar` · `chromatogram` · `icon`)- 无模型,无 GPU。 |
| `offload_generate_audio` | `text`, `kind?`, `clone?`, `lang?`, `seconds?`, `seed?`, `out?` | 合成语音(Chatterbox TTS)或音乐(ACE-Step)在本地 GPU 上 → `{audio_path, ...}`,或延期。 |
| `offload_generate_video` | `prompt`, `still?`, `model?`, `frames?`, `seed?`, `out?` | 将静态图像动画化为短视频(Hunyuan I2V)在本地 GPU 上 → `{video_path, seed}`,或延期。 |
| `offload_nim` | `prompt`, `model?`, `system?`, `base?`, `max_tokens?`, `temperature?`, `list_models?` | **选择性远程。** 调用 NVIDIA NIM 端口(托管免费目录或自托管)→ `{model, content, ...}`,或延期。密钥来自 `$NVIDIA_API_KEY`(仅发送到 NVIDIA 主机);永远不会记账。 |
> **输入保持本地。** 图像、音频和视频作为 **本地文件路径** 或 `data:` URI 接受 - **绝不是远程 URL**,因此没有媒体的网络出口。
## 它如何工作
管道是置信度分级的级联。请求进入一个小层级,只有在结果确实不确定时才会升级;如果所有本地层级都失败,则延期给调用者。
```mermaid
flowchart LR
A[请求] --> B[缓存 + 上下文预算修剪]
B --> C[构建提示 + GBNF 语法]
C --> D[小层级<br/>llama.cpp + 语法]
D --> E[解析 → 验证 → 模式验证]
E --> F{置信度门控}
F -->|通过| G[接受 ✓]
F -->|低余量 /<br/>验证失败| H[升级到更大层级]
H --> E
F -->|所有层级失败 /<br/>输入截断| I[延期调用 ↩]
G --> J[追加到代币记账 JSONL]```
**级联。** 任务进入适合该作业的层级,只有在验证失败 **或** 低决策置信度信号时才会升级:
- **分类 / 分类** → 小快速层级(入口)
- **总结 / 提取** → 中工作层级
- 失败或不确定 → 升级到更大的近前沿 MoE 层级
- 所有本地层级失败 → **延期** 调用
**基于置信度的升级。** 对于分类/分类,工具请求每个令牌的 logprobs 并计算 **类别质量余量** 在决策令牌(原始预语法分布,按合法类所以 `Yes`/`yes` 不会拆分)。低于阈值意味着模型被撕裂 → 升级而不是接受硬币翻转。分类还保留了自我报告的置信度门控(防御深度)。**可靠的结构化输出。** 目标模型在 llama.cpp 的 `--json-schema` / `response_format` 上崩溃,因此层级改为强制执行 **GBNF 语法**(按请求生成,无外部依赖项依赖项)
**可靠的结构化输出。** 目标模型在 llama.cpp 的 `--json-schema` / `response_format` 上崩溃,因此层级改为使用 Go 中的 **GBNF 语法**(按请求生成,无外部依赖)通过聊天补全的 `grammar` 字段,然后宽容地解析和模式验证结果。提取的值必须原样出现在源文本中(基础)。
# 大型 MoE 升级: --cpu-moe --n-gpu-layers 999 --parallel 1 (env GGML_CUDA_DISABLE_GRAPHS=1)
```
<details>
<summary><b>服务注意事项(负载均衡)</b></summary>
- **`--reasoning off` 是必须的** — 否则模型的思考模式会占用短输出预算并返回空回复。
- **不使用推测性草稿(MTP)** — 它会在语法字段上出现 500 错误。服务时启用 flash-attention,f16 KV,关闭推理。
- **永远不要使用 `--json-schema` / `response_format`** — 它们会使模型崩溃;绑定程序会传递一个原始的 GBNF `grammar` 字段。
- **视觉:使用 VLM 的 Instruct 版本** (Thinking 变体会静默绕过 GBNF)并将多模态投影仪保持在 **F16** 以进行 OCR(Q8 会产生幻觉文本)。
- **语音转文本:关闭服务器端的 flash-attention** — 它会降低非英语 / 嘈杂转录的质量; turbo 仍然是 5–8 倍实时速度。
</details>
## 要求
| | |
|---|---|
| **操作系统** | Linux,macOS,Windows |
| **Go** | 1.26+(用于构建) |
| **GPU** | NVIDIA,约 8 GB VRAM 用于文本 + 视觉级联 |
| **RAM / 磁盘** | 推荐 32 GB+ 系统 RAM 和快速 SSD(模型权重,MoE CPU 外设) |
| **外部** | 运行的 llama.cpp 服务器;`ffmpeg` 在 PATH 中用于音频/视频;用于 STT 的 whisper.cpp 服务器;用于图像生成的 ComfyUI(所有功能均可选) |
## 故障排除
<details>
<summary><b>每次调用都返回 <code>deferred: true</code></b></summary>
使用 `local-offload doctor` 检查端点。最常见的原因是 llama.cpp 服务器未运行或在 `endpoint` 处无法访问。 defer 在低置信度、截断或过长输入时也是正常的 — 这些输入应该返回给调用者。
</details>
<details>
<summary><b>空或截断的模型输出</b></summary>
您几乎肯定是在启用推理模式的情况下提供服务的。在 llama.cpp 服务器上添加 `--reasoning off` 。还要确认您 **没有** 传递 `--json-schema` / `response_format` — 它们都会使模型崩溃并破坏语法路径。
</details>
<details>
<summary><b>OCR 或图像字段看起来不正确</b></summary>
使用 **Instruct** 视觉版本(不是 Thinking)并将多模态投影仪保持在 **F16** 。在信任密集文档之前,请验证它们 — 服务器上的精细 OCR 对非常小的文本有已知的精度回归。
</details>
<details>
<summary><b>"缓存不可用(被 MCP 服务器持有?)"</b></summary>
意料之中。bbolt 缓存是单写入器;当长期运行的 MCP 服务器持有它时,并发 CLI 运行会继续无缓存。JSONL 账本不受影响 — 两者都可以追加。
</details>
## 贡献
欢迎贡献。在打开拉取请求之前,请运行 `go test ./...` 和 `go vet ./...` ,并将更改范围限定在特定区域内。有关构建/测试的详细信息,请参见 `CONTRIBUTING.md` 。
## 安全
所有内容都在 **本地** 运行 — 没有云调用,没有凭证,没有媒体输出(输入仅限本地路径或 `data:` URI)。要报告漏洞,请参见 `SECURITY.md` 而不是公开问题。
## 许可证
[Apache 2.0](LICENSE).
## 致谢
基于 [llama.cpp](https://github.com/ggml-org/llama.cpp) 和 [whisper.cpp](https://github.com/ggml-org/whisper.cpp), [Gemma](https://ai.google.dev/gemma) 和 [Qwen-VL](https://github.com/QwenLM/Qwen3-VL) 模型家族, [ComfyUI](https://github.com/comfyanonymous/ComfyUI), [模型上下文协议 Go SDK](https://github.com/modelcontextprotocol/go-sdk),以及 [bbolt](https://github.com/etcd-io/bbolt)。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器