在 Agent 开发中最容易让人陷入绝望的莫过于“玄学调优”改动了一句 Prompt原本答得很好的三个场景突然失效了增加了一个查询工具Agent 却开始疯狂陷入无意义的循环调用。很多团队将大量时间耗费在人工逐条输入、肉眼比对输出结果的低效循环中这种开发模式不仅不可持续更无法支撑严谨的工程化交付。在过去一个月构建轻量 Agent 的过程中我们彻底摒弃了“凭感觉改 Prompt”的作法确立了**评测驱动开发Evaluation-Driven Development, EDD**的迭代模式。通过将业务场景固化为确定性断言与 LLM 辅助打分测试集每次架构微调与 Prompt 迭代都有了精确的量化指标支撑。评测体系设计三大断言维度一个轻量 Agent 的生命周期通常包含意图解析、工具路由、参数提取、执行与多轮状态流转。评测若只关注“最终回答好不好看”粒度就太粗了。我们将评测断言拆解为三个严格的检查维度路由与工具调用确定性Deterministic Assertions工具命中率在特定用户指令下是否命中了预期的 Tool。参数有效性提取的 JSON Schema 参数是否符合类型定义与业务约束有无产生不存在的幻觉字段。步数开销完成目标所需的执行轮数是否在预算阈值内严防无效重试。状态机流转守卫State Transition Guards终止条件任务完成或遇到不可逆错误时能否在指定轮数内干净利落地退出循环。上下文污染率历史轮次中的临时垃圾数据是否被正确清理。输出语义质量评分Semantic Quality Evaluation采用结构化评分模版利用高阶模型或确定性规则比对关键信息覆盖率。最小自动化评测框架实现我们没有引入沉重庞大的外部评测云服务而是用 TypeScript 编写了一套不到 150 行的本地轻量评测套件能够无缝嵌入 Vitest / Jest 的 CI 流水线中。import { describe, it, expect } from vitest; export interface AgentTestCase { id: string; userInput: string; expectedTool?: string; expectedParamsSubset?: Recordstring, any; maxAllowedSteps: number; mustContainKeywords: string[]; } export interface AgentExecutionTrace { calledTools: { name: string; params: Recordstring, any }[]; stepsCount: number; finalAnswer: string; } // 模拟轻量 Agent 执行器评测包装函数 export async function runAgentEval( agentRunner: (input: string) PromiseAgentExecutionTrace, testCases: AgentTestCase[] ) { const results []; for (const testCase of testCases) { const trace await agentRunner(testCase.userInput); // 1. 断言最大步数限制 const stepPassed trace.stepsCount testCase.maxAllowedSteps; // 2. 断言预期工具调用 let toolPassed true; if (testCase.expectedTool) { const toolCall trace.calledTools.find((t) t.name testCase.expectedTool); toolPassed !!toolCall; if (toolCall testCase.expectedParamsSubset) { for (const [key, val] of Object.entries(testCase.expectedParamsSubset)) { if (toolCall.params[key] ! val) { toolPassed false; break; } } } } // 3. 断言最终输出关键词 const contentPassed testCase.mustContainKeywords.every((kw) trace.finalAnswer.includes(kw) ); results.push({ id: testCase.id, passed: stepPassed toolPassed contentPassed, details: { stepPassed, toolPassed, contentPassed, trace }, }); } return results; }在测试用例定义中我们将常见场景严格分类export const agentBenchmarkDataset: AgentTestCase[] [ { id: TC-001-GIT-COMMIT, userInput: 帮我看一下暂存区的变更并起一个符合规范的提交信息, expectedTool: git_diff_staged, maxAllowedSteps: 2, mustContainKeywords: [feat:, fix:, chore:], }, { id: TC-002-FILE-SEARCH, userInput: 查找 packages/core 目录下所有的 tsconfig 配置文件, expectedTool: glob_find, expectedParamsSubset: { pattern: packages/core/**/tsconfig*.json }, maxAllowedSteps: 1, mustContainKeywords: [tsconfig.json], }, { id: TC-003-REJECT-UNKNOWN, userInput: 把这个月的销售报表发到财务邮箱, expectedTool: undefined, // 期望不触发本地开发工具 maxAllowedSteps: 1, mustContainKeywords: [暂不支持, 能力范围], }, ];基于评测的量化收益对比在建立这套评测基准之前与之后我们进行了四轮针对系统 Prompt 和 Few-Shot 示例的迭代。每次迭代前后的测试结果都有清晰的量化对照迭代版本评测用例通过率平均调用步数工具幻觉率调用不存在的工具平均 Token 消耗Baseline (无评测手工盲调)56.2%3.8 步18.5%2,840 tokensIteration 1 (约束 Tool Schema)71.4%2.6 步6.2%2,100 tokensIteration 2 (优化 Few-Shot 分发)88.6%1.9 步1.1%1,650 tokensIteration 3 (轻量负向防御规则)97.1%1.3 步0.0%1,120 tokens最显著的变化体现在防御性拒答与单步命中率上彻底根除了工具调用死循环在早期Agent 在提取不到合法文件路径时会反复重试 5 次以上。引入步数阈值与空结果主动熔断机制后无效重试降低为零。Token 开销直降 60%由于每次调用直奔目标工具多余的解释性废话和无意义的思考链路被大幅修剪。重构底气充足在将底层模型从重量级推理模型切换至轻量高性价比模型时我们仅用 3 分钟运行了 50 个基准用例立即发现 4 处微小 schema 不兼容并快速修正整个迁移过程没有任何上线盲区。落地心法从第一天开始写基准用例很多开发者总觉得“评测是项目成熟之后才考虑的事”。但在实际研发中Agent 系统的脆弱性远超传统业务系统。一旦缺少量化测试网你每一次自以为聪明的 Prompt 微调都可能在悄无声息地破坏另外 30% 用户的核心体验。实践评测驱动的极简原则包括用例来源于真实报错每当在生产或内测中发现一个失败的 Agent 轨迹第一件事不是直接改代码而是将这个失败样本提炼为一条评测 Case 录入数据集。评测自动化守门将轻量断言挂载到 Gitpre-push或 PR CI 中通过率低于阈值严禁合并。拥抱小数据集不需要一开始就搞上万条的大模型评测。20~50 个覆盖边界场景的高质量测试用例就足以解决日常 90% 的回退问题。