恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
Agent落地实战:多模态、Harness与MCP协议三大底层功夫
首页
资讯中心
/
Agent落地实战:多模态、Harness与MCP协议三大底层功夫
Agent落地实战:多模态、Harness与MCP协议三大底层功夫
发布时间:2026/10/12 2:23:48
最近整理开发机里的技术笔记发现这半年大部分精力其实都耗在三件事上多模态输入、Agent Harness 和 MCP 协议。不少刚接触 Agent 开发的朋友总以为最难的是“选一个大模型”但真正决定一个 Agent 能不能从 Demo 变成可用系统的往往是这三件容易被忽略的底层功夫。这篇文章不聊概念只记录我实际踩过坑之后沉淀下来的笔记适合正在做 Agent 应用、或者准备从“调 API 玩一下”跨到“做正式功能”的开发者参考。1. 多模态先让 Agent 长出眼睛1.1 三种常见的多模态接入姿势现在的大模型普遍支持图片、音频、视频帧输入但接入方式远不止“把文件直接丢给模型”这一种。我实际项目里常用的有三种姿势。第一种是原始信号直传。直接把截图、照片、音频片段交给多模态模型让模型自己完成 OCR、目标识别、语义理解。这种方案的好处是信息不损失能识别出图片里的图标状态、表格错位、甚至情绪语气坏处是 token 消耗大延迟高。一张高分辨率截图可能折合上千 token如果业务流量大成本会非常可观。第二种是本地预处理成文本。比如先用 OCR 工具提取文字用表格解析库把结构化信息抽出来再以纯文本方式送进模型。好处是省 token、响应快适合需求明确的场景比如只识别发票号、订单号、错误码。缺点也很明显一旦遇到图片里“只可意会”的信息比如 UI 布局、色彩变化、图表趋势预处理就会丢东西。第三种是混合路由也是我现在最推荐的方式。在进入大模型之前先用一个轻量级分类器判断图片属于什么类型比如纯文档、图表、截图、照片再决定走 OCR 预处理还是直接原图进模型。这么做相当于给 Agent 装了一个“分诊台”把昂贵的大模型视觉能力留给真正需要它的请求。三类方案的选择可以参考这张表方案延迟成本信息保真度适用场景原始信号直传高高高UI 截图、图表分析、复杂场景理解预处理成文本低低中文档、票据、固定模板混合路由中中高生产级系统流量复杂1.2 多模态落地必须处理的三个坑第一个坑是 token 校准。不同模型对图片的 token 计算规则不一样有的是按分辨率区间有的是按切片数量。我在一个“客服工单截图自动分类”的模拟项目里最初按文本 token 的单价估算成本结果月底一看账单远超预期。后来养成了习惯模型选型阶段先拿十张典型图片做 token 实测再按业务日活做预算表把“一张图等于多少 token”这种系数写进项目文档。第二个坑是上下文漂移。把图片塞进长对话模型过几轮之后经常忘记图片里的关键细节。比如用户上传一张报错截图Agent 第一轮能准确说出报错码但聊到第五轮再让它确认报错码时它可能给出一个“看起来很像”但实际错误的答案。我的解决办法是在图片进入上下文的同时强制模型产出一份“视觉摘要”把关键信息抽成结构化文本存起来后续轮次优先读取摘要而不是反复看图。第三个坑是文件生命周期。多模态输入绕不开临时文件很多 Agent 会把上传的图片存到本地目录用完之后却不清理。这是个既占空间又泄露隐私的操作。我现在的做法是所有临时文件统一放在一个带随机后缀的临时目录下每次请求结束无论成功失败都走 finally 清理同时保证模型只能读到当前请求相关的文件避免一个工具调用把整个目录内容都暴露给模型。关于图片数量还有一个经验不要在一个请求里塞超过三张图。某次做“多页合同对比”时把五页截图同时放进 prompt模型的反事实幻觉明显增多经常把第一页的内容安到第三页上。后来改成逐页处理、再汇总对比准确率才恢复到可用水平。2. Harness让模型从“会聊天”变成“会干活”2.1 Harness 到底在解决什么问题大模型本身只是一个“无状态函数”给它一段输入它吐一段输出。但真实业务中的 Agent 需要完成多步任务接收请求、拆解计划、调用工具、观察结果、修正动作、最终答复。这些流程不能靠模型一次生成完成必须有个外部系统把它们组织起来这个系统就是 Harness。我在项目里见过太多“貌似智能”的 Agent本质上只是把用户请求和一句“请调用工具完成”塞给模型。模型确实生成了工具调用但因为缺少循环和状态管理一旦第一次执行失败整个流程就断了。Harness 的核心价值在于把“模型推测”封装成“可用系统”它会负责上下文维护、工具派发、失败重试、终止判定让模型只专注于它最擅长的决策部分。一个合格的 Harness 至少包含这几个能力输入校验、状态存储、工具路由、循环控制、日志记录、安全护栏。其中安全护栏最容易被忽略但也是线上事故的主要来源。比如一个允许模型执行 shell 命令的 Agent如果没有白名单机制模型受 prompt 注入影响后可能执行危险命令。Harness 必须在模型意图和真实动作之间加一层硬校验。2.2 一个可复用的最小 Harness 结构我经常使用的 Harness 主循环核心逻辑可以简化成下面这段伪代码while not done and step max_steps: context build_context(user_request, history, tool_results) action model.decide(context, available_tools) if action.is_finish(): done True break if not validate(action.tool_name, action.arguments): history.append(invalid action: action.reason) continue result execute_tool(action.tool_name, action.arguments) history.append((action, result)) if is_stuck(history): switch_strategy(history) step 1这里每一行都有讲究。max_steps 是循环上限我一般设 5 到 8太少模型来不及计划太多则是成本失控。validate 函数做工具参数校验防止模型生成一个不存在的工具名或者非法参数。is_stuck 检测连续失败模型有时会在同一个错误上反复尝试比如工具返回“文件不存在”模型下次还按原路径去找这时候就需要强制切换策略而不是放任死循环。状态存储也是 Harness 的重要部分。对话历史、工具返回、中间决策都要有清晰的存取路径。我用的方案是在 Harness 内部维护一个类似“备忘录”的字典每个阶段产生的关键信息都会写入模型每一轮都可以读取。这个备忘录的好处是让 Agent 不依赖完整上下文也方便开发者排查问题。上面只是一个最简版本真实项目里还需要考虑并发隔离。每个用户请求应该跑在独立的 session 里session 之间不能共享临时状态。我就遇到过因为复用了同一个上下文对象导致用户 A 的工具调用结果跑到用户 B 对话里的情况排查了很久才发现是状态存储写成了全局变量。2.3 Harness 的可观测性建设很多人把 Harness 写出来能跑就完事了但线上出问题时才发现完全没有日志可查。我现在的习惯是给每次 Agent 运行生成一个 request_id然后把每一步的模型决策、工具调用参数、工具返回结果、token 消耗、耗时全部记录到结构化日志里。这样既能在出问题时快速定位也能回放整轮交互分析模型在哪个环节开始跑偏。我还把 Harness 的运行轨迹抽象成“步骤序列”每个步骤至少包含四件事当时的用户意图、模型选择的工具、工具返回的关键信息、Agent 对结果的判断。有了这个序列即使换一个模型也能用同一套轨迹做回归对比判断行为差异是否来自模型升级还是代码改动。3. MCP给 Agent 换上万用插座3.1 MCP 的核心设计思路MCP 的全称是 Model Context Protocol它要解决的问题很现实Agent 每接一个外部系统就得写一套定制适配逻辑数据库一套、文件系统一套、告警平台又一套。时间一长工具调用层全是 if-else 和硬编码改一个接口就要动一遍主流程。MCP 采取的是 Client-Server 架构。Agent 这边作为 MCP Client统一管理各种能力连接各个外部系统通过 MCP Server 暴露工具、资源和提示词模板。两者之间用标准化的 JSON-RPC 2.0 通信传输层可以走标准输入输出也可以走 HTTP。对 Agent 开发者来说最直观的好处是接入一个新的 MCP Server 就像插上一个 USB-C 设备系统会自动发现它提供哪些工具而不需要为每个新服务单独写解析代码。MCP 定义了三种核心能力Tools 是可执行的操作比如查订单、发消息Resources 是可供模型读取的数据资产比如配置文件、数据库表结构Prompts 是预置的提示词模板方便复用场景化的 prompt 工程。三种能力各自独立实践中我通常先从 Tools 开始接入因为这是 Agent 完成任务最需要的。3.2 从零写一个最小 MCP Server拿一个最常用的场景举例给我自己的 Agent 加一个“查询订单状态”的能力。用某 Python 库实现一个最小 Server 非常简单核心代码如下from mcp.server.fastmcp import FastMCP mcp FastMCP(order-server) mcp.tool() def query_order(order_id: str) - str: # 这里是真实业务查询逻辑 return forder {order_id}: paid, shipping, expected 2025-05-20 if __name__ __main__: mcp.run()这段代码就完成了工具的定义。Agent 侧连接时需要告诉 Client 这个 Server 的启动方式。如果是本地走标准输入输出配置大概长这样{ mcpServers: { order-server: { command: python, args: [path/to/order_server.py] } } }配置好之后Agent 能自动发现 query_order 这个工具把它加到可用工具列表里。后续如果新增“取消订单”功能只需要在 Server 里再加一个函数Agent 侧无需任何改动。这个解耦特性在实际项目里非常舒服因为业务接口变化频繁但 Agent 主流程可以保持稳定。鉴权方面我的建议是不要把数据库账号、API 密钥直接放到 Agent 的主配置里。MCP Server 应该自己持有密钥对 Agent 只暴露“工具名 参数”这层接口。这样就算 Agent 提示词被注入攻击攻击者拿到的也只是工具调用权限而不是底层凭据。3.3 MCP Server 接入治理MCP Server 接入方便之后新的麻烦也会冒出来团队里每个人都往里加 Server工具列表越来越长模型反而不知道该选哪个。我遇到过工具数量超过五十个时模型频繁选错工具的情况。解决办法是给每个工具加清晰描述并且对相似工具做合并让模型在决策时面对的选择更少、更明确。另一个要重视的是超时和幂等。工具调用是真实的外部操作比如发消息、改配置一旦超时后 Agent 自动重试很可能造成重复操作。我现在的做法是MCP Server 层实现幂等控制同一个 request_id 的重复请求只执行一次Agent 侧则设置合理超时超时后先查状态再决定是否重试而不是盲目重发。进程隔离也是一个不能偷懒的环节。如果是本地运行的 MCP Server互相之间最好用独立进程承载防止某个 Server 崩溃把整个 Agent 拉垮。权限上遵循最小原则文件类 Server 只开放指定目录数据库类 Server 只开放只读账号这是底线。4. 三者合体一个 Agent 的落地全景4.1 一个“工单处理助手”的实际串联案例把多模态、Harness、MCP 放到同一个场景里看才能理解它们如何协作。我在一个模拟项目里做过一个“工单处理助手”用户会发来一张截图“磁盘满了帮忙看一下”。整个过程是这样的。多模态层最先介入识别截图里到底是哪个磁盘、容量多大、剩余多少同时提取出“磁盘使用率 97%”这种关键信息生成一份视觉摘要。Harness 拿到这份摘要后开始规划第一步查进程占用和文件分布第二步定位大文件第三步与用户确认是否清理第四步执行清理动作。前两步通过 MCP Server 调用系统的磁盘查询接口第三步用消息确认工具征求用户同意第四步调用清理工具。这个串联过程里的关键设计是“人类确认”这个环节。Harness 在规划时明确标记了删除类操作需要用户授权所以 Agent 做到第三步会停下来等待用户反馈而不是自作主张把文件删了。这不是多余动作而是安全护栏的一部分。没有这个设计Agent 在测试环境也许没事一旦接入生产就是事故。4.2 从零搭建时的步骤建议我自己搭这类系统时坚持“由窄到宽”的顺序。先只支持一种输入比如纯文本工单跑通 Harness 主循环然后接一个 MCP Server比如只有查询能力稳定之后再加多模态输入最后才考虑加写操作类工具。很多人一上来就想做全能助手结果模型行为失控、工具调用混乱反而浪费时间。开发阶段优先固定输入输出 Schema 也很重要。用户请求、工具调用的参数、工具返回的结果都要有明确的 JSON 结构。我吃过不少亏比如把工具返回设计成自由文本模型经常从里面提取出错误信息后来改成结构化返回 模型只需要读取指定字段情况好了很多。4.3 给新场景预留的扩展位这套架构好就好在扩展成本低。新增一个垂直场景比如“服务器巡检”最主要是把对应的 MCP Server 写好然后在 Harness 的 tools 列表里注册进来再准备一套该场景的示例轨迹做评测。多模态层如果新场景需要识别特定图表就单独做一版视觉摘要 prompt。整体骨架基本不用动。这也引出一个原则不要为了新场景频繁改动 Harness 主循环。主循环是最核心、最需要稳定性的部分应该像操作系统一样保持精简。业务差异通过工具集和 prompt 配置来体现而不是每次需求一来就重写循环逻辑。5. 常见问题与排查技巧实录5.1 踩坑速查表这部分内容来自我真实调试记录按症状列在这里方便遇到同样问题的朋友快速定位。症状可能原因解决手段模型把图里文字识别错图片被压缩或格式转换统一存 PNG不经过二次缩放多轮后模型忘记图片细节视觉摘要缺失每张图进入上下文时强制产出摘要Agent 频繁选错工具工具数量过多或描述含糊精简工具列表补充触发场景描述工具调用超时但系统已执行缺少幂等控制Server 层用 request_id 去重Harness 卡在循环中出不来缺少失败切换策略连续失败三次强制换方案临时文件越积越多缺少生命周期管理请求结束统一清理用户 A 看到用户 B 的上下文状态存储用了全局变量改为 session 隔离5.2 我的排障固定流程遇到 Agent 行为异常我有一套固定排查流程。先看 Harness 日志里的工具轨迹确认模型到底调用了哪些工具、参数是什么再对比当时的多模态摘要看是不是输入信息在第一步就错了最后检查 MCP Server 的返回确认工具层是否正常工作。按照这个顺序倒着查基本能覆盖大部分问题。建议所有工具调用都打上时间戳和 token 数。有一次我发现某次任务特别贵查日志发现模型反复读取同一个大文件五次每次都要解析完整内容浪费了大量 token。后来在工具层加了一层缓存同一会话内的重复读取直接返回上次的结果成本立刻降了下来。5.3 独门经验先有降级通道再谈智能把多模态、Harness、MCP 搭建得再漂亮也不能保证模型永远正确。我的最后一个建议是每一类关键操作都要有“人工兜底”通道。比如清理磁盘这种操作Agent 执行前发一个确认消息比如模型连续推理失败三次直接转给人工处理队列。不要追求 Agent 全自动完成所有事情而是让它在能力边界处优雅地交接给人类这才是生产级系统的样子。我现在的习惯是每接一个新场景先估算一次真实成本再写第一行代码。多模态负责看得准MCP 负责拿得到Harness 负责想清楚、做完整。这三件事的顺序千万别搞反一旦反了后面全是补锅的活。