智能体评测系统架构设计与工程化落地实践
2026/9/6 14:05:23 网站建设 项目流程

如果你在公司里负责智能体平台,一定绕不开一个问题:怎么证明你开发的Agent真的比上一个版本强?跑几个例子发给同事看,效果再惊艳也只是个案,模型一换、Prompt一调,好与坏全凭感觉。我在过去半年里正好从零搭建了一套智能体评测系统,核心目标只有一个:把“我觉得它变好了”变成“数据说明它变好了”。这套系统的架构设计、工程化落地过程中踩的坑、总结的经验,今天全部拆开来讲。

智能体评测不是传统意义上的自动化测试,评测对象是一个会思考、会调用工具、会跟你来回多轮对话的系统。它的结果不仅受模型影响,还受Prompt、上下文、工具返回、甚至随机种子影响。如果不把评测系统建成分层、可扩展、可观测的工程化设施,上线第一天就会陷入“用例怎么维护、结果怎么解读、分数怎么对比”的泥潭。本文适合正在做智能体平台、准备给Agent搭建评测体系,或者想把评测结果接入发布流程的工程师参考,内容不涉及具体的商业产品绑定,而是围绕评测系统本身的架构思路与工程实施展开。

1. 为什么应该把智能体评测当成一套系统来建设

1.1 智能体评测和传统单元测试完全是两码事

传统后端单元测试讲究的是确定性:输入一个参数,输出一个返回值,断言相等或不相等。智能体评测则面对的是一个“概率性”对象。同一个问题,两次调用可能得到不同表达方式、不同步骤顺序,甚至不同结论。如果你的评测方式还停留在“比对字符串是否包含某个关键词”,很快就会误判大量结果。

我最早踩过这个坑。当时团队直接写了个Python脚本,把几十条问题丢给Agent,然后检查输出里有没有“好的”“已为您”这些词。结果一次Prompt迭代后,Agent开始用更自然的表达,不再说“已为您”,脚本全挂,但真实用户体验其实是变好的。这件事让我意识到,评测必须支持“多维度判定”,而不是一个函数里的几个断言。

智能体的评测还要处理多轮对话状态。比如用户先问“杭州明天天气”,Agent回答后又追问“那后天呢”,这里“后天”必须依赖前文语境。用例数据如果不包含多轮对话和中间状态,测出来的结果就没有参考价值。

再加上智能体普遍会调用外部工具,比如搜索、查库、写工单。这意味着一轮评测可能触发真实外部请求,如果不对工具层做Mock或沙箱隔离,测试环境会被污染,线上数据也可能被误操作。所以智能体评测系统,其实是一个集用例管理、执行调度、工具隔离、结果判定、可视化分析于一体的复杂工程,绝不是拿个脚本跑一遍就完事。

1.2 评测系统的能力边界:评测什么、不评测什么

在动手设计之前,先想清楚边界。我一般把评测系统拆成五个关注面:功能达成度、内容质量、性能、成本和安全性。

功能达成度是“任务有没有完成”,例如用户要查天气,Agent有没有给出天气信息;用户要订会议室,Agent有没有真的调用接口并确认成功。内容质量是“答得好不好”,包括表达是否清晰、格式是否满足要求、有没有胡编乱造。性能主要看首Token延迟、完整响应时长、工具调用耗时。成本主要看Token消耗和工具调用次数。安全性则关注Prompt注入、越权访问、敏感信息泄露等。

评测系统需要明确自己不做什么。我不建议把线上真实用户满意度直接塞进评测系统里当唯一指标,因为线上行为受运营活动、网络环境、用户意图偏差影响太大。评测系统的价值在于“受控环境下的标准化比较”,要评估一个Prompt或一个模型可不可用,用固定数据集跑回归,得出横向对比分数;用户在真实场景下的反馈,应该走另一套监控和可观测体系。

边界定义清楚之后,系统的模块划分、数据模型和调度策略也就有了依据。

2. 整体架构设计方案与关键选型思路

2.1 架构总览:任务编排、隔离执行、结果回流

我最终落地的架构可以分成五层:入口接入层、任务编排层、执行层、数据层和分析展示层。

入口接入层负责接收评测触发命令,可以是人工点击,也可以是Git提交触发的Webhook,还可以是定时任务。任务编排层把评测请求拆解成原子任务单元,分发给执行器,并负责状态流转、重试策略和超时控制。执行层运行真正的智能体实例,通过适配器连接Dify、扣子等智能体平台,或者直接调用内部Agent服务,执行过程中记录完整日志和Trace。数据层存储评测用例、运行记录、评测结果、打分明细、Token用量等。分析展示层把原始数据聚合成趋势报表、对比图表和失败样本列表。

分层的好处在于每一层都能独立扩展。比如开始团队只有几十条用例,执行层用本地进程池就够了;后来用例增长到数千条,我只需要把执行层换成分布式Worker,入口和编排逻辑完全不用动。同理,今天你要接一个新的智能体平台,只需新增一个适配器,不影响数据层和分析层。

2.2 为什么用分布式任务队列而不是同步轮询

早期版本我非常天真,评测直接用HTTP同步请求,一次评测发起几十个并发请求,然后阻塞等结果。用例少的时候没什么问题,但用例一多,上游服务稍微慢一点,整个评测脚本就卡死在那里,一次全量评测跑一个多小时,而且失败一个也不知道怎么回事。

后来我把执行链路改成了异步任务队列。整体结构是:评测发起方把任务写入队列,Worker从队列里拉取任务,执行完把结果写入存储,前端通过WebSocket或轮询查询进度。这套模型可以轻松支持上千个并发任务,还能在某个智能体服务抽风时通过队列积压避免雪崩。

队列选型上,早期我用Redis的List实现了一个轻量队列,优点是部署简单、无额外依赖,缺点是缺乏任务确认(ACK)和延迟队列能力,一旦Worker崩溃就会丢任务。后来切换到RabbitMQ,使用持久化队列和手动ACK,才真正解决可靠投递问题。如果你的团队已经在用Kafka,也可以使用Kafka的消费者机制,但要注意不能把Kafka默认的at-least-once语义当成恰好一次,消费端必须做好幂等。

2.3 用例、数据集、智能体实例如何建模

评测系统里的核心模型有三个:评测用例、评测数据集、智能体实例配置。

评测用例是最小执行单元,包含用户输入、初始上下文、期望行为、建议答案或检查点。我通常用JSON保存一份用例,里面存对话轮次列表,每一轮包含role、content、期望工具调用等信息。

评测数据集是用例的集合,并带有版本号、标签、创建人、变更说明。数据集需要像代码一样做版本管理,因为每次模型升级后,我们必须用同一份数据集去对比新旧模型效果,不同时间跑出来的分数才有可比性。

智能体实例配置是评测系统与具体Agent服务的连接描述,包括平台类型、API地址、API Key别名、模型名称、Prompt版本、工具开关等。评测执行时会把“数据集+智能体实例配置”组合成一次评测任务,这样同样一批用例,可以分别跑“旧Prompt”和“新Prompt”,也可以跑“GPT-4”和“Claude”的对比。

3. 核心模块的工程化落地实操

3.1 用例与数据集管理:版本、标签、依赖注入

用例管理是我建议优先做的事。很多团队直接从Excel维护用例,一开始还好,过了两百条就彻底失控。我们现在的做法是用Git管理用例文件,每个用例是一个JSON文件,目录结构按照业务域划分,比如“天气查询”“会议室预定”“工单处理”。

每个用例文件包含id、status(active/disabled)、tags、priority、dialogue、expected、owner等字段。这里最关键的字段是tags,我通常会打上“回归”“冒烟”“边界”“多轮”“工具调用”等标签,这样执行评测时可以按标签筛选,比如每次发版前只跑冒烟集,每周五跑全量回归。

数据集管理要做到“不可变”。我使用语义化版本号命名数据集,例如weather-dataset-v1.3.0,每次修改都要追加变更记录。评测报告里必须记录当时使用的数据集版本,否则一周后发现分数变了,你根本不知道是模型变了还是用例变了。

依赖注入是指用例里需要外部变量时,不能写死。比如用户问“查一下杭州未来三天的天气”,这个用例如果第二天跑步,杭州天气确实在变,但Agent返回结果都无法断言对错。我们的做法是在用例里定义变量占位符,例如{city}{date},执行器在运行前从变量池随机或按规则注入。这样同一套用例可以反复使用,也避免固定答案对Agent产生误导。

3.2 执行器设计:如何让评测过程可重复、可隔离

执行器是整个系统的引擎,设计上必须解决三个问题:隔离、超时、幂等。

隔离方面,每个评测任务最好跑在独立环境里。开始我直接用多线程调用Agent API,代价是一个Agent因为上下文太长卡住,线程池全部占满,其他用例跟着遭殃。后来我改成进程池+Docker容器,每条用例或一组用例分配一个独立容器,容器里可以起一个轻量HTTP服务,内部封装对Agent服务的调用。这样即使某个用例触发了无限循环的工具调用,最多只影响当前容器,杀掉重跑即可。

超时控制要分层设计。每次工具调用、每个对话轮次、整条评测任务都要有独立的超时时间。我通常设置单轮等待超时15秒,整条多轮任务超时120秒,超过就把任务标记为“超时失败”,并保留超时前的全部日志。超时后的重试次数默认2次,但如果第一次已经把外部工具真的执行了,重试前需要确认工具是否具备幂等性,否则不能盲目重试。

幂等性主要体现在消费任务时。评测任务可能因为网络问题重复投递,Worker必须保证同一任务不会反复写入重复结果。我们用任务ID在存储层做唯一约束,插入结果时如果发现主键冲突就丢弃本次执行,保证结果表里一个任务只对应一条核心记录。

执行器通过适配器模式连接不同Agent平台。每个适配器只需要实现两个方法:construct_messages() 和 execute()。前者把评测用例的对话轮次转换成目标平台要求的消息格式,后者负责发起调用并接收响应。只要接口一致,新增平台只是多写一个适配器的事。

3.3 评判模块:规则、LLM-as-Judge、人工抽检的三层结构

智能体评测最难的部分是结果判定。我实践下来,最可靠的是三层判定结构。

第一层是规则判定,适合有明确结构或关键行为的结果。比如Agent是否在指定参数下调用了某个工具、返回JSON是否包含必填字段、多轮对话中是否出现指定节点。规则判定执行成本低、结果稳定,能用就用。

第二层是LLM-as-Judge,用一个大模型去评判Agent的输出。适合内容质量类指标,比如“回答是否清晰完整”“是否准确引用了文档”“是否规避了敏感问题”。这里必须注意两点:一是Judge模型和被测模型最好不要是同一个模型,否则容易出现系统性偏好;二是Judge的Prompt要写得非常具体,最好给出评分维度和样例,避免让模型输出一个空洞的分数。

第三层是人工抽检。LLM打分再准也不可能100%可靠,所以我会对每次评测自动抽5%到10%的失败样本,推送给人工复核。人工复核结果回填到数据库,用于持续优化规则和校准Judge的 Prompt。

三层结构落地时,每个判定结果都要保留可解释信息。规则判定要有命中了哪条规则,LLM打分要有思考过程或打分理由,人工抽检要记录复核人。不能只存一个总分,否则后续排查“为什么这条用例挂了”完全无从下手。

3.4 报告与可观测性:失败样本如何追溯

评测报告不是给机器看的,是给工程师和产品经理一起看的。所以我要求每次评测任务结束后,系统自动聚合一份可读报告,至少包含:本次评测总体通过率、关键指标趋势、失败用例列表、Token消耗统计、对比例(如果有旧版本基线)。

失败样本追溯是最容易被忽略,但也是实际排查效率最高的环节。每一条失败样本必须关联完整的执行链路,包括每一轮对话的输入输出、每次工具调用的参数和返回结果、整体耗时、Token消耗、以及最终打分结果。这样当业务方来问“为什么说这个用例没过”时,你可以在十分钟内贴出一条完整记录,而不是让业务方去看一堆日志。

技术栈上,我用ClickHouse存储评测明细记录,用PostgreSQL存储配置类和聚合报表数据。ClickHouse对这类时序性日志查询效率很高,一条用例的完整Trace可以通过trace_id一次性拉出来。展示端一开始用Grafana,后来发现Grafana不适合做复杂的评测报告,就换成自研的React页面,只展示评测相关视图,逻辑更聚合。

4. 对接常见智能体框架与平台时要注意的细节

4.1 对接Dify和扣子这类平台Agent API

现在很多团队不是从零写Agent,而是基于Dify、扣子这类平台搭工作流,评测系统必须能友好对接。

这类平台基本都提供API接口,关键是要弄清楚会话管理的粒度。有的平台每个Session独立记忆,评测时必须为每条用例创建新的Session,避免上一条用例的历史污染下一条。有的平台支持通过参数覆盖模型配置,评测时可以把模型名和Prompt模板作为变量传入,这样一次能跑多组对比。

另一个细节是平台方的限流策略。很多SaaS平台的API有并发限制,评测系统如果一下子打到几十路并发,很容易触发429。我的做法是在适配器层做令牌桶限流,同时设置重试机制。限流参数要可配置,不同平台的配额不一样。

我之前接Dify时踩过一个坑:Dify的会话接口返回时默认只返回最终答案文本,工具调用过程要通过日志接口查询。如果评测只看最终文本,很多“过程错误但最后蒙对”的用例会被放行。所以适配器里如果平台支持查询工具调用日志,一定要一并拉取,并把工具调用记录纳入规则判定。

扣子这边的情况类似,平台API会返回消息体,但不同插件的输出格式差异很大,评测用例里的期望工具调用需要尽量结构化成统一的中间格式,比如tool_calls: [{name, input, output}],这样分析层不需要关心底层平台差异。

4.2 多智能体与工具调用场景的评测怎么设计

现在复杂业务早就不止单个Agent了,很多是“主Agent+多个子Agent”编排,或者“Agent+大量工具插件”协作。评测系统如果只测最终答案,会漏掉链路中的关键故障。

我在实际项目中把多智能体评测拆成两个层次:一个是整链路结果评测,用户问题丢进去,看最终输出是否满足需求;另一个是节点级评测,重点是“关键决策点是否正确”。例如用户问“我要订周五下午三点的会议室”,主Agent判断意图,调用会议室查询工具,子Agent确认会议室状态,然后调用预定接口。如果最终反馈“预定成功”,但过程中查询日期是错的,整链路评测可能会给通过,节点级评测就能抓出问题。

为此我在用例模型里增加了一个预期链路字段,叫做expected_trace,记录关键步骤的顺序和参数。评测执行时,适配器会把实际执行Trace与预期Trace做对齐,这里不要求完全相等,但每个关键节点必须存在且参数正确。

工具调用参数验证也很讲究。不能只看工具有没有被调用,还要看入参是不是从用户对话里正确抽取的。比如用户说“帮我定后天下午三点的会议室”,Agent如果算对了“后天”的具体日期但把时间配成了下午3点半,这个错误在最终结果里可能看不出来,但参数校验一定会暴露。

4.3 把评测接入CI/CD和灰度发布流程

评测系统最大的价值在于持续回归。如果只是人想起就跑一次,很快就会荒废。正确做法是把评测接入研发流程,强制每次变更都经过回归。

我建议在CI流水线里加两个阶段:提交级评测和发布级评测。提交级评测只跑冒烟集,包含20到50条核心用例,目标是快速发现问题,整个流程控制在10分钟以内。发布级评测跑全量回归,包含几百甚至上千条用例,可能耗时较长,一般放在构建后的独立任务里跑。

全量评测跑完后,系统会自动生成一份与最新基线版本的对比报告。如果通过率下降超过一定阈值,比如2%,流水线直接失败,不允许发布。这里阈值设置要动态调节,一开始我们设5%,发现经常漏问题,后来改成2%,但偶尔会因为数据标注不准确引发误报,于是加了一个“人工确认可豁免”的机制。

灰度发布阶段,我建议把评测配置也纳入灰度。比如新Prompt先对10%的真实流量放量,同时后台用评测系统对新Prompt跑一遍全量回归,两边的结果互相印证。这样即使用户反馈有滞后,评测回归也能提前暴露风险。

5. 常见问题与排查技巧实录

5.1 结果不稳定:同一用例两测结果不一样

这是接触评测系统的人第一个崩溃点。同样一条用例,上午跑通过了,下午跑挂了;换一个模型,之前一大批用例全挂;模型没变,只是随机种子变了,分数波动很大。

根本原因在于智能体是概率模型,相同输入可能生成不同输出。排查方向有三个。第一,先看模型采样参数,比如temperature、top_p,如果允许随机性较大,评测结果波动是正常的,我通常评测环境把temperature设为0或0.1,让输出尽量稳定。第二,看外部依赖,工具返回的实时数据可能变化,这就要在评测环境对工具做Mock,或者依赖注入固定参数。第三,看上下文污染,如果Session复用或者全局Prompt被其他任务修改,也会导致结果漂移。

我排查这类问题时,习惯固定一个“复现专用配置”:固定模型版本、固定数据集版本、固定工具Mock数据、固定最大Token和temperature,然后反复跑五次。如果波动仍然很大,基本就是评测设计本身不够稳定,需要调整用例断言,而不是抱怨Agent不听话。

5.2 评测任务卡死:超时、连接不释放、并发死锁

评测系统跑了一段时间后,最容易出现“任务一直卡在运行中”的问题。第一次遇到时,我以为是网络慢,等了十分钟发现还在运行,然后整个队列都被堵住了。

逐层排查后,最大的罪魁祸首是HTTP连接不释放。很多HTTP客户端默认连接池大小有限,并发一高,连接被占满,新请求排不上队,任务就一直等着。解决方法是给每次调用设置明确的超时时间,包括连接超时、读取超时和总超时,并且把所有超时时间配置化,不要写死在代码里。

另一个原因是任务重试逻辑设计有误。如果任务因为超时失败后立即重试,而底层Agent服务还是卡着的,重试只会加重故障,形成“重试风暴”。后来我在重试策略里加了指数退避,第一次等5秒,第二次等20秒,并且设置最大重试次数。

对于彻底卡死的任务,还要靠“看门狗”兜底。我实现了一个定时任务,每隔30秒扫描一次运行中状态超过阈值的任务,强制标记为失败,并记录失败原因为heartbeat_timeout。这样即使Worker本身崩溃,也不会让评测任务永远悬挂在队列里。

5.3 LLM打分不稳定:偏见、幻觉、规则冲突

LLM-as-Judge并不是银弹。我踩过最大的坑是模型打分时带有明显的“偏好”:同一个答案,被Judge模型评价为高质量,换一个Judge模型就给了低分;甚至同一个模型,题目顺序调换,分数也变。

后来我做了几个优化。第一,Judge的Prompt改成结构化的评分卡,明确列出“内容正确性”“完整性”“表达清晰度”三个维度,每个维度给权重,并要求模型输出JSON格式。输出里必须包含“评分理由”,不能只给分数。第二,对Judge结果做一致性校验,如果多次打分结果方差过大,自动标记为“低置信度”,转入人工抽检。第三,出现规则判定和LLM打分冲突时,以规则判定为准,并在报告中标注冲突详情。

还有一个常见问题是模型幻觉。Judge模型可能因为“觉得”某个答案看起来像官方文风,就给高分,但答案实际引用了不存在的接口。这类问题靠规则判定兜底比较有效,凡是用例里声明了必须包含某些信息或格式的,先跑规则,再跑LLM打分,最后两个结果交叉。

5.4 数据泄漏:测试集被模型学到以后,分数虚高

这是最隐蔽、影响最大的问题。如果评测用例集长期固定且不脱敏,模型在生产环境或者Fine-tuning时可能已经“背过”答案,评测分数会高得离谱,完全失去参考意义。

我处理数据泄漏有三个原则。第一,评测数据集与训练/精调数据必须物理隔离,禁止互相混用。第二,用例数据集按月滚动,加入新的真实用户问题,淘汰明显过时或模型已经“背熟”的题目。第三,对每一条用例记录“首次加入时间”和“最后修改时间”,如果一条用例很久没更新且通过率长期100%,会触发提醒让运营人工审核是否还有价值。

有一次我们的一个内部Agent模型通过率突然从88%涨到96%,所有人都很高兴,只有我觉得不对劲。查了日志才发现,是评测数据集里的部分问题被采集到了线上日志,又在Fine-tuning时混进了训练集。去掉这些重叠用例后,真实通过率回落到89%。从那以后,数据泄漏检测就加进了每周评测报告里,自动化扫描数据集和训练集的文本重叠情况。

6. 成本控制与持续迭代机制

6.1 算力与Token消耗怎么估算

评测系统跑一次全量回归,成本比大部分人想象的高。以前跑500条用例,每条大概10轮对话,每轮调用一次模型,算下来5000次模型调用,如果每次都携带较长上下文,一次全量评测可能就要消耗几百万Token。如果一天跑多轮,成本很快失控。

我建议在评测发起前先做一个成本估算。很简单,根据数据集里用例的平均对话轮数和平均Token数,乘上模型单价,得出每次评测的预估成本。如果超过预设阈值,系统会弹窗提醒,要求选择“只跑冒烟集”或“限制并发”。

执行过程中,我也对每条用例单独记录Token消耗,最终报告里能看到Token最高的Top 20用例。很多高成本用例其实是大段上下文塞入了引用文档,但在评测场景里并不需要那么长上下文,这个时候就应该在用例里精简输入,而不是让模型白白多算一遍。

6.2 少样本高覆盖:从冒烟集到全量集

不要一开始就追求大规模评测用例。我建议分成三层来建设。

第一层是冒烟集,10到20条,覆盖核心主流程,例如“天气查询”“创建待办”“订阅新闻”,目标是把链路通断测出来,任何一次Prompt修改都先过这层。第二层是回归集,100到300条,覆盖典型业务场景和常见边界情况,比如“超出上下文长度的长文本”“工具参数缺省”“多轮指代消解”。第三层是全量集,1000条以上,用于重大版本发布前的全面评估,覆盖长尾场景和异常输入。

很多团队上来就拼命堆用例,结果数据质量差,每条用例里还有大量错误标注,评测得出的分数完全不可信。我宁愿先把500条高质量用例打磨好,也不建议盲目扩到5000条低质量用例。质量优先,数量其次。

对于冒烟集和回归集,我还有一个强制要求:任何一次模型升级、Prompt迭代、平台切换,都必须先跑回归集,不在CI里做一次完整回归,不允许进入下一步。这条规则看着粗暴,但极大避免了“模型升级后功能整体退化”的线上事故。

6.3 评测结果如何反哺智能体优化

评测系统不是终点,它的数据必须回流到Agent开发流程里,才能形成闭环。

我落地了几个机制。第一个是“失败样本周会”,每周从评测系统里导出分类好的失败样本,分发给对应的Agent开发工程师,每人领走自己负责模块的问题,修复后提交新的评测任务进行验证。第二个是“回归基线自动更新”,当新版Agent通过率连续稳定高于旧版后,系统自动把基线切到新版,避免一直拿老版本做对比,让新优化受到老问题的拖累。第三个是“提示词变更关联”,每次Prompt或者工具描述改动,都可以在评测系统里建立一次实验,实验ID关联到评测报告,方便回溯哪次改动造成了哪个指标波动。

我还把评测结果接入了团队的消息通知,全量评测完成或通过率下降超过阈值时,自动发送到IM群。这个看似简单的功能,实际使用率比任何数据看板都高,因为人是被事件驱动的,而不是靠主动进系统看报表。

回到最初的问题:智能体评测系统到底该怎么做?我的答案很简单:先定义边界,再搭架构,后端用分布式任务队列保证扩展性,用例和数据集必须版本化管理,执行模块要隔离和可观测,评判用三层结构,结果必须能追溯到执行链路。工程化落地不是把脚本重构成服务,而是让评测这件事成为团队内部的基础设施,像CI系统一样可靠、可重复、可依赖。

我个人在实际操作中的体会是,评测系统最难的不是写代码,而是接受“不完美”。它永远会有误报、漏报和不稳定,但只要能把问题快速暴露出来,就已经比“拍脑袋判断Agent好坏”强了百倍。最后再分享一个技巧:如果你还在用脚本临时测Agent,可以先别急着上平台,把你现在的脚本输出改成统一JSON格式,每条结果带一个trace_id,再给用例加上版本号,你会惊讶地发现,这两个小改动就能让评测工程化往前推进一大步。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询