ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Claude Code+Ollama+调度层:打造局域网NUC推理集群

Claude Code+Ollama+调度层:打造局域网NUC推理集群 在实际的私有化开发环境里最理想的状态是既保留 Claude Code 这种 Agent 编码工具的体验又不必把所有请求都发到远程 API。标题里的 Yeschef 项目就是这种思路的一种落地Claude Code 作为任务入口局域网里跑 3 台 NUC每台 NUC 上都装 Ollama中间再由一个调度层把 Claude Code 发出的推理请求分发到不同节点最终在局域网内部获得 627 tok/s 级别的生成速度。这套组合的核心价值是把“控制流”和“模型推理”解耦。Claude Code 负责读取代码、生成工具调用、维护多轮上下文Ollama 只负责加载模型并输出 tokenYeschef 这个调度层则负责协议转换、节点选择和流量分配。三者各干各的任何一个环节都可以单独替换。对正在做本地模型网关、私有化编码助手或多节点推理集群的人来说这套架构可以直接作为参考。这篇文章会先拆解整套链路里三个角色的职责再说明为什么选择“局域网 NUC 集群”而不是单台服务器然后从零搭建一个最小可运行系统三台 NUC 装 Ollama、Claude Code 连接本地端点、调度层完成请求转换和节点路由最后给出吞吐验证方法和一份针对三层架构的排错手册。1. 先理解这套架构的三个角色Claude Code、Ollama 和调度层1.1 Claude Code 的定位它是一个 Agent 控制器不只是聊天客户端Claude Code 是 Anthropic 推出的命令行编程 Agent能够在终端里读取项目文件、执行命令、调用工具并根据上下文生成代码改动。它的核心能力不是“生成一段文本”而是维护一套完整的工具调用循环用户发出需求Claude Code 决定调用哪个工具、读取哪些文件、执行什么命令然后根据结果继续推进。但这个 Agent 本身不运行大模型它需要把对话历史和工具结果发送给一个模型推理端点拿到模型的下一步决策。默认情况下这个端点是 Anthropic 的云 API。也就是说Claude Code 和模型之间是标准的 HTTP 请求关系而这也意味着只要请求格式能被正确解释模型推理发生在哪里并不重要。这正是整套架构能被改造的基础。Claude Code 并不强制请求必须发到某个固定地址它读取环境变量或配置来确认 API 地址然后发送 Anthropic Messages API 格式的请求。1.2 Ollama 的定位本地模型运行时通过 REST API 暴露推理能力Ollama 是一个面向本地部署的模型运行工具它把模型下载、量化管理、显存/内存调度和 REST API 封装在一起。开发者只需要拉取模型就能在本地起一个 HTTP 服务。Ollama 默认监听127.0.0.1:11434提供两个最常用的接口POST /api/chat发送多轮对话支持流式返回。POST /api/generate输入一段 prompt直接生成补全。它还提供GET /api/tags查看本机已下载的模型列表GET /api/ps查看当前正在运行的模型和加载状态。这些接口对后面做健康检查和负载估算非常有用。Claude Code 默认发送的是 Anthropic Messages API 格式而 Ollama 的原生接口不是这种格式因此不能直接把 Claude Code 的ANTHROPIC_BASE_URL指向 Ollama 的11434端口。两者之间必须有一个格式转换层。1.3 调度层 Yeschef 的职责格式转换、模型映射、节点路由题目里的 Yeschef 承担的就是这个“中间人”角色。它的职责可以拆成三件事第一格式转换。接收 Claude Code 发来的 Anthropic Messages 请求转换成 Ollama/api/chat请求再把 Ollama 返回的 NDJSON 流转换成 Anthropic SSE 流返回给 Claude Code。第二模型映射。Claude Code 传入的模型名是 Anthropic 体系的名称例如claude-sonnet-4-20250514。Ollama 可用的模型名则是qwen3:32b、llama3.2:3b这样的格式。调度层维护一张路由表把“Claude Code 请求的模型名”映射到“某台 NUC 上的某个 Ollama 模型”。第三节点路由。一台 NUC 跑一个模型三台 NUC 就构成一个小型模型集群。调度层根据请求的模型名、节点健康状态、当前并发数和响应速度决定把请求发给哪一台。下面用表格总结三者边界组件职责直接对外暴露的接口Claude Code任务编排、工具调用、上下文管理命令行入口消费 APIYeschef 调度层协议转换、模型映射、节点分发对外提供/v1/messagesOllama 节点加载模型、执行推理、返回流式结果对内提供/api/chat、/api/tags理解了这个分层后面每一步操作就都围绕同一个目标把三层之间的协议和地址打通然后让流量按预期路由。2. 为什么是“局域网 NUC 集群”选型逻辑和 627 tok/s 的解读2.1 NUC 集群解决什么问题单台性能很强的服务器当然能直接跑 Ollama但如果只是做个人编码助手成本偏高而且大规模 GPU 服务器不一定适合放在办公环境。NUC 是 Intel 的迷你主机体积小、功耗低、噪音小多台叠加起来可以形成一个低成本的家庭或办公室推理集群。三台 NUC 的典型配置常见于 8 到 16 核 CPU、16GB 到 64GB 内存、NVMe SSD部分型号带 Iris Xe 核显。这个配置跑量化后的 7B 到 32B 模型是可行的关键是模型文件和内存要匹配。如果单台机器只有 16GB 内存跑 32B 模型会比较吃力更适合的方案是每台 NUC 各跑一个不同的中小模型由调度层按任务类型分发。集群的意义在于“分工”三台 NUC 可以分别加载三个模型也可以让同一模型在多个节点上各放一份副本。前者扩大可用的模型种类后者提升并发吞吐。标题中的场景选择了三台 NUC本质上是用横向扩展换单机性能不足。2.2 627 tok/s 应该怎么理解627 tok/s 是一个很亮眼的数字但要放在特定条件下去看不能简单理解为“单次回复每秒生成 627 个 token”。这个数值通常来自两种可能多请求并发时的聚合吞吐。例如同时发起多个流式请求三台 NUC 各自以 150 到 250 tok/s 的速度生成叠加后总吞吐接近 627 tok/s。加载了参数量较小的量化模型。比如 3B 或 7B 的 Q4 量化模型在内存带宽充足的 NUC 上可以达到很高的单流速度。对实际开发体验来说单流速度影响“第一个 token 多久出现、回复多快打满”聚合吞吐影响“同时处理多少个请求不排队”。验证 627 tok/s 时先明确是单流还是并发聚合否则压测结果没有可比性。2.3 网络和硬件准备局域网是这个架构的默认前提。所有推理流量都在内网传输不依赖外网带宽延迟低且数据不出内网。对于网络千兆以太网以内是够用的。Ollama 返回的文本 token 数据量并不大瓶颈一定在模型推理不在网络。2.5G 网口属于可选项只有在大量并发请求、大量工具结果回传时才有明显收益。WiFi 也可以跑通但更推荐有线连接因为长时间推理会产生持续流量无线网卡在弱信号下可能抖动。硬件准备清单如下项目建议说明CPU8 核以上决定 CPU 推理吞吐上限内存16GB 起步32B 模型建议 32GB模型权重、KV Cache 都要占内存存储NVMe SSD预留模型空间32B Q4 模型大约需要 20GB 左右网络千兆有线稳定性和延迟都优于无线散热NUC 底部架空避免叠放长时间推理会持续发热降频会直接影响 tok/s2.4 NUC 选型时最容易忽略的点NUC 型号很多不同代际的 CPU 性能和核显能力差异很大。选择时先确认三个问题准备跑多大的模型。如果只跑 3B 到 8B16GB 到 32GB 内存足够如果要跑 32B至少 32GB 内存。是否依赖核显。部分 NUC 的核显能被 Ollama 调用但更稳妥的做法是先把它当成 CPU 推理环境再单独测试核显是否被识别。是否长期高负载。多台 NUC 放在同一个封闭机柜里散热必须考虑。连续推理半小时后如果 CPU 降频627 tok/s 会掉到原速率的 60% 甚至更低。3. 在每台 NUC 上部署 Ollama 并暴露到局域网3.1 安装 OllamaOllama 支持 Linux、macOS 和 Windows。NUC 通常安装 Linux这里以 Ubuntu/Debian 类系统为例。官方提供安装脚本curl -fsSL https://ollama.com/install.sh | sh执行前先确认脚本来源可信安装完成后检查服务状态systemctl status ollama ollama --version如果系统没有自动启动服务可以手动启动sudo systemctl enable ollama sudo systemctl start ollama3.2 修改监听地址让 Ollama 能被局域网访问Ollama 默认只监听本机127.0.0.1其他机器访问不到。要让调度层访问每台 NUC 的 Ollama需要修改环境变量OLLAMA_HOST。编辑 systemd 服务文件sudo systemctl edit ollama追加配置[Service] EnvironmentOLLAMA_HOST0.0.0.0:11434然后重启sudo systemctl daemon-reload sudo systemctl restart ollama检查是否监听在局域网地址上ss -tlnp | grep 11434此时从调度层所在机器执行以下命令如果返回 JSON 列表说明局域网访问已经打通curl http://nuc-ip:11434/api/tags3.3 常用 Ollama 环境变量Ollama 除OLLAMA_HOST外有几个环境变量在集群场景很常用环境变量作用建议值OLLAMA_HOST监听地址默认 127.0.0.1:114340.0.0.0:11434OLLAMA_MODELS模型存放目录按磁盘分区单独指定OLLAMA_KEEP_ALIVE模型在内存中驻留时间高频使用建议5m或更长OLLAMA_MAX_LOADED_MODELS最多同时加载几个模型按内存大小设置 1 到 3OLLAMA_NUM_PARALLEL单个模型并发请求数默认 1性能测试时可调大OLLAMA_DEBUG输出调试日志排错时设为 1需要注意调大OLLAMA_NUM_PARALLEL会增加内存占用因为多个并发请求需要更多 KV Cache 空间。如果节点内存不够并发请求会被 Ollama 排队实际吞吐不会随并发增加而线性增长。3.4 模型规划三台 NUC 如何分工在拉模型之前先想清楚每个节点跑什么模型。下面是一份可行的规划节点建议模型适合场景内存需求参考nuc-01qwen3:32b复杂代码修改、长文分析约 24GB 到 32GBnuc-02llama3.2:3b或qwen3:8b快速回复、简短问答8GB 到 16GBnuc-03qwen2.5:14b或llama3.1:8b通用任务、中档负载16GB 到 24GB具体选型要结合机器内存和实际任务来判断。如果三台都是 32GB 内存可以都跑 32B 模型形成三副本提升并发能力如果内存差异较大就按模型大小分配。拉取模型命令ollama pull qwen3:32b ollama pull llama3.2:3b拉取完成后确认模型存在ollama list如果网络不稳定导致拉取很慢不要反复删除重试。Ollama 支持断点续传重复执行ollama pull会从已有进度继续。另外如果团队内有多台机器需要相同的模型文件可以在一台机器上拉取完成后把整个模型目录拷贝到其他节点绕开重复下载。3.5 确认每个节点健康状态节点上线后先逐个验证两个接口# 查看可用模型 curl http://nuc-01-ip:11434/api/tags # 查看当前加载模型和并发情况 curl http://nuc-01-ip:11434/api/ps/api/ps返回每个模型当前是否加载、加载进程的 CPU/内存占用、是否在处理请求等字段。这个接口适合作为调度层的健康检查路径。4. 安装并配置 Claude Code把请求指到本地调度层4.1 安装 Claude CodeClaude Code 以 npm 包形式分发需要先准备 Node.js 环境。安装命令npm install -g anthropic-ai/claude-code完成检查版本claude --version不同版本对 API 端点、模型名和登录策略的支持有差异。如果安装后无法登录或提示当前地区不可用先确认版本和官方文档要求的支持范围再考虑是否需要降级或升级。有一种常见报错是deepseek-v4-pro is not a model this version of claude code recognizes这说明该版本 Claude Code 会校验模型名遇到不认识的模型名会直接拒绝启动。解决办法不是去更换模型名而是去修改 Claude Code 侧配置让它使用一个能识别的模型名再由调度层把这个名字映射成本地模型。4.2 通过环境变量覆盖 API 端点Claude Code 支持通过环境变量或 settings 配置自定义 API 地址。常见的做法是在~/.claude/settings.json里写入{ env: { ANTHROPIC_BASE_URL: http://scheduler-ip:8787, ANTHROPIC_AUTH_TOKEN: local-test-token } }其中ANTHROPIC_BASE_URL指向调度层的地址而不是直接指向某台 NUC。ANTHROPIC_AUTH_TOKEN是调度层定义的令牌用于区分请求来源。Claude Code 不管这个令牌是不是 Anthropic 签发的它只负责带在请求头里。如果使用命令行验证也可以临时注入export ANTHROPIC_BASE_URLhttp://scheduler-ip:8787 export ANTHROPIC_AUTH_TOKENlocal-test-token claude4.3 模型名的处理策略Claude Code 启动后会读取模型配置。在本地场景里最稳妥的方式是让 Claude Code 使用一个合法的 Anthropic 模型名例如claude-sonnet-4-20250514然后在调度层把该名称映射为某个 Ollama 模型。这样 Claude Code 端不会报模型名无法识别调度层也能准确知道自己该把请求路由到哪里。如果通过/model命令切换模型同样保持 Claude Code 侧的模型名在它认识的范围内调度层再决定这个名称对应哪个本地模型。4.4 验证通路此时 Claude Code 启动后会向http://scheduler-ip:8787/v1/messages发请求。如果调度层还没有实现启动后会出现连接失败或 404。这是正常现象下一步就来实现调度层。5. 实现 Yeschef 调度层协议转换和节点路由5.1 调度层要处理的核心问题调度层本质上是一个带路由能力的协议适配器。它需要处理四件事接收 Claude Code 发来的 Anthropic Messages 请求。根据模型名映射到具体节点和 Ollama 模型名。把 Anthropic 请求体转换成 Ollama/api/chat请求。把 Ollama 的 NDJSON 流式响应转换成 Anthropic SSE 流返回。下面用 Python 和 FastAPI 实现最小版本。这个示例用于说明核心思路实际项目要结合自己的包名、路径和版本调整并补充异常处理、认证、日志和配置外置化。5.2 路由表与模型映射路由表用一个独立文件管理方便不重启服务就调整映射关系# routes.py ROUTE_TABLE { # Claude Code 认识的模型名 - (Ollama 节点地址, 本地模型名) claude-sonnet-4-20250514: (http://nuc-01:11434, qwen3:32b), claude-3-5-haiku-latest: (http://nuc-02:11434, llama3.2:3b), claude-3-opus-latest: (http://nuc-03:11434, qwen2.5:14b), }路由表是关键配置。它把 Claude Code 侧的模型名和局域网内的 Ollama 节点解耦。以后想换本地模型只需要修改这张表不需要改 Claude Code 配置。5.3 FastAPI 入口接收 Anthropic 请求# main.py import json import httpx from fastapi import FastAPI, Request from fastapi.responses import StreamingResponse from routes import ROUTE_TABLE app FastAPI() def select_node(model_name: str): if model_name in ROUTE_TABLE: base_url, local_model ROUTE_TABLE[model_name] return base_url, local_model # 未匹配时回退到默认节点避免直接报错 return http://nuc-01:11434, qwen3:32b app.post(/v1/messages) async def dispatch(request: Request): body await request.json() base_url, local_model select_node(body.get(model, )) ollama_payload build_ollama_payload(body, local_model) # 转发到目标 Ollama 节点 async with httpx.AsyncClient(timeout300) as client: upstream await client.post( f{base_url}/api/chat, jsonollama_payload, ) if upstream.status_code ! 200: return StreamingResponse( iter([json.dumps({error: upstream.text})]), status_code502, media_typeapplication/json, ) # 这里应当改为流式转发下面单独说明 return StreamingResponse( upstream.aiter_text(), media_typetext/event-stream, )上面的代码只完成了转发但 Ollama 返回的是 NDJSON不是 Anthropic SSE直接转发 Claude Code 无法解析。所以必须做格式转换。5.4 请求体转换Anthropic 到 OllamaAnthropic Messages 和 Ollama Chat 请求结构不同需要转换的主要字段如下Anthropic 请求字段Ollama 请求字段说明modelmodel由路由表映射后的本地模型名messages[].content字符串或块数组messages[].content文本需要拍平拆块systemsystem系统提示单独传max_tokensoptions.num_predict控制最大生成 token 数streamstream两个体系都有流式模式不直接对应options.num_ctx控制上下文窗口按模型能力设置转换函数def build_ollama_payload(body: dict, local_model: str): system_parts [] messages [] for item in body.get(messages, []): role item.get(role) content item.get(content, ) if role system: if isinstance(content, str): system_parts.append(content) continue if isinstance(content, str): messages.append({role: role, content: content}) continue # content 是块数组时只提取文本块工具块按需处理 text_parts [] for block in content: if block.get(type) text: text_parts.append(block.get(text, )) messages.append({role: role, content: \n.join(text_parts)}) options { num_predict: body.get(max_tokens, 2048), num_ctx: 8192, } return { model: local_model, messages: messages, system: \n.join(system_parts), stream: True, options: options, }注意如果 Claude Code 的请求里有工具调用块真实项目需要把tool_use和tool_result保留或转换为 Ollama 模型支持的工具格式。不同模型对工具调用的 JSON 结构要求不同这一层往往是适配工作量最大的地方。5.5 流式响应转换Ollama NDJSON 转 Anthropic SSEOllama 流式返回的是 JSON Lines每行一个 JSON 对象文本在message.content字段里。Anthropic SSE 则要求按content_block_delta、message_delta、message_stop等事件返回。def convert_stream(upstream): async def generator(): async for line in upstream.aiter_lines(): if not line.strip(): continue data json.loads(line) delta data.get(message, {}).get(content, ) if delta: yield event: content_block_delta\n yield fdata: {json.dumps({type: content_block_delta, delta: {type: text_delta, text: delta}})}\n\n if data.get(done): yield event: message_delta\n yield fdata: {json.dumps({type: message_delta, delta: {stop_reason: end_turn}})}\n\n yield event: message_stop\n yield data: [DONE]\n\n return generator()然后在dispatch中使用async with httpx.AsyncClient(timeout300) as client: async with client.stream( POST, f{base_url}/api/chat, jsonollama_payload ) as resp: if resp.status_code ! 200: ... return StreamingResponse( convert_stream(resp), media_typetext/event-stream, )这里最关键的是保持流式特性。不要在调度层把整个响应读完再返回否则用户会感觉“要等全部生成完才开始输出”丢失了流式体验。5.6 健康检查与简单的负载选择多节点路由要避免把请求发给已经挂掉或过热的节点。调度层可以定期访问每个节点的/api/ps和/api/tags做健康检查。async def check_health(base_url: str): try: async with httpx.AsyncClient(timeout3) as client: resp await client.get(f{base_url}/api/ps) return resp.status_code 200 except Exception: return False完整的健康检查还要考虑模型是否加载、是否处于饱和状态、连续请求延迟是否变高等指标。一个简单策略是每 10 秒检查一次节点可用性并在路由选择时跳过不健康的节点如果所有节点都不可用调度层返回 503并在响应头里带上诊断信息。5.7 启动调度层pip install fastapi uvicorn httpx uvicorn main:app --host 0.0.0.0 --port 8787调度层启动后先用curl做一次非流式验证curl http://scheduler-ip:8787/v1/messages \ -H Content-Type: application/json \ -H x-api-key: local-test-token \ -H anthropic-version: 2023-06-01 \ -d { model: claude-sonnet-4-20250514, max_tokens: 64, messages: [{role: user, content: 你好回复一句话} ]}如果返回的是 SSE 格式文本并且能看到content_block_delta事件说明链路已经打通。6. 跑通最小演示并测量吞吐6.1 端到端验证调度层启动后进入 Claude Codeclaude在交互界面里输入一个简单问题例如请列出当前目录下的文件并解释每个文件的作用。正常情况下Claude Code 会先调用工具读取目录然后把结果发送给调度层调度层转换后交给某台 NUC 上的 Ollama 模型生成文本后再经调度层返回。这个链路如果通了说明三层架构基本成立。6.2 用压测脚本计算聚合吞吐627 tok/s 的验证不能靠人工观察需要脚本统计。思路是并发发送多个流式请求统计每个请求生成的 token 数总和再除以总耗时。import asyncio import time import json import httpx async def send_one(client, index): payload { model: claude-sonnet-4-20250514, max_tokens: 256, messages: [{role: user, content: 写一段 100 字左右的技术说明介绍 HTTP 和 WebSocket 的区别}] } tokens 0 start asyncio.get_event_loop().time() async with client.stream(POST, http://127.0.0.1:8787/v1/messages, jsonpayload) as resp: async for line in resp.aiter_lines(): if not line.startswith(data: ): continue data line[6:] if data [DONE]: break try: obj json.loads(data) except json.JSONDecodeError: continue delta obj.get(delta, {}) if isinstance(delta, dict) and delta.get(type) text_delta: tokens len(delta.get(text, )) cost asyncio.get_event_loop().time() - start return tokens, cost async def main(): total_tokens 0 max_cost 0.0 async with httpx.AsyncClient(timeout300) as client: results await asyncio.gather(*[send_one(client, i) for i in range(8)]) for tokens, cost in results: total_tokens tokens max_cost max(max_cost, cost) print(f总 token 数: {total_tokens}) print(f最快请求耗时: {max(results[0][1] for results in [results]):.2f}s) print(f聚合吞吐: {total_tokens / max_cost:.2f} tok/s) asyncio.run(main())这里用字符数近似 token 数只用于整体估算。更精确的做法是读取 Ollama 每个流式响应末尾的eval_count字段把它累加起来。6.3 627 tok/s 的结果解读如果得到的聚合吞吐在 600 tok/s 左右说明三台 NUC 的推理资源基本被用起来了。此时单次请求的响应速度可能仍然不算快因为单个请求只落在某一台节点上聚合吞吐是多节点并行带来的。测试时要注意变量一致。模型相同、量化相同、并发数相同数据才有可比性。影响吞吐的常见因素包括模型参数量和量化级别。并发请求数OLLAMA_NUM_PARALLEL是否调大。生成长度。短文本生成无法充分体现吞吐。机器是否降频。连续压测时散热不足会导致吞吐逐步下降。7. 常见问题排查从三层链路定位故障7.1 先确定问题在哪一层整套系统有三层Claude Code、调度层、Ollama 节点。排查问题的顺序应该是先看 Claude Code 到调度层是否通再看调度层到 Ollama 是否通最后看模型本身是否正常工作。问题现象优先排查层检查项Claude Code 启动就报模型名无法识别Claude Code模型名是否在支持范围内请求发出后长时间无响应调度层是否有请求进入日志路由表是否匹配调度层返回 404Ollama 节点/api/chat是否存在模型名是否写错连接被拒绝Ollama 节点OLLAMA_HOST是否设为 0.0.0.0返回内容乱码调度层和终端编码是否为 UTF-8流式拼接是否有误7.2 Ollama 连接被拒绝现象curl: (7) Failed to connect to 192.168.x.x port 11434: Connection refused检查顺序ss -tlnp | grep 11434 curl http://127.0.0.1:11434/api/tags如果本机能访问但其他机器不能检查OLLAMA_HOST是否仍是127.0.0.1以及防火墙是否放行 11434 端口。7.3 模型名无法识别Claude Code 报xxx is not a model this version of claude code recognizes时本质是 Claude Code 在本地做模型名校验请求还没到达调度层。解决方式不要试图让 Claude Code 接受一个本地模型名而是让 Claude Code 使用它能识别的模型名然后在调度层路由表里做映射。7.4 调度层返回 502 或 404如果 Claude Code 能看到错误码排查调度层日志。常见原因路由表里的节点地址写错。Ollama 节点上没有该模型/api/chat返回 404。请求体转换后缺少必填字段。在调度层临时加上日志把select_node的结果和 Ollama 返回的状态码打出来能快速定位。7.5 请求被 Killed 或进程退出Ollama 日志里如果出现plugindaemoninternalservererror: killed通常说明内存不足模型加载时被系统 OOM Killer 终止。检查本机可用内存和模型大小free -h ollama list解决方案是使用更小的量化模型、减少OLLAMA_NUM_PARALLEL或增大机器内存。不要为了并发把内存耗尽。7.6 中文乱码如果 Claude Code 终端或调度层返回的中文乱码先确认终端编码是 UTF-8locale再检查调度层转发 SSE 时是否有截断或分块拼接问题。Ollama 流式返回的每一行都是一个完整 JSON不要在调度层按固定字节切分也不要尝试把多个 chunk 手动拼接后再编码否则容易出现半个字被截断的乱码。7.7 局域网访问不稳定如果 NUC 使用无线网卡长时间推理时吞吐波动大优先换成有线网络。部分 Realtek 无线网卡在功率管理开启时会出现延迟抖动可以在系统层面检查无线网卡驱动和电源管理策略但最省事的方案还是网线直连交换机。8. 生产化和扩展方向8.1 从演示到可用的三个步骤当前示例只是最小链路真实使用还需要补齐三件事第一认证。调度层不应该对所有局域网请求开放。可以在请求头校验自定义 token并在多次认证失败后记录日志。第二日志和监控。为三个环节分别打日志Claude Code 请求到达时间、调度层转发节点、Ollama 返回状态码和耗时。用 Prometheus 收集/api/ps的模型加载状态也不错但要先保证基础日志能帮助定位问题。第三配置外置化。路由表、模型名映射、节点地址不要写死在代码里。建议用 YAML 管理routes: - claude_model: claude-sonnet-4-20250514 node: http://nuc-01:11434 ollama_model: qwen3:32b max_tokens: 4096调度层启动时加载这份配置变更后重新加载即可不需要改代码。8.2 模型策略同一模型多副本还是多个模型如果开发团队主要做通用编码任务建议让三台 NUC 都加载同一个能力较强的模型形成三副本调度层按负载分发。这种方式能最大化并发吞吐缺点是模型种类单一。如果团队经常需要在“快速回复”和“复杂分析”之间切换更适合不同节点跑不同模型。调度层根据请求模型名选择节点小任务落到小模型复杂任务落到大模型。8.3 学习环境和生产环境差异学习环境可以一台 NUC 一台机器地扩展先两台节点跑通再加第三台。生产环境必须从一开始就考虑每个节点监控内存、温度、吞吐。调度层部署为 systemd 服务异常自动重启。路由变更走配置发布而不是直接改代码。增加熔断逻辑某节点连续超时后自动摘除。8.4 可复用的部署检查清单检查项命令或位置预期结果Ollama 监听局域网地址ss -tlnp | grep 11434显示 0.0.0.0:11434节点模型列表可用curl http://nuc-ip:11434/api/tags返回 models 数组调度
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进