把 Claude Code 接到本地模型,是最近社区里讨论度很高的玩法。在线 API 虽然效果稳定,但代码数据要出网、按 token 计费,团队跑批量任务时成本会比较敏感。本地模型则相反:数据不出内网、推理只花电费,但单台机器性能有限,交互式编程体验往往不如云端。这篇文章要拆解的是一个相对完整的方案:通过一个叫 Yeschef 的轻量调度层,把 Claude Code 发出来的任务,分发到局域网内的多台 Ollama 节点上,再把结果汇总回来。标题里提到的 627 tok/s,就是在 3 台 NUC 组成的集群上,聚合多个节点吞吐量得到的参考数据。整篇文章会覆盖硬件规划、Ollama 部署、调度层编写、Claude Code 接入、性能优化和常见坑点,适合想尝试本地模型编程助手、又不想只用单机跑小模型的开发者。
1. Yeschef 是什么:本地模型调度的整体思路
1.1 为什么不能直接让 Claude Code 连 Ollama
先说结论:Claude Code 默认面向 Anthropic 官方模型通信,走的是 Anthropic Messages API 协议;Ollama 原生提供的是/api/chat和/api/generate接口,两者协议并不一致。虽然 Ollama 也暴露了/v1的 OpenAI 兼容端点,但那是 OpenAI 格式,和 Anthropic 格式仍有差异。因此直接把ANTHROPIC_BASE_URL指向 Ollama 地址,通常并不能正常工作,需要有一个中间层把 Anthropic 协议翻译成 Ollama 能理解的请求,再把响应翻译回去。这个中间层,就是 Yeschef 这类调度器存在的意义:它既做协议转换,也做多节点路由,还负责集群的健康检查和负载分配。
1.2 整体架构
把整个链路画出来其实很直观:
[Claude Code CLI] | | Anthropic Messages API 协议 v [Yeschef 调度层] (可以跑在一台 NUC 上,也可以跑在 Docker 容器里) | 路由 / 协议转换 / 健康检查 / 并发控制 +------------> [NUC-1: Ollama 节点] +------------> [NUC-2: Ollama 节点] +------------> [NUC-3: Ollama 节点]Claude Code 只认识调度层的地址,它不知道背后是几台机器,也不关心模型具体跑在哪块硬件上。调度层收到请求后,根据预设策略选择一台可用的 Ollama 节点,把 Anthropic 格式的消息体转换成 Ollama 的/api/chat格式,等待推理完成后,再把 Ollama 返回的内容包装成 Claude Code 期望的响应格式。这样的好处是,上层的 Claude Code 配置非常简单,下层的节点增加或减少也不会影响客户端。
1.3 关键组件职责
Claude Code 是 Anthropic 推出的命令行编程工具,能在终端里完成代码阅读、生成、重构、提交信息撰写等操作,体验上更像一个能看懂整个仓库的结对程序员。和 Codex 这类工具相比,Claude Code 更强调对话式交互和仓库上下文的自动采集,它会在需要时读取文件、执行命令,并根据结果继续推理。
Ollama 是一个本地模型运行框架,它把模型下载、量化、推理、GPU 加速这些繁琐的事情封装成简单的命令和 API。对开发者来说,ollama pull下载模型、ollama run启动对话、OLLAMA_HOST控制监听地址,大部分场景下不需要直接接触底层推理引擎。
NUC 是 Intel 的迷你主机系列,体积小、功耗低,很适合放在家里或办公室组成小型集群。3 台 NUC 的算力虽然比不上动辄 8 卡 GPU 的服务器,但跑 7B 到 14B 级别的量化模型已经足够,关键是它可以长期开机,电费成本可控。
Yeschef 在这个架构里承担“大脑”的角色。它不负责推理,只负责调度:节点挂了自动跳过、请求多了做并发控制、模型名称做别名映射。没有这一层,每台 NUC 就是一座孤岛,Claude Code 只能连其中一台,无法利用集群的整体算力。
2. 环境准备与硬件规划
2.1 硬件选型参考
NUC 的具体型号差异很大,这里不推荐具体到某款,重点看三个指标:内存容量、存储类型、是否有可用 GPU 或 NPU。
| 节点 | 建议配置 | 主要用途 |
|---|---|---|
| NUC-1 | 32GB 内存,1TB NVMe SSD,可选 GPU | 运行调度层,同时跑 7B 模型 |
| NUC-2 | 32GB 内存,1TB NVMe SSD | 跑 7B 或 14B 模型 |
| NUC-3 | 32GB 内存,1TB NVMe SSD | 跑 7B 模型,参与并行推理 |
内存是本地推理最重要的资源。7B 模型的 Q4 量化版本大约需要 5GB 左右显存或内存,14B 模型大约需要 10GB 左右,32GB 内存的 NUC 可以比较从容地同时加载两个模型。硬盘建议用 NVMe SSD,因为模型文件动辄 4GB 到 10GB,机械硬盘加载模型会明显拖慢首次响应速度。
如果 NUC 带有支持 Vulkan 的核显或独立显卡,Ollama 可以自动利用 GPU 加速。部分新款 AMD 平台带有 Ryzen AI NPU,能否被 Ollama 调用取决于推理后端是否支持,需要以实际运行ollama ps的输出为准,不要只看硬件宣传参数。
2.2 软件环境
三台 NUC 建议统一安装 Linux 发行版,Ubuntu 24.04 LTS 或 Debian 12 都是常见选择。统一系统版本可以减少排查成本,尤其当你要写 systemd 服务或 Docker Compose 时,环境差异越小越好。
调度层可以选择在宿主机直接跑 Python,也可以用 Docker 容器隔离。如果只是个人实验,直接跑 Python 更简单;如果希望开机自启、统一管理,建议用 Docker Compose。Claude Code 安装在开发机上,开发机可以是 Windows、macOS 或 Linux,只要 Node.js 环境满足要求即可。Ollama 的安装、Claude Code 的安装,都以各自官方仓库的最新版为准,不需要刻意追求某个固定版本。
2.3 网络规划
在动手之前,先把网络规划好。三台 NUC 建议使用静态 IP,例如:
| 节点 | IP 地址 | 端口 |
|---|---|---|
| NUC-1 | 192.168.1.11 | 11434 / 8080 |
| NUC-2 | 192.168.1.12 | 11434 |
| NUC-3 | 192.168.1.13 | 11434 |
在路由器后台给每台 NUC 绑定 DHCP 保留地址,或者在系统里直接配置静态 IP。静态 IP 的价值在于调度层的配置文件不需要频繁修改,Claude Code 的开发机也不需要重新设置环境变量。
Ollama 默认只监听127.0.0.1,也就是只能本机访问。要让其他机器通过局域网调用,必须修改监听地址,这一步会在下一节详细说明。另外要记住,Ollama 本身没有内置鉴权机制,只要监听在0.0.0.0,同网段任何设备都能访问。所以在家庭和办公网络里,建议把三台 NUC 放在独立的 VLAN 里,或者在调度层增加简单的 API Key 校验,避免被同网段其他设备滥用。
3. 部署 Ollama:从安装到局域网接入
3.1 安装 Ollama
在三台 NUC 上分别执行官方安装脚本:
curl -fsSL https://ollama.com/install.sh | sh安装完成后,先确认服务状态:
systemctl status ollama如果输出了active (running),说明 Ollama 已经作为系统服务在运行。安装脚本会创建ollama用户和 systemd 服务文件,日志可以通过journalctl -u ollama -f查看。
如果你所在的网络环境访问官方源比较慢,下载安装脚本或模型文件都很吃力,不建议反复重试浪费时间。更稳妥的办法是在一台网络条件好的机器上下载好模型文件,或者从已有的 Ollama 环境直接拷贝模型目录,再导入到 NUC 上。Ollama 的模型默认存放在~/.ollama/models,你可以通过设置OLLAMA_MODELS环境变量来指定模型存储路径,方便统一管理。
3.2 开启局域网访问
安装完成后,Ollama 默认只监听本机。需要修改 systemd 服务配置来开放局域网访问:
sudo systemctl edit ollama这个命令会打开一个覆盖配置文件,写入以下内容:
[Service] Environment="OLLAMA_HOST=0.0.0.0:11434" Environment="OLLAMA_NUM_PARALLEL=4" Environment="OLLAMA_MAX_LOADED_MODELS=2" Environment="OLLAMA_KEEP_ALIVE=10m"各参数含义如下:
OLLAMA_HOST=0.0.0.0:11434:监听所有网卡地址,允许局域网内其他机器访问。OLLAMA_NUM_PARALLEL=4:同一个模型最多并行处理 4 个请求。如果多个任务同时到达,模型不需要重复加载,吞吐量会明显提升。OLLAMA_MAX_LOADED_MODELS=2:最多同时保持 2 个模型在内存中。如果任务交替使用不同模型,避免频繁换入换出。OLLAMA_KEEP_ALIVE=10m:模型在空闲 10 分钟内不卸载,减少重复加载带来的延迟。
保存并退出编辑器后,重新加载配置:
sudo systemctl daemon-reload sudo systemctl restart ollama确认监听地址已经变化:
ss -lntp | grep 11434如果看到0.0.0.0:11434,说明局域网访问已经开启。
3.3 下载模型
在三台 NUC 上分别拉取代码类模型,这里以qwen2.5-coder:7b为例:
ollama pull qwen2.5-coder:7b模型下载时间取决于网络环境。如果下载速度不理想,可以考虑以下方案:
- 查看
~/.ollama/models目录,确认模型文件是否完整。 - 在能正常访问官方源的机器上下载模型,然后把整个
models目录拷贝到 NUC 的对应位置,并保证目录权限正确。 - 使用 Ollama 支持的 GGUF 本地导入方式,把已有的模型文件转换为 Ollama 可加载的格式。
无论是哪种方式,都要注意模型文件较大,传输时优先走有线网络,避免 WiFi 传输不稳定导致文件损坏。
3.4 验证 Ollama API
在三台 NUC 上各执行一次验证请求,确保 API 可用:
curl http://192.168.1.11:11434/api/tags返回结果中应该能看到qwen2.5-coder:7b。再测试生成接口:
curl http://192.168.1.11:11434/api/generate \ -d '{"model":"qwen2.5-coder:7b","prompt":"print hello","stream":false}'如果返回了包含response字段的 JSON,说明推理链路正常。注意,此时三台 NUC 的 Ollama 都相当于“裸奔”状态,只要知道 IP 和端口就能调用,建议只在可信内网环境做这一步。
4. 编写调度层:把请求分发到 NUC 集群
4.1 调度策略设计
调度层的核心职责有三个:协议转换、节点选择、异常兜底。
协议转换是指把 Claude Code 发出的 Anthropic Messages API 请求,转换成 Ollama/api/chat能识别的格式。Anthropic 请求里的system字段、messages数组、max_tokens参数,都需要映射到 Ollama 对应的字段。Ollama 的响应里虽然有message.content,但不是 Anthropic 的content数组结构,需要重新包装。
节点选择最简单的策略是轮询(round-robin)。每来一个请求,调度层就按顺序把请求发给下一台 NUC,三台机器轮流干活,代码量最少,也最容易理解。进阶方案可以根据每台节点的实时负载做加权分配,比如 GPU 空闲的节点多分一些请求,但这需要额外的监控数据。
异常兜底是指当某台 NUC 不可达或推理超时时,调度层能自动切换到下一台节点,而不是把错误直接抛给 Claude Code。健康检查可以放在调度层内部:维护一个节点列表,每次请求前做一次轻量探测,或者根据最近请求的失败次数动态调整节点权重。
4.2 Python 实现一个轻量调度器
下面给出一个演示级的调度器实现,核心思路是:监听/v1/messages,轮询选择节点,把请求转换为 Ollama/api/chat格式,再把结果包装回 Anthropic 响应格式。
# yeschef/scheduler.py import itertools import os import requests from flask import Flask, request, jsonify app = Flask(__name__) NODES = os.getenv( "NODES", "http://192.168.1.11:11434,http://192.168.1.12:11434,http://192.168.1.13:11434", ).split(",") pool = itertools.cycle(NODES) def pick_node(): # 演示版只做轮询,生产环境应结合健康检查与权重 node = next(pool) return node @app.route("/v1/messages", methods=["POST"]) def messages(): payload = request.get_json() model = payload.get("model", "qwen2.5-coder:7b") messages = payload.get("messages", []) system = payload.get("system") ollama_payload = { "model": model, "messages": messages, "stream": False, "options": { "temperature": 0.2, }, } if system: ollama_payload["system"] = system node = pick_node() try: resp = requests.post( f"{node}/api/chat", json=ollama_payload, timeout=300, ) data = resp.json() except Exception as exc: return jsonify({"error": f"node {node} failed: {exc}"}), 502 content = data.get("message", {}).get("content", "") # 包装成 Anthropic Messages API 风格响应 return jsonify({ "content": [ {"type": "text", "text": content} ], "model": model, "usage": { "input_tokens": data.get("prompt_eval_count", 0), "output_tokens": data.get("eval_count", 0), }, }) if __name__ == "__main__": app.run(host="0.0.0.0", port=8080)这段代码的逻辑很容易看懂。NODES从环境变量读取节点列表,itertools.cycle实现轮询,每次请求都会按顺序切到下一台 NUC。/v1/messages端点接收 Claude Code 传来的 JSON,把system字段单独取出,messages原样透传给 Ollama,然后把 Ollama 返回的文本内容包装成content数组。
需要注意的是,这是一个演示版本,没有处理工具调用、流式输出、多轮 tool 这种复杂场景。Claude Code 在实际使用中会频繁触发工具调用,比如读取文件、执行命令,如果调度层不处理这些能力,Claude Code 的自动化能力会大打折扣。真正的生产级调度器要么完整实现 Anthropic 协议里的工具调用,要么在返回前主动剥离工具相关字段,避免客户端行为异常。
4.3 用 Docker Compose 部署调度层
如果你不希望调度层直接跑在宿主机上,可以用 Docker 打包。创建如下文件:
# yeschef/Dockerfile FROM python:3.11-slim WORKDIR /app COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY scheduler.py . EXPOSE 8080 CMD ["python", "scheduler.py"]# yeschef/requirements.txt flask requests# yeschef/docker-compose.yml services: yeschef: build: . ports: - "8080:8080" environment: NODES: "http://192.168.1.11:11434,http://192.168.1.12:11434,http://192.168.1.13:11434" restart: unless-stopped启动命令:
docker compose up -d --build启动后,调度层默认监听在8080端口。先用curl验证一下调度层是否正常工作:
curl http://192.168.1.10:8080/v1/messages \ -H "Content-Type: application/json" \ -d '{ "model": "qwen2.5-coder:7b", "messages": [{"role": "user", "content": "用 python 写一个快速排序"}] }'如果调度层配置正确,你会拿到一个包含content数组的 JSON 响应,内容来自三台 NUC 中的某一台。多请求几次,观察日志里请求落到了哪些节点,确认轮询生效。
5. 让 Claude Code 使用本地模型
5.1 接入方式的取舍
Claude Code 官方设计上是面向 Claude 模型的,但社区实践中通常通过两种方式接本地模型。
第一种是指定自定义 Base URL,让 Claude Code 把请求发到你的调度层地址,同时通过环境变量指定模型名。这种方式的优点是配置简单,一条环境变量搞定,缺点是对协议兼容性要求高,调度层必须能处理 Claude Code 发出的所有请求类型。
第二种是使用社区的路由工具,比较常见的是claude-code-router这类工具。它们本质上是把 Claude Code 的请求拦截下来,再根据配置文件把请求转发到 Ollama、OpenAI 兼容端点或国内模型 API 上。这类工具通常已经处理好了工具调用和流式响应的适配,适合不想自己写协议转换层的场景。
选择哪种方式取决于你的目标。如果你只是想验证本地模型能不能接,或者想深入理解协议细节,自己写调度层更有价值;如果你希望快速跑通一个可用环境,社区工具更省事。本文后面以自己写的调度层为例,因为它更贴近“把工作分发到局域网 Ollama”这个核心目标。
5.2 配置环境变量
在开发机上设置以下环境变量,然后启动 Claude Code:
export ANTHROPIC_BASE_URL="http://192.168.1.10:8080" export ANTHROPIC_MODEL="qwen2.5-coder:7b" export ANTHROPIC_API_KEY="local-test-key" claude这里三个变量的含义要理解:
ANTHROPIC_BASE_URL:告诉 Claude Code 所有 API 请求都发到调度层地址,而不是 Anthropic 官方服务器。ANTHROPIC_MODEL:指定模型名称。调度层会把这个名称透传给 Ollama。ANTHROPIC_API_KEY:本地实验可以随便填一个非空字符串,因为请求根本不会到 Anthropic 官方鉴权。如果路由工具要求必须填,就填一个占位值。
启动后,如果调度层日志里出现了来自 Claude Code 的请求,说明接入成功。你可以在终端里输入一个简单的编程问题,观察响应内容。
5.3 模型名称与别名问题
一个常见的坑是模型名称不匹配。Claude Code 有自己对模型名称的识别逻辑,如果你设置一个它不认识的模型名,它可能会报类似"xxx" is not a model this version of claude code recognizes的错误。本质上这不是 Ollama 的问题,而是模型名没有通过 Claude Code 的校验规则。
解决思路有两种。一是把ANTHROPIC_MODEL设置成 Claude Code 认识的官方模型名,比如claude-sonnet-4-0或claude-3-5-sonnet,然后在调度层里做模型名映射:请求进来时,把官方模型名替换成你真正要用的本地模型。二是直接接受报错,使用路由工具或自定义调度层时,看它是否支持自定义模型白名单,把本地模型名加进去。
调度层的模型映射逻辑很简单,在scheduler.py里加一个字典即可:
MODEL_ALIASES = { "claude-sonnet-4-0": "qwen2.5-coder:7b", "claude-3-5-sonnet": "qwen2.5-coder:7b", } def resolve_model(requested: str) -> str: return MODEL_ALIASES.get(requested, requested)这样既保证了 Claude Code 的模型名校验能通过,又让实际推理落到你真正想用的本地模型上。
5.4 模型选择建议
本地模型的选择直接影响编程体验。目前社区里评价比较高的代码模型包括qwen2.5-coder系列、deepseek-coder-v2系列和llama3.1系列。7B 级别的模型在 NUC 上可以流畅运行,代码补全和小型重构表现尚可;14B 级别质量更高,但对内存和推理速度的要求也更高。建议先在三台 NUC 上都部署同一个 7B 模型,跑通链路后再尝试混合部署:一台跑 14B 模型处理复杂任务,另外两台跑 7B 模型处理简单任务,调度层根据任务类型分发。
6. 性能优化:从“能跑”到“跑得快”
6.1 tok/s 是怎么计算出来的
tok/s全称是 tokens per second,表示模型每秒生成的 token 数量,是衡量本地推理速度最直观的指标。Ollama 在/api/generate和/api/chat的响应中会返回eval_count和eval_duration两个字段,前者是本次推理生成的 token 数,后者是生成耗时(纳秒),两者相除就是单次请求的生成速度。
写一个小脚本可以快速测出每台 NUC 的速度:
# speed.py import requests def speed(node, model, prompt): data = requests.post( f"{node}/api/generate", json={"model": model, "prompt": prompt, "stream": False}, timeout=300, ).json() tokens = data.get("eval_count", 0) seconds = data.get("eval_duration", 0) / 1e9 return tokens / seconds for node in ["192.168.1.11", "192.168.1.12", "192.168.1.13"]: s = speed(f"http://{node}:11434", "qwen2.5-coder:7b", "def fib(n):") print(f"{node}: {s:.1f} tok/s")注意,首轮请求通常包含模型加载时间,所以最好先发一个预热请求,再测正式速度。
6.2 影响单机速度的关键因素
单机生成速度主要受三方面影响。
第一是推理设备。GPU 的显存带宽远高于 CPU 内存带宽,同样是 7B 模型,有 GPU 加速的 NUC 可能跑出 80 到 150 tok/s,纯 CPU 推理可能只有 10 到 30 tok/s。如果 NUC 没有独立显卡,建议优先选择更小的量化版本,比如q4_k_m,减少内存带宽压力。
第二是模型量化等级。量化等级越低,模型体积越小,推理越快,但精度会有所下降。q8_0、q4_k_m、q2_k是常见的量化档位,代码生成场景通常选择q4_k_m,兼顾速度和质量。
第三是并发参数。上一节在 systemd 里配置的OLLAMA_NUM_PARALLEL很关键。如果同一时刻只有一个请求,模型是串行推理的;如果能并行处理多个请求,吞吐量可以成倍提升。7B 模型在 32GB 内存的 NUC 上可以比较轻松地并行处理 4 个请求,这也是多节点聚合速度能到几百 tok/s 的基础。
6.3 多节点并行聚合的收益
单台 NUC 的速度再快也有上限,但 3 台 NUC 可以同时工作。调度层每次把一个请求轮流发给不同节点,相当于三个推理进程并行。假设每台 NUC 的 7B 模型稳定输出 180 tok/s,三台并行时,整个集群每秒能产出的 token 总数就是 540 tok/s 左右,再加上并发参数和缓存优化的增益,接近 627 tok/s 是合理的。
这里要注意一个概念:聚合速度不等于单次请求的响应速度。Claude Code 的某个请求还是由某一台 NUC 单独完成,单次响应速度并不会因为集群而变快。627 tok/s 是“整个调度层在一段时间内处理的总 token 数除以总时间”,更适合衡量批量任务场景。如果你需要单次响应更快,应该优化单机推理速度,而不是增加节点数。
6.4 进一步调优的切入点
如果实测速度不理想,按顺序排查:
- 确认模型是否有 GPU 加速,查看
ollama ps输出。 - 确认
OLLAMA_NUM_PARALLEL是否生效,多次并发请求时观察节点日志。 - 确认模型没有频繁换入换出,适当调大
OLLAMA_KEEP_ALIVE。 - 确认网络不是瓶颈,Ollama 节点之间不应通过 WiFi 传输大量请求,能走有线尽量走有线。
- 确认调度层没有性能瓶颈,请求量和日志量很大时,调度层自身也要能扛住。
7. 常见问题与排查思路
把部署过程中最容易遇到的几个问题整理成了一张表,方便后续对照排查。
| 问题现象 | 常见原因 | 解决思路 |
|---|---|---|
| Ollama 下载太慢 | 访问官方源网络不稳定 | 提前下载模型文件后离线导入,或设置模型存储路径后统一拷贝 |
| 局域网内其他机器连不上 Ollama | 默认只监听 127.0.0.1 | 修改 systemd 配置,设置OLLAMA_HOST=0.0.0.0:11434并重启服务 |
| 修改 systemd 后不生效 | 没有执行 daemon-reload | 依次执行systemctl daemon-reload和systemctl restart ollama |
| Claude Code 提示模型不被识别 | 模型名未通过 Claude Code 校验 | 在调度层做模型别名映射,或使用路由工具的自定义模型白名单 |
| 请求返回 529 错误 | 目标服务过载或限流 | 检查是否并发过高,调低OLLAMA_NUM_PARALLEL,或让调度层做请求排队 |
| Dify 中 Ollama 模型处理超时 | 推理时间超过 Dify 超时阈值 | 在 Dify 中调大超时时间,同时优化模型量化等级和并发参数 |
| 模型输出乱码 | 字符编码处理不一致 | 确保调度层请求和响应均使用 UTF-8,检查客户端终端编码 |
| 提示组织已禁用 Claude 订阅访问 | 企业策略限制了 Claude 官方服务 | 这是订阅与账号策略问题,本地模型接入无法解决,需要联系企业管理员确认 |
| AMD Ryzen AI 平台 GPU 不生效 | 推理后端未支持该硬件 | 查看ollama ps确认是否走 GPU,确认驱动和 Vulkan 环境正常 |
| 局域网内有 IPv6 但设备无法访问 | 网络路由或防火墙配置问题 | 优先使用静态 IPv4 地址来规避 IPv6 环境差异 |
其中有两个问题需要额外说明。
第一,关于模型不识别。很多时候用户不是模型下载失败,而是 Claude Code 对模型名做了硬性校验。解决思路是让调度层“瞒住”Claude Code:对外暴露官方模型名,对内映射到本地模型。这个方案在前面已经写过代码,就不再重复了。
第二,关于企业订阅限制。如果你在公司环境运行 Claude Code,遇到类似your organization has disabled claude subscription access for claude code的提示,说明账号或组织策略禁止了 Claude Code 的订阅访问。这种情况和本地模型接入无关,即使你配置了本地调度层,Claude Code 的授权校验也可能发生在连接之前。需要找企业管理员确认能否放开限制,或者使用不被组织策略影响的个人账号环境。
8. 安全与工程最佳实践
8.1 不要让 Ollama 裸奔到公网
Ollama 默认没有鉴权机制,任何人只要能访问到11434端口,就可以拉取模型列表、发起推理请求、占用 GPU 和内存资源。如果 Ollama 监听了0.0.0.0,又有公网端口映射,后果会非常严重:不仅模型会被滥用,还可能被用来消耗流量、挖矿或发起恶意请求。因此生产环境必须控制访问范围,核心原则是“默认拒绝,按需开放”。
最稳妥的做法是把 Ollama 节点放在独立的内网网段,用防火墙规则限制只有调度层所在的机器能访问11434端口。如果必须跨网段访问,优先用调度层做统一入口,Ollama 本身不直接暴露给客户端。调度层对外提供服务时,可以加一层简单的 API Key 校验,防止未授权调用。
8.2 调度层的认证与限流
即便在内网,也建议在调度层增加认证和限流。认证可以用一个简单的请求头实现:
API_TOKEN = os.getenv("API_TOKEN", "change-me") @app.before_request def check_token(): if request.headers.get("X-API-Key") != API_TOKEN: return jsonify({"error": "unauthorized"}), 401客户端调用时带上请求头即可。限流可以用内存计数实现,也可以用现成的 Flask 扩展,核心目的是防止某个误操作把三台 NUC 的推理资源全部打满。
8.3 日志、监控与备份
调度层和 Ollama 都应该记录日志。调度层至少记录每次请求的时间、来源、目标节点、模型名、响应耗时和错误信息;Ollama 的日志可以通过journalctl -u ollama查看。监控指标重点看三件事:模型加载数量、并行请求数、平均生成速度。如果发现某台节点频繁超时,及时把它从节点列表里摘除。
模型文件本身是容易恢复的,不存在不可重建的业务数据,但如果有自定义的 Modelfile、系统提示词或调度配置,建议纳入版本管理。所有配置文件的修改,先记录变更、再应用,避免某次手误把整个集群配置改坏。
8.4 生产环境注意事项
最后说几条生产环境建议。
不要把未鉴权的 Ollama 暴露在不可信网络中,这条前面已经反复强调过。在正式使用前,用最小权限原则配置服务账号,Ollama 进程尽量不要以 root 身份运行。改配置前先备份,尤其是 systemd 覆盖文件和模型目录。推送大模型到多台节点时,优先用批量脚本或配置管理工具,不要手动一台一台操作。
如果你要在企业内部推广这套架构,还需要考虑合规问题:本地模型是否有许可证风险、员工上传的代码是否敏感、调度层日志是否保存足够长的时间,这些都需要和法务、安全团队一起确认。
9. 总结与实践建议
这篇文章的主题很明确:用 Yeschef 这样一个轻量调度层,把 Claude Code 的任务分发到局域网内的多台 Ollama 节点上。整条链路可以拆成四个环节:部署 Ollama 并开放局域网访问、编写调度层做协议转换和节点路由、配置 Claude Code 指向调度层、通过并发参数和多节点并行优化吞吐量。每一步都不复杂,但每一步都有容易踩坑的地方,尤其是协议转换和模型名别名这两个点,值得多花时间理解。
如果你是从零开始,建议按下面的顺序动手实验:
先在单台 NUC 上把 Ollama 部署好,用curl验证模型推理正常。再写一个最简单的调度器,只做协议转换,不关心集群,先让 Claude Code 通过调度层跑通单节点。单节点稳定后,再把另外两台 NUC 加进节点列表,观察轮询是否生效。最后再谈性能优化,调整并发参数、测量 tok/s、尝试模型别名映射。一次只改一个变量,出了问题也容易定位。
进阶方向有几个:一是完善调度器的工具调用支持,让 Claude Code 的自动化能力真正跑起来;二是引入更智能的路由策略,比如按任务复杂度把请求分给不同规模的模型;三是接入可观测体系,用 Prometheus 采集节点指标,配合 Grafana 做可视化。这些方向都能让这套本地集群从“能跑”变成“好用”。
如果你也正在折腾 Claude Code 和 Ollama 的本地部署,希望这篇文章能帮你少走弯路。配置过程中遇到报错,优先看日志,再看网络,最后看模型和协议字段,大多数问题都能在这三步里找到答案。