Agent 工程实习复盘 15|模型能力如何贯穿上传链路:默认模型、视觉能力与文件转换契约
本文基于 Agent 应用中模型配置、文件上传和多模态处理的一组改造整理。文中使用通用技术名称,不涉及具体项目、公司、模型供应商、密钥或用户文件。
关联工作包括默认模型显式配置、模型能力 API、上传时的模型能力校验、转换后文件路径契约,以及后台模型探测链路简化。
一、先说结论
在多模型 Agent 应用里,“用户能不能上传 PDF”不是一个前端按钮问题,而是一个跨越配置、前端、Gateway、文件转换和 Agent Middleware 的能力契约问题。
如果这些环节各自猜测,就会出现很典型的体验断裂:
- 页面显示当前模型支持看图,上传接口却拒绝文件。
- 用户已切换到支持视觉的模型,预上传仍按旧模型或默认模型判断。
- PDF 已经转换成页面图片,模型却只收到原始 PDF 路径,不知道该看哪一张图。
- 后台探测某个模型“能连通”,产品却误把它当成“支持视觉”或“支持图片生成”。
这次改造的核心不是增加更多判断,而是把模型能力变成一条一致的事实链:配置声明能力,模型 API 下发能力,前端携带当前选择,Gateway 最终裁决,转换产物通过 manifest 交给 Agent。
二、先分清三个概念:默认模型、当前模型和能力声明
它们经常被混成一个概念,但实际职责不同。
| 概念 | 含义 | 使用场景 |
|---|---|---|
| 默认模型 | 工作区没有显式选择时的兜底模型 | 新会话、上传未携带 model_name、运行时 fallback |
| 当前模型 | 本次会话或当前输入实际选择的模型 | 这一次上传和 Agent Run |
| 能力声明 | 模型是否支持视觉、思考、图片生成等 | UI 展示、上传校验、工具装配 |
默认模型不能再隐式等于配置列表的第一个元素。模型排序经常因后台操作、灰度验证或配置合并改变;一旦第一个模型变了,上传和运行时的兜底行为就会悄悄漂移。
因此配置增加显式的 default_model。解析默认模型时先看这个字段,只有旧配置没有声明时才兼容性回退到第一个已配置模型。
三、能力从哪里来:连通性不是能力证明
模型能力需要由系统配置显式声明,例如:
supports_vision:能否接收并理解图片或页面图像。supports_thinking:是否提供可控的思考模式。supports_image_generation:能否生成图片。
模型 API 会将这些非敏感字段和默认模型名一起返回给前端。前端据此决定展示什么入口、上传时附带哪个模型名;但它不拥有最终裁决权。
graph TD;
A[模型配置];
B[声明默认模型和能力];
C[模型列表 API];
D[前端模型选择器];
E[上传请求携带 model_name];
F[Gateway 按配置校验];
G[Agent Runtime 使用同一模型配置];
A --> B;
B --> C;
C --> D;
D --> E;
E --> F;
F --> G;
这里有一个重要边界:后台探测可以检查模型地址、认证和基本调用是否可用,但它不能凭一次文本请求推断视觉、图片生成或其他复杂能力。探测用于减少配置错误;能力声明仍是产品契约,应该由管理员明确维护。
四、上传校验必须知道用户当前选的是谁
上传常常发生在真正发送消息之前。为了提升体验,前端会先执行 pending upload,再由用户确认发送。如果上传接口只读取默认模型,就会有一个竞态:
- 默认模型是文本模型。
- 用户在当前会话切到视觉模型。
- 用户选择 PDF 并触发预上传。
- 后端没有收到当前模型名,仍按默认文本模型拒绝 PDF。
因此上传 API 增加可选 model_name 参数。前端从当前模型选择状态带入该字段;后端再按下面优先级计算本次上传的有效模型:
本次 model_name > 显式 default_model > 旧配置兼容回退
不过,前端传入模型名只是提示,不是信任边界。Gateway 会检查该模型是否存在于当前服务端配置;未知模型返回客户端错误,不能通过伪造字符串绕过能力限制。
graph TD;
A[用户选择文件];
B[前端读取当前模型];
C[上传请求带 model_name];
D[Gateway 解析有效模型];
E{模型配置存在};
F[返回未知模型错误];
G{文件需要视觉能力};
H[返回能力不支持错误];
I[保存文件并进入转换流程];
A --> B;
B --> C;
C --> D;
D --> E;
E -->|否| F;
E -->|是| G;
G -->|是且不支持| H;
G -->|否或支持| I;
五、为什么 PDF 的边界最容易暴露问题
普通文本文件可以作为文本交给模型;图片天然对应视觉输入;PDF 介于两者之间。
PDF 既可能包含可提取文字,也可能依赖表格、版式、扫描页、图表和图片。为了让 Agent 稳定理解文档,上传链路会把可转换文件处理成一组 Agent 可消费的资产,例如:
- 从原始文件提取的 Markdown 或文本页。
- 每页对应的页面图片。
- 描述源文件、页序、Markdown 路径和图片路径的 manifest。
如果当前模型不支持视觉,让用户上传 PDF 并承诺完整理解页面布局是不诚实的。因此 Gateway 会在写文件和启动转换前拒绝该组合,并返回明确提示:切换到支持视觉的模型后再上传。
这不是限制用户,而是避免后续 Agent 假装看到了自己实际上无法理解的版式信息。
六、转换完成后,模型为什么还会找不到文件
文件转换不是结束,最常见的第二个问题是路径契约断裂。
早期实现容易让模型根据原文件名猜路径,例如认为 report.pdf 的页面图片一定是 report.png。这种猜测在重名文件、分页、多图、不同转换器和历史目录兼容下都会失败。
正确做法是由上传服务产出 manifest,记录真实生成的资产;Middleware 读取 manifest 后把精确路径注入本轮 Agent 上下文。模型不需要猜,也不应该扫描整个上传目录。
graph TD;
A[上传原始文件];
B[转换服务生成 Markdown 和页面图片];
C[写入 manifest];
D[Upload Middleware 读取 manifest];
E[构造本轮 uploaded_files 上下文];
F[模型读取精确文本路径];
G[视觉模型按精确图片路径查看];
A --> B;
B --> C;
C --> D;
D --> E;
E --> F;
E --> G;
这份上下文会区分:原始文件、Markdown 文件、图片文件和 manifest 自身。对视觉模型,提示会明确哪些页面图片可以传给看图工具;对非视觉模型,至少仍可使用转换出的文本资产,而不会凭文件扩展名猜测不存在的图像路径。
七、上传与执行不是同一件事:pending 状态的意义
上传可能先于用户真正发送消息完成。pending 状态把“文件已接收并在处理”和“这批文件应当成为下一轮 Agent 输入”分开。
这样做有三个好处:
- 用户取消输入时,可以清理尚未确认的附件和转换资产。
- 同一轮消息可以一次确认多个已完成的附件。
- Agent Middleware 只注入本轮确认的增量文件,不把所有历史上传重复塞进 Prompt。
能力校验发生在文件真正进入后端时,而不是等用户点击发送后才失败。这样既避免无效转换成本,也让用户在选择错误模型时立即得到可操作的反馈。
八、为什么后端还要保留最终校验
即使前端已经根据 supports_vision 隐藏或显示上传入口,后端也不能省略检查:
- 前端代码可能尚未更新,或用户持有旧版本页面。
- 请求可能来自移动端、脚本、外部 API 或重放流量。
- 用户可能切换模型后仍保留旧页面状态。
- 任何客户端字段都可以被手工构造。
因此 Gateway 是最后的能力策略执行点。前端负责尽早提示,Gateway 负责不能绕过,Runtime 负责在通过校验后正确使用产物。
九、模型探测应当简化,不应承担所有语义
后台模型管理中常见的误区是把探测流程做得过长:尝试不同请求格式、不同参数、不同工具调用,再根据某次结果推导模型是否可用。
这会让“保存配置”和“在线探测”耦合,失败原因也变得难以解释。更稳妥的拆法是:
| 动作 | 解决的问题 | 不应解决的问题 |
|---|---|---|
| 保存模型配置 | 管理员声明地址、模型名和能力 | 不保证上游此刻可用 |
| 最小探测请求 | 基础连接、认证、请求格式是否通 | 不自动推断完整能力矩阵 |
| 运行时上传校验 | 本次模型是否允许处理该文件 | 不替代模型健康监控 |
这样,模型卡片的保存语义保持确定,探测失败也不会悄悄改写已经配置好的能力声明。
十、验证:验证的是能力契约,不是上传接口 200
相关回归覆盖的重点是前后端是否对同一个模型得出同一个结论:
| 场景 | 期望结果 |
|---|---|
| 未传 model_name 且默认模型支持视觉 | PDF 可以进入上传与转换流程 |
| 未传 model_name 且默认模型不支持视觉 | PDF 在 Gateway 被拒绝 |
| 传入当前视觉模型 | PDF 按当前模型能力放行 |
| 传入当前文本模型 | PDF 被拒绝,提示切换模型 |
| 传入不存在的模型名 | 返回明确的 unknown model 错误 |
| 前端 pending upload | URL 包含当前 model_name 和 pending 标记 |
| 转换生成多页资产 | manifest 记录精确 Markdown 和图片路径 |
| Agent 消费转换结果 | Middleware 只注入 manifest 中存在的精确路径 |
| 后台模型探测失败 | 不把一次探测失败误写成能力声明变化 |
后端测试覆盖默认模型回退、未知模型、非视觉模型 PDF 拒绝和转换资产;前端测试覆盖上传请求是否携带当前 modelName。这些测试的重点是避免前后端各自判断、最终互相矛盾。
十一、几个看起来合理、实际会出问题的方案
11.1 用 models 数组第一个元素当默认模型
配置排序不是业务语义。只要有人调整模型顺序,上传和运行时 fallback 就会无声变化。
11.2 前端只根据模型名称写规则
用模型名字符串判断视觉能力会快速腐化:自部署模型、别名、版本更新和新增供应商都会让规则漂移。能力应来自服务端配置。
11.3 只在前端禁止 PDF 上传
脚本和旧客户端仍可以直接调接口。没有 Gateway 最终校验,能力限制不是安全或成本边界。
11.4 PDF 转换后让模型自己猜图片路径
文件重名、分页和转换器升级都会让猜测失效。manifest 才是上传服务和 Agent 的稳定契约。
11.5 一次文本探测成功就标记模型支持视觉
连通性、文本生成和视觉理解是不同能力。自动猜测容易给用户错误承诺。
十二、面试时我会怎么讲
我会这样概括:
我参与过多模型 Agent 应用的上传能力治理。问题不是单一的 PDF 校验,而是默认模型、当前选择模型、前端上传请求、Gateway 校验、文件转换和 Agent 上下文之间存在能力漂移风险。我将默认模型改为显式配置,通过模型 API 下发视觉等能力;前端预上传携带当前 model_name,Gateway 仍以服务端配置做最终校验。对于 PDF,只有视觉模型才能进入页面图片转换链路,转换后由 manifest 把精确的 Markdown 和图片路径交给 Middleware,避免模型猜路径。这样前后端对同一次上传使用同一能力事实,也避免了不支持视觉的模型假装能理解文档版式。
如果继续追问,我会补充:模型连通性探测和能力声明必须分开。前者是运维诊断,后者是产品契约。
结语
多模型 Agent 的能力不是一个静态标签。只要能力会影响上传、转换、工具调用或用户预期,它就必须从配置一路传递到运行时,并且由后端守住最后边界。
把模型能力做成可声明、可下发、可验证、可消费的契约,才能让模型切换真正成为产品能力,而不是前端换了一个名字。