
1. 把本地模型当“断网版云模型”是Agent项目里最贵的误会我做过的Agent项目不算少见过太多团队在模型选择上栽跟头。最典型的心态是“云端API按token计费太贵或者数据敏感必须本地化那就把Agent后端直接换成加载本地模型当成一个免费且私密的云模型用。”这个思路听起来合理跑起来完全是另一回事。本地模型根本不是云模型的离线镜像它在能力边界、成本结构、安全语义上和云端模型是两种完全不同的东西。把两者画等号轻则任务质量马上崩重则你以为“数据没出内网”实际上早就通过旁路流出去了。这个误会之所以贵是因为它通常在架构早期就定型了。等到路由逻辑、工具调用、上下文缓存都围绕“本地云模型的平替”写好再返工就是推倒重来。我写这篇东西就是想把这些年见过的坑、试过的方案、最后沉淀下来的任务路由设计思路一次性说清楚。不管你是在做内部知识库Agent、桌面端AI助理还是企业级多Agent编排这篇文章要解决的只有一个核心问题本地模型和云端模型怎么分工才能既保住效果又守住数据边界。1.1 参数规模不是被“裁剪”了而是能力根本不在一层经常有人问我本地跑一个8B、14B的量化模型跟云端几百B的旗舰模型差多少我的回答是差的不只是“聪明程度”而是推理深度的层次。你有机会观察两个模型对同一道逻辑题的反应就知道了。小模型不是能力被打了折它的工作记忆、注意力分配、步骤规划能力上限就摆在那里这不是靠更好的prompt能填平的。在Agent场景里差距会加倍放大。Agent工作负载的特点是短任务不少长链条更多。比如一个Agent要“读取三份文档、提取关键信息、对比差异、生成报告并调用内部API归档”这种多步骤任务对小模型来说非常吃力。云模型能稳稳地把十几步的规划走完本地小模型经常在中途“失忆”要么漏掉一个关键约束要么干脆重新解释你的指令输出一套自洽但完全错误的结果。这不是说本地模型没用。文本改写、摘要生成、信息抽取、意图分类这类“单点任务”本地模型表现相当不错。但如果你把它塞进Agent的规划链路里让它承担推理、排序、决策判断你就会看到一个又一个莫名其妙的问题。我自己的经验是本地模型的定位是“熟练的执行员”不是“思考型的总指挥”。这个定位一旦想清楚后面的路由设计就顺了。1.2 成本结构完全不同一个是一次性买断一个是按量计费很多团队选本地模型第一理由是省钱。但算过总账的人会告诉你本地部署可能更贵。云模型是“按量计费”你用多少付多少任务量小的时候一个月可能就几百元本地部署是“一次性买断持续维护”硬件开销、机房电费、模型更新、环境调试、故障处理这些全是成本。我给你算一笔真实账一台能流畅跑70B量化模型的机器双卡起步整机下来至少五六万元。如果你的Agent每天只有几百次调用这笔钱够你调用云端旗舰模型好几年。而且云端API迭代速度快新模型一个月就上一个台阶本地模型要追版本每次下载、量化、重测都是一轮人力投入。更要命的是并发能力。云模型扛高并发靠的是服务商的海量算力而本地模型的并发极限是你的显卡显存。在显存里塞下模型之后剩下的空间才能用来跑上下文。一台单卡机器同时跑三五个Agent任务就可能OOM。遇到“agent被并发打爆”的场景本地部署的体验远不如云端API平滑。所以本地模型的真正价值不在“省钱”而在“数据可控”和“固定高负载下的边际成本低”。只有在这两个条件成立时本地部署才值得做。把这个前提想明白你再看任务路由思路就完全不一样了。1.3 “部署在本地”不等于“数据安全”这是我最想强调的一点。很多人觉得模型跑在本机就天然安全其实本地部署只是把模型加载位置放到了你的机器上数据链路是否安全取决于你整个Agent系统的架构。我见过不少系统推理模型确实在本地但Agent框架本身会调用云端Embedding、云端rerank、外部搜索API甚至日志系统直接把prompt原样传到第三方。你说数据没出网可它分明在别的环节出去了。判断数据是否安全要看的是“任何字节是否可能跨出你设定的边界”而不是看“主推理模型在哪里”。这意味着数据安全靠的是路由层、网络策略和日志治理不是靠模型部署位置。任务路由在这里的真正意义就出来了它不只是性能优化工具更是一条强制性的数据边界。2. 敏感度分级先行任务能不能出边界在这里就定死聊到任务路由很多人第一反应是“按任务复杂度给模型打分”。这个想法没错但它应该排在第二位。第一位永远是把数据敏感度分级做扎实因为路由的底线不是“效果最优”而是“不该出去的数据绝不能出去”。复杂度判断错了最多是结果质量差一点敏感度判断错了就是安全事故。2.1 一张可以拿去直接用的数据分级表数据分级这活儿听起来高大上实际落地可以很朴素。我在项目里常用五级分类跑通之后效果很好。你完全可以照着这个框架按自己公司的业务去调整。级别定义Agent场景举例允许流向L0完全公开天气查询、新闻摘要、公开法规条文改写任意模型L1低敏感已脱敏产品公开文档润色、去除个人信息后的问卷分析任意模型L2内部数据公司内部项目文档摘要、非公开会议纪要素材本地模型优先确有必要上云必须先自动脱敏L3敏感数据客户联系方式、合同原文、薪酬记录、健康信息仅限本地禁止出边界L4机密密钥、未公开的并购信息、审计备查底稿仅限本地且需要额外访问审计这个分级表的核心逻辑很简单L0和L1随便跑L2需要“申请脱敏”L3和L4直接死在边界内。和“关键词黑名单”那种思路相比分级的好处是让规则可解释、可审计。当安全团队问你“为什么这个任务去了云端”你可以直接说“它是L2且已经过脱敏”而不是支支吾吾。2.2 敏感度判断不能靠关键词要用“前置过滤器”很多人做敏感判断的第一反应是堆关键词出现“合同”“身份证”“薪资”就打标。这个方法漏洞非常大。攻击者或者用户稍微变个说法比如把“合同”说成“协议”把“客户电话”说成“联系方式”关键词规则就被绕过了。而且同一份文本里关键信息可能藏在附件名、表格引用代码、对话上下文里关键词根本抓不住。更可靠的做法是“前置过滤器”在任务进入Agent之前先用一个独立的敏感度判定模块做检测。这个模块可以结合三种手段基于规则的命名实体识别NER识别姓名、电话、地址、银行卡号、企业税号等模式基于本地小模型的分类器判断文本涉及的主题域合同、人事、财务、研发等基于上下文的来源标注比如字段中标记了“来自客户CRM系统”的任务默认升一级。这里有个细节值得注意分类器本身也应该跑在本地。你总不能让一个负责判断“是否敏感”的模块先把文本发到云端去分析吧那就本末倒置了。我把这个前置过滤器放在Agent主流程之外每一条任务进来先过过滤再进路由。这么做的收益是巨大的即使Agent内部某个子Agent写得很烂或某个工具调用的配置有误敏感数据也没机会走到边界外。2.3 复杂度与时延是第二、第三准则敏感度分级搞定之后再来谈“怎么分才能保住效果”。我的原则很简单同等级任务里能用本地模型解决的尽量不上云本地模型搞不定的再走云端。但“搞不定”这三个字不能拍脑袋得有一个稳定的判断标准。我自己总结了适合本地模型的任务画像单点、短上下文、不需要复杂推理、对格式要求固定。比如把一段录音转写后的文本整理成会议纪要、把用户提问做意图分类、从文档里抽取指定字段、批量改写固定风格的文案。这些任务本地模型跑起来又快又稳还不花钱。而需要云模型的任务画像则恰恰相反多跳推理比如“根据A和B文档里的数据算出C并给出建议”、长上下文依赖比如分析一份100页PDF的关联逻辑、高难度代码生成与重构、需要极强指令遵循能力的复杂工具编排。这些活儿交给本地模型结果是大概率返工反而是最浪费的。时延是第三条线。本地模型单次推理速度可能并不慢但排队能力弱。如果系统同时来了10个Agent子任务本地队列会越排越长。在这种情况下你可以把L2以下、不紧急的任务继续留在本地队列而把需要实时响应的交互任务哪怕复杂度中等也路由到云端去兜底。这个“实时交互优先上云”的策略很多生产环境已经在用。3. 路由实现的三种思路规则表、模型自决和框架强制明确了路由标准下一步就是怎么落地。我见过三种主流实现规则路由、模型自我路由、框架强制路由。它们的可靠性、灵活性和实现成本完全不同这里拆开讲。3.1 规则路由最土的手段往往最可靠规则路由的思路极其朴素先定一套静态规则任务进来之后逐条匹配命中哪条就往哪条对应的模型走。规则可以是正则表达式、关键词组合、数据来源标记也可以是更精细的NER结果。看一个简单的Python示例def route_task(task: Task) - str: # 第一优先级敏感度不可商量 if task.sensitivity_level 3: return local # 第二优先级来源标记 if task.source crm_sync or task.source hr_system: return local # 第三优先级复杂度打分可由分类模型预先算好 if task.complexity_score 0.7: return cloud # 默认低风险任务留在本地 return local对应的路由配置可以外置成YAML方便非开发角色一起维护rules: - name: 敏感数据强制本地 condition: sensitivity 3 target: local - name: 复杂推理走云端 condition: complexity_score 0.7 and sensitivity 2 target: cloud - name: 实时交互优先云端 condition: latency_sla interactive and sensitivity 1 target: cloud规则路由的最大优点是确定性和可审计性任何一次路由都可以回溯到具体规则出了问题能解释、能修复。缺点也明显规则需要持续维护。业务一变化你就要回头补规则否则覆盖率会不断下降。但即便它有维护成本我也建议先把规则路由搭起来因为它是最佳的安全底线。3.2 模型自我路由图省事可以把命交出去不行有一种“高级”做法很诱人不写路由规则而是让Agent自己判断——它觉得任务简单就调用本地模型觉得复杂就调用云端模型。有些Agent框架甚至提供了model selector之类的能力看起来像是“智能路由”。我的态度很明确让模型自己决定“自己行不行”这件事在目前的技术条件下极其不可靠。小模型普遍高估自己的能力经常把复杂任务判成简单任务然后硬着头皮执行结果输出一团糟。更要命的是如果你让模型同时决定“这个任务敏不敏感”那就等于把数据安全的决定权交给了一个不稳定的概率系统。我见过不止一次模型非常自信地把一份含有客户电话的文件摘要“智能地”送进了云端API。那个操作没有任何恶意但后果直接是合规事故。所以模型自我路由只适合用在一种场景L0/L1数据上让Agent自己决定“简单任务走本地、复杂任务走云端”来优化成本。敏感判断和强制边界永远不该交给模型自决。3.3 框架强制路由把“不让数据出去”变成架构刚性考虑到前面两种方案各有短板我在正式项目里最推荐的是框架层强制路由。简单说就是在Agent框架的执行链路上加一个不可绕过的拦截器。所有任务进出都必须经过这个拦截器它负责敏感度检查、路由分配、脱敏转换和审计打点。拦截器放在什么位置很关键。不能只放在推理模型调用之前因为Agent的子任务可能通过工具调用直接触发外部API绕过你的模型路由。完整的强制路由需要在两个位置生效模型调用入口强制把任务分配给指定模型工具调用出口检查工具的目标地址如果目标是外部网络且任务含L2以上数据直接阻断。我用伪代码描述一下拦截器的核心逻辑class RoutingInterceptor: def on_model_call(self, task): route decide_route(task) # 分级、复杂度、规则表 if route local: return local_model.invoke(task) elif route cloud: if has_sensitive_data(task): raise BlockedByPolicy(sensitive data cannot leave boundary) return cloud_model.invoke(task) else: raise RouteNotFound def on_tool_call(self, tool): if tool.destination_is_external() and self.context.sensitivity 3: raise BlockedByPolicy(external tool call blocked) return tool.execute()这种设计的核心价值在于“不可绕过”。哪怕某个Agent子任务写得再糟糕或者某个模型插件配置出错都无法越过策略边界。它把“不泄密”从一句口号变成了架构事实。3.4 三种方案的取舍直接给结论方案可靠性实现成本维护成本适用场景规则路由高低中高大多数业务安全底线模型自我路由低低低L0/L1任务的成本优化框架强制路由极高中高中合规严格、数据敏感的企业级场景我自己的项目通常采用“框架强制路由做底座规则路由做决策模型自决做L0/L1优化”的组合。三层各管一段既守住边界又不牺牲灵活性。4. 接入本地模型后才会暴露的三类问题路由设计好了模型真的接进来后面才是真正的折腾。光是“调用本地模型”这五个字就能引出大量和云模型完全不同的坑。下面这几个问题是我在多个项目里反复遇到过的你大概率也会撞上。4.1 OpenAI兼容接口只是“兼容”不是“等价”很多人加载本地模型时选的是LM Studio或Ollama这类工具因为它们提供OpenAI兼容接口。看起来是不是很省事项目里只要把base_url改成http://localhost:1234/v1就完事了。但“兼容”这两个字的含金量比你想象的低。举个真实例子某个项目用Claude Code风格的Agent客户端调用LM Studio加载的本地模型配置好ANTHROPIC_BASE_URL、API key占位符之后前几个简单对话没问题一进入复杂工具调用场景就报错agent execution terminated due to error。折腾了很久才发现本地模型的输出流在stream_options、tool call格式上和云模型存在细微差异客户端收到的结构化结果不规范直接把任务中断了。这类问题多数不会在“你好”这种打招呼对话里暴露只会在真实多步任务中出现排查起来极其费神。我的建议是凡是接本地模型进Agent必须先准备一个“协议兼容测试集”。测试集至少包含带工具调用的任务、多轮上下文延续任务、长输出流任务、空输出和异常输出任务。先用这个测试集跑一遍再谈性能评测。不要以为在接口文档层面兼容行为层面就真的兼容。4.2 function calling是最脆弱的环节Agent依赖工具调用工具调用依赖模型输出结构化的function call参数。云模型在这方面已经打磨得很成熟输出格式基本稳定本地小模型则是重灾区。你经常能看到一个7B、8B模型在function calling时输出乱七八糟的JSON、返回空数组、甚至把参数名都改了。框架侧按标准Schema解析一头撞上非法格式整个执行链就断了。这个问题没有一劳永逸的解法只能靠工程手段降低风险。我在生产环境里常用三层防线校验层对模型输出做JSON Schema校验不合法就直接重试最多重试两次回退层如果本地模型连续失败把任务回退到云端模型前提是敏感度允许纠错层用一个轻量的本地规则把常见的格式错误做自动修复比如补全缺失的引号、把单引号替换成双引号。这三层用下来工具调用的成功率能稳住。但它也说明一个残酷的现实本地模型需要更多“保姆式”的工程处理这不是某一次调优能结束的而是要固化成模块长期维护。4.3 上下文工程要“本地特供”不能一套prompt走天下云模型动辄几十万的上下文窗口让你可以轻松塞进去一整套系统提示词、几百条few-shot示例和背景资料。本地模型则完全不行——显存有限时光是把模型权重加载进去能给上下文用的KV cache空间就所剩无几。强行塞长上下文结果往往是生成质量断崖式下降因为模型在长输入下连基础的任务遵循都做不到。所以给本地模型跑的prompt必须单独设计而且方向是“精兵简政”系统提示词浓缩到必要规则few-shot只保留最典型的一两个示例上下文信息里只保留当前任务真正依赖的内容不要再堆砌“背景知识大全”。我在项目里甚至会把同一个Agent写成两套提示词一套给云模型用信息丰富、约束详细一套给本地模型用结构极简、任务单一。两套提示词独立维护效果差距才拉得回来。4.4 结构性泄密“你只传了摘要但摘要本身就是秘密”有些系统自以为做了脱敏处理——把全文留在本地只把“摘要”或“关键信息”发给云端做二次处理。这个想法很危险因为摘要往往已经包含了最敏感的核心事实。比如一段客户会议摘要里写了“某公司计划在Q3上线新品”你以为这不是原文所以安全但实际上这句话本身就是机密。结构性的数据外泄往往是这种“我已经处理过了”的错觉造成的。我处理这个问题一般用两个手段第一在转发到云端前对将要出边界的字段做“最小字段化”检查每条内容都要有明确的脱敏规则比如人名替换成角色名、金额模糊成区间、公司名替换成代号第二对云端返回的内容不直接写入敏感系统必须经过一个“本地校验层”检查输出合规性。这两个手段配合所谓“不泄密”才是逻辑闭环的。5. 一套半离线HR Agent的路由配置实例聊了这么多原则最后放一个完整实例。这个案例来自一个真实项目为一家中型企业搭建HR领域的Agent处理简历筛选、候选人沟通摘要、邮件起草、内部ATS系统操作等任务。这个系统的特点非常典型大量数据属于L3敏感级别不能出内网但同时某些非敏感任务又想借助云端模型的效果。下面就是最终跑通的路由配置。5.1 场景需求和路由决策逻辑先说路由矩阵怎么定的。我们按“任务类型敏感级别复杂度”三个维度把系统的所有Agent任务归了类任务类型典型内容敏感级别推荐模型原因简历解析与字段抽取候选人简历转结构化学历/项目经历L3本地模型含个人信息绝不出边界内部ATS操作更新招聘进度、候选人状态L3本地模型写入内部系统外部调用风险大沟通摘要生成电话沟通记录整理成要点L3本地模型含候选人隐私强制本地招聘邮件起草基于模板生成面试通知、拒信L2本地模型模板化程度高本地模型足够JD改写优化公开职位描述重写、风格优化L1云端模型无敏感信息借助云模型效果招聘数据周报生成汇总统计数据、生成趋势分析L2本地模型云模型分步统计源本地算文字润色可走云端这个矩阵的核心思路是凡是碰候选人个人信息的一律在边界内处理凡是纯文字润色、公开资料处理的才交给云模型。哪怕云模型效果再好也不可能让它触碰L3数据。5.2 路由配置的落地写法实际实现中我没有把路由逻辑写死在代码里而是抽成了一个YAML配置方便运维和HR系统负责人一起维护router: default_target: local sensitivity_levels: - level: L0 allowed_targets: [local, cloud] - level: L1 allowed_targets: [local, cloud] - level: L2 allowed_targets: [local] cloud_after_sanitize: true - level: L3 allowed_targets: [local] - level: L4 allowed_targets: [local] tasks: - name: resume_parse sensitivity: L3 target: local timeout_seconds: 30 - name: mail_draft sensitivity: L2 target: local fallback: cloud_with_sanitize - name: jd_rewrite sensitivity: L1 target: cloud cost_limit: 0.5配置里有一行容易被忽略但极其重要的字段cloud_with_sanitize。它的意思是L2数据允许上云但上云前必须经过脱敏管线把姓名、公司名、联系方式替换为占位符并且在云端返回结果后再做一次合规校验才允许写回。这套机制上线后既保住了邮件起草的文案质量又堵住了“摘要即机密”的结构性泄漏口。5.3 上线后的三个踩坑记录这套配置跑起来之后遇到的几个问题也很有代表性。第一个坑出现在简历解析任务上。测试时本地模型对格式整齐的PDF简历解析得很好但真人投来的简历五花八门有的是扫描图片、有的是表格嵌套本地模型处理这些复杂格式时频繁输出乱码字段。解决办法是引入了一个前置OCR模块把图片简历转文本后再进解析流程解析成功率才稳定在可接受范围。第二个坑是邮件起草的语气问题。本地模型生成的模板化邮件过于生硬业务方抱怨候选人体验不好。我们不能为了语气把邮件数据发到云端于是换了个思路用云模型处理公开的“邮件风格指南”和示例库生成风格基准再让本地模型在风格基准的提示下起草邮件。这样敏感内容不出边界同时语气质量也提升了。第三个坑是日志泄露。我无意中发现Agent框架默认会把完整prompt和模型输出写入日志文件而日志文件会上传到集中日志平台平台在云端。这不就等于把L3数据绕了个弯送出去了吗最终的修复是把日志脱敏层加在日志写出之前所有入日志的内容必须先经过和路由一样的敏感检测命中敏感字段就替换成掩码。5.4 路由日志和审计字段最后说一句审计。就算路由本身设计得正确没有日志和审计佐证合规上也是站不住脚的。我建议每一个任务都记录一份路由审计日志至少包含以下字段字段说明task_id唯一任务标识task_type任务类型名sensitivity_level分级结果L0-L4route_target实际去向local/cloud/blockedmodel_name实际使用的模型标识sanitize_applied是否执行了脱敏处理tokens_used本地或云端token消耗latency_ms任务耗时decision_rule命中哪条路由规则final_status成功/失败/阻断有了这些字段你才能回答“这个任务为什么走了云”“这个任务做了什么处理”“这条数据到底在哪里流过”三连问。没有审计的路由跟没做路由在严谨性上差别不大。从我自己的实操感受来说任务路由这件事最难的不是写规则也不是选模型而是建立一套“所有数据流动都可解释”的纪律先定分级再定去向最后强制拦截。等这套纪律跑顺了本地模型和云模型的配合就不再是一门玄学而是一个稳定、可靠、可审计的工程结构。后面你再接入新的本地模型只要重跑一遍路由测试集根据模型能力微调阈值就行。