这两年AI Agent的讨论热度一直没降,但大多数教程都默认了一个前提:你的服务器能顺畅访问公网的大模型API。而我最近大半年做的项目几乎全是反过来的——AI Agent要跑在一个隔离内网里,模型必须本地部署,数据不出域,业务系统要和内网OA、数据库、消息中间件直接打通,甚至连镜像仓库和pip源都是内网私有的。这个场景听起来不够“前沿”,但真正落地过的人都知道,它比在云上调API麻烦得多。
这篇文章把我在隔离内网环境下完整搭建AI Agent工程的全过程拆开讲一遍。从方案选型、架构设计,到vLLM本地推理、LangGraph编排、技能包离线部署、FastAPI服务化,再到并发治理和问题排查,全部是实际项目里踩过坑之后总结出来的东西。适合三类人看:手里正捏着内网AI项目需求不敢接的工程师,已经在做内网Agent但被并发和网络折腾得头疼的同学,以及想评估“本地模型做Agent到底靠不靠谱”的技术负责人。
1. 场景与总体设计思路
1.1 为什么会有这种需求
先说清楚“隔离内网”到底是个什么概念。很多公司内部的办公网和生产环境之间是做了网络隔离的,两个区域之间不能随意互通流量,能互通的也必须经过审批和指定的通道。还有一些行业是强监管行业,比如金融、医疗、政务,数据必须留在私有网络内,连外网的模型API都不能碰,因为数据出域本身就是违规。
我遇到过的最典型需求是这样的:有一个内部知识库,沉淀了大量客服话术和行业文档,领导想让AI能自动回答员工问题、自动生成业务简报、甚至自动在OA系统里填单子。但公有云大模型API在安全评审这一关直接就被打回来了。于是方案就成了:把模型权重部署到内网服务器,把Agent编排代码部署到同一网段,让Agent去调内网的数据库和业务接口来完成一系列任务。
这种需求有一个鲜明的特点:它不像互联网C端产品那样要求百万级并发,但要求长时间稳定运行、结果可追溯、权限受控。说白了,先保证能用,再保证好用。这一点决定了后面所有的技术选型。
1.2 技术路线选型:三条路的对比
我在设计这个项目时,认真评估过三条路线,这里把当时的对比逻辑直接放出来。
| 路线 | 实现方式 | 优点 | 缺点 | 结论 |
|---|---|---|---|---|
| 网关转发 | 在内网部署转发服务,把请求转发到云上模型 | 模型能力强,部署快 | 数据出域不合规;隔离网出口带宽不稳定;链路长延迟高 | 直接排除 |
| 纯本地模型 | 开源模型权重部署到内网GPU服务器 | 数据完全不出域,可控性强,响应稳定 | 模型能力弱于顶级云端模型;需要自购GPU硬件 | 本项目采用 |
| 混合路由 | 简单任务走本地小模型,复杂任务走云端大模型 | 兼顾成本和质量 | 仍然有数据出域风险;路由策略复杂 | 部分场景备用 |
最终的结论很明确:纯隔离内网环境下,只能选纯本地模型。这不是技术偏好问题,是合规边界问题。你做技术选型的时候,第一件事不是比谁的模型分数高,而是先搞清楚“数据能不能出去”这条红线。
1.3 方案边界:哪些事必须做,哪些别做
还有一个特别重要的点是方案边界管理。很多内网Agent项目烂尾,不是因为技术做不到,而是因为预期管理没做好。比如有人问“能不能让Agent帮我们写PPT”,这个可以。但“能不能让Agent写一份完整的产品技术方案并且直接能用”,这个对7B、14B级别的本地模型来说就很吃力。
我把这个项目的目标切成三层:
- 必须做到:内网环境下模型能稳定跑起来,Agent能按预设流程调用内部工具,能通过API被业务系统调用。
- 尽量做到:并发请求不把GPU打崩,任务执行状态可查询,常用技能包能离线加载。
- 坚决不做:面向公网用户的开放式Agent服务,实时音视频级别的低延迟交互,需要复杂数学推理和深度代码生成的任务。
把边界划清楚之后,后面所有技术决策都会变得顺畅很多。你不用再纠结“怎么把模型能力再提一个档”,而是会把重心放到“怎么让现有能力稳定服务好”。
2. 核心架构拆解
2.1 五层模型:从模型到业务的完整链路
做内网Agent工程,最忌讳的就是把代码写成一坨“大模型套壳”。我建议先按五层架构去思考问题,每一层职责清晰,后面换模型、换工具、换框架都不会伤筋动骨。
| 层 | 职责 | 选型 | 关键点 |
|---|---|---|---|
| 模型服务层 | 加载模型权重,提供OpenAI兼容的推理API | vLLM / Ollama | 统一API协议,便于上层无感切换 |
| Agent编排层 | 决定Agent“下一步做什么” | LangGraph | 状态图机制支持分支、循环、人工审批 |
| 工具调用层 | Agent执行具体动作 | MCP规范或Python函数注册 | 把内网的数据库、API包装成可调用工具 |
| 业务接入层 | 对外开放统一接口,对接业务系统 | FastAPI + 异步队列 | 入队即返回任务ID,后台异步执行 |
| 运维观测层 | 日志、监控、审计、模型输出过滤 | Prometheus + 数据库审计表 | 内网环境的可观测性常被忽视,必须补上 |
每一层之间用标准接口衔接,比如模型服务层对外暴露的是OpenAI兼容的/v1/chat/completions,编排层只负责调度不关心模型怎么部署;业务接入层只关心入队和回调,不关心Agent内部状态。这样分层之后,团队开发时可以并行推进,我一个人也能在有限时间内把整条链路补齐。
2.2 模型服务层:vLLM还是Ollama
隔离内网里部署模型,我首选的推理框架是vLLM,而不是Ollama。不是说Ollama不好,它的体验确实很友好,一条命令就能拉模型跑起来,做原型验证最快。但到了生产环境,Ollama对并发控制的粒度、对显存利用率的优化都不如vLLM精细。
vLLM的拿手好戏是PagedAttention显存管理,可以显著提升吞吐,还能通过--max-model-len控制单请求的最大token长度,避免一个超长请求把整个显存吃光。另外vLLM原生提供OpenAI兼容接口,这意味着你之前写的那些面向OpenAI SDK的代码,只需要改一下base_url就能切换到本地模型。
模型参数量级的选型,我按显存规模给一个参考表:
| 模型规模 | 推荐显存 | 适配场景 | 说明 |
|---|---|---|---|
| 7B~8B | 16GB以上 | 文档问答、信息抽取、工具调用 | 单张4090可跑,性价比最高 |
| 14B | 28GB以上 | 复杂指令跟随、代码生成 | 单张4090有点紧张,建议A100/A800 |
| 32B(量化后) | 约40GB | 高质量对话、复杂推理 | 双卡或一张80GB卡 |
我这边实际使用的是一张40GB显存的计算卡,跑的是量化后的14B级别模型。之所以不直接上32B,是因为内网Agent项目更看重延迟稳定性和长时间不出错,14B在这个维度上的表现更可控。
2.3 编排层:为什么用LangGraph而不是传统Chain
Agent编排层是整个架构里最能体现工程量的地方。很多初学者会用LangChain的Chain或者直接写死一个prompt -> call_llm -> response的线性流程。但真实的内网业务场景里,Agent经常需要循环、分支、甚至人工审批节点。
举个例子,Agent拿到一个“查询本月设备故障率并生成报告”的任务。它先要判断这个任务需要哪些工具,然后去查数据库,查完之后可能发现数据不够,还得再发一次查询,最后把结果交给大模型总结。这个过程的流程分支不是线性的,而是图状的。LangGraph的核心价值就是把流程变成显式的状态图,每个节点是一个处理单元,节点之间通过共享状态传递数据,遇到分支条件可以走不同路径。
用生活化的类比来说,传统Chain像是流水线,一个工位干完传给下一个工位,方向是死的。LangGraph则像车间里的一套生产调度系统,每一步做完都看当前状态,再决定下一步派给哪个工位,还能回头返工。以前有人问“基于Rust语言能不能做AI Agent”,当然能做,但Agent工程的核心难点在生态和编排能力,目前Python生态在模型调用、数据处理、框架支持上依然是最省事的。Java那边也有Spring AI在做类似的事,但论编排灵活度,LangGraph这类专业Agent框架目前还是更顺手。
2.4 工具层:MCP规范与本地函数注册
Agent要“下地干活”,必须能调用工具。内网场景里的工具五花八门:查询MySQL、写Redis、调用内部审批系统的接口、发企业微信消息、读文件目录等等。
我在这个项目里主要采用了自定义Python函数注册的模式,然后用MCP规范做了一层封装。两者并不矛盾:底层是函数,加了MCP协议之后,工具的描述、参数Schema、调用约束都标准化了,模型理解工具的成本会大幅下降。尤其是当你的技能包(Skill)越来越多时,规范化的工具定义能让Agent在复杂场景里更准确地选择该用哪个工具。
工具层设计里有三个容易踩坑的点:
- 工具描述一定要写清楚“什么时候用它”和“什么时候不要用它”,大模型选错工具很多时候是因为描述太模糊。
- 工具的入参要做严格的类型校验,Agent传来的参数经常是字符串,如果你直接拿去拼SQL,会出大问题。
- 所有外部调用必须有超时控制,内网服务也有抖动,一个工具卡住会把整个Agent流程拖死。
3. 从零到一的实操部署
3.1 内网服务器环境准备
内网环境最讨厌的一点是很多自动化安装脚本默认走公网源,所以在装环境时必须先确认能不能用内网镜像源。我在项目启动时先做了三件事:
第一,检查GPU服务器的驱动和CUDA版本。执行nvidia-smi确认显存、驱动版本和CUDA版本,驱动版本太旧直接会影响后面容器运行。第二,确认Docker可用。因为vLLM官方镜像是直接从容器仓库拉取的,如果内网有镜像仓库,就先把vllm/vllm-openai镜像推进去。第三,确认Python相关的包能通过内网PyPI源安装。如果内网没有PyPI代理源,那就只能在有网的机器上把依赖包下载成离线包,再拷贝进去。
这几步听起来很简单,但实际操作中我遇到过整台服务器都没有外网权限的情况,连apt-get install都执行不了,最后是拿着移动硬盘在内网外来回拷贝离线包才解决了环境问题。所以部署内网项目时,建议把“离线安装包准备”当作一个正式任务列进计划,别指望现场临时下载。
3.2 启动本地模型推理服务
环境准备好之后,启动模型服务我用的是vLLM的Docker方式。这里放一个可以直接参考的启动命令:
docker run --runtime nvidia --gpus all \ -v /data/models:/models \ -p 8000:8000 \ vllm/vllm-openai:latest \ --model /models/Qwen2.5-14B-Instruct-Q4_K_M.gguf \ --served-model-name local-agent \ --max-model-len 8192 \ --gpu-memory-utilization 0.92 \ --dtype auto有几个参数值的取舍必须说清楚。
--gpu-memory-utilization 0.92表示允许模型使用92%的显存,留一点余量给KV cache和推理过程中的中间张量,填满100%很容易在长上下文场景里直接OOM。--max-model-len 8192限制了模型处理的最大上下文长度,1个token约等于不到1个汉字,8K上下文对内网文档问答基本够用,再大就要吃更多显存。--served-model-name设置的是对外暴露的模型名,内网其他系统调用时只用这个名字,后续换模型文件不影响调用方。
启动之后,用curl http://127.0.0.1:8000/v1/models验证一下是否返回模型信息。能返回基本就说明服务起来了。这时候建议再发一个测试请求确认整体链路没毛病,再去写Agent编排代码。
3.3 技能包(Harness+Skill)的内网落地
很多Agent框架里都有“技能包”的概念,有些叫Skill,有些叫Harness。它本质上是把一组工具使用说明、提示词模板和示例放在一起,统一打包给Agent,让它知道“在什么场景下可以用什么技能、怎么用”。
有一个比较常见的需求场景:DeepSeek Harness附带了一批Skill,你要把这套东西部署到内网服务器上。我实际操作下来,步骤并不复杂:
- 在一台能访问公网的机器上,把Harness仓库和Skill内容完整拉取下来。
- 把Skill里的所有引用的Python依赖做离线打包,内网机器安装时走内网PyPI源或者离线wheel包。
- 把Skill的配置文件里的模型地址全部改成内网的vLLM服务地址,比如
http://192.168.10.20:8000/v1。 - 把Skill目录放到指定的配置路径下,然后用框架自带的加载器启动。
看起来就这么四步,实际上最耗时间的不是拷贝文件,而是依赖冲突和路径适配。比如SkillA依赖pandas=2.0,SkillB依赖pandas=1.5,两个塞在一起很容易崩。我的习惯是给每个核心技能包建一个独立的Python虚拟环境,Skill之间通过Agent主进程做调度,避免依赖互相污染。
技能包写好之后,建议用一个元数据文件来登记每项技能的名称、描述、入口函数和调用方式。这样编排层在决定“该用哪项技能”时,可以快速从元数据里选出匹配项。
3.4 用LangGraph编写Agent主流程
等模型服务和技能包都就位,就可以写Agent调度逻辑了。我用LangGraph画整个执行流程,核心节点包括“接收任务”“任务拆解”“调用工具”“结果生成”“终止判断”。
下面是一个简化版本的关键代码结构:
from langgraph.graph import StateGraph, END from typing import TypedDict, Annotated import operator class AgentState(TypedDict): task: str messages: list tool_calls: Annotated[list, operator.add] result: str def plan_node(state: AgentState): # 调用本地模型,把任务拆解成若干子步骤 pass def tool_node(state: AgentState): # 根据子步骤选择并执行技能包里的工具 pass def generate_node(state: AgentState): # 汇总工具执行结果,生成最终回答 pass def should_continue(state: AgentState): # 判断任务是否完成,或者是否需要重新规划 if state.get("result"): return END return "plan" graph = StateGraph(AgentState) graph.add_node("plan", plan_node) graph.add_node("tool", tool_node) graph.add_node("generate", generate_node) graph.set_entry_point("plan") graph.add_conditional_edges("plan", should_continue, {"continue": "tool", END: "generate"}) graph.add_edge("tool", "generate") graph.add_edge("generate", END) app = graph.compile()这个代码虽然简化了细节,但能看出关键设计思路:Agent不是一次性生成完结果,而是“规划-执行-判断”循环。这样当某个工具调用失败时,模型可以在下一轮规划里修正自己的方案,而不是直接放弃。
另一个重点是状态管理。AgentState里我刻意用了Annotated[list, operator.add],这样多个工具调用返回的结果会按顺序累积,不会被覆盖。内网Agent跑长任务时,工具调用可能有十几轮,每一步的过程数据都要留得住,便于事后审计。
3.5 用FastAPI把Agent包成一个服务
单纯跑通Agent还不行,业务系统要调用它,必须暴露一个HTTP接口。我选了FastAPI作为接入层框架,原因很简单:它有原生的异步支持,配合任务队列能轻松解决同步阻塞问题;自带Swagger文档,内网其他团队对接时直接看文档就能调。
接口层我设计了两个核心Endpoint:
from fastapi import FastAPI from pydantic import BaseModel app = FastAPI() class TaskRequest(BaseModel): task: str biz_type: str = "default" callback_url: str = "" @app.post("/api/agent/run") async def create_task(req: TaskRequest): task_id = await queue.put(req) return {"task_id": task_id, "status": "pending"} @app.get("/api/agent/task/{task_id}") async def get_task(task_id: str): return task_store.get(task_id)入口接口负责接收任务并立即返回任务ID,不阻塞调用方。任务真正执行由后台Worker负责,Worker处理完把结果写入任务存储,同时如果有回调地址则通知调用方。这个模式在工程上叫“异步任务处理”,好处是即使任务执行需要几分钟,调用方也不用一直等HTTP连接挂着。
实际项目中我还加了鉴权逻辑,所有进来的请求头上都要带一个内网签发Token。内网不代表绝对安全,Agent能调工具、能查数据,如果接口裸奔被扫到,后果比公网泄露还严重。
3.6 局域网访问与Webhook回调对接
模型服务和Agent服务都启动后,内网的其他业务系统想访问,直接用服务器内网IP加端口就行了。比如http://192.168.10.20:8000是模型服务,http://192.168.10.20:9000是Agent服务。这一步只要网络策略放行了端口,基本没什么问题。
真正麻烦的是Webhook回调。比如Agent执行一轮任务后需要通知另一个部门的系统,对方系统又在我们这台Agent服务器的另一个网段,两边互相不主动访问。很多人第一反应是“搞内网映射”,我的建议是别碰这类方案,内网安全策略大概率不允许,而且也很不稳定。
正确做法是顺着网络架构设计连接方向。我遇到的实际情况是:Agent需要等待另一个系统处理完一项审批后,再生成结论。最后选了Agent主动查询方案,即Agent定期调用对方系统的查询接口,拿到结果后再继续后续流程。不强行要求“对方系统回调我们”,而是从“查询者的角度”去设计编排流程,整个链路反而简单稳定得多。
4. 并发问题:内网Agent怎么扛住真实业务压力
4.1 先搞清楚瓶颈在哪一层
“AI Agent怎么扛并发”是很多团队关心的问题,但答案必须先看瓶颈在哪里。在隔离内网场景下,系统链路有这么几层:HTTP接入层、Agent编排层、推理服务层、模型性能层。用一张表格来看每一层的并发瓶颈:
| 链路层 | 并发瓶颈 | 解耦手段 |
|---|---|---|
| HTTP接入层 | 连接数限制 | FastAPI异步接口,快速返回任务ID |
| Agent编排层 | 状态存储压力 | 任务状态存Redis |
| 工具调用层 | 内网业务系统QPS限制 | 工具调用加信号量限速 |
| 推理服务层 | GPU显存与计算吞吐 | vLLM批次调度,控制并发数 |
| 模型性能层 | 单token生成时间 | 降低上下文长度、选更小模型 |
这里的实践经验是:绝大多数情况下,最开始被打爆的不是GPU,而是第三方内网业务系统。比如Agent并发执行时,每个任务都去查OA系统的接口,对方系统是若干年前的老架构,一秒能扛的请求量也就几十个,Agent一开并发立刻就被封了IP。所以真正的并发控制不是只盯着模型服务,而是要给工具调用层做限速。
4.2 用任务队列和异步Worker做并发控制
我在FastAPI接入层和Agent执行层之间,加了一个基于asyncio.Queue的任务队列,配合固定数量的Worker进程去消费任务。核心代码如下:
import asyncio queue = asyncio.Queue(maxsize=100) WORKER_COUNT = 4 async def worker(): while True: req = await queue.get() try: result = await run_agent(req) await notify_done(req, result) except Exception as e: await notify_error(req, str(e)) finally: queue.task_done() @app.on_event("startup") async def startup(): for _ in range(WORKER_COUNT): asyncio.create_task(worker())这里解释一下为什么用队列,而不是开几百个协程直接执行任务。Agent任务不是普通HTTP请求,它内部会调用大模型,单个任务可能耗时几十秒甚至几分钟,如果无限并发,只要来100个请求GPU直接爆显存。控制Worker数量就是控制同时对GPU的占用数量。
另外队列的maxsize=100也很关键,队列满了新请求马上被拒,并提示“任务排队中,请稍后重试”。这套机制保证了在突发流量下,系统不会雪崩,只是会正常排队。
4.3 超时、重试与优雅降级
内网环境虽然整体比公网稳定,但也不是没故障。我用一套比较保守的容错策略:
| 策略 | 参数 | 原因 |
|---|---|---|
| 模型单次调用超时 | 60秒 | 本地模型通常30秒内能返回,给足余量 |
| 工具调用超时 | 10秒 | 内网接口一般很快,10秒不返回说明有问题 |
| 单任务总超时 | 300秒 | 长任务也有上限,避免排队堆死 |
| 工具调用重试次数 | 2次 | 最多重试一次,再失败就交给模型规划新的路径 |
| 总任务失败后动作 | 记录审计日志并通知人工 | 内网Agent涉及的业务往往重要,不能静默失败 |
这种策略在实际运维中非常管用。比如某个内网接口偶尔慢一下,10秒超时重试2次基本能绕过;如果连续3次都失败,就说明对方系统可能挂了,这时候让模型去尝试备用工具,如果还是没有备用方案,就明确告诉用户“当前无法处理”,而不是生成一个看似合理但错误的结果。对Agent来说,“诚实地承认失败”比“强行编造结果”重要一百倍。
4.4 一组可以拿来当参考的实测数据
我觉得光讲理论不够,这里贴一组我真实跑过的数据,设备是单张40GB显存卡,跑的14B量化模型,任务类型是“内网文档知识库问答+调用查询工具生成周报”。
| 并发Worker数 | 平均单任务耗时 | 最慢任务耗时 | 服务端成功率 |
|---|---|---|---|
| 1 | 48秒 | 91秒 | 100% |
| 2 | 52秒 | 103秒 | 100% |
| 4 | 63秒 | 135秒 | 99.5% |
| 8 | 81秒 | 180秒 | 92% |
可以看到,Worker从4个加到8个后,成功率反而开始下降,因为并发推理导致显存压力上升、batch等待变长,单个任务耗时明显增加。最后我把生产环境的Worker数固定在了3个,并用排队队列挡住多余的请求,整体运行非常稳定。这可能和很多人的预期“并发越大越好”相反,但GPU推理的真相是:盲目加并发等于谁都跑不动,合理限流才是对内网算力的最大利用。
5. 内网部署的常见问题与排查实录
5.1 高频问题速查表
内网Agent部署不像云上那么“友好”,什么问题都可能冒出来。我把自己遇到的频率最高的问题整理成了一个速查表,后续新项目直接照着查。
| 现象 | 可能原因 | 排查步骤 | 解决办法 |
|---|---|---|---|
| 模型服务启动就退出 | 显存不足或驱动和容器版本不匹配 | 执行nvidia-smi查显存,查看vLLM容器日志 | 调低gpu-memory-utilization,升级驱动 |
| 请求超时 | 上下文太长推理变慢;并发太高排队 | 看模型服务监控,查当前活跃请求数 | 降低max-model-len,减少Worker数 |
| 调用Agent返回服务不可用 | 内网机器无法解析服务器主机名 | ping服务IP能通就换IP访问,不能通就查防火墙 | 统一走IP或维护内网hosts文件 |
| Webhook回调失败 | 对方系统无法主动访问Agent网段 | 在Agent服务器上尝试连对方系统的回调地址 | 改Agent主动轮询对方接口 |
| 时间不同步导致登录态失效 | 服务器时间偏离,JWT校验失败 | 对比Agent服务器和业务系统时间 | 配置内网NTP时间同步 |
| 模型答非所问 | 用了过大的max-model-len占用显存 | 检查显存占用和KV cache指标 | 精简上下文,及时清理历史消息 |
第4个问题是高频中的高频,我单列一节展开讲。
5.2 一次真实排查:Webhook回不来到底卡在哪
这个项目上线后没多久,收到一条告警:Agent执行完一个流程,调用业务系统A的回调接口时失败了。一开始我看日志以为是对方系统没启动,手动用curl去访问对方接口完全是通的,但那台回调服务器确实收不到Agent发来的请求。
排查到最后才发现,问题不在Agent,也不在对方服务,而在于网络策略。Agent部署的服务器和目标系统不在同一个安全域,两个安全域之间只允许“目标系统所在网段主动发起连接”的单向通道,反过来从Agent网段向目标网段发起访问是受限的。
这事给了我一个非常深刻的教训:内网架构里“网络方向”比“网络连通性”重要得多。很多系统之间并不是物理不通,而是策略上只允许某些方向的访问。后来我再设计Agent和外部系统交互时,第一件事就是问清楚“谁可以访问谁”,然后顺着现有方向设计流程。Agent需要查系统B的数据,如果系统B不能主动推给Agent,就设计成Agent定时轮询;Agent需要通知系统C结果,如果Agent不能访问系统C,就找消息中间件作为中转。本地网络通信能力是需要慎重设计的资源。
5.3 安全与合规的工程落地细节
内网Agent的安全问题,不像公网Web服务那么强调WAF和防SQL注入,但每一条都同样要命。
第一点是能力权限最小化。Agent要访问数据库,就创建一个只读账号,只授权到特定库表;要调OA接口,只给一个只能处理指定流程的专用账号。大模型有时候会“自作主张”发起不存在的请求,如果账号权限太大就是灾难。
第二点是全链路审计。Agent的每一次规划、每一次工具调用、每一次最终输出都要写审计日志。我见过不少团队只记录最终回答,一旦出问题复盘时完全还原不了现场。我自己做的方案是把规划链和执行链都存到数据库里,哪个环节出问题,按任务ID一查就能定位。
第三点是输出内容过滤。大模型生成的内容不能直接展示给用户,我会在输出层挂一个过滤组件,屏蔽掉手机号、身份证号等敏感信息,同时对涉及金额、审批结论等严肃场景的内容,强制采用“工具返回结果优先”的策略,不允许模型在关键参数上自由发挥。模型负责组织语言,业务事实以工具返回为唯一依据。
最后说点实在的
做内网Agent工程有一段时间了,我最大的体会是:这个项目的难点从来不在模型多聪明,而在工程连接。外网环境里十几分钟能搞定的接口对接,在内网里可能要为了一个网络方向问题调上好几天;云端随手拉的镜像,在内网里可能要带着移动硬盘来回拷好几趟。但恰恰是这些“不酷”的部分,才是真正决定项目能不能落地的关键。
如果你正准备在隔离内网环境里上Agent项目,我的建议是先别急着调模型、写Prompt,而是花时间把网络分区、访问方向、离线依赖、权限边界这几个基础问题摸透。基础打牢之后,再照着“模型服务、Agent编排、技能工具、业务接入、运维观测”这条链路,一层一层把系统填起来。最后再分享一个小技巧:内网环境里先跑通最小闭环,哪怕只是“用户提交问题-模型回答”的纯对话场景,也比盯着完整的架构图规划半个月更实在。能跑通的系统,才有资格谈优化。