多Agent协作测试:从单兵到编排

发布时间:2026/7/30 18:43:59
多Agent协作测试:从单兵到编排 之前在全链路拆解那篇文章里把一套完整的AI自动化测试Agent从头到尾捋了一遍——执行端动手、决策层动脑、知识库查经验、记忆体攒经验四个组件串成一个闭环。那套单Agent架构跑了挺久大部分场景够用。但随着测试场景越来越复杂一个Agent同时干导航、操作、校验三件事上下文越来越长推理质量反而开始往下掉。这篇文章聊聊从单Agent到多Agent协作的演进。怎么把一个什么都干的Agent拆成导航、操作、校验三个专职Agent再设计一个编排层把它们串起来。不是所有场景都值得这么拆——文章最后也会说哪些情况下单Agent反而更好。单Agent遇到了什么问题全链路那篇文章里写的架构跑了大半年大部分测试场景都能覆盖。但今年开始接了一批更复杂的回归测试任务——一个测试流程动辄二三十步跨五六个页面中间还有各种弹窗和异常流。跑着跑着就发现单Agent架构有三个问题越来越明显。第一个是上下文膨胀。单Agent在每一步都要同时处理三件事看截图识别当前在哪个页面导航、决定下一步点什么操作、判断这步操作有没有达到预期校验。这三件事的上下文全塞在一个Agent的messages里步骤一多上下文就跟着膨胀。之前那篇文章里写的三层记忆架构——滑动窗口、知识库归档、语义检索——确实能缓解token爆炸但治标不治本。根本问题在于一个Agent的注意力是有限的上下文里塞了太多不同类型的信息推理质量就会被稀释。差不多到第十五步之后Agent开始出现忘了自己在干嘛的情况——明明在测购物车流程突然跳回去点首页的搜索框。第二个是角色混乱。全链路那套架构里Agent的角色定义写的是你是一个移动端自动化测试专家但实际干活的时候这个专家要同时当导航员、操作员和裁判。一个人干三个角色Prompt就得写得很大很全结果就是每个角色都做得不够专注。防止自作聪明那篇文章里提过这个问题——Agent有时候会自作主张该点的时候不点不该点的时候乱点。后来分析发现很多时候是因为Prompt里同时有导航指令和校验指令Agent在两种思维模式之间来回切换容易产生矛盾的行为。比如导航逻辑说应该点击购物车图标但校验逻辑同时在说先确认当前页面没有异常弹窗两个指令打架Agent就懵了。第三个是稳定性衰减。两种路径那篇文章里讨论过用例驱动和自主执行两种模式不管哪种模式单Agent在简单场景下表现都还行。但场景复杂度上来之后稳定性明显下降。跑十次同样的流程可能七次通过三次失败失败的原因每次还不一样——有时候是导航判断错了有时候是操作坐标偏了有时候是校验逻辑漏了。排查问题也很头疼因为所有逻辑都在一个Agent里你很难定位到底是哪个环节出了问题。这三个问题不是孤立的而是相互关联的。上下文膨胀导致推理质量下降推理质量下降导致角色混乱加剧角色混乱又导致稳定性进一步衰减。形成一个负向循环。拆Agent的逻辑想明白这三个问题之后方向其实挺清楚的把一个什么都干的Agent拆成几个专职的。但拆几个拆两个的话导航和操作可以合在一起校验单独出来——但导航和操作的思维方式差异挺大一个是在做空间规划一个是在做精确执行合在一起还是会有角色混乱的问题。拆五个的话又太碎了通信开销和编排复杂度会上来得不偿失。最后落地的方案是拆三个导航Agent、操作Agent、校验Agent。每个Agent只干一件事Prompt精简、上下文干净、角色清晰。三个Agent之上再加一个编排层负责任务分发、状态管理和异常处理。这个拆法的好处是每个Agent的Prompt可以写得非常聚焦。导航Agent的Prompt只管看路——分析截图、识别页面类型、规划路径。操作Agent的Prompt只管动手——根据导航信息生成具体操作指令。校验Agent的Prompt只管裁判——对比操作前后的截图判断是否达到预期。三个Agent各干各的互不干扰。共享的基础设施——知识库和记忆体——还是放在外面三个Agent都可以访问。但每个Agent只检索和自己职责相关的经验不会把导航的经验塞给操作Agent。三个Agent各干什么导航Agent导航Agent干的事情跟人测试时候看一眼屏幕想想下一步往哪走差不多。它接收当前截图和任务描述输出的是页面分析结果和路径建议不直接输出操作指令。具体来说导航Agent做三件事识别当前页面是什么页面首页详情页购物车、找出页面上有哪些可交互元素以及它们的大致位置、规划从当前页面到目标页面的路径。这些信息以结构化JSON输出传给操作Agent。导航Agent不用管操作坐标的精确度也不用管操作结果对不对。它只管看路看完把信息递出去就行。这样它的上下文就很干净——只有截图、任务描述和历史路径不需要塞操作记录和校验结果进来。操作Agent操作Agent拿导航Agent给的路径信息生成具体的操作指令。它干的事情跟全链路那篇文章里写的执行端对接差不多——输出归一化坐标的action指令比如do(actionTap, element[450, 280])。操作Agent的Prompt可以写得很简洁因为它不需要理解整个测试流程只需要根据当前页面信息和目标路径决定下一步操作是什么。它的上下文里只有当前截图、导航Agent的输出、上一步操作的结果。不掺杂导航分析和结果校验的信息。校验Agent校验Agent是最后出场的。操作Agent执行完操作之后校验Agent拿到操作前后的截图对比判断操作有没有达到预期效果。它的输出是结构化的校验结果——通过还是失败失败原因是什么建议怎么处理。把校验单独拆出来好处比想象中大。之前单Agent架构里操作和校验是同一个人干容易产生自己干自己评的问题——Agent执行了操作之后倾向于认为自己的操作是对的校验标准会不自觉地放宽。拆成独立Agent之后校验Agent不知道操作Agent想干什么它只看结果对不对判断更客观。代码层面三个Agent的角色定义大概长这样# 导航Agent — 只管看路NAVIGATOR_PROMPT 你是一个页面导航专家。分析当前屏幕截图 识别页面类型和可交互元素规划到目标页面的路径。 你不执行操作只输出分析结果。 输出格式{page_type: ..., elements: [...], next_step: ...} # 操作Agent — 只管动手OPERATOR_PROMPT 你是一个操作执行专家。根据导航信息生成操作指令。 使用归一化坐标(0-999)输出action指令。 输出格式do(actionTap, element[450, 280]) # 校验Agent — 只管裁判VALIDATOR_PROMPT 你是一个结果校验专家。对比操作前后的截图 判断操作是否达到预期。你不知道操作意图只看结果。 输出格式{status: pass/fail, reason: ..., suggestion: ...} 三个Prompt都不长每个只关注自己的领域。跟之前单Agent那种又长又全的Prompt比推理质量和稳定性都有提升。编排层让Agent们配合起来三个Agent拆好了但谁来指挥它们谁先跑谁后跑谁负责把上一个Agent的输出传给下一个出了异常谁处理这些事情就是编排层干的。编排层不是Agent它是一段确定性的调度逻辑。用确定性的代码来编排而不是再搞一个管理Agent来调度——这点挺重要的。之前试过用一个Agent来调度其他Agent结果调度Agent自己也会产生推理偏差相当于多了一层不确定性。后来改成纯代码编排确定性逻辑做调度AI只做执行这样整个系统的行为更可控。编排层的职责可以归纳为四个任务分发、状态管理、结果汇总、异常处理。任务分发就是根据当前状态决定调用哪个Agent。流程是固定的先调导航Agent分析页面拿到结果后调操作Agent生成指令执行完之后再调校验Agent验证结果。这个顺序不需要AI来决定写死在代码里就行。状态管理负责维护整个任务的执行上下文——当前执行到第几步、每步的导航结果和校验结果、累计重试次数。这些状态用Python字典管理就行不需要搞复杂的状态机。异常处理是编排层最花心思的部分。校验Agent返回fail之后怎么办直接重试换个策略还是请求人工介入这些判断逻辑是写在编排层里的不是让Agent自己决定。编排层的调度逻辑大概长这样classOrchestrator:def__init__(self):self.navigatorAgent(roleNAVIGATOR_PROMPT)self.operatorAgent(roleOPERATOR_PROMPT)self.validatorAgent(roleVALIDATOR_PROMPT)self.max_retry3defrun_task(self,task_desc):steps[]retry_count0whilenotself._task_complete(task_desc,steps):# 导航Agent看路navself.navigator.run(screenshotself._capture(),tasktask_desc)# 操作Agent动手actionself.operator.run(nav_infonav,screenshotself._capture())before_shotself._capture()self._execute_on_device(action)# 校验Agent裁判resultself.validator.run(beforebefore_shot,afterself._capture())ifresult[status]fail:retry_count1ifretry_countself.max_retry:self._escalate(task_desc,result)break# 重试时让导航Agent重新分析不沿用上次路径continuesteps.append({nav:nav,action:action,result:result})retry_count0returnself._build_report(steps)有几个细节值得说一下。重试的时候不让操作Agent沿用上次的导航信息而是让导航Agent重新分析——因为操作失败可能就是因为导航判断错了重新看一遍可能发现新的路径。另外校验Agent的Prompt里特意写了你不知道操作意图只看结果——这会让校验更严格不会因为操作Agent想点这个按钮就放宽判断标准。实际跑起来什么效果拆成多Agent之后跑了一段时间对比数据。同样的回归测试套件大概四十多个用例单Agent和多Agent各跑了一周。通过率方面单Agent那周大概在85%上下浮动好的时候能到90%差的时候掉到78%。多Agent那周稳定在92%左右波动小了不少。提升主要来自复杂场景——那些超过十五步的用例单Agent的通过率大概只有60%出头多Agent拉到了80%以上。简单场景五步以内的两者差不多多Agent甚至偶尔还不如单Agent因为多了编排层的调度开销。稳定性方面改善更明显。之前单Agent跑同一个用例十次可能七次过三次挂失败原因还各不相同。多Agent之后十次里大概九次能过偶尔失败的基本都是设备或网络问题不是Agent推理出了偏差。排查问题的效率也高了。之前单Agent出了问题要扒一大坨上下文日志在导航逻辑、操作逻辑、校验逻辑里来回找。现在每个Agent的输入输出都是独立的导航出了问题看导航Agent的日志操作出了问题看操作Agent的日志定位快了很多。前面说的都是好的方面但也得说说不好的。成本是第一个问题。三个Agent意味着三次大模型调用而单Agent只需要一次。token消耗大概是单Agent的三倍。如果测试量大这笔开销不小。简单场景用多Agent有点杀鸡用牛刀——五步以内的流程单Agent完全够用多Agent反而增加了调度开销。调试复杂度也上来了。单Agent出问题看一个日志就行。多Agent出问题要看三个Agent的日志加编排层的调度日志有时候还要对比它们之间的输入输出是否匹配。虽然定位问题更快了但看日志的工作量反而更大了。还有一个不太容易注意到的问题——Agent间的信息损耗。导航Agent看到的页面信息传递给操作Agent的时候需要做一次序列化从视觉信息变成文本描述。这个过程中有些细节会丢失比如导航Agent注意到某个按钮颜色不对可能是禁用状态但如果这个信息没有被结构化输出捕捉到操作Agent就不知道可能还是会去点那个按钮。这种信息损耗在单Agent架构里不存在因为同一个人看和做不需要传递信息。所以我的建议是复杂场景超过十步、跨多个页面、有异常流用多Agent简单场景继续用单Agent。不用一刀切两种架构可以共存——编排层加个判断根据任务复杂度决定走单Agent还是多Agent路径。从单Agent到多Agent说到底是分工的问题。一个人什么都干效率不一定高拆开各干各的配合好了效率能提上来但配合本身也有成本。这个度得根据自己的项目情况来把握。之前写的全链路拆解是一套Agent长什么样这篇算是Agent多了之后怎么管。后续打算再聊聊多Agent场景下的知识库和记忆体怎么设计——三个Agent共享一个知识库还是各用各的这个问题也挺有意思。