资讯动态

局域网自建AI Agent平台:Docker部署本地大模型与编排服务实战

发布时间:2026/10/14 11:53:20 来源:尧图企业网站定制
1. 为什么要在局域网里自建 AI Agent 平台1.1 从调用云端 API到把模型搬进机房的转变过去一年我身边不少做企业内部工具的朋友都经历了同一个心路历程一开始图省事直接调用公有云的大模型接口写几行代码就能跑通对话。但真到了要落地到业务场景里问题就一个接一个冒出来——数据不能出内网、调用量一大成本失控、网络抖动导致响应超时、敏感业务日志不敢往外部传。尤其是做制造业、医疗信息化、金融后台这类对数据边界极其敏感的行业把原始业务数据送到公网模型上本身就是一道过不去的坎。于是局域网自建 AI Agent 平台这个需求就变得非常实在。所谓 AI Agent不是简单的聊天机器人而是能调用工具、读写本地文件、查询内部数据库、按流程执行多步任务的智能体。它需要一个能稳定运行模型推理服务、能挂载工具链、能管理会话与记忆的运行时环境。而 Docker 恰好是承载这套运行时最省心的方式——镜像一次构建到处运行依赖全打包环境不污染宿主机。这篇内容要聊的就是怎么用 Docker 把一套本地大模型推理服务加上 Agent 编排层部署到一台普通的局域网服务器上让内网里的同事通过浏览器或内网 API 就能用上自己的 AI Agent。整套方案不依赖任何外部网络模型权重、对话记录、工具调用全部留在你自己的机器里。1.2 这套方案适合谁能解决什么问题先说清楚适用人群。如果你是完全没碰过 Linux 和命令行的纯小白这篇会让你有点吃力但跟着步骤走也能跑起来如果你是有一定运维或后端基础的开发者那基本可以当作一份可复现的部署手册来用。典型的使用场景包括团队内部想有一个统一的 AI 助手入口但不想每个人都去申请外部账号需要让模型读取内网文档、知识库做私有化的问答想研究 Agent 的工具调用机制需要一个可以随便折腾、不怕搞坏线上环境的沙箱预算有限只有一台带独立显卡或者内存够大的普通服务器。它解决的核心问题就三个字可控性。模型在哪跑、数据存哪、谁能访问、调用多少次全部由你自己说了算。下面我会从整体架构讲到具体落地把每一步的取舍逻辑都摊开说。2. 整体架构设计与方案选型思路2.1 三层结构推理层、编排层、接入层一套完整的局域网 AI Agent 平台我习惯把它拆成三层来看这样排查问题和做扩展的时候思路会清晰很多。推理层负责真正跑大模型对外暴露一个兼容 OpenAI 格式的 HTTP 接口。这一层的关键是选一个推理引擎把模型权重加载进显存或内存然后高效地处理并发请求。常见的选择有基于 llama.cpp 的轻量方案、vLLM 这类高吞吐方案以及 Ollama 这种开箱即用的封装。局域网自建场景下我一般推荐 Ollama 或者 vLLM前者胜在简单后者胜在并发性能。编排层是 Agent 的大脑负责接收用户输入、决定要不要调用工具、维护多轮对话的上下文、把工具执行结果再喂回模型。这一层通常是一个 Python 服务用 FastAPI 之类的框架写内部对接推理层的接口。它还要管理记忆——短期的是当前会话的上下文窗口长期的可能落到向量数据库里做检索增强。接入层就是用户看到的东西可以是一个网页聊天界面也可以是内网其他系统调用的 REST 接口。这一层要做的是鉴权、限流、会话隔离保证不同用户的对话不会串。三层之间通过 Docker 网络互联各自是独立的容器。这样做的好处是任何一层要升级或替换都不会牵动其他两层。比如你哪天想把推理引擎从 Ollama 换成 vLLM只要接口格式保持一致编排层几乎不用改。2.2 为什么用 Docker 而不是直接装宿主机有人会问就一台服务器直接 pip install 装上去不就行了何必套一层 Docker我踩过的坑告诉我Docker 在这里的价值远超多一层封装的成本。第一是依赖隔离。推理引擎对 CUDA 版本、Python 版本、系统库版本极其挑剔而 Agent 编排层可能又依赖另一套 Python 包。直接装在宿主机上两边的依赖很容易打架升级一个搞崩另一个。容器化之后各管各的互不干扰。第二是可复现。你今天在这台机器上跑通了明天换一台配置类似的机器只要 Docker 和驱动装好docker compose up一敲就起来了不用重新回忆当初装了哪些包、改了哪些配置。第三是资源可控。Docker 可以限制每个容器的 CPU、内存占用避免推理服务把整台机器的内存吃光导致 SSH 都连不上。这在只有一台服务器的场景下特别重要。第四是清理方便。实验失败想推倒重来删掉容器和镜像就行宿主机干干净净不会留下一堆散落的配置文件。注意GPU 直通到容器需要宿主机装好对应的显卡驱动和容器运行时工具包这一步是整套方案里最容易卡住的地方后面会单独讲。2.3 硬件与网络的前置判断在动手之前先做个现实评估。模型能不能跑得动取决于你的硬件。一个粗略的经验值7B 参数量的模型用 4-bit 量化后大约需要 4 到 6GB 显存13B 量化后大概 8 到 10GB再往上 30B 级别的没有 24GB 显存基本别想流畅。如果只有 CPU也不是不能跑但 7B 量化模型在普通服务器 CPU 上大概每秒只能吐几个字做演示可以做生产力工具就勉强了。网络方面局域网部署意味着所有访问都走内网 IP。你需要确认服务器的内网地址是固定的静态 IP 或者 DHCP 保留否则重启后 IP 一变大家的书签就全失效了。端口方面推理服务、编排服务、Web 界面各占一个端口规划好别冲突。3. 环境准备与 Docker 基础配置3.1 宿主机系统与驱动检查我一般选 Ubuntu 22.04 或 24.04 作为宿主机系统社区资料最全踩坑时容易搜到答案。装好系统后第一件事是确认显卡驱动正常。执行nvidia-smi如果能看到显卡型号、驱动版本、显存占用说明驱动没问题。如果提示命令找不到就得先装驱动。驱动装好后还要装容器访问 GPU 需要的运行时。这一步很多人会漏导致容器里死活看不到显卡。装完之后用一条测试命令验证跑一个带 CUDA 的基础镜像进去执行nvidia-smi能输出就说明直通成功。# 验证容器内能否访问 GPU docker run --rm --gpus all nvidia/cuda:12.4.0-base-ubuntu22.04 nvidia-smi如果这条命令报错说找不到--gpus参数说明 Docker 版本太老升级一下即可。如果报错说没有可用的设备那就是运行时没配好回头检查驱动和运行时安装步骤。3.2 Docker 与 Compose 的安装要点Docker 的安装我强烈建议走官方源不要用系统自带的旧版本。旧版本对 GPU 支持和 Compose V2 的兼容性都有问题。装完之后确认两件事docker compose version能输出版本号注意是带空格的docker compose不是老的docker-compose以及当前用户已经加入 docker 组否则每条命令都要 sudo很烦。# 把当前用户加入 docker 组之后重新登录生效 sudo usermod -aG docker $USERCompose 文件我习惯放在一个专门的目录里比如/opt/ai-agent/里面再分data、models、config几个子目录。模型权重文件体积大单独挂载出来这样重建容器时不用重新下载。数据目录挂载出来保证对话记录、向量库不会随容器删除而丢失。3.3 目录规划与数据持久化设计目录结构设计得好后期维护省一半力气。我的习惯是这样/opt/ai-agent/ ├── docker-compose.yml ├── config/ │ ├── agent.env │ └── nginx.conf ├── data/ │ ├── ollama/ # 模型权重缓存 │ ├── agent/ # 会话与记忆数据 │ └── vectordb/ # 向量库持久化 └── logs/关键在于所有会变的数据都挂载到宿主机。容器本身是无状态的随时可以删了重建。模型权重放在data/ollama里第一次拉取后就有了之后重建容器直接复用不用重新下载几个 G。会话数据放在data/agent用户的历史对话不会因为一次升级就丢失。提示挂载目录的权限要注意。容器内进程往往以非 root 用户运行如果宿主机目录权限是 root 独占容器写不进去。提前用chown把目录归属调整好能省掉后面一堆权限拒绝的报错。4. 推理层部署把模型跑起来4.1 推理引擎选型对比推理层是整个平台的地基选错了后面全是麻烦。我把几个主流方案拉出来对比一下方便你按自己的场景选。方案部署难度并发性能显存效率适合场景Ollama极低中等中等快速验证、单用户、小团队vLLM中等高高多用户并发、生产环境llama.cpp 服务中等中等高CPU 为主、资源受限其他封装方案低视实现视实现特定硬件适配我的建议是先用 Ollama 把整条链路跑通验证可行性等确认要长期用了再考虑换 vLLM 提升并发。因为 Ollama 的接口和 OpenAI 格式兼容编排层不用改代码就能切换迁移成本很低。4.2 用 Compose 定义推理服务下面是一段我实际在用的 Compose 配置做了精简。核心是把 GPU 直通、模型目录挂载、端口映射三件事配好。services: ollama: image: ollama/ollama:latest container_name: ai-ollama restart: unless-stopped ports: - 11434:11434 volumes: - ./data/ollama:/root/.ollama environment: - OLLAMA_KEEP_ALIVE24h - OLLAMA_NUM_PARALLEL2 deploy: resources: reservations: devices: - driver: nvidia count: all capabilities: [gpu]几个参数值得解释。OLLAMA_KEEP_ALIVE24h让模型常驻显存避免每次请求都重新加载否则第一次响应会慢到让人怀疑人生。OLLAMA_NUM_PARALLEL2控制并发处理的请求数设太大显存扛不住设太小又浪费。这个值要根据你的显存和模型大小调7B 模型配 2 到 4 比较稳妥。restart: unless-stopped保证服务器重启后容器自动拉起不用人工干预。deploy.resources那段是 GPU 直通的关键count: all表示把所有可见的显卡都给这个容器。4.3 拉取模型与验证推理接口容器起来之后进容器拉模型。模型的选择上7B 级别的通用模型在中文场景下表现已经够用如果显存充裕可以上更大的。拉取命令在容器内执行docker exec -it ai-ollama ollama pull 模型名拉完之后验证一下接口通不通curl http://localhost:11434/api/generate -d { model: 模型名, prompt: 用一句话介绍你自己, stream: false }能返回一段正常的文本说明推理层就绪。如果卡住不动多半是模型还在加载等一会儿再试。如果报显存不足就得换更小的模型或者更激进的量化版本。实操心得第一次拉模型时网络可能很慢如果宿主机本身访问外部资源受限可以提前在能联网的机器上把模型文件下好再拷贝到data/ollama目录里。Ollama 的模型存储结构是分层的直接拷贝整个目录通常能识别。5. 编排层搭建让模型变成 Agent5.1 Agent 编排的核心逻辑推理层只是会说话编排层才让它会做事。一个 Agent 的运转循环大致是这样接收用户消息连同历史上下文一起发给模型模型返回的内容里如果包含工具调用意图编排层就解析出来执行对应工具把结果再拼回上下文发给模型模型基于工具结果生成最终回复。这个循环可能重复多轮直到模型不再请求工具为止。工具可以是任何东西查内网数据库、读本地文件、调内部 API、做数学计算、搜索知识库。编排层要做的就是把这些能力注册成模型能理解的函数描述然后在运行时调度。5.2 用 Python 写一个最小可用的编排服务下面这段代码是一个极简的编排服务骨架用 FastAPI 暴露接口内部对接推理层。它演示了工具调用的基本流程实际用的时候按需扩展。from fastapi import FastAPI from pydantic import BaseModel import httpx, json app FastAPI() INFER_URL http://ollama:11434/api/chat MODEL 模型名 # 注册可用工具 TOOLS [ { type: function, function: { name: get_internal_doc, description: 根据关键词查询内网知识库文档, parameters: { type: object, properties: {keyword: {type: string}}, required: [keyword], }, }, } ] def run_tool(name, args): if name get_internal_doc: # 这里替换成真实的检索逻辑 return f关于 {args[keyword]} 的文档内容…… return 未知工具 class ChatReq(BaseModel): message: str history: list [] app.post(/chat) async def chat(req: ChatReq): messages req.history [{role: user, content: req.message}] async with httpx.AsyncClient(timeout120) as client: resp await client.post(INFER_URL, json{ model: MODEL, messages: messages, tools: TOOLS, stream: False }) data resp.json() msg data[message] # 如果模型请求调用工具 if msg.get(tool_calls): for call in msg[tool_calls]: result run_tool(call[function][name], call[function][arguments]) messages.append(msg) messages.append({role: tool, content: result}) async with httpx.AsyncClient(timeout120) as client: resp await client.post(INFER_URL, json{ model: MODEL, messages: messages, stream: False }) data resp.json() return {reply: data[message][content]}这段代码的价值在于把模型请求工具 → 执行 → 回喂这个循环讲清楚了。真实项目里工具注册、参数校验、错误处理、超时控制都要做得更细但骨架就是这个样子。5.3 容器化编排服务与网络互联编排服务同样用 Compose 管理关键是让它和推理服务在同一个 Docker 网络里这样可以直接用服务名互相访问不用管 IP。agent: build: ./agent container_name: ai-agent restart: unless-stopped ports: - 8000:8000 volumes: - ./data/agent:/app/data environment: - INFER_URLhttp://ollama:11434 depends_on: - ollama注意INFER_URL里写的是ollama这个服务名而不是localhost。在 Compose 创建的网络里服务名会自动解析成对应容器的地址。这是容器编排最方便的地方之一服务之间不用关心对方的真实 IP。depends_on保证启动顺序先起推理服务再起编排服务。不过它只保证容器启动顺序不保证推理服务已经加载完模型所以编排层里最好加个重试逻辑第一次请求失败时等几秒再试。6. 接入层与局域网访问配置6.1 Web 界面还是纯 API接入层怎么选取决于你的用户是谁。如果只是自己或者几个技术同事用直接暴露 API 加一个简单的网页就够了。如果要给非技术同事用那就需要一个像样的聊天界面支持多会话、历史记录、Markdown 渲染。现成的开源聊天前端不少很多都支持配置自定义的后端地址。把它们也容器化通过 Nginx 统一入口是最省事的做法。Nginx 在这里承担反向代理的角色把/api转发到编排服务把/转发到前端静态资源。6.2 Nginx 反向代理配置server { listen 80; server_name _; location /api/ { proxy_pass http://agent:8000/; proxy_set_header Host $host; proxy_read_timeout 300s; } location / { proxy_pass http://webui:3000/; } }proxy_read_timeout 300s这个参数很关键。大模型生成回复可能耗时几十秒甚至更久默认的 60 秒超时会导致请求被掐断用户看到的就是网络错误。把它调大让长回复能完整返回。6.3 内网访问与基础鉴权局域网访问意味着任何能连到这台服务器的人都能用。如果只是内部小范围使用问题不大但如果网络里有不受信任的设备就得加一层鉴权。最简单的做法是在 Nginx 层加 HTTP Basic Auth配置几行就能挡住大部分误访问。# 生成密码文件 htpasswd -c ./config/.htpasswd 用户名然后在 Nginx 的 location 里加上auth_basic和auth_basic_user_file两行即可。更严格的做法是接入内网的统一认证但那涉及组织内部的账号体系这里就不展开了。注意不要把服务端口直接暴露到公网。局域网自建的初衷就是数据不出内网一旦映射到公网前面的努力全白费。确认防火墙规则只放行内网网段。7. 常见问题与排查技巧实录7.1 部署阶段高频问题速查现象可能原因排查方向容器内看不到 GPU运行时未装或未配检查驱动与容器运行时模型加载报显存不足模型太大或并发太高换小模型或降并发首次响应极慢模型未常驻显存设置 keep-alive请求超时中断代理超时太短调大 read timeout容器写数据失败挂载目录权限不对调整目录归属服务间连不上不在同一网络检查 Compose 网络配置这张表基本覆盖了我遇到过的八成问题。下面挑几个展开说。7.2 显存不足的几种应对显存不足是最常见的拦路虎。除了换更小的模型还有几个办法。一是用更激进的量化比如从 8-bit 降到 4-bit显存占用能砍掉一半代价是精度略有下降但日常对话基本感知不到。二是限制并发数把OLLAMA_NUM_PARALLEL降到 1牺牲并发换稳定。三是限制上下文长度上下文越长占用的显存越多把默认的上下文窗口调小能省不少。如果这些都不够那就只能上 CPU 推理或者加显卡了。CPU 推理的配置思路和 GPU 类似只是不需要 GPU 直通那段把模型换成量化版本速度会慢但能跑。7.3 响应慢的定位思路响应慢要分清楚是首字慢还是整体慢。首字慢通常是模型加载或 prompt 处理耗时解决办法是让模型常驻显存以及精简系统提示词。整体慢则是生成速度问题取决于硬件算力只能靠换硬件或换更小的模型。还有一个容易被忽略的点如果编排层每次请求都重新建立到推理层的连接握手开销也会累积。用连接池复用连接能省下这部分时间。httpx 的 AsyncClient 默认就带连接池但要注意别每次请求都新建一个 client 实例。7.4 数据持久化的坑我见过有人升级容器时直接把旧容器删了结果对话记录全没了。原因就是数据没挂载出来存在容器可写层里容器一删数据就没了。所以再强调一遍所有需要保留的数据必须挂载到宿主机。模型权重、会话数据、向量库、日志一个都不能少。另外挂载目录如果被多个容器同时写要注意并发问题。比如两个编排服务实例共用一个 SQLite 文件很容易锁冲突。这种场景要么改用支持并发的数据库要么保证只有一个写实例。8. 性能调优与后续扩展方向8.1 让平台跑得更顺的几个调优点平台能跑起来只是第一步跑得顺才是目标。几个我实测有效的调优点模型常驻。前面提过的 keep-alive 一定要设否则每次冷启动的等待时间会让人崩溃。上下文裁剪。多轮对话历史无限增长会拖慢推理也吃显存。设置一个上限超过就丢弃最早的几轮或者做摘要压缩。摘要压缩的做法是让模型把早期对话总结成一段话既保留信息又控制长度。批处理。如果并发请求多vLLM 这类支持连续批处理的引擎能显著提升吞吐。Ollama 的批处理能力弱一些但小团队够用。缓存。相同或相似的问题反复问可以加一层语义缓存命中就直接返回不消耗算力。简单的做法是对问题做向量化相似度超过阈值就复用答案。8.2 从单机到多机的演进单机跑久了总会遇到瓶颈。要么是显存不够要么是并发扛不住。这时候可以考虑把推理层独立出去放到专门的推理服务器上编排层和接入层留在原来的机器。Compose 里把INFER_URL指向新的地址即可改动很小。再往上推理层本身也可以做多实例前面加一个负载均衡。多个推理实例共享同一个模型存储请求分发到不同实例上。这种架构下编排层要处理实例故障转移复杂度会上升但扩展性也上去了。8.3 安全与权限的持续加固局域网不等于绝对安全。随着使用人数增加权限管理会越来越重要。至少要做的几件事给每个用户分配独立的会话空间防止互相看到对话对工具调用做权限校验不是所有人都能查敏感数据记录操作日志出问题能追溯。工具调用的权限尤其要注意。一个能读文件系统的工具如果被恶意 prompt 诱导可能读到不该读的文件。所以工具的实现里要做路径白名单只允许访问指定目录。这类防护在自建平台里往往被忽略但一旦出事就是大事。9. 我在这套方案里踩过的几个真实坑最后分享几个只有实际动手才会遇到的细节文档里通常不会写。第一个坑是模型名的大小写和标签。不同来源的模型命名规则不一样有的带:latest标签有的不带。编排层里写死的模型名如果和推理层实际拉取的不一致请求会直接报模型不存在。解决办法是拉取后先用ollama list确认准确名称再填到配置里。第二个坑是Docker 网络的 DNS 缓存。容器重建后 IP 会变但有些客户端会缓存旧的解析结果导致连不上。遇到这种情况重启一下依赖它的容器通常能解决。更稳妥的做法是在编排层里用服务名而不是 IP让 Docker 的 DNS 每次重新解析。第三个坑是磁盘空间。模型文件动辄几个 G加上日志和向量库磁盘很快就满了。我建议单独给数据目录挂一块盘并且设置日志轮转别让日志无限增长。定期清理不用的模型镜像也能释放不少空间。第四个坑是时区和编码。容器默认可能是 UTC 时区日志时间对不上中文处理时如果编码没设对会出现乱码。在 Compose 里加上TZ环境变量Python 服务里显式指定 UTF-8能避免这类问题。这套平台我从最初的一台旧服务器折腾到现在稳定运行中间推倒重来过好几次。最大的体会是先把最小链路跑通再逐步加功能。一上来就想把工具链、向量库、多用户全配齐很容易在某个环节卡住然后失去信心。先用一个模型加一个简单接口验证可行性跑通了再往上叠每一步都有正反馈整个过程会顺畅很多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑