把模型输出的结果跟预期 Schema 对比时

小Max爱学习 高级 17小时前 122 浏览 13 点赞 约 2 分钟

在公司推行 AI 自动化测试的时候,我最容易掉进去的坑就是“过度信任预期结果”。前段时间我在跑一个集成测试,用了一个比较硬核的校验机制:在模型运行前,先由测试框架生成一个预期的 exec 调用对象并将其冻结,然后要求模型在执行时必须原封不动地发送这个 JSON。只要模型发出的参数跟冻结的对象有一丁点对不上,测试直接判定为 EXEC_ARGUMENTS_MISMATCH 失败。

结果在跑 RUN_004 这个用例时,模型被 flag 了。我当时的第一反应是:这模型又在乱发挥,没能严格遵守我的指令。

但仔细拆解后我发现,问题根本不在模型,而是在我定义的“预期”本身就错了。

当时我的测试代码是这么写的:

const expectedExecArguments = validateExecArguments({
 command: `node ${artifactPath('verifier')} ${artifactPath('payload')} ${artifactPath('manifest')}`,
});

在这个逻辑里,我的预期对象只有一个 command 键。但模型实际发出来的 JSON 是这样的:

{"intent": "Run candidate verification", "command": "node /opt/tf/uploads/candidate-verifier.cjs /opt/tf/uploads/candidate-payload.json /opt/tf/uploads/candidate-command-manifest.json"}

它多了一个 intent 字段。按照我的校验逻辑,这当然是 mismatch。但我之前习惯性地把这归结为“模型不听话”,直到我翻开 @truefoundry/[email protected] 的源码,看了看 dist/core/sandbox/Sandbox.mjs 里的 sandboxExecSchema 定义:

var sandboxExecSchema = z.object({
 intent: z.string().describe(
 "A brief, user-facing explanation of the purpose of this command. Avoid technical jargon and code details."
 ),
 command: z.string().describe("The shell command to execute in the sandbox."),
 cwd: z.string().optional().describe("Working directory for command execution."),
 env: z.record(z.string(), z.string()).optional().describe("Additional environment variables to set.")
});

真相很讽刺:在这个运行环境下,intentcommand 都是必填项(Required)。这意味着,如果模型真的按照我给的那个只有 command 的 JSON 去发送,它根本过不了沙箱的 Schema 校验,调用会直接报错。

所以,模型在面对“我的指令(只要 command)”和“运行时的强制要求(必须有 intent)”这两个冲突的权威时,它聪明地选择了后者。它并没有偏离轨道,而是我的测试框架在用一个错误的标准去衡量它。

这时候最简单的修法可能是“放宽校验”,比如只比对 command 字段,忽略其他多出来的键。但我认为这种做法太偷懒,因为这会导致测试失去控制力——如果以后 Agent 偷偷发了一些奇怪的参数,这种宽松的校验根本捕捉不到。

所以我最后采取的方案是把预期结果修正为符合实际 Schema 的状态,直接在代码里定义一个常量:

export const CANDIDATE_VERIFICATION_INTENT = 'Run candidate verification';

const expectedExecArguments = {
 command,
 intent: CANDIDATE_VERIFICATION_INTENT,
};

这次教训对我最大的启发是:在做 AI 自动化验证时,Mismatch(不匹配)只能证明两者不同,但它不能告诉你谁才是正确的。很多时候我们习惯于把模型当成“被测试者”,潜意识里认为只要结果不对就是模型的问题。但实际上,很多所谓的“模型幻觉”或“不遵循指令”,其实是我们的测试预期与实际运行时的 Schema 发生了脱节。

以后在写验证逻辑时,我得先确认运行时的真实 Schema 到底是什么,而不是凭感觉写一个 expected 对象。

工作流ZodLLM EvaluationTrueFoundryIntegration Testing

全部回复 (3)

副业中创业者 初级 17小时前
要是字段顺序变了,你的校验机制能自动忽略掉吗?
0 回复
阿海爱学习 高级 17小时前
我之前就试过这种死磕校验,结果模型换个空格就报错,纯属浪费时间。
0 回复
阿杰在路上 中级 17小时前
我也被坑过,特别是那些可选字段,模型不输出就报错,其实逻辑是对的。
0 回复

发表回复

支持 Markdown 格式