模型配置为什么要做成可动态修改的?连通性测试要测什么?
简化版
模型的接口地址、API Key、模型名、温度、最大输出都是要反复调的:换服务商、换 Key、给某个功能换一个更便宜的模型,写在配置文件里每次都要改文件、重启服务。做成动态配置,就是把这些参数存进数据库,由模型工厂按库里的配置构建模型对象,并用配置内容拼缓存 key,管理员改完,下一次调用就用新配置。连通性测试是用一条已经保存的配置真实调一次最小请求,确认地址、Key、模型名都对;做得完整一些还要检查输出是否被长度上限截断、向量模型实际返回的维度是否和向量表一致,结果同样写进调用日志。
详细版
动态模型配置由四部分组成:
ai_model_config 表 用途、类型、服务商、接口地址、Key、模型名、温度、最大输出、向量维度、启用
模型工厂 按一行配置用 builder 构建模型对象,按配置内容缓存
统一调用出口 业务代码按「用途」取配置,再从工厂拿模型
连通性测试 用某一行已保存的配置发一次最小请求,结果写调用日志
几个关键设计:
| 设计点 | 做法 | 解决什么 |
|---|---|---|
| 缓存 key | 用地址、Key、模型名等内容拼,不用主键 | 改了 Key 后仍命中旧客户端 |
| 按用途取 | 业务代码只说「我要行程编排模型」 | 不同功能用不同模型,互不影响 |
| 一个用途一条生效 | 启用新的自动停用旧的,或约定取 id 最小的 | 同时启用多条时取到哪条不确定 |
| 地址归一 | 去掉末尾斜杠和误填的接口路径 | 几种写法请求到同一个地址 |
| 连通性测试 | 按类型发最小请求,检查截断和维度 | 配置错误在用户用之前暴露 |
完整版教学
一、写在配置文件里有什么问题
最常见的起步写法是把模型参数写进 application.yml 或环境变量,框架启动时读一次,生成一个模型对象注入到业务代码里。它能跑,但对应不了下面这些真实需求:
| 需求 | 写在配置文件里 | 存进数据库 |
|---|---|---|
| 换一把 API Key | 改文件、重启服务 | 页面上改完,下一次调用生效 |
| 给某个功能换便宜模型 | 所有功能共用一个模型,或者代码里写死多套 | 按用途各配一条 |
| 看某条配置到底能不能用 | 只能等业务报错 | 连通性测试一键验证 |
| 看某个模型调用了多少次 | 没有 | 调用日志带模型配置 ID |
判断一个参数该不该放进数据库,标准是「会不会反复调」。模型参数正是要反复调的那一类。
二、存进数据库之后,模型对象怎么跟着变
模型对象(比如 ChatClient、ChatModel)创建时会带上地址、Key、模型名,创建有成本,所以要缓存复用。问题出在缓存 key 上:
用主键做 key:
管理员把 id=1 的 Key 从 sk-aaa 改成 sk-bbb
下一次调用 cache.get(1) 命中的仍是用 sk-aaa 构建的对象
页面上改了等于没改,只能重启
用配置内容做 key:
key = baseUrl | apiKey | modelName | temperature | maxTokens
Key 一改,key 字符串就变了,缓存未命中,自动构建新对象
用内容做 key 会留下旧对象:每改一次配置,缓存里就多一个再也不会被命中的实例。常见的处理是设一个上限,比如 16 条,满了整体清空,下一次调用重建一次就回来了。模型对象的数量只和「用途 × 改配置次数」有关,这个上限绰绰有余。
还有一点要知道:已经在执行中的调用手里拿的是旧对象,会用旧配置跑完;改动从下一次取模型开始生效。
三、按用途取配置
一个系统里往往有好几种模型调用:长篇编排要大的输出上限,一句话抽取只要很小的上限,向量化要专门的向量模型。给配置表加一个「用途」字段,业务代码按用途取:
// 业务代码只说要哪个用途的模型,不关心是哪家、哪个模型名
AiModelConfig config = aiChatService.resolveEnabledConfig("行程编排");
同一用途可能被配了多条,必须约定只有一条生效,常见两种做法:
| 做法 | 优点 | 代价 |
|---|---|---|
| 启用新配置时自动停用同用途的旧配置 | 页面上看到的启用状态就是实际生效的那条 | 保存逻辑多一步 |
| 允许多条启用,查询时按 id 取最小的一条 | 实现简单 | 页面上多条都显示启用,要靠约定理解 |
取到的配置还要检查是否完整:地址、Key、模型名缺一项就当作没配,直接提示「未配置启用的某某模型,请先去模型配置页填好」,而不是把请求发出去等服务商报一个英文错误。
四、地址写法要归一
管理员填接口地址的写法不统一,而框架会在基础地址后面自己拼 /chat/completions 或 /embeddings:
| 管理员填的 | 归一后的基础地址 | 实际请求 |
|---|---|---|
https://api.deepseek.com | 原样 | .../chat/completions |
https://api.deepseek.com/ | 去掉末尾斜杠 | .../chat/completions |
https://api.deepseek.com/v1/chat/completions | 去掉接口路径 | .../v1/chat/completions |
api.deepseek.com | 没有协议头,直接拒绝保存或测试 | —— |
不归一的话,第三种写法会请求到 /chat/completions/chat/completions,报一个 404,很难想到是地址多写了一段。
五、连通性测试到底测什么
「测试连接」不是 ping 一下地址,而是用这条配置真实调用一次模型。最小请求能暴露的问题:
| 检查 | 怎么测 | 暴露的问题 |
|---|---|---|
| 地址、协议 | 发一次真实请求 | 地址写错、网络不通、超时 |
| Key | 同上 | Key 无效、欠费、没开通该模型 |
| 模型名 | 同上 | 模型名拼错、服务商下线了该模型 |
| 输出上限 | 对话模型检查结束原因是不是长度截断 | 最大输出配得太小,一句话都写不完 |
| 向量维度 | 向量模型比对实际返回的维度 | 配置的维度和向量表对不上 |
请求要尽量小:对话模型让它「用一句话确认连接正常」,向量模型向量化一小段固定文本,成本几乎可以忽略。
记忆钩子:连通性测试要回答的不是「地址通不通」,而是「这条配置拿去跑业务会不会出错」。
六、为什么用库里已保存的配置测,为什么写日志
测试接口只收配置的主键,按主键从库里读,不读页面上还没保存的表单。这样测通的就是业务真正会用的那一行,不会出现「弹窗里测通了、保存时手滑改了一个字母」的情况。测试也要走和业务相同的统一出口,结果写进调用日志:成功能看到耗时和 Token,失败能看到翻译后的原因,管理员在日志页按「模型连通测试」场景筛出来就能对照。
停用的配置能不能测?应该能。管理员往往是先测通、再启用;只允许测已启用的配置,就要先启用一条不知道能不能用的配置,业务那边可能立刻就用上了它。
七、一个维度对不上的算例
一个知识库有 3000 个片段要向量化,向量表按 1024 维建好。管理员新配了一个向量模型,实际输出 1536 维:
没做维度检查:
批量向量化开始,每个片段一次调用
前 N 个片段的调用都成功了,写向量表时才报维度不匹配
最坏情况下 3000 次调用都已经发出,全部白花
测试时做维度检查:
点一次「测试」,1 次调用
提示「实际返回 1536 维,与向量表的 1024 维不一致」
改好配置再开始批量任务
1 次调用和 3000 次调用的差距,就是连通性测试多检查一项的价值。
八、常见误区与追问
- 误区:连通性测试就是看接口地址能不能连上。 地址通了,Key、模型名、输出上限、向量维度都可能是错的,要真实调用一次。
- 误区:模型对象按配置主键缓存就行。 改了 Key 或模型名之后,按主键还会命中旧对象,改了等于没改。
- 误区:只允许测试已启用的配置。 这会逼着管理员先启用一条没验证过的配置,业务可能马上用上它。
- 误区:配置取不到时用一套默认配置兜底。 管理员停用了配置功能照常跑,会以为停用没生效,排查时也看不出实际用的是哪套。
- 追问:改了配置,正在执行的调用会不会受影响? 不会,正在执行的调用拿的是旧对象,改动从下一次取模型开始生效。
- 追问:测试请求为什么要写调用日志? 测试失败时日志里有翻译后的原因和耗时,和业务调用放在一起看,能判断是配置问题还是服务商问题。
九、加强记忆
模型参数要反复调,所以存数据库而不是配置文件。存库之后三件事要做对:工厂按配置内容拼缓存 key,改了就自动重建,缓存设上限整体清;业务按用途取配置,同一用途只能有一条生效,配置不完整按没配处理并提示去哪补;地址先归一再交给框架。连通性测试用库里已保存的那一行真实调一次最小请求,除了地址、Key、模型名,还要看输出有没有被截断、向量维度对不对得上,停用的配置也能测,结果和业务调用一样写进调用日志。
项目实战落地
项目里怎么做的
《AI Agent旅游行程智能规划平台》的 ai_model_config 预置了三条配置:行程编排(最大输出 32000)、偏好抽取(最大输出 2048)、向量模型(维度 1024),API Key 全部留空,由管理员在页面上填。围绕这张表:
- 工厂按配置构建。
LangChain4jModelFactory不用框架的自动配置,拿表里的一行当参数,用 builder 构建对话模型和向量模型;缓存 key 由地址、Key、模型名、温度、最大输出五项拼成,缓存达到 16 条时整个清掉。 - 业务按用途取。
resolveEnabledConfig按model_purpose查启用中 id 最小的一条;地址、Key、模型名任一为空按没配处理,提示「未配置启用的「xx」模型,请先在【AI模型配置】启用并填好 Base URL、API Key、模型名称」。 - 地址归一。 去掉末尾斜杠和误填的
/chat/completions、/embeddings,没有 http 协议头的地址直接拒绝。 - 连通测试。 按主键取库里的配置,不经过「按用途取启用配置」,停用的配置也能测。对话模型发一句「请用一句话确认连接正常。」,结束原因是长度截断时不给出「配置可用」;向量模型向量化一段固定文本,再核对实际维度。两种调用都走统一出口,结果写进
ai_usage_log,场景记为「模型连通测试」。
《AI Agent智能会议纪要辅助系统》用另一种约定保证一个用途只有一条生效:同一用途只允许一条启用,启用新配置时自动停用同用途的旧配置。
为什么这样取舍
- 缓存 key 带上温度和最大输出。 编排和抽取两条配置可以填同一把 Key、同一个模型名,只是最大输出一个 32000、一个 2048;只用地址、Key、模型名拼 key,两个用途会共用同一个模型对象,其中一个的最大输出就是错的。
- 截断也算测试不通过。 这个模型连一句话都写不完,说明最大输出配得有问题;测试时说「可用」、真用起来篇篇截断,两个口径就打架了。截断怎么检测,见「如何控制大模型的输出长度并处理截断?」。
- 停用的配置也能测。 测试走主键而不走「按用途取启用配置」,管理员可以先测通再启用。
配置中心另外两块:API Key 怎么在页面上展示和修改,见「模型配置存进数据库后,API Key 在管理页面上怎么展示和修改?」;Prompt 模板怎么管,见「Prompt Registry 在 LLMOps 中解决什么问题?」。
面试官还会追问
- 向量维度在模型配置和系统参数两处都能填,保存配置和连通测试时以哪一处为准?为什么?
- 模型配置里的温度和最大输出允许留空,留空时工厂构建模型对象怎么处理?
学完《AI Agent旅游行程智能规划平台》,上面这些追问你都会迎刃而解。