资讯动态

Docker搭建局域网私有AI Agent平台:DeepSeek Harness实战

发布时间:2026/10/15 12:03:57 来源:尧图企业网站定制
搭建局域网里的私有 AI Agent 平台听起来是个挺“重”的活但用 Docker 把 DeepSeek Harness 拉起来之后整个流程比我想象中轻太多。这篇文章不聊虚的直接从我的实际部署经历出发把从容器编排到服务调通的完整链路拆开讲清楚包括那些文档里不会写的坑和参数取舍。如果你也有一台闲置的 Linux 机器或者一块还不错的显卡想在办公室或实验室局域网里跑一套属于自己的 Agent 服务这篇应该能帮你省掉至少一个周末的折腾时间。1. 项目定位与整体思路拆解1.1 为什么需要在局域网里部署 AI Agent先说需求背景。现在各种在线 AI 服务确实方便但把内部数据、对话记录、工具调用全部交给云端很多团队心里是不踏实的。尤其涉及代码仓库、运维脚本、内部知识库这类敏感内容时更稳妥的做法是让模型服务跑在自己的网络里所有请求不出内网。DeepSeek Harness 本质上是一套封装好的 AI Agent 运行环境它把模型推理、工具调用、记忆存储、对话管理这些能力打包成了可以独立运行的服务天然适合用 Docker 做隔离和编排。我在某公司做内部工具链的时候最头疼的就是“算法团队给的模型 demo 跑得飞起但没人能把它变成稳定服务”。Harness 这类方案解决的就是这个问题它把 Agent 前后端、推理引擎、依赖环境都容器化部署方只需要关心端口映射和数据卷挂载。局域网部署的核心诉求有三个。第一是数据不出网所有推理请求和工具执行都在本地完成第二是统一入口团队里不同角色通过同一个 Web 界面或 API 使用能力而不是各跑各的脚本第三是资源可控通过容器限额把显卡显存和内存分配死避免某个任务把整台机器拖垮。从架构角度看这是一个典型的“调度层 执行层 存储层”拆分。调度层负责接收请求、路由到对应 Agent、管理会话状态执行层是真正跑模型推理和工具调用的部分通常包含多个可横向扩展的工作节点存储层则是向量数据库和对象存储用来保存知识库切片和对话历史。Docker Compose 之所以适合这个场景是因为它能在一台机器上用声明式配置把这三个层面全部拉起并且每条服务之间的网络通信由 Compose 自动处理。1.2 为什么选择 Docker 而不是裸机部署很多人在评估阶段会犹豫直接在一台机器上装 Python 环境、装 CUDA、拉模型权重然后手动启动服务看起来更直接。我一开始也这么想直到被依赖地狱折磨了一遍。裸机部署的问题在于不可复现。换一台机器、换一个显卡驱动版本、甚至换一个 Python 小版本都可能导致推理引擎起不来。而 Docker 把运行环境跟宿主机隔离镜像里装好所有依赖同一个镜像在任何支持 Docker 的机器上行为一致。这对于团队协作尤其重要——我在那台机器上验证通过的配置直接打包成镜像伙伴在另一台机器上拉下来就能跑。另一个关键因素是升级回滚。DeepSeek Harness 迭代很快模型版本、Agent 框架版本、前端面板版本经常要同步更新。用 Docker 的话我可以同时保留两个版本的镜像切换时只需改一行 compose 配置再docker compose up -d一旦发现新版本有问题把配置回退再重启一次就完成回滚。裸机部署的话卸载旧版本这件事本身就能让人崩溃。1.3 整体架构和核心组件拆解我最终落地的架构包含五个容器分工如下网关容器统一接收 HTTP 请求做路由转发、鉴权、限流所有外部访问只经过这一个入口。推理服务容器加载模型权重提供 OpenAI 兼容的推理接口是真正消耗显卡资源的部分。Agent 编排容器负责工具注册、任务规划、上下文管理相当于整个平台的大脑。向量存储容器提供知识库的向量化和相似度检索基于内存型向量数据库实现不依赖外部服务。前端面板容器提供 Web 操作界面让非开发人员也能通过页面与 Agent 交互。这五个容器通过 Docker 内部网络互联对外只暴露网关和前端两个端口。推理服务由于需要访问宿主机 GPU使用了特殊的容器运行时而其他容器保持轻量级避免每个容器都背上 CUDA 依赖。从资源分配角度推理服务容器分配了大部分显存向量存储容器限制内存上限Agent 编排容器则吃 CPU 和内存为主。这个分配方式在后面调参时验证是合理的真正吃资源的是推理和向量检索编排逻辑本身开销不大。2. 环境准备与容器编排设计2.1 硬件要求和你需要准备的东西先泼一盆冷水这套平台虽然容器化程度高但对硬件还是有一定要求的。得益于推理框架的优化和量化方案硬件门槛比我预想低不少。最低配置方面CPU 要求 8 核以上内存 32GB 起步系统盘建议 NVMe 且剩余空间至少 50GB。显卡是重点如果你打算跑 7B 级别的量化模型一张 12GB 显存的卡就够用要跑 14B 级别显存最好到 24GB。我实际使用的是一张 24GB 显存的卡跑量化后的 14B 模型非常从容上下文长度开到 32K 时显存占用大约 18GB 左右。如果完全不打算用 GPU纯 CPU 推理也能运行但我劝你放弃实时对话的幻想。7B 模型的量化版本在 CPU 上生成一个 token 大约需要 1-2 秒对话体验基本没法用。CPU 模式只适合跑批处理任务比如批量分析文档、定时生成摘要。软件层面需要准备的东西主要三个装了 Docker Engine 和 Compose 插件的 Linux 系统、NVIDIA 驱动以及对应的容器运行时工具包。这里有个容易踩的坑光装显卡驱动还不够Docker 默认运行时无法访问 GPU必须安装 NVIDIA 的容器工具包它会在 Docker 里注册一个新的运行时让容器内能看到宿主机显卡。验证显卡驱动是否正常的最快方式是运行nvidia-smi能正常输出显卡信息表就说明驱动层面没问题。然后测试容器 GPU 访问能力时我用了一个极小的 PyTorch 镜像去执行torch.cuda.is_available()返回 True 才继续下一步。这一步值得花时间确认因为后面推理服务起不来八成问题出在容器访问不到 GPU。2.2 Compose 编排设计要点整个部署的核心是一个docker-compose.yml文件。我在设计编排时坚持几个原则配置与镜像分离、数据卷独立、显式声明依赖关系。配置分离的意思是镜像里只放程序代码和基础依赖所有跟具体环境相关的配置模型路径、推理参数、知识库地址、密钥信息通过环境变量注入。这样同一个镜像在测试机和生产机上表现完全一致区别只是环境变量不同。数据卷独立是重中之重。模型权重、向量数据、对话记录、上传的文档这些全部要通过命名数据卷挂载绝不能写进容器可写层。容器重建是家常便饭如果数据写在容器层里一次docker compose down up操作就能让你的一切积累灰飞烟灭。我的数据卷划分是模型权重单独一个卷、向量数据一个卷、日志一个卷、用户上传内容一个卷。依赖关系的声明同样关键。Agent 编排容器依赖推理服务和向量存储向量存储又依赖初始化容器完成索引创建。Compose 的depends_on配合健康检查才能确保服务启动顺序正确。我踩过很深的坑就是在推理服务还没加载完模型时编排容器就开始发请求结果一堆超时错误。后来给推理服务加了健康检查端点编排容器等它返回 healthy 后才开始对外提供服务。2.3 网络模型选择独立网络还是共享宿主机网络网络模型我在部署时专门做了对比最终选择用 Compose 默认创建的桥接网络而不是host模式。桥接网络的好处是容器间通信走虚拟网络逻辑清晰端口不会跟宿主机冲突。容器通过服务名互相访问比如推理服务的地址是http://inference:8000这个 DNS 解析由 Docker 内建完成不需要记 IP。前端面板连接编排服务时也直接写服务名。host 模式乍一看性能更好因为少了 NAT 转发但代价是每个服务都直接用宿主机端口互相之间容易冲突而且 IP 绑定配置会很乱。实测下来桥接网络在单机场景的性能损失几乎可以忽略在千兆局域网里跑对话请求感受不到任何延迟差异。对外访问方面我只把网关端口和前端端口映射到宿主机0.0.0.0这样局域网内任何设备都能通过宿主机 IP 访问。推理服务、向量存储这类内部组件不映射端口外部根本摸不到攻击面小很多。3. 核心服务配置与关键参数3.1 推理服务配置模型加载与显存管理推理服务是整个平台里配置最讲究的部分。它负责加载模型权重、响应生成请求也是所有组件中唯一直接操作 GPU 的容器。模型加载方面我选择的是量化后的通用对话模型在帮助、编程和逻辑推理任务上表现均衡。部署时模型权重带在镜像内启动阶段加载到显存大约需要 1-2 分钟这个时间取决于磁盘读取速度和模型尺寸。显存管理是我重点调优的部分。推理框架提供显存自适应机制如果设置成自动模式它会根据请求负载动态增减显存占用这对共享机器很友好但缺点是响应速度波动较大。我在实际测试后改成了固定分配模式通过环境变量指定最大显存占用为 20GB预留一部分给系统和其他进程。固定分配的好处是请求延迟稳定生成 token 速度几乎不波动坏处是显存不够用时模型加载会失败或触发重启。上下文长度、温度参数等我在 4.2 节详细展开这里先只说跟容器运行直接相关的参数并发请求数在框架里默认为 8但受显存限制实际能同时处理的数量大概 2-3。如果你用ab工具做压测会发现并发超过 3 后请求开始排队这是正常的不要盲目调大并发否则显存会爆。3.2 Agent 编排容器接入自定义工具的正确方式Agent 编排容器是连接模型和实际任务执行的关键环节它负责把用户请求拆解成计划然后调用注册好的工具函数完成具体动作。我在这套平台里注册了三个典型工具一个是文件读取工具用来读取服务器上指定路径的文本文件一个是代码执行工具在沙箱环境里运行用户提交的 Python 代码并返回输出还有一个是搜索工具从本地知识库检索相关内容。工具接入的坑在于工具执行的权限边界一定要靠容器隔离来实现。我让 Agent 编排容器以非 root 用户运行并且把宿主机路径以只读方式挂载进容器这样即使 Agent 被恶意提示词操纵去读取敏感文件容器内部权限也限制了它的操作范围。另一个参数值得注意工具调用的超时限制。我把每个工具的超时设置为 30 秒超过就终止调用并返回错误。某个代码执行工具如果跑了个死循环30 秒后会被强制结束不会拖垮整个服务。这个参数来自真实教训——我最早设置成 300 秒结果一个失控的脚本让编排容器 CPU 跑满了好几分钟。3.3 向量存储与知识库配置向量存储容器负责把知识文档切片转成向量嵌入并在检索阶段计算相似度。这个组件是整个平台里最容易被低估的配置不当会让整个知识问答功能变成“人工智障”。我在第一次部署时偷懒直接把所有文档整篇扔进去让系统向量化结果检索效果惨不忍睹。后来按标准做法把文档按 500 字左右切块块与块之间有 50 字左右重叠来保持上下文连贯性。这个切块参数直接影响检索质量切太碎会丢失上下文切太大又会让相似度匹配不精确。向量维度也要跟模型匹配。我用的嵌入模型输出 1024 维向量向量库建索引时就按这个维度设置。你如果换了嵌入模型维度变了旧的索引全部要重建这个操作在向量库里是重活尽量在初期就确定嵌入模型不轻易换。相似度检索的返回条数也很关键我设置的是召回前 4 条切片拼进上下文。数量太少可能漏掉关键信息太多则会把无关内容塞进上下文稀释模型的注意力。如果你发现回答质量不稳定优先调整这个参数而不是去调推理温度。3.4 前端面板与网关服务配置网关和前端面板是用户直接打交道的部分配置思路完全不一样。网关追求的是简单可靠前端面板追求的是好用好懂。网关服务我用轻量级反向代理实现主要做三件事路径转发、鉴权校验、限流。路径转发是指把/api/chat这类统一入口转发到 Agent 编排服务的对应端点鉴权校验是通过请求头里的 API Key 判断调用者身份限流按用户维度做普通用户每分钟最多 30 次请求防止有人写个循环把服务打爆。前端面板我选择的是一个开源项目它提供类似在线聊天工具的界面。用户可以在页面里切换不同 Agent、查看工具调用过程、管理会话历史。这个面板的配置核心是一个环境变量文件里面填的是面板如何去连接编排服务的地址、默认模型名称、站点标题。需要注意的坑是代理模式配置。很多面板默认在前端直连推理服务这在单机部署时没问题但在局域网场景里会把内部服务暴露到所有能访问前端的设备上。正确的做法是通过环境变量开启“服务端代理模式”让面板的所有请求经过后端中转前端只跟面板服务通信这样内部组件的地址永远不会泄露给浏览器。4. 实操过程从镜像拉取到平台完全落地4.1 准备配置目录和数据卷这里给你一套能直接照抄的目录结构。我习惯把所有相关文件集中在一个主目录下方便备份和迁移。mkdir -p /opt/agent-platform/{compose,models,data,logs} cd /opt/agent-platform目录规划如下compose目录放编排文件和所有环境配置文件models目录存放模型权重data目录挂载给向量数据库logs目录收集所有容器的输出日志。数据卷的初始化逻辑我会在主编排文件中声明一个初始化容器。它负责创建向量索引目录、设置目录权限、检查模型文件完整性。这样做的好处是每次重新部署时初始化容器会先跑一遍确保环境就绪后续服务不会因为缺目录而启动失败。4.2 编写主编排文件的完整示例下面是我部署时使用的核心配置文件你可以直接复制修改镜像版本等参数。version: 3.8 services: init: image: platform-init:v1 volumes: - model-data:/models - vector-data:/data/vector command: [sh, -c, mkdir -p /models /data/vector chown -R 1000:1000 /models /data/vector] inference: image: deepseek-harness-inference:v1 runtime: nvidia environment: - NVIDIA_VISIBLE_DEVICES0 - MAX_MODEL_LEN32768 - GPU_MEMORY_UTILIZATION0.85 - SERVED_MODEL_NAMEdeepseek volumes: - model-data:/models ports: - 127.0.0.1:8001:8000 healthcheck: test: [CMD, curl, -f, http://localhost:8000/health] interval: 10s timeout: 5s retries: 30 depends_on: init: condition: service_completed_successfully vector: image: deepseek-harness-vector:v1 environment: - DIMENSION1024 - INDEX_TYPEHNSW - MEMORY_LIMIT8GB volumes: - vector-data:/data/vector ports: - 127.0.0.1:8002:8000 healthcheck: test: [CMD, curl, -f, http://localhost:8000/health] interval: 5s timeout: 3s retries: 20 depends_on: init: condition: service_completed_successfully agent: image: deepseek-harness-agent:v1 environment: - INFERENCE_URLhttp://inference:8000/v1 - VECTOR_URLhttp://vector:8000 - TOOL_TIMEOUT30 - MAX_HISTORY_TURNS10 volumes: - upload-data:/data/uploads ports: - 127.0.0.1:8003:8000 depends_on: inference: condition: service_healthy vector: condition: service_healthy gateway: image: deepseek-harness-gateway:v1 environment: - AGENT_URLhttp://agent:8000 - API_KEYsk-local-5f8a3c1e ports: - 8080:80 depends_on: agent: condition: service_started web: image: deepseek-harness-web:v1 environment: - GATEWAY_URLhttp://gateway:80 - ENABLE_PROXY_MODEtrue ports: - 3000:3000 depends_on: - gateway volumes: model-data: vector-data: upload-data:这里有几个参数值得你特别注意。inference服务的端口写成了127.0.0.1:8001:8000意思是只映射到宿主机回环地址局域网其他设备访问不到这个端口。这样做是为了安全外部用户只能通过网关进入不能直接摸到推理服务。如果你在排查问题时需要用本地工具直接调用推理接口用宿主机上的curl http://127.0.0.1:8001/health就够了但绝对不能把这个端口映射到0.0.0.0。MAX_MODEL_LEN32768是上下文窗口长度也就是模型一次能“看到”的最多 token 数。窗口越大能处理的对话历史、知识库切片越多但显存占用也越高。我建议的量力而行策略是显存小于 16GB 就设 1638424GB 以上再考虑 32768。别一上来就拉满显存溢出时推理服务会反复重启体验极差。TOOL_TIMEOUT30和MAX_HISTORY_TURNS10这两个参数是控制 Agent 行为和资源消耗的。前者限制每个工具的调用时长后者保留历史对话轮数超出后最旧的消息会被截断。它们组合起来决定了一次请求最多会消耗多少 token避免出现单个任务把上下文窗口塞爆的情况。4.3 首次启动与基础验证配置写好后接下来是启动和验证环节。顺序上我建议分步启动别一次性 all-in否则出了问题不好定位。先执行初始化容器的构建和启动确认模型文件与目录准备无误。然后单独启动推理服务观察日志里是否出现模型加载完成、服务地址就绪这类关键信息。等待时间通常在 1-2 分钟视显卡和磁盘而定。首次加载模型时推理服务会打印显存占用、上下文长度等运行时信息看到这些就说明模型加载成功。推理服务就绪后先用一个简单的补全请求验证它能正常输出curl http://127.0.0.1:8001/v1/completions \ -H Content-Type: application/json \ -d {model:deepseek,prompt:你好,max_tokens:16}如果返回了包含生成文本的 JSON 响应推理链路就是通的。之后依次启动向量存储、Agent 编排、网关和面板服务每启动一个就检查对应健康接口。最后一个验证动作是从局域网另一台设备访问http://宿主机IP:3000能看到 Web 界面并能发起对话整套平台就算跑通了。完整的验证流程我通常按这个顺序走一遍通过网关调用一次对话接口确认鉴权和路由正常在面板里发起一场包含多轮追问的对话确认记忆功能生效上传一份文档建立知识库再提问文档中的具体细节确认检索链路正常在局域网另一台机器上重复上述操作确认网络隔离正确、外部设备能正常访问。5. 常见问题与排查技巧实录5.1 推理服务容器反复重启这是我在部署和后续使用中最常遇到的问题几乎 70% 的故障都出在这里。我排查时固定按“显存、模型路径、运行时”三步走。先看容器日志。如果日志里出现显存不足相关报错优先检查两个配置GPU_MEMORY_UTILIZATION是否设置过大以及宿主机上是否有其他进程占了显存。有一条经验是这里闭眼照抄最有用的显存利用率别超过 0.9给系统 UI 和驱动留点余量。如果宿主机的桌面环境或监控工具本身也要用一点显存就要把利用率调更低。模型路径报错通常出现在数据卷挂载不对的场景。检查方式很简单进入容器docker exec -it inference ls /models确认目录下真的有权重文件。如果目录是空的大概率是数据卷名字写错生成了一个新的空卷。空卷挂载后模型加载器会找不到文件直接退出容器无限重启。运行时问题则出在runtime: nvidia这一行。如果你没有安装 NVIDIA 容器工具包Docker 根本不知道这个运行时是什么会直接报错拒绝启动。这个问题只在刚开始部署时遇到装好工具包后就没再出现过。5.2 局域网其他设备无法访问面板这个问题的特征很典型宿主机自己能访问localhost:3000但局域网其他设备访问http://宿主机IP:3000超时或拒绝连接。排查要从三个层面做。第一确认容器端口是否映射到了0.0.0.0如果像我在 4.2 节写的内部服务那样映射到127.0.0.1外部自然访问不到。面板容器对外提供服务必须映射成0.0.0.0:3000:3000。第二检查宿主机防火墙。很多 Linux 发行版默认防火墙是开启状态只放行了 SSH 端口。临时放行方式我贴一下命令注意不要在生产环境长期开放所有端口sudo firewall-cmd --zonepublic --add-port3000/tcp --permanent sudo firewall-cmd --reload第三检查面板服务自身的配置。如果面板开启了监听localhost模式即使端口映射正确它也只接受来自回环地址的请求。通过环境变量设置监听0.0.0.0才能接受所有网络接口的连接。5.3 向量知识库回答质量差回答质量差基本集中在两类检索不到相关内容和检索到的东西跟问题无关。检索不到的排查思路是确认文档已被正确切割和向量化。我在前端面板的管理页面里能看到向量库中的文档块数量和状态如果数量为 0说明上传流程有 bug。一个容易被忽略的坑是文件名编码问题中文文件名如果没有做 UTF-8 编码转换解析阶段可能直接跳过。检索到无关内容的问题通常发生在切块参数不合适时。前面说过我最终用的是每块 500 字、重叠 50 字。如果改成每块 2000 字检索召回的都是大段混合内容模型从中提取信息的难度直线上升如果改成每块 100 字检索结果碎片化严重同义表达和指代会丢失上下文线索。5.4 常见问题速查表我把自己遇到过的问题整理成了速查表按症状、原因和处理办法三栏列出来遇到问题可以直接对着查。症状可能原因处理办法推理容器无限重启显存不足或模型路径错误查看日志定位调低显存利用率、确认模型文件挂载正确容器启动报 nvidia runtime 错误未安装 NVIDIA 容器工具包安装对应工具包后重启 Docker 服务再重新创建容器局域网设备访问超时端口映射为仅回环地址或防火墙拦截修改端口映射为 0.0.0.0检查防火墙放行规则对话回答内容看起来“胡言乱语”上下文窗口被历史消息或知识切片塞满调低MAX_HISTORY_TURNS减少知识库召回条数面板上传文档后搜索不到文件名编码问题或切块失败检查上传日志重命名文件后再传一次并发请求高时响应极慢推理服务并发数设置过高导致排队调低并发参数适当降级为更小的量化模型6. 运行一段时间后的经验沉淀与调优方向整套平台在局域网里跑了几个月之后我在配置和日常使用上又有一些新的心得。这些内容属于“正常运行后才发现”的经验比首次搭建的步骤更值得收藏。6.1 日常维护与资源监控平台跑起来之后日常维护的核心就是三个字看日志。我写了一个简单的定时任务每天检查所有容器运行状态和资源占用超过阈值就告警到通知群里。下面是一个简化版的健康检查脚本你按需调整即可#!/bin/bash threshold85 usage$(df -h | awk /\/opt\/agent-platform/{print $5} | sed s/%//) if [ $usage -gt $threshold ]; then echo 磁盘使用率超过 ${threshold}% | mail -s Agent 平台空间告警 adminlocal fi磁盘空间是最容易爆的。模型权重本身占大头但真正快速增长的是上传的文档和日志。我经历过一次/opt/agent-platform/data目录被日志文件塞满、整个平台假死的状况从那以后给日志数据卷单独设置了大小限制同时让日志轮转工具在超过 100MB 时自动分割归档。6.2 模型更新与回滚流程模型迭代是常态我的更新流程已经完全标准化了。先选择一个夜间或低负载时段备份当前数据卷拉取新版本镜像修改编排文件中的镜像版本号或模型名称执行docker compose up -d完成滚动更新。更新后先用测试集跑一遍对话和知识检索验证尤其是回归测试之前遇到过的失败用例。确认无问题后再把旧镜像标记为不可用避免误用。这套平台的好处是每次更新只是换镜像数据卷和配置都不动整个过程耗时基本取决于模型加载时间。有一次我图省事跳过验证环节直接上了新模型结果知识库回答质量明显下降最后花了一个多小时才定位到是嵌入模型变化导致向量索引不兼容。从此以后恢复验证步骤被我写进了团队的操作手册谁都不许跳。6.3 后续可以继续扩展的方向这套 Docker 部署方案跑通之后扩展方向还有很多。对我来说下一步重点是接入更多外部工具链比如让 Agent 能够调用内部 API 完成数据分析任务或者把消息通知接入到现有的内部协同工具里让平台主动推送任务执行结果。多机横向扩展是另一个方向。当前方案是单机部署如果后续并发量涨上来可以把推理服务和向量存储容器拆出来分别放到不同的机器上组成一个小型集群。Docker Compose 切换到集群模式的工作量并不大主要在于数据卷的共享方案和负载均衡策略。如果你准备在团队里推广这套平台我建议先搭好一套标准的“使用文档 权限规范”明确谁能上传知识库、谁能调用工具、谁可以修改 Agent 配置。平台本身提供再多能力没有配套的规范用起来也会乱。我在实际维护这套系统的过程中最深的感受是容器化带来的不光是部署方便更是一种“环境快照”的安全感。模型升级失败了回滚就是一瞬间的事某台机器炸了重新拉起来也很从容。局域网里能有这样一个完全自主可控的 AI Agent 平台带来的自由度是云服务给不了的。如果你也正在考虑搭一套照着这份流程走一遍有问题随时对照速查表基本两天内能跑起来。

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

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

免费获取报价 →
↑