多模态、Harness与MCP:Agent开发工程实践全记录

发布时间:2026/10/15 5:32:22
多模态、Harness与MCP:Agent开发工程实践全记录
1. Agent 开发的新常态为什么把多模态、Harness 与 MCP 放在同一本笔记里做 Agent 开发这两年我有一个很深的感触这个领域的门槛正在从能不能调通模型 API快速转移到能不能让 Agent 在真实场景里稳定地产出结果。回想最早做 Agent 的时候任务很简单给模型一个 prompt让模型输出一段文本再解析这段文本里的 JSON调外部工具。那时候最头疼的是模型不听指令输出格式不稳定。但现在的问题已经完全不一样了。用户希望 Agent 能看懂截图、听懂语音希望它能自己调用十几个工具完成跨系统的操作还希望整个流程可以被追溯、被验证。也就是说Agent 从一个会聊天的对话程序变成了一个需要感知世界、操作世界的执行体。这个变化引出了三个我必须持续投入精力的方向。第一是多模态能力。真实世界的输入不只是文本还有图片、表格、音频、视频。如果 Agent 不能理解这些非文本信息它的可用范围就被限制在纯粹的文本对话里很多东西做不了。比如用户拍了一张合同照片问 Agent 某一条款有没有问题纯文本模型是完不成这个任务的。第二是Harness也就是 Agent 的测试与评估框架。这是很多人忽略的部分。模型能力只是在提高单次回答的质量但 Agent 是一个多步骤的系统它要调用工具、要处理中间结果、要在不同的情况下做出决策。系统的可靠性不能靠偶然一次跑通来保证必须有一套可重复的评估机制。Harness 就是给 Agent 准备的考试系统没有它Agent 项目会永远困在自己调着觉得挺好一到线上就翻车的循环里。第三是MCPModel Context Protocol。它解决的是 Agent 与外部工具之间的连接问题。早期做一个工具调用要为每个系统写一套适配代码每换一个工具就多一堆胶水代码。MCP 提供了一种标准化的接入方式让 Agent 可以以统一的方式发现工具、调用工具、接收工具结果相当于把USB-C 接口引入了工具生态。对我的实际工作来说最大的价值是可以把注意力从怎么接上转移到接上之后做什么。这本笔记就是我在实际开发中对这三个主题的记录。文章会尽量贴近工程的实际情况不写泛泛的概念介绍而是把我遇到过的具体问题、做过的选择、踩过的坑都铺开来聊聊。不管你是正打算进入 Agent 开发的工程师还是已经在做多模态应用、工具调用和评测体系的老手这篇文章应该都能给你一些可以参考的经验。2. 多模态输入不是把图片塞进去这么简单多模态在 Agent 里的角色不只是模型能看图。它直接决定了 Agent 能处理的信息范围。要把多模态能力用好先要弄清楚几种不同的输入形态以及每种形态背后隐藏的工程代价。2.1 三种输入形态图文、音频、视频先说说图文混合。这是目前最常用也是落地最容易的一类。形式上很简单请求体里同时包含文本和图片模型自己会做跨模态的语义理解。难点主要在产品层——用户拍照时可能模糊、逆光、角度歪斜模型要能容忍这些噪声。我做过一个合同审核类的 Agent用户上传的合同照片经常是桌子上的纸质文件有阴影、有手指遮挡甚至还有透视形变。如果期望模型像处理干净扫描件一样处理这些输入结果会非常糟糕。所以我们的做法是在 Agent 的预处理链路里先加入一个文档图像矫正步骤检测页面边缘、做透视变换、再进 OCR 或直接进视觉模型。比起图文音频输入要更复杂一些。这里有个关键选择到底是用传统 ASR 把音频转成文本然后走纯文本链路还是直接用支持音频理解的多模态模型。我个人的经验是当音频内容只有单一说话人、环境噪声可控时先转文本再处理性价比极高延迟低效果稳定。但如果是会议录音这类多说话人叠加、有笑声和打断声的复杂音频直接交给多模态模型理解往往会有惊喜因为它可以利用语气、停顿、副语言信息判断说话人的态度。代价是延迟更高token 消耗更大所以我一般只在文本链路结果置信度不高时才额外调用多模态模型做二次校验。视频输入是最烧资源的一类。完整的视频理解目前还很难在常规 Agent 场景下保证延迟。工程上通常做抽帧处理按时间间隔抽取关键帧再聚合这些帧的视觉信息。这里有一个经验抽帧间隔要根据场景动态调整。信息密度低的场景比如监控画面每 5 秒抽一帧就够了信息密度高的场景比如操作教程视频可能需要每秒抽两到三帧并且要做前后帧的去重——不然 Agent 会把同一块画面当成不同信息重复分析多次浪费时间和 token。2.2 多模态接入的工程细节在 API 层面传图片并不复杂无非是把图片编码成 Base64 或者用图片 URL塞进消息的合适位置。真正值得琢磨的是信息量的调度。图片分辨率对 token 消耗的影响极大。同样一张图按 2048 分辨率送入和按 512 分辨率送入模型对细节的敏感度完全不同而 token 消耗可能差出一个数量级。我现在的做法是先看任务对图片细节的要求如果需要读取屏幕截图上的小字号文字、图表标签或者表格单元格就用高分辨率如果只是让模型确认图片是室内还是室外、物品的大类是什么用低分辨率就足够。不要盲目地把所有图片都按最大分辨率处理否则一次多模态调用的成本可能会超过整个 Agent 其他部分成本的总和。延迟和容错也很关键。多模态模型在部分问题上的响应延迟波动比文本模型更大因为图片预处理环节在服务端有时会出现排队。所以我在 Agent 里会为多模态调用单独设置超时时间和重试策略。这里有个小技巧如果模型在给定 prompt 下对一张图片给出空回复或异常回复可以先让模型描述图片里有哪些物体拿到一个基础描述之后再让它回答原始问题效果常常会好很多。我自己把这种做法叫视觉锚定本质上是用低难度的中间任务给模型一个稳定的上下文锚点避免模型在面对复杂图像时直接眩晕。还有一类任务很多人会忽略——纯多模态的输出。比如让 Agent 根据数据分析结果生成一个图表或者生成一份包含视觉排版建议的页面描述。这类任务的核心不是让模型直接输出图片而是让 Agent 输出可供渲染的中间结构如绘图代码或 JSON 配置再由执行层渲染成图片。这样既保留了模型的内容生成优势又规避了目前多模态生成在精确排版上的弱点。2.3 多模态评测的特殊性幻觉与感知粒度多模态的评测和纯文本评测很不一样。文本评测至少在答案对错上有较清晰的判断多模态评测要面对的难题是幻觉——模型可能一本正经地说出图片里根本不存在的东西。常见幻觉有三种。第一种是对象幻觉图片里没有杯子模型说有一个杯子第二种是属性幻觉图片里有一辆车但颜色是白的模型说是黑的第三种是空间关系幻觉左边和右边它完全说反了。为了量化这个问题我建立了多模态评测的最小测试集。里面特别设计了一类对抗性样例在每道题的图片中刻意加入干扰元素。比如图片里同时放着一本书和一支笔模型被问到图中有哪些电子设备时如果它回答了书本说明它的对象判定能力不合格。这类样例用一次就知道模型的边界在哪比泛泛地问图片里有什么有诊断价值得多。更实用的一种测试方法是局部裁剪测试。给定一张包含多个信息区域的截图比如一个包含表格、曲线、批注的 PDF 页面先让模型从整体上定位各个信息区域再逐块裁剪放大让模型看。我发现很多多模态模型在处理同时关注多个细节区域的任务时效果很差——不是能力不够而是注意力的分配被整页的视觉复杂度干扰了。通过局部裁剪可以把单次理解的复杂度降下来准确率能提升不少。这也提醒我多模态 Agent 的设计不应该只是简单地把图传给模型而是要考虑如何组织视觉信息。3. Harness给 Agent 装上一套考试系统如果只让我选一个对 Agent 开发最有价值的基建我选 Harness。模型能力再强没有评估你根本无法保证迭代方向是对的。Agent 系统尤其如此因为它是一个会调用工具、产生副作用、多轮循环的系统其复杂度远高于单次对话。3.1 为什么普通单元测试不够用传统软件的单元测试思路是给定输入、验证输出。Agent 开发里当然也需要这种测试但问题是失真。真实用户不会按照你写好的 prompt 那样说话更不会保证所有外部系统的状态都正常。用户可能提交一张模糊不清的图片、一个拖了很久的工单上下文、一个已经失效的会话状态。这些东西在你写单元测试时很难提前想到。所以我倾向于把 Harness 理解成一个在线运行时的沙盘考场。它不只验证模型的文本输出对不对还要看完整的行为链路工具调用参数是否正确、调用顺序是否合理、失败后是否进行了合适的恢复、最终结果是否满足用户需求。3.2 Harness 的五个组成件一个真正可用的 Harness至少要包含五个部分一是测试集管理。配有稳定的样本库来自两个渠道人工构造的典型场景以及线上日志回放。人工样本保证基础能力不退化回放样本保证历史问题不复发。二是运行器。它负责启动 Agent 并把样本喂进去同时模拟外部工具的响应。运行器要有能力注入故障——比如让某个工具随机返回超时或者让某个依赖系统返回异常代码——来检验 Agent 在异常情况下的表现。三是观测器。它会把 Agent 运行过程中所有的内部事件都接出来模型输出了什么、模型调用了哪个工具、传的参数是什么、返回结果是什么、Agent 在每一步花了多少时长。这些日志是判断问题的关键证据。四是断言器。这是最需要打磨的部分。断言不是简单判断Agent 最终回答是否包含某个关键词而是判断行为路径是否符合预期。比如一个订票 Agent断言应该包括是否调用了查询航班工具、传参里的日期格式是否正确、是否在查到结果之后才做推荐、是否在用户给出歧义输入时主动澄清了意图。我见过太多一上来就追求端到端最终回答正确率的团队结果出了问题时根本定位不了是哪一步错的把 Harness 的定位搞偏了。五是报告器。把多轮样本的运行结果汇总成一份可快速浏览的回归报告标识出哪些样本从通过变成了不通过哪些新增的能力点有待人工确认哪些样本的延迟开始恶化。没有报告Harness 只能算个跑批脚本。3.3 用 Harness 驱动迭代的实战流程我在实际项目中用的是三阶段回归节奏第一阶段每模型版本更新时跑全量回归。样本量控制在几百条级别单条样本运行时间平均一分钟左右一轮全量回归大概跑四五个小时。跑完重点关注两个数据整体通过率以及工具调用准确率这个行为指标。很多时候模型的文本得分并没有下降但工具调用参数出现了格式偏差——这种问题单看文本输出是发现不了的。第二阶段针对失败样本做重放调试。从回归结果里找出失败的样本把观测器记录的完整日志拉出来一行一行看模型在哪个环节开始跑偏。我遇到的典型情况是模型在第三步调用了一个多余的工具然后被这个工具返回的意外内容带偏了方向。这种问题只有在完整日志的视角下才会暴露。第三阶段根据失败模式补充新测试样本。每修完一个 bug就把对应的场景固化成新的样本加进测试集。这样能形成负反馈闭环这个坑未来再出现Harness 会第一时间报警。一个实际项目里我负责的 Agent 最初全量回归通过率约六成。通过三阶段循环迭代两个版本之后通过率稳定到了九成以上。这中间的提升几乎全都来自失败日志 → 定位行为路径 → 调整提示或调用策略,而模型本身的能力几乎没有变化。这说明 Harness 的首要价值不是测模型而是测 Agent 的编排逻辑。3.4 防止评估过拟合的几个原则用过 Harness 一段时间后会面临另一个危险过拟合测试集。Agent 开始变得很会考试但在真实场景里还是翻车。我总结了几条反过拟合的实操原则第一不要让测试样本里的 prompt 词汇和线上对话高度重合。评估样本应该不断换说法否则 Agent 可能记住了题面答案而不是学会了如何推理。第二要加入对抗性输入样本用户表达得含糊、带错字、误解了能力边界。这类样本往往最能暴露 Agent 的脆弱点。比如用户说帮我退掉这个订单但订单处于已发货状态Agent 是否应该主动核实退单政策、是否应该向用户说明退单可能产生费用这类边界场景比标准流程更能体现系统的成熟度。第三要避免评估指标只看最终成功率。要多看子环节的指标比如意图识别覆盖率、工具参数准确率、一步走错后恢复的概率。最终成功率好但子环节不稳定通常说明 Agent 的某一步在靠运气兜底这是隐患。在实际操作中我发现很多团队只搭了最终回答对比级别的简易评估跑起来很快但对项目早期发现问题几乎没什么帮助。工具调用断言、过程日志断言才是 Harness 里最值得投资的部分。4. MCP把工具接入做成即插即用MCP 是我在 Agent 开发里讨论得最多、也是争议最多的一个话题。我一开始觉得它就是一套新的接口协议但用了几个项目之后我的判断变了MCP 对 Agent 开发的影响更像当年浏览器统一了 Web 标准、USB-C 统一了外设接口。它把接入工具从一场逐一定制的苦工变成了一项标准化的插拔过程。4.1 MCP 到底解决了什么问题在没有 MCP 的时期做一个能调用天气、日历、邮件、数据库、内部 API 的 Agent代价非常高。每一个工具供应商都可能给出不同的接口签名、不同的认证方式、不同的数据格式。你为天气服务写的取数函数换一个航班查询服务就完全失效。当时团队里维护了一堆适配器代码每个新服务的接入都要人工对接能借助的通用性非常有限。MCP 的核心贡献是把工具发现和工具调用统一成一套基于 JSON-RPC 的交互流程。一个 Agent 对接一个 MCP 服务端可以像列目录一样列出所有可用的工具看清每个工具的参数 schema然后用标准格式发出调用请求再以标准格式接收结果。整个交互不关心背后调用的是真实 API、本地脚本还是云端数据库。我自己用一个比喻来理解 MCP它就像一个万能插头。服务端只需要实现一套 MCP 规范任何符合规范的 Agent 客户端都能直接通信无需逐家定制。正如 USB-C 取代各种充电接口这段关系对 Agent 的整个工具生态来说至关重要。4.2 工程上如何落地 MCP落地之前先想清楚一个原则问题MCP 的粒度。我常见的做法是把一个职责边界清晰的域做成一个 MCP 服务端。比如内部订单系统一个服务端、知识库查询一个服务端、图像处理工具集一个服务端而不是让一个庞大的服务端暴露二十个松散隔离的工具。这样做的理由很简单粒度适中既方便调试也方便权限控制。某个用户只需要订单查询能力时我只需要在配置里暴露订单服务端绝对不需要让 Agent 知道知识库里有哪些私有标记。管理上的收益是很直观的每次只改一个服务端出问题也不会影响全部工具。在 Agent 与 MCP 服务端之间还有一个关键的配置项工具启用的白名单。虽然服务端可以列出十个工具但具体的某个 Agent 也许只应该启用其中三个。这个白名单必须在 Agent 侧控制而且要有清晰的审计日志。否则一个 Agent 会随意调用所有它手上能用的工具这不是能力强大这是事故隐患。在 Agent 的内部实现里我会把 MCP 调用封装成一个独立的工具层这个工具层负责三件事将 Agent 的自然语言工具意图解析为严格符合 schema 的调用参数统一接收 MCP 服务端返回的错误、超时、异常状态并做标准化处理把这些调用事件写入系统的运行日志供 Harness 重放和排查问题。4.3 权限与安全最容易踩的坑Agent 的安全边界和普通 API 不同。用户直接调用 API 时权限基本由账号系统划定Agent 则是在自主决策它可能会合理地调用出一些用户没想到的操作。所以我现在坚持三条原则第一条是最小权限。每个 MCP 服务端只开放任务所必需的操作集合。一个负责查询预算的服务端不应该暴露修改预算的工具。即使同一个数据库里有这两个能力也应该分成两个服务端服务。第二条是人工确认关卡。对高风险操作比如删除数据、发起转账、发送消息Agent 必须走到人工确认这一步。我做过的最有效的方式是让 Agent 在调用这些高风险工具前先调用一个确认请求工具把将要执行的操作以结构化描述返回给客户端用户在界面上点了确认之后Agent 才真正执行。这一步看似增加交互成本但对系统的可信度帮助最大。第三条是审计日志闭环。MCP 调用日志必须保留足够长的周期而且要和用户会话 ID 绑定。一旦出现Agent 背地里做了不该做的操作能否快速定位完全依赖这些日志。这个能力一定不能只在出了问题之后补应该一开始就当成基础设施来建。4.4 多模态 Harness MCP 的一次完整串联这三个能力从来不是孤立使用的我实际的项目里有一个场景可以很好地展示它们如何协同工作。需求是用户拍一张植物叶片的照片Agent 需要识别出可能的病害从知识库中调取对应的防治方法最终生成一份图文并茂的报告。整个流程听上去简单拆开之后每一步都必然要用到上面的技术点。用户先发来照片。多模态组件抽取出叶片特征描述输出黄化、扇形分布、叶缘枯焦这些视觉证据。然后是 MCP 的职责Agent 调用病害分类服务端的查询工具拿着视觉描述去匹配数据库。这里有一个设计细节匹配不是直接把视觉描述丢进 SQL而是先把描述转成结构化的特征向量查询请求再交给 MCP 服务端处理这样可以把视觉层的输出和业务层的工具调用解耦。结果返回以后Agent 还要从防治知识库服务端获取用药指导。但药剂名称和剂量格式因地区而异Agent 需要调用一个药品说明书解析工具做标准化这又落在 MCP 的服务边界里。最后生成的报告需要多模态模型输出一份包含图表的 HTML 渲染代码再由渲染模块执行传给用户。这整个链路如果不做 Harness 记录会非常难调试。所以我们在 Harness 里给这个场景构造了二十多个样例覆盖不同病害、不同拍照质量、不同知识库命中情况。每个样例都要断言这些关键行为视觉特征是否被正确抽取、疾病查询的工具参数是否规范、药剂标准化是否成功、最终报告是否包含了推荐使用的剂量信息。一次全量回归跑下来我可以快速看出是视觉特征抽取层的问题、还是 MCP 工具调用层的问题、或者是最终排版生成的问题。这个体验让我强烈地感受到做 Agent 开发已经不能再像早期那样把模型、工具、评估分开来对待。它们必须被放在同一个工程闭环里协同设计。5. 常见问题与排查技巧实录下面这些是过去部署 Agent 过程中最常遇到的问题我整理成速查表并把每个问题背后的排查要点写在后面。问题现象常见原因排查步骤解决建议多模态模型把图片里没有的物体描述出来低分辨率输入导致模型脑补细节检查送入模型的图片实际分辨率与编码压缩率提高分辨率或对局部区域做裁剪放大后二次确认Agent 明明调到了正确工具但最终结果错误工具返回结果被模型误读通过 Harness 日志查看工具结果在上下文中如何呈现调整工具返回结果的摘要结构先做字段裁剪与格式化MCP 工具偶尔出现超时Agent 整体失败上游服务不稳定导致单点失败查看是否为偶发超时、超时时长设置是否过短给工具调用加自动重试与退化提示不要让 Agent 直接放弃任务Agent 在某个任务上自说自话不调用任何工具上下文里少了触发工具的信号检查 prompt 对工具的描述是否足够显性在系统提示里为工具调用场景补充先检查数据再回答的约束Harness 回归通过率很高但线上仍然翻车测试集与实际线上输入分布不一致对比线上日志与测试样本的典型输入结构定期把线上失败日志回放到测试集里形成闭环覆盖多模态调用延迟过高影响用户体验每轮对话都把整张高清图喂给模型查看消息里图片是否逐轮重复传递对话过程中裁剪图片尺寸、在关键步骤才传递完整图MCP 服务端工具数量膨胀后Agent 开始选择错误工具工具描述与命名区分度不够查看模型实际选工具时的输入上下文为每个工具写更精细的描述必要时启用白名单缩小选择范围Agent 在中间步骤出错后不重试直接给用户错误结果缺少重试逻辑的状态机查看异常分支的路径记录增加工具调用失败后的重试与替代方案提示评测报告显示失败但不确定是模型问题还是编排问题断言粒度太粗无法定位环节检查是否有分步骤的日志断言为工具调用、参数校验、最终输出分别设立独立断言用户在对话中改口Agent 忽略新信息继续旧路径上下文信息的时效处理不足检查模型是否把旧指令权重放得太高在上下文中标注指令时间戳或对旧指令做明确的作废操作除了这些有明确现象的问题还有几个纯经验的建议。第一日志记录要先于问题发生。不要等到线上出了事故才去埋点。MCP 调用日志、多模态请求的图片缩略记录、Harness 里每一步的结果快照这些都应该在系统上线第一天就开着。第二评估样本要多于新功能开发量。每开发一个新能力至少要同时构造五到十个覆盖该能力成功与失败路径的样本。这个习惯让整个 Agent 的质量基线始终是上升的。第三要能回放任意一次线上对话。只要用户会话 ID 在手就能用 Harness 把当时的状态、工具结果、模型输出重新跑一遍。没有这项能力排查问题就只剩下凭感觉猜效率极低。第四模型的升级评估不要只看分数。有的模型升级后整体得分持平但在某个特定工具调用格式上出现系统性退化。必须用 Harness 分类统计各工具类型的准确率才能发现这类隐蔽回归。最后再分享一点实际的体会写到这里最想跟同行的朋友说的是Agent 开发这个领域真正决定上限的往往不是某一个模型的聪明程度而是工程基础设施的完整度。我见过不少团队把大量精力花在调 prompt、换模型上每次换一个模型都能让 demo 更惊艳但上线后总是被意想不到的失败打穿。后来大家慢慢意识到问题不在模型的单点能力而在于没有一个可靠的方式来发现失败、重现失败、定义失败。Harness 就是补上这个缺口的关键角色。多模态的引入进一步放大了对 Harness 和 MCP 的需求。因为视觉输入的不确定性远高于文本工具调用的范围又远大于单次对话整个系统的不确定性成倍增长没有标准化的工具接入方式和可靠的评估反馈环Agent 根本走不出实验环境。我在实际开发里的习惯是所有新能力的第一版都从能不能被评测开始设计。如果这个能力无法用 Harness 断言它成功或失败那就先不接入生产环境先给这个能力设计测试样例。这个习惯看上去慢但它让系统的每一次迭代都踩在可验证的基线上长期看反而稳得多。如果这篇文章能给你一个新项目的规划提供参考我会建议你在第一天就把三样东西想清楚Agent 要处理哪些多模态输入、工具接入是否统一走 MCP、如何用 Harness 定义做对了。这三件事想清楚了后面的大部分工程弯路都能避开。