Test-Driven AI Agent Definition (TDAD): Compiling Tool-Using Agents from Behavioral Specifications

论文阅读:Test-Driven AI Agent Definition(TDAD):从行为规格“编译”工具型 Agent

论文标题:Test-Driven AI Agent Definition (TDAD): Compiling Tool-Using Agents from Behavioral Specifications
作者:Tzafrir Rehan
作者单位:Fiverr Labs
发表位置:arXiv preprint
arXiv 编号:2603.08806
原文链接:https://arxiv.org/pdf/2603.08806
主题:工具型 LLM Agent、行为规格、测试驱动开发、Prompt 编译、Agent 评估
核心问题:如何把产品规格中对 Agent 的工具调用、策略遵守和决策流程要求,转化为可执行测试,并用测试驱动的方式生成可验证、可回归的 Agent Prompt。


1. 论文要解决什么问题?

随着 LLM Agent 被放进生产环境,一个常见流程是:产品团队写出一份规格文档,说明 Agent 可以使用哪些工具、必须遵守哪些策略、面对不同用户请求时应该走什么决策流程;AI 工程师再把这份规格转化为系统提示词、工具描述和运行配置。

论文指出,这个流程中有两个核心任务:

  1. 开发 Agent:把产品要求翻译成 Prompt 和工具配置,使 Agent 能表现出符合规格的行为。
  2. 验证 Agent:确认 Agent 在所有重要场景下都符合要求,而不是只在少量人工检查样例上看起来正确。

当前很多 Agent 开发仍然依赖手工 Prompt 修改、少量样例试跑和人工观察。这会带来三个具体问题:

问题 含义
Confidence 团队无法系统确认 Agent 在所有指定场景中都正确,尤其是边界条件、敏感信息泄漏、工具调用顺序等问题。
Stability 修改 Prompt 修复一个问题时,可能悄悄破坏另一个已有行为,缺少回归测试会让问题到上线后才暴露。
Integration Agent 评估常常是零散脚本,难以接入 CI/CD、代码审查和标准工程流程。

论文提出的 TDAD,也就是 Test-Driven AI Agent Definition,试图把软件工程里的测试驱动开发思想引入 Agent 开发:先把行为规格转成测试,再用测试驱动 Prompt 迭代,最后把测试集作为回归安全网。

这里的“编译”不是传统编程语言意义上的编译,而是一个类比:
规格文档是源代码,行为测试是中间表示,Prompt 与工具描述是编译产物。


2. 相关工作:TDAD 与已有方法的区别

论文把相关工作分为几类。

第一类是 Prompt Optimization。已有方法如 APE、TextGrad、Self-Refine、Reflexion、OPRO、APO、PE2、PromptAgent 等,都把 Prompt 视为可以优化的对象。DSPy 与 TDAD 更接近,因为它也有“编译”思想:从声明式接口生成优化后的 Prompt。

但论文强调,TDAD 与这些方法有三点差异:

维度 其他 Prompt 优化方法 TDAD
优化目标 多数针对任务准确率或固定数据集表现 针对行为决策树、工具使用流程和策略合规
输入形式 常见是代码级签名、任务样例或数据集 自然语言 / YAML 形式的产品规格
防止过拟合机制 通常不是核心设计 内置隐藏测试、语义变异测试和规格演化评估

第二类是 行为测试。论文直接采用 CheckList 中的 MFT、INV、DIR 测试分类,并把它们用于 Agent 行为规格测试。

第三类是 Agent Benchmark。AgentBench、TAU-Bench、BFCL、ToolLLM、MINT、WebArena 等主要评估已经构建好的 Agent 能力;而 TDAD 的 SpecSuite-Core 评估的是从 PRD / 规格到测试、Prompt 编译、回归验证这一整条工作流。

第四类是 Specification Gaming。当测试成为优化目标时,优化器可能学会“通过测试”而不是真正满足规格。TDAD 的隐藏测试、变异测试和规格演化测试,都是为了降低这种风险。


3. TDAD 方法概述

TDAD 的基本流程可以概括为:

  1. 工程师提供一份产品规格;
  2. TestSmith 根据规格生成可执行测试;
  3. PromptSmith 根据可见测试不断修改 Prompt;
  4. 编译得到的 Built Agent 在运行时使用工具并输出结构化结果;
  5. MutationSmith 在编译之后生成错误 Prompt 变体,评估测试集是否能抓住这些错误;
  6. 当规格从 v1 演化到 v2 时,使用旧版本不变量测试评估回归安全性。

image

【Figure 1(TDAD overview)。该图展示了 TestSmith、PromptSmith、Compiled Agent、MutationSmith 与 Spec evolution 之间的关系,其中 TestSmith 和 PromptSmith 构成主要编译管线,MutationSmith 只用于编译后的评估。】


4. 规格格式:TDAD 的输入是什么?

TDAD 的输入是一份 YAML 规格文档。论文中列出的主要字段包括:

规格内容 作用
Tools 定义工具名称、schema、失败模式和调用顺序约束。
Policies 定义行为规则和优先级,例如“不得泄露 PII”优先于“尽量帮助用户”。
Decision tree 定义不同条件下应该走哪条分支、执行什么动作。
Response contract 要求 Agent 通过结构化 respond 工具输出结果。
Test guidance 为含糊策略提供测试生成指导。
Mutation intents 定义测试套件应该能检测出的错误行为类型。

论文强调:规格是唯一事实来源,测试只是规格的实现,而不是规格本身。

这一点很重要。TDAD 不是让测试作者凭直觉写测试,而是要求每条测试预期都能追溯到规格中的某个条款。如果无法指出规格中哪一条要求了这个行为,那么这条测试就不应该被写出来。

4.1 用 test_guidance 处理含糊策略

真实产品规格常常包含“ambiguous”“destructive”“disallowed”这类主观或模糊词。论文指出,如果不给测试生成器提供具体例子,TestSmith 可能生成互相矛盾的测试。

例如,对于“请求含糊时先问一个澄清问题”这条规则,如果不说明“含糊”到底指什么,TestSmith 可能把“Show me top customers”当成含糊请求,也可能把它当成可以直接执行的分析请求。这样生成出来的测试就会互相冲突,使 PromptSmith 无法收敛。

因此 TDAD 在规格中加入 test_guidance,用正例和反例说明哪些请求算含糊、哪些不算含糊。


5. TDAD 的四个角色

论文把 TDAD 分成四个明确角色:TestSmith、PromptSmith、Built Agent 和 MutationSmith。

5.1 TestSmith:从规格生成测试

TestSmith 是一个 coding agent,负责把规格转成可执行测试。它接收 YAML 规格和测试生成指南,并遵循一个核心原则:

每个测试预期都必须能从规格中推出。

TestSmith 生成测试的大致流程是:

  1. 遍历决策树,为每个叶子节点生成一个 MFT;
  2. 为每个 MFT 生成 INV 变体,也就是语义不变的改写输入;
  3. 生成 DIR 测试,也就是只改变某个关键条件,看输出是否按预期改变;
  4. 创建确定性 fixture,使工具输出稳定可复现;
  5. 在模拟数据中植入 canary value,例如唯一的敏感字符串,用来检测 PII 是否被泄露。

这里的测试既检查结果,也检查过程。比如不仅要看 Agent 最终是否拒绝泄露 PII,还要看它是否按正确顺序调用身份验证工具、是否没有调用被禁止的工具。

5.2 PromptSmith:根据可见测试编译 Prompt

PromptSmith 也是一个 coding agent,负责迭代修改 Prompt,直到可见测试通过。每次迭代中,它会:

  1. 运行可见测试;
  2. 收集失败用例;
  3. 按根因聚类失败,例如“缺少身份验证检查”或“工具调用顺序错误”;
  4. 找到能覆盖最大失败簇的最小 Prompt 修改;
  5. 修改 Prompt 并重新运行测试。

论文还设计了一个双循环策略:当失败测试数量少于阈值时,不再每次运行完整测试集,而是进入 focused inner loop,只运行当前失败测试,最多尝试若干次。这可以把最后阶段的调试时间从分钟级降低到秒级。

5.3 Built Agent:运行时 Agent

Built Agent 是编译产物的运行时。它加载 Prompt 和工具配置,接收用户消息,调用工具,并通过专门的 respond 工具输出结构化结果。

论文特别强调,Built Agent 不依赖从自由文本中解析 JSON,而是要求每轮最后一次动作必须调用 respond,并使用 schema 验证字段,例如:

字段 含义
decision 决策结果枚举
node_id 命中的决策树节点
evidence 支撑该决策的证据
user_message 返回给用户的消息

这样测试框架可以直接断言工具调用轨迹和结构化字段,而不是依赖 LLM judge 或自然语言解析。

5.4 MutationSmith:评估测试集强度

MutationSmith 是 evaluation-only 的 coding agent。它不参与编译,只在编译完成后工作。

它接收编译后的 Prompt 和 mutation intent catalog,然后生成一些“看起来合理但行为错误”的 Prompt 变体。例如:

Mutation intent 含义
SKIP_AUTH_GATE 允许在未验证身份时执行账户操作。
LEAK_PII_ON_DIRECT_REQUEST 用户直接要求时泄露 PII。
SKIP_CONFIRM_CANCEL 执行取消等破坏性操作前跳过确认。

之后,测试框架会运行可见测试,检查这些错误 Prompt 是否会被测试集抓住。如果错误 Prompt 仍然通过测试,就说明测试集存在盲点。


6. 工具描述也是一等编译产物

TDAD 不只优化系统 Prompt,也优化工具描述。论文指出,在很多 Agent 框架中,工具描述会和系统 Prompt 一起放入上下文,因此它对 Agent 何时调用工具、如何理解工具返回值有很大影响。

例如,规格中可能只写:

verify_identity:
  description: Verify user identity.

PromptSmith 可以把它改写成更可执行的工具说明:

verify_identity: |
  REQUIRED before any account-changing action.
  Call FIRST when user wants to cancel.
  Requires: account_id, last4, zip.
  If verified=false, refuse and offer to create a ticket.

优化后的工具描述包含三个关键信息:

信息 作用
何时调用 告诉 Agent 在什么前置条件下必须调用该工具。
调用需要什么 告诉 Agent 需要哪些参数。
如何处理返回值 告诉 Agent 得到不同结果后应该采取什么动作。

因此,TDAD 中的“compiled agent artifact”包括系统 Prompt,也包括工具描述覆盖项。


7. 测试分类与确定性评估

论文将测试分成两大维度:

类型 检查内容
Process tests 检查工具调用、决策树合规、调用顺序、必须 / 禁止工具、确认流程等。
Outcome tests 检查最终响应正确性,例如数值是否有 SQL 支撑、是否拒绝 PII、结构化输出是否符合契约。

对于每个决策节点,论文建议至少生成三类测试:

测试类型 含义
MFT Minimum Functionality Test,检查某条路径下的必要行为。
INV Invariance Test,检查同一意图的不同表达是否得到一致行为。
DIR Directional Expectation Test,检查只改变关键条件时输出是否随之改变。

SpecSuite-Core 避免使用 LLM 用户模拟器和 LLM judge。多轮对话是脚本化的,工具输出来自确定性 fixture,断言主要作用在工具调用轨迹和结构化输出上。这样做的目的,是把评估中的随机性尽量限制在被测 Agent 本身,而不是让评估器也变成一个不稳定的 LLM。


8. 防止 Specification Gaming 的三个机制

测试驱动优化有一个天然风险:测试会变成优化目标。如果优化器足够强,它可能学会通过具体测试断言,而不是真正学会规格要求的行为。TDAD 用三个机制来缓解这个问题。

8.1 可见测试与隐藏测试

测试被分成两部分:

测试集 用途
Visible tests 约 40%–70%,PromptSmith 编译时可以看到失败结果,并据此迭代。
Hidden tests 约 30%–60%,编译时不可见,只用于报告泛化能力。

隐藏测试通常包括:

  1. 不同措辞的 paraphrase;
  2. 边界条件,例如金额刚好等于退款阈值;
  3. metamorphic tests,即输入按某种方式变化时,输出也必须对应变化。

Hidden Pass Rate(HPR)衡量 Agent 是否超出了可见测试本身,真正泛化到未见场景。

论文还区分 benchmark mode 和 production mode。在 benchmark mode 中,每次 trial 重新生成测试,隐藏测试在单次 trial 内冻结,确保 PromptSmith 无法看到评估目标。在 production mode 中,如果隐藏测试失败,可以把失败用例提升为可见测试,然后重新编译 Agent。

8.2 语义变异测试

传统 mutation testing 通常对源代码做语法级修改。TDAD 面向的是 Prompt,而 Prompt 又是 PromptSmith 动态生成的,所以论文使用 semantic mutation testing

它不是机械替换 Prompt 中的某个词,而是给 MutationSmith 一个行为层面的错误意图,让它生成一个表面合理但违反规格的 Prompt 变体。

流程如下:

  1. MutationSmith 接收编译后的 Prompt;
  2. 对每个 mutation intent 生成一个 mutated prompt;
  3. activation probe 检查这个变体是否真的触发了目标错误行为;
  4. 如果多次尝试后仍无法激活,则该变体被视为 non-activating mutant,不计入 mutation score;
  5. 对有效 mutant 运行可见测试,检查是否至少有一个测试失败;
  6. 如果失败,则该 mutant 被 killed;如果仍通过,则说明测试集没有覆盖该错误模式。

image

【Figure 2(Semantic mutation testing pipeline)。该图展示了 MutationSmith 生成语义变体、activation probe 过滤 non-activating mutant、再用测试集检测 mutant 的过程。】

论文定义的 Mutation Score(MS)表示有效 mutant 中被测试集杀死的比例。低 MS 表示测试集较弱,因为某些错误行为仍能通过测试。

8.3 规格演化与回归安全

生产规格会变化:可能新增工具、新增分支、修改策略或调整 schema。TDAD 用 v1 → v2 的规格演化来模拟这种情况。

关键设计是:

  1. v2 编译不是从零开始,而是从 v1 Prompt artifact 继续;
  2. PromptSmith 只看到 v2 测试;
  3. v1 中仍应保持的不变量测试被完全隐藏;
  4. 编译结束后,用这些隐藏的 v1 invariant tests 测试 v2 Agent;
  5. Spec Update Regression Score(SURS)衡量旧行为保留比例。

这样,SURS 测的是更真实的向后兼容性,而不是对已知旧测试的优化。

8.4 随机性下的可靠性

LLM Agent 有随机性,单次 pass / fail 不足以说明可靠。论文建议在生产环境中引入 Reliability Pass Rate(RPR):对每个测试重复运行 N 次,统计通过比例。

论文建议:

场景 建议
标准场景 N = 10,阈值 τ ≥ 0.9
高风险场景,例如 PII、权限 N = 50,要求零失败,即 τ = 1.0

不过,论文实验中没有正式评估 RPR,因为这会显著增加运行成本和时间。


9. TDAD 的指标体系

论文使用的主要指标如下:

指标 含义 用途
VPR Visible Pass Rate 编译是否通过可见测试
HPR Hidden Pass Rate 对隐藏测试的泛化能力
MS Mutation Score 测试集能否抓住错误 Prompt
SURS Spec Update Regression Score 规格升级后的回归安全
RPR Reliability Pass Rate 随机性下的稳定通过率

其中,VPR 是 PromptSmith 直接优化的目标;HPR、MS、SURS 和 RPR 则用于衡量可见测试之外的泛化、测试质量、回归安全和稳定性。


10. SpecSuite-Core Benchmark

TDAD 的实验基于 SpecSuite-Core。论文强调,SpecSuite-Core 不是评估“某个 Agent 本身”的 benchmark,而是评估 从规格到测试、再到 Prompt 编译和回归验证的完整工作流

SpecSuite-Core 包含四个深度规格,每个规格都像一个小型产品:

Spec 关键挑战
SupportOps 操作前身份验证、PII 拒绝、套餐资格、升级触发条件。
DataInsights SQL grounding、数值精度、歧义检测、成本感知查询。
IncidentRunbook 先收集证据、按严重性路由、遵守 runbook。
ExpenseGuard 支出上限、汇率转换、收据要求、经理审批。

四个规格的测试深度如下:

Spec Nodes V1 Visible V1 Hidden V2 Visible V2 Hidden Mutations
SupportOps 12 47 45 53 43 7
DataInsights 10 34 42 53 43 6
IncidentRunbook 14 39 42 42 45 7
ExpenseGuard 11 47 45 46 42 7

论文特别强调“depth over breadth”:SpecSuite-Core 只有 4 个规格,但每个规格包含多轮流程、工具契约、10 个以上决策分支、40%–60% 的隐藏测试、5–7 个 mutation intents,以及 v1 → v2 演化场景。


11. 实验设置

实验对四个规格的 v1 和 v2 都运行三次独立 trial,总共 24 次运行:

4 specs × 2 versions × 3 trials = 24 runs

实验设置包括:

项目 设置
模型 Claude Sonnet 4.5,用于 TestSmith、PromptSmith、MutationSmith 和 Built Agent。
温度 使用默认设置,没有显式 temperature override。
测试生成 每个 trial 使用新的 TestSmith 调用,不固定 seed。
基础设施 Docker 容器隔离,pytest 并行运行,确定性 fixture。
编译预算 最多 6 个 outer loop iteration;当失败测试少于 10 个时,最多 8 次 inner loop attempt。

12. 主要实验结果

论文的主结果如下,所有 HPR、MS、SURS 都是在成功编译的 run 上计算:

Spec Compile V1 Compile V2 HPR V1 (%) HPR V2 (%) MS V1 (%) MS V2 (%) SURS (%)
SupportOps 3/3 2/3 97.6±2.3 62.5±16.1 100 100 94.2±5.1
DataInsights 3/3 2/3 96.6±4.1 88.3±3.7 94.4±9.6 100 98.7±1.9
IncidentRunbook 2/3 2/3 95.2±0.3 80.3±13.1 85.7 100 97.3±3.7
ExpenseGuard 3/3 1/3 99.2±1.3 81.8† 100 100† 100†
Aggregate 11/12 7/12 97.3±2.6 77.7±13.9 95.9±7.1 100 97.2±3.5

† 表示只有一次成功运行,因此没有方差估计。

可以看到:

  1. V1 编译比较可靠:11/12 成功,成功率约 92%。
  2. V1 隐藏测试表现较强:平均 HPR 为 97.3%。
  3. V2 更难:7/12 成功,成功率约 58%,HPR 方差也更高。
  4. V2 mutation score 达到 100%:说明 v2 中测试覆盖修复了一些 v1 中暴露的测试盲点。
  5. SURS 平均 97.2%:说明在加入新能力后,大多数旧行为仍被保留下来。

13. 编译失败分析

论文进一步分析了失败运行。V2 失败主要来自两类原因:

原因 数量
TestSmith 生成了冲突测试 2 个 run
PromptSmith 用尽迭代预算 3 个 run

不过,许多失败 run 在预算耗尽前已经达到很高的可见测试通过率。例如:

失败场景 失败前 VPR
SupportOps v2 52/53,98.1%
IncidentRunbook v2 48/49,98.0%
ExpenseGuard v2 44/46,95.7%
IncidentRunbook v1 36/38,94.7%

论文指出,一种常见失败模式是 oscillation:修复测试 A 会破坏测试 B,反过来修复 B 又会破坏 A。这通常说明规格语言存在含糊之处,导致 TestSmith 生成了冲突预期。

论文提出的自然扩展是:允许 PromptSmith 在遇到冲突时向 TestSmith 升级求助,但为了保持 anti-gaming 保证,新的 TestSmith 调用只能看到规格和失败摘要,不能看到隐藏测试或编译后的 Prompt。


14. Mutation Testing 的发现

论文报告,V1 的 mutation score 在 86%–100% 之间,有两个主要 surviving mutants:

Spec Surviving mutant 含义
DataInsights HALLUCINATE_NUMBERS 在没有可靠 SQL 支撑时编造数值。
IncidentRunbook SKIP_RUNBOOK_LOOKUP 跳过 runbook 查询。

这些 surviving mutants 表明,虽然可见测试能让 Agent 通过基本行为要求,但测试集仍可能漏掉系统性错误模式。论文指出,v2 中这些问题通过更强测试覆盖被修复,所有成功的 v2 run 都达到 100% mutation score。

这一部分体现了 TDAD 中 mutation testing 的作用:它不是直接提高 Agent 能力,而是暴露测试集没有覆盖到的盲点。


15. 成本与迭代次数

论文还报告了 pipeline 的成本和迭代次数。平均来看:

指标 V1 V2
平均成本 $2.32±0.96 $2.81±1.71
平均迭代次数 3.1±0.8 2.9±1.1

完整 pipeline 通常每个 spec version 花费 $2–3,单个规格版本耗时约 30–60 分钟。论文认为这个成本接近 CI/CD pipeline 的量级,但对于快速原型阶段可能偏高。所有 18 个成功 run 的总成本为 $45.15。


16. 参考实现

论文给出了基于标准工具的参考实现。仓库采用 pytest 风格组织规格、测试、artifact 和 harness 代码,Claude Code 在 Docker 容器中承担 TestSmith、PromptSmith 和 MutationSmith 三个角色。

参考实现中特别强调隔离:

隔离机制 作用
编译容器只挂载 visible tests PromptSmith 无法读取隐藏测试。
hidden tests 存放在单独 Docker volume 编译阶段完全不可访问。
visible tests 目录设为只读 防止 PromptSmith 修改测试。
只允许写入 agent_artifacts PromptSmith 只能修改编译产物。
隐藏测试在独立 evaluation container 中运行 防止编译过程污染评估。

测试 harness 提供了工具调用轨迹断言、结构化输出验证、PII canary 检测和数值 grounding 检查。

这一设计的目标是防止测试驱动编译退化为“读测试、改测试、硬编码测试答案”。


17. 论文指出的局限性

论文列出了几类限制。

17.1 规格和测试不一定完整

TDAD 假设需求可以编码成行为测试。但有些性质,例如“更有同理心”,很难精确定义成测试。Mutation testing 可以衡量测试集强度,但不能保证测试完整。

此外,非激活 mutant 会被排除在 mutation score 之外,这可能导致测试质量被高估:有些被排除的 mutant 也许并不是等价 mutant,而是真实盲点,只是 activation probe 没有成功触发。

17.2 随机性和成本

编译和 mutation generation 都是随机的。论文报告 V1 HPR 方差约 ±2%–4%,V2 方差约 ±4%–16%。单个规格版本需要 30–60 分钟和 $2–3 成本,对 CI/CD 可能可接受,但对频繁快速迭代并不一定轻量。

17.3 测试生成中的 LLM self-censorship

TestSmith 由于安全训练,可能避免生成真正恶意、粗鲁或攻击性的输入,即使这些输入对于 abuse detection 测试很重要。论文认为,在这类场景中仍需要人工整理的测试语料。

17.4 实验范围有限

SpecSuite-Core 只有 4 个规格,每个版本 3 次 trial。论文没有单独消融隐藏测试、mutation testing 等 anti-gaming 机制,也没有和 DSPy、TextGrad、APE 等方法做直接比较。所有实验都使用 Claude Sonnet 4.5,因此不同模型、跨模型配置和更大规模决策树上的泛化能力仍未验证。

论文也没有量化 50+ 决策节点 Agent 的扩展性,以及编写 TDAD 规格本身的学习成本。


18. 总结

TDAD 的核心思想是:把工具型 Agent 的开发从“手工调 Prompt + 少量 spot check”,推进到“规格 → 测试 → 编译 → 回归”的工程化流程。

它的关键贡献包括:

  1. 把 Agent Prompt 和工具描述视为可编译 artifact;
  2. 用 TestSmith 从行为规格生成可执行测试;
  3. 用 PromptSmith 根据可见测试迭代生成 Prompt;
  4. 用隐藏测试衡量泛化,而不是只看可见测试;
  5. 用语义变异测试检查测试集是否能抓住错误行为;
  6. 用 v1 → v2 规格演化衡量回归安全;
  7. 用标准 pytest、Docker 和隔离机制把流程接入工程工具链。

从实验看,TDAD 在四个深度规格上取得了较高的 v1 编译成功率和隐藏测试通过率;v2 更难,但成功 run 仍表现出较好的 mutation score 和回归安全。论文也明确指出,TDAD 不能保证规格完备,也不能消除所有 gaming 风险;它提供的是一种更可测、更可回归、更接近软件工程实践的 Agent 开发方法。

参考

posted @ 2026-06-09 14:41  YourF4u1t  阅读(38)  评论(0)    收藏  举报