传统测试依赖确定性代码路径,LLM 介入后系统行为变为概率性的——测试重心需从「代码是否按路径执行」转向「系统是否达成目标」。
传统软件测试假设系统行为由确定性代码路径和配置所控制。一旦 LLM 进入执行循环,这一假设就会削弱。挑战从验证代码是否遵循预期路径,转变为评估系统是否表现恰当并达成预期结果。
这一区别从根本上改变了我们测试的内容、编写断言的方式,甚至"正确性"的含义。我们正在从验证确定性代码,转向评估概率性系统行为。
在传统软件系统中,行为被封装到方法、API、配置和外部依赖中。即使系统变得极其复杂,行为仍然 ultimately 由代码决定。
流经服务的一个请求的输出,可以大致看作是以下因素的组合:
Output ≈ Input × Configuration × Infrastructure × Dependencies × Code Version
最终的状态空间可能非常庞大,但它仍然 largely 对枚举用例的系统化测试开放。这是软件测试建立的基础。覆盖足够多的状态空间,就能获得系统将正确运行的信心。
以一个工作流为例:它从配置存储读取配置,调用客户 profile API,调用定价 API,应用确定性业务规则,并产生推荐。测试这个系统相对直接。我们可以:
控制配置状态
分布式系统引入自己的挑战——网络延迟、节点故障和部分中断——但像混沌工程这样的成熟测试技术可以提供信心,确保系统在那些条件下表现正确。
现在,用 LLM 驱动的规划器替换确定性业务规则。API、工具和数据保持不变,但工作流现在必须决定:
是否需要更多信息
如何处理歧义
如何构建最终响应
好处显而易见:系统变得 dramatic 更灵活,能够处理从未被明确编程过的场景。
坏处是测试覆盖面显著扩大。行为驱动因素不再仅仅是代码;现在它是一个运行在应用程序内部的概率推理系统。即使是 temperature-0 推理,在许多生产 LLM 部署中也不能始终保证完全可重复的输出,这 due to 模型更新、基础设施差异和实现细节。
结果是系统行为更难预测、更难约束、因此更难测试。
"代码是否完全按照预期执行?"
"系统是否表现恰当?"
一旦我们接受智能体行为不能总是通过确定性断言来验证,下一个问题就变成了:我们 actually 在评估什么?
智能体测试显著扩展了正确性的含义。我们不再问函数是否返回了正确的值,而是问整体行为是否可接受。响应可能在事实上正确,但同时是不完整的、违反指令的,或者通过低效或危险的行动序列得出正确答案。
因此,评估智能体通常意味着从多个维度来评估它:
这些指标关注智能体是否成功完成了任务。
响应完整性——智能体是否完全完成了任务,还是只处理了部分请求?
响应正确性——答案是否 factually 准确,基于可用上下文,并符合指令?
这些指标评估智能体的执行效率。
运行时和延迟——智能体响应和完成工作有多快?
成本效率——完成任务需要多少 token、模型调用和外部资源?
这些指标衡量系统在事情不按计划进行时的行为。
故障处理——智能体是否能从工具故障、超时、格式错误的输入和缺失数据中 graceful 恢复?
这些指标关注最终输出的实用性和呈现方式。
响应质量——输出是否清晰、简洁、结构良好,适合目标受众?
这些指标确保系统在可接受的边界内运行。
安全与安全——智能体是否对 prompt 注入、越狱、数据泄露企图和其他对抗性输入有韧性?
这些指标评估智能体如何得出答案,而不仅仅是答案本身。
轨迹质量——智能体是否遵循了一条合理的路径来得到答案,还是在不必要的推理和工具调用上浪费了精力?
综合来看,这些维度揭示了一个重要的转变:
我们不再评估一段代码是否返回了预期值。我们评估的是一个智能系统是否在一系列 often 相互竞争的目标中 effective 地运行。
一旦我们知道想要评估什么,下一个挑战就是弄清楚如何测量它。
在传统软件测试中,断言通常是确定性的。我们提前知道预期输出,可以将实际行为与之比较。
assert calculate_tax(100) == 18
许多智能体评估维度并不能 natural 转化为这种"硬"测试风格。
我们如何为以下问题编写确定性断言:
答案是否完整?
响应是否忠实于提供的上下文?
智能体是否 appropriate 地使用了检索到的信息?
语气是否专业?
这些都是语义问题,而不是计算问题。
因此,现代 AI 评估框架 largely 收敛于三种 broad 方法。
有些维度可以使用统计技术来测量。
例如,下面是 RAGAS 指标文档中关于答案相关性(Answer Relevancy)的摘录:
答案相关性指标衡量响应与用户输入的相关程度。它的范围是 0 到 1,分数越高表示与用户输入的对齐越好。
如果答案直接且恰当地解决了原始问题,则被认为是相关的。该指标关注答案与问题意图的匹配程度,不评估事实准确性。它会对不完整或包含不必要细节的答案进行惩罚。
该指标使用 user_input 和 response 计算如下:
根据响应生成一组人工问题(默认是 3 个)。这些问题旨在反映响应的内容。
计算用户输入嵌入(E_u)和每个生成问题嵌入(E_q)之间的余弦相似度。
取这些余弦相似度分数的平均值,得到答案相关性。
Answer Relevancy = (1/N) Σ cosine_similarity(E_q, E_u)
你可以在这里找到 RAGAS 提供的完整指标目录
有些评估维度使用专门的机器学习模型来测量,这些模型针对特定任务进行了训练。
在这些情况下,评估器本身是一个针对特定分类或评分任务进行了优化的模型。
越来越常见的方法之一是使用另一个 LLM 来评估被测系统的输出。
评估器模型不是将输出与精确的预期值进行比较,而是被要求评估响应是否满足特定的评分标准。
DeepEval 和 RAGAS 等框架将这些技术打包成可重用的指标,工程师可以直接在测试套件中应用。
例如,与其从头实现忠实度评分,不如使用框架提供的预建指标:
from deepeval.metrics import FaithfulnessMetric
metric = FaithfulnessMetric()
结果是工程师可以专注于定义应用程序的良好行为是什么样的,而不是从第一性原理构建评估逻辑。
这是一个重要的转变。在传统软件中,我们主要针对输出编写断言。在智能体系统中,我们越来越多地针对行为编写断言,而那些行为通常通过指标而不是精确的预期值来量化。
大多数传统测试技术仍然同样重要。不同的是,它们 now 验证系统的不同部分。智能体仍然构建在代码、API、数据库、配置、身份验证系统和外部依赖之上。这些确定性组件应该继续使用几十年来行之有效的技术进行测试。
单元测试验证 API 客户端、解析器和重试逻辑等构建块。
集成测试用于验证工具契约以及与数据库或向量库的连接。
功能性/E2E 测试则验证结果,确保在给定输入 X 和环境 Y 的条件下,智能体能够达成目标 Z。
混沌测试和性能测试确保系统在工具故障或超时情况下仍能保持高性能并优雅降级。
因此,传统测试在智能体系统中并不会消失。它继续为栈中的确定性层提供信心保障。
了解要衡量什么只是问题的一半。下一个挑战是设计能够产生有意义且可重复信号的测试。
第一步是明确一个测试实际代表什么。对于智能体而言,测试通常以场景或行为为中心。
一个典型测试包含:
创建不稳定智能体测试最简单的方法之一,就是允许环境在多次运行之间发生变化。
工具响应、配置状态、数据集和外部依赖都应尽可能受到控制。这与传统测试没有区别,但由于 LLM 本身已经引入了变异性,这一点变得更为重要。
如果没有环境控制,就很难判断失败是由智能体本身还是由不断变化的依赖引起的。
有些行为是不可妥协的,违反时应立即失败。例如:
这些是硬断言。
其他行为则本质上是主观的,通常更适合用分数或阈值来表示。例如:
这些是软断言。
在实践中,大多数智能体测试会同时结合两者。
由于智能体行为具有概率性,单次测试执行通常不足以得出结论。与其问:
"智能体通过的一致性如何?"
不如通过多次运行的成功率来衡量可靠性,而不是二元结果。
在探索了多个智能体评估框架后,我发现它们大多数都收敛于一套类似的能力集。
无论你关注的是 DeepEval、RAGAS、LangSmith、Arize 还是其他新兴工具,实现细节各有不同但核心思想基本一致。
大多数框架聚焦于三大领域:
大多数现代框架都提供某种形式的追踪或插桩能力。这使得理解以下内容成为可能:
这些捕获的数据点提供了原始信号,许多评估指标都由此衍生。
例如,DeepEval 允许开发者对应用的部分进行插桩,并收集可在后续检查或评估的执行追踪:
from deepeval.tracing import observe
@observe
def retrieve_documents(query):
...
一旦行为可以被观察,下一个挑战就是评估它。
大多数框架提供一组可复用的指标,这些指标抽象了评估的复杂性。团队无需为每个用例构建自定义评分逻辑,而是可以将现有指标组合成测试断言。
例如,DeepEval 的一个典型评估可能如下:
from deepeval.metrics import FaithfulnessMetric
from deepeval.test_case import LLMTestCase
metric = FaithfulnessMetric()
test_case = LLMTestCase(
input="What is Kubernetes?",
actual_output=response,
retrieval_context=context
)
metric.measure(test_case)
assert metric.score > 0.8
这里重要的不是具体的指标本身,而是这种抽象层。工程师不再直接针对输出编写断言,而是越来越多地针对行为特征编写断言。
最后一个支柱是持久化。
一旦测试被定义,就需要随着系统演进进行存储、版本控制和重新执行。
提示词变更、模型升级、工作流修改、工具添加和检索改进都可能引入意想不到的回归。没有持久化的评估套件,就很难判断更改是在改进系统还是在悄无声息地损害系统。
一个测试用例成为一个可复用的产物,包含:
一旦持久化,这些数据集就成为可在整个开发和部署过程中反复执行的回归套件。
当我深入思考这些想法时,有一件事变得越来越清晰:
即使拥有全面的评估数据集,也没有一个测试套件能够真实地覆盖自主智能体在现实世界中会遇到的每一个场景。
这就是为什么现代评估框架如此强调追踪和指标。同样的信号不仅在测试期间用于评估智能体,还可以用于理解它们在生产环境中的行为。
我发现特别有趣的是,这些能力不仅对测试有用。它们是能够从自身行为中学习的系统的基础构建块。
这是我将在未来文章中探索的主题,但它始于一个简单的想法:
在一个系统能够从其行为中学习之前,我们首先需要能够测量它。
传统软件测试在 LLM 驱动的智能体面前失效,因为行为具有概率性。
智能体评估需要从 6+ 个维度进行测量(结果、运营、可靠性、质量、治理、行为)。
三种主要测量方法:数学指标、专业模型和 LLM 即评判者。
传统测试对于确定性系统层仍然至关重要。
现代框架收敛于追踪、指标和持久化测试数据集。
未来在于可观测性驱动的开发,测试指标为生产行为提供信息。
最初发表于 Substack
AI 智能体的承诺是灵活性。它们能够解决我们从未预料到的问题。挑战在于控制。传统测试无法捕捉智能体会遇到的每一个场景。这就是为什么现代评估框架正在转向可观测性:持续测量智能体在结果、可靠性、成本和安全维度上的行为。
我们正在构建 Agentplane,为这一转变提供基础设施层。TokenOps 是我们的 FinOps 控制平面,在整个智能体委托树中强制执行 Token 预算和治理策略,让你获得实时成本归属和风险执行。Chronicle 从每次智能体运行中捕获执行追踪和行为信号,将可观测性数据转化为可操作的改进和合规洞察。
它们共同弥合了测试与生产之间的差距:在开发期间测量你的智能体,在运行时执行策略,并从真实世界的行为中学习。