1. 从"跑一次仿真要三天"说起:代理模型到底在解决什么问题
如果你做过结构优化、天线设计、流体仿真或者任何涉及数值计算的工作,大概率经历过这种绝望:一个参数扫描跑下去,几十组工况,每组仿真两三个小时起步,等结果出来黄花菜都凉了。更别提那些基于遗传算法、粒子群算法的迭代优化,动辄需要成百上千次目标函数评估,纯靠真实仿真根本跑不动。
代理模型就是在这种场景下被逼出来的东西。它的核心思路非常朴素:用一个计算代价极低的"替身"去近似那个计算代价极高的真实函数。你花一些时间采样若干真实仿真点,用这些点训练一个数学模型,之后优化算法再调用目标函数时,直接问这个替身就行,毫秒级返回结果。原本要跑三天的优化,可能二十分钟就收敛了。
但这里有个关键问题:替身的精度能信吗?这就是代理模型全部技术含量的所在。不是随便拟合一下就完事,你需要关心采样策略是否覆盖了设计空间、模型类型是否匹配问题的非线性程度、精度验证是否可靠、什么时候该更新模型。这些环节任何一个出问题,优化结果都可能把你带进沟里——你以为找到了最优解,实际上只是代理模型的一个拟合误差。
与此同时,另一个看似不相关的领域正在发生类似的事情。大语言模型驱动的智能体越来越普及,但每次调用云端大模型都有延迟和成本问题。很多团队开始尝试在本地部署小模型来处理一些高频、简单的调度决策,把复杂任务才交给云端大模型。这本质上也是代理模型的思想:用一个轻量的本地模型代理重型云端模型的部分职能,在响应速度和能力之间找平衡。
这两个场景看似跨度很大,但底层逻辑高度一致——都是在"精确但昂贵"和"近似但廉价"之间做权衡。我在这两个方向上都做过实际项目,踩过的坑不少,下面把完整的思路和实操细节拆开讲。
2. 代理模型的核心分支与选型逻辑
2.1 四种主流代理模型的适用边界
代理模型不是一个单一技术,而是一类方法的统称。实际项目中最常用的是这四种:Kriging(克里金/高斯过程回归)、径向基函数(RBF)、多项式响应面(PRS)和支持向量回归(SVR)。近些年神经网络代理模型也用得越来越多,但在小样本场景下传统方法仍然更稳。
选型这件事,很多人上来就问"哪个精度最高",这其实是个错误的问题。正确的问法是:我的问题维度多高、样本量多少、非线性程度如何、是否需要提供预测不确定性。
| 模型类型 | 适合维度 | 适合样本量 | 非线性能力 | 是否给不确定性 | 典型场景 |
|---|---|---|---|---|---|
| 多项式响应面 | 低维(<10) | 极少(10-30) | 弱 | 否 | 快速摸底、线性趋势 |
| Kriging | 中低维(<50) | 中等(30-200) | 强 | 是 | 高精度优化、贝叶斯优化 |
| RBF | 中维(<100) | 中等 | 较强 | 否 | 工程通用、易实现 |
| SVR | 中高维 | 中等偏多 | 较强 | 否 | 高维回归、鲁棒性要求高 |
Kriging之所以在工程优化里地位特殊,核心原因是它自带预测方差。这个方差不是摆设,它直接告诉你"这个位置的预测有多不可信",从而指导下一步该去哪里补充采样点。贝叶斯优化框架里的EI(期望改进)、PI(改进概率)这些采集函数,全都依赖这个方差。没有不确定性估计的代理模型,做自适应采样就很被动。
RBF的优势在于实现简单、训练快、对中等维度问题表现稳定。它的核心是核函数宽度参数的选择,这个参数选不好,要么过拟合要么欠拟合。我一般用交叉验证来调,不要拍脑袋定。
多项式响应面现在用得少了,但在做初步探索时仍然有价值。你用一阶或二阶多项式快速拟合一下,看看哪些变量显著、趋势大概什么样,成本几乎为零。它的定位是"侦察兵",不是"主力部队"。
2.2 为什么我通常从Kriging起步
做了这么多项目,我的默认选择是Kriging起步,原因有三。
第一,它给不确定性。这一点在自适应采样和贝叶斯优化里是刚需。你不可能一次性把采样点布得完美,必然需要迭代补点,而补点的依据就来自不确定性。
第二,它对小样本友好。工程仿真往往一个点就要跑很久,你能拿到的样本量通常很有限,几十到一两百个点。Kriging在这个区间表现很好,不像神经网络那样需要大量数据。
第三,它的超参数有明确的物理意义。相关长度参数反映了函数在各个方向上的变化剧烈程度,核函数方差反映了整体波动幅度。这些参数调出来之后,你能反过来理解问题的特性。
当然Kriging也有明显的短板。样本量超过几百之后,协方差矩阵求逆的代价是O(n³),会变得很慢。高维问题(比如超过50维)下,相关长度参数的优化也会变得困难。这些情况下我会转向RBF或者SVR。
2.3 采样方法:LHS不是万能药
确定了模型类型,下一步是采样。最常见的做法是拉丁超立方采样(LHS),它比纯随机采样能更好地覆盖设计空间。但LHS有个问题:它只保证每个维度上的投影均匀,不保证空间填充性。也就是说,可能出现两个样本点在空间上挨得很近的情况。
改进方案是最优拉丁超立方(OLHS),在LHS基础上加一个优化准则,比如最大化最小距离(maximin)或者最小化势能。我实测下来,同样样本量下OLHS比普通LHS的代理模型精度能提升10%-20%,这个提升在样本稀缺时非常值。
还有一个容易被忽略的点:样本量怎么定。经验法则是样本量至少是维度的10倍,但这只是下限。更靠谱的做法是先采一批(比如10倍维度),训练模型,看交叉验证误差,如果误差大就继续加点。不要一次性采太多,仿真资源很贵,逐步加点是更经济的策略。
注意:采样前一定要确认设计空间的边界是否合理。我见过有人把变量范围设得过大,导致大量样本点落在物理上不可能的区域,白白浪费仿真资源。边界应该基于工程经验收紧,而不是随便给个数量级范围。
3. 从采样到可用模型:一条完整的实操链路
3.1 数据预处理里那些容易翻车的细节
拿到仿真数据之后,别急着往模型里灌。预处理这一步做不好,后面全白搭。
第一件事是检查异常点。仿真有时候会因为网格质量问题、收敛失败等原因产生明显偏离的数据。这些点如果混进去,Kriging会强行去拟合它们,导致整个模型变形。我一般用箱线图或者基于马氏距离的方法筛一遍,可疑的点回去查仿真日志确认。
第二件事是归一化。不同变量的量纲差异可能巨大,比如一个是毫米级尺寸,一个是兆帕级应力。不归一化的话,Kriging的相关长度参数会被大量纲变量主导,小量纲变量的影响被淹没。标准做法是归一化到[0,1]或者标准化到零均值单位方差。输出值也建议归一化,尤其是当输出跨度很大的时候。
第三件事是确认没有重复点。听起来很蠢,但确实会发生——参数化建模时两个不同的参数组合生成了几何上完全相同的模型。重复点会让协方差矩阵奇异,Kriging直接报错。
3.2 Kriging超参数的优化:别用默认值
Kriging的核心是超参数:核函数方差、相关长度、以及回归趋势项。这些参数决定了模型的形状。很多工具包会给你默认值或者用简单的最大似然估计,但在实际项目里,我强烈建议手动检查一下优化结果。
具体做法是:用最大似然估计(MLE)优化超参数,但要用多起点策略,因为似然函数是非凸的,单起点很容易陷入局部最优。我一般跑10-20个随机起点,取似然最大的那组。
优化完之后,看一下相关长度参数。如果某个维度的相关长度特别大(接近无穷),说明这个维度对输出的影响很小,可以考虑把它从模型中剔除,降低维度。如果相关长度特别小,说明这个维度变化剧烈,可能需要在这个方向加密采样。
还有一个实操技巧:相关长度可以分组。如果某些变量物理意义相近(比如同一类几何尺寸),可以共享一个相关长度参数,这样能减少待优化参数数量,提升小样本下的稳定性。
3.3 精度验证:交叉验证怎么做才靠谱
模型训练完了,怎么知道它能不能用?留一交叉验证(LOOCV)是最常用的方法:每次留一个点做测试,其余点训练,循环一遍,计算预测误差。这个方法在小样本下很实用,因为它最大化了训练数据的使用。
但LOOCV有个陷阱:它给出的误差是"平均"误差,可能掩盖了局部区域的大误差。我建议同时看最大误差和误差分布。如果最大误差远大于平均误差,说明某些区域模型拟合很差,需要针对性补点。
评价指标方面,R²和RMSE是最常用的。R²接近1、RMSE接近0当然好,但要注意:R²高不代表模型可用于优化。因为优化算法会去探索设计空间的边缘和未采样区域,这些地方的预测精度才是关键。所以我一般还会做额外测试集验证:单独留出10%-20%的样本不参与训练,专门用来测试。
一个经验判断:如果LOOCV的R²低于0.9,这个模型基本不能直接用于优化,需要补点或者换模型。R²在0.95以上才比较放心。
3.4 自适应采样:把仿真资源花在刀刃上
一次性采样往往不够,自适应采样是提升效率的关键。核心思路是:根据当前模型的不确定性或者优化需求,决定下一个采样点在哪里。
最常用的准则是最大预测方差:在当前模型预测方差最大的地方补点。这个策略能快速降低全局不确定性,适合构建全局精度较高的模型。
另一个准则是期望改进(EI):综合考虑预测值和不确定性,选择最有可能改进当前最优解的位置。这个策略更适合优化场景,它会把采样集中在最优解附近,而不是均匀覆盖整个空间。
我通常的做法是混合策略:前期用最大方差准则快速降低全局不确定性,后期切换到EI准则聚焦优化。这样既保证了模型整体质量,又不会在无关区域浪费仿真。
自适应采样的停止条件也很重要。常见的有:最大样本数限制、误差阈值、或者连续若干次补点后最优解不再改进。我一般设一个最大样本数(比如初始样本的2-3倍),到了就停,避免无限迭代。
4. 智能体本地小模型调度:另一个战场上的代理思维
4.1 为什么智能体需要本地小模型
大语言模型驱动的智能体现在很火,但实际部署时会遇到一个很现实的问题:每次决策都调用云端大模型,延迟和成本都扛不住。一个稍微复杂一点的任务,智能体可能需要几十甚至上百次决策,每次都走云端API,响应时间累积起来很可观,费用也不低。
本地小模型的价值就在这里。它不需要处理所有任务,只需要处理那些高频、简单、模式固定的调度决策。比如:判断用户意图属于哪个类别、决定下一步调用哪个工具、从结构化数据里提取字段、对简单查询生成回复。这些任务本地小模型完全能胜任,响应时间从秒级降到毫秒级。
这本质上和代理模型的逻辑一模一样:用一个轻量的本地模型代理重型云端模型的部分职能。区别只是,工程优化里的代理模型近似的是数值仿真函数,而这里的代理模型近似的是大模型的决策函数。
4.2 本地小模型的选型与量化部署
选本地小模型,核心看三个指标:参数量、推理速度、任务精度。参数量决定了模型能承载多少知识,推理速度决定了能不能满足实时性要求,任务精度决定了它能不能可靠地完成代理任务。
目前主流的选择是1B到7B参数量的模型。1B-3B适合做非常简单的分类和提取任务,7B左右可以处理稍微复杂一点的调度决策。再大就不适合本地部署了,推理成本会超过直接调用云端API。
量化是本地部署的关键技术。4-bit量化是目前性价比最高的方案,模型大小压缩到原来的四分之一左右,精度损失通常在可接受范围内。8-bit量化精度损失更小,但模型还是偏大。我实测下来,对于调度决策这类任务,4-bit量化后的7B模型和原始模型的表现差异很小,但推理速度提升明显。
部署框架方面,llama.cpp和Ollama是最常用的两个。llama.cpp更底层,适合需要精细控制的场景;Ollama封装得更好,上手快,适合快速验证。如果追求极致性能,可以考虑vLLM,它的PagedAttention机制对并发推理优化很好,但资源占用也更高。
4.3 调度策略:什么任务交给本地,什么任务上云端
这是整个方案里最需要经验的部分。分错了,要么本地模型处理不了导致任务失败,要么白白浪费云端调用。
我的分类原则是这样的:
本地模型处理的任务:意图分类(把用户输入归到预定义的几个类别)、实体提取(从文本里抽取结构化字段)、简单问答(基于固定知识库的查询)、工具选择(根据意图决定调用哪个API)、格式转换(把结构化数据转成自然语言)。
云端大模型处理的任务:复杂推理(需要多步逻辑链)、创意生成(文案、方案设计)、长上下文理解(超过本地模型上下文窗口的输入)、知识密集型问答(需要广泛世界知识)、代码生成与调试。
这个划分不是绝对的,需要根据实际任务表现动态调整。我一般会先让本地模型处理所有任务,记录失败案例,分析失败原因。如果某类任务本地模型失败率超过阈值(比如10%),就把它划到云端。
还有一个技巧:置信度路由。本地模型对每个决策输出一个置信度分数,高于阈值就本地处理,低于阈值就转云端。这样能在保证质量的前提下最大化本地处理比例。置信度的获取可以用模型输出的logprob,或者训练一个简单的分类器来判断。
4.4 本地模型与云端模型的协同机制
本地小模型和云端大模型不是替代关系,而是协同关系。设计好协同机制,能同时拿到低延迟和高能力。
缓存机制是最简单有效的协同方式。本地模型处理过的请求,把输入输出对缓存起来。下次遇到相同或相似的请求,直接返回缓存结果,连本地模型都不用跑。对于高频重复的调度决策,缓存命中率可以很高。
降级机制是保证可靠性的关键。本地模型推理失败或者超时,自动降级到云端。这个降级要做得无感,用户不应该感知到背后的切换。实现上可以用一个简单的try-catch包裹本地推理,失败就走云端。
反馈机制用于持续优化。云端处理的结果可以回流到本地,作为本地模型的训练数据。定期用新数据微调本地模型,它的能力边界会逐步扩展,能处理的任务越来越多。这是一个正向循环。
注意:本地模型和云端模型的输出格式要统一。我见过有人本地模型输出JSON、云端输出自然语言,结果下游解析逻辑要写两套,维护起来很痛苦。建议在调度层做一层格式适配,对下游暴露统一的接口。
5. 两个场景共通的坑与应对经验
5.1 外推风险:模型在训练数据之外有多不可靠
代理模型最危险的场景就是外推。优化算法探索到训练数据覆盖范围之外时,代理模型的预测可能完全离谱,但模型自己"不知道",仍然给出一个看起来合理的值。
Kriging在这方面稍微好一点,因为它的预测方差在外推区域会显著增大,能给你一个警告信号。但RBF、SVR这些没有不确定性输出的模型,外推时就是盲飞。
应对方法有两个。一是约束优化范围,把优化算法的搜索空间限制在采样覆盖的区域内。二是监控预测方差,如果优化过程中出现预测方差超过阈值的情况,暂停优化,补充采样点。
本地小模型也有类似问题。训练数据没覆盖的输入类型,本地模型可能给出完全错误的决策。所以置信度路由机制很重要,低置信度就转云端,不要硬撑。
5.2 精度与速度的平衡点怎么找
代理模型和本地小模型都面临同一个问题:精度和速度的权衡。模型越复杂越准,但越慢;越简单越快,但越不准。
这个平衡点没有通用答案,取决于你的具体需求。工程优化里,如果仿真一次要几个小时,那代理模型哪怕推理慢一点(比如几秒)也完全可以接受,精度优先。本地小模型调度里,如果要求毫秒级响应,那模型就得小,精度可以适当牺牲。
我的做法是先确定可接受的精度下限和可接受的速度上限,然后在这个约束下选最简单的模型。不要一上来就追求最高精度,很多时候简单模型已经够用了。
5.3 模型更新:什么时候该重新训练
代理模型和本地小模型都不是训练一次就一劳永逸的。数据分布变化、任务类型扩展、精度下降,都需要更新模型。
代理模型的更新触发条件比较明确:交叉验证误差超过阈值、优化结果与真实仿真偏差过大、设计空间扩展。本地小模型的更新触发条件更模糊一些:缓存命中率下降、降级到云端的比例上升、用户反馈质量下降。
我一般设一个定期评估机制,比如每周跑一次评估集,看指标有没有明显退化。退化超过阈值就触发重新训练。不要等到问题严重了才更新,那时候用户体验已经受影响了。
5.4 实际项目中的资源分配建议
最后说一个很现实的问题:资源怎么分配。代理模型项目里,仿真资源是瓶颈;本地小模型项目里,GPU显存和推理算力是瓶颈。
代理模型这边,我建议采样阶段大方一点,训练阶段抠一点。采样点质量决定了模型上限,多花仿真资源采好点值得。训练阶段Kriging的超参数优化虽然耗时,但那是CPU时间,相对便宜,可以多跑几个起点。
本地小模型这边,推理阶段抠一点,训练阶段大方一点。推理是要实时响应的,模型越小越快越好。训练可以离线做,用大一点的模型或者更多的数据都行,不影响线上性能。
这两个原则看起来矛盾,其实逻辑一致:把资源花在决定上限的环节,在决定效率的环节节省。采样决定了代理模型的上限,训练决定了本地小模型的上限,这两个环节值得投入。