Skip to main content

Javascript 断言

javascript 断言 允许你提供一个自定义的 JavaScript 函数来验证 LLM 输出。

一个名为 output 的变量被注入到上下文中。如果输出通过断言,函数应返回 true,否则返回 false。如果函数返回一个数字,它将被视为分数。

你可以在函数中使用任何有效的 JavaScript 代码。LLM 的输出作为 output 变量提供:

assert:
- type: javascript
value: "output.includes('Hello, World!')"

在上面的例子中,javascript 断言检查输出是否包含字符串 "Hello, World!"。如果包含,断言通过并记录分数 1。如果不包含,断言失败并返回分数 0。

如果你想返回一个自定义分数,你的函数应返回一个数字。例如:

assert:
- type: javascript
value: Math.log(output.length) * 10
threshold: 0.5 # 任何大于 0.5 的值都将通过

在上面的例子中,输出越长,分数越高。

如果你的函数抛出错误,断言将失败,错误信息将包含在失败原因中。例如:

assert:
- type: javascript
value: |
if (errorCase) {
throw new Error('这是一个错误');
}
return {
pass: false,
score: 0,
reason: '断言失败',
};

处理对象

如果 LLM 输出一个 JSON 对象(例如在工具/函数调用的情况下),那么 output 已经被解析为一个对象:

assert:
- type: javascript
value: output[0].function.name === 'get_current_weather'

返回类型

你的 JavaScript 函数的返回值可以是布尔值、数字或 GradingResult

type JavascriptAssertionResult = boolean | number | GradingResult;

// 用于更复杂的结果
interface GradingResult {
pass: boolean;
score: number;
reason: string;
componentResults?: GradingResult[];
}

如果设置了 componentResults,将在 Eval 视图的测试输出模态框中显示断言详情的表格。

多行函数

JavaScript 断言支持多行字符串:

assert:
- type: javascript
value: |
// 在此处插入评分逻辑...
if (output === '预期输出') {
return {
pass: true,
score: 0.5,
};
}
return {
pass: false,
score: 0,
reason: '断言失败',
};

使用测试上下文

context 变量包含提示和测试用例变量:

interface AssertContext {
// 发送给 LLM 的原始提示
prompt: string;

// 测试用例变量
vars: Record<string, string | object>;
}

例如,如果测试用例有一个变量 example,可以在 JavaScript 函数中这样访问它:

tests:
- description: '带上下文的测试'
vars:
example: '示例文本'
assert:
- type: javascript
value: 'output.includes(context.vars.example)'

你也可以使用 context 变量执行更复杂的检查。例如,你可以检查输出是否比测试用例变量中定义的某个长度更长:

tests:
- description: '带上下文的测试'
vars:
min_length: 10
assert:
- type: javascript
value: 'output.length >= context.vars.min_length'

外部脚本

要引用外部文件,请使用 file:// 前缀:

assert:
- type: javascript
value: file://relative/path/to/script.js
config:
maximumOutputSize: 10

JavaScript 文件必须导出一个断言函数。以下是一个示例:

module.exports = (output, context) => {
return output.length > 10;
};

这是一个使用断言的 YML 文件中定义的配置数据的断言示例:

module.exports = (output, context) => {
return output.length <= context.config.maximumOutputSize;
};

以下是一个更复杂的示例,它使用异步函数来调用外部验证服务:

const VALIDATION_ENDPOINT = 'https://example.com/api/validate';

async function evaluate(modelResponse) {
try {
const response = await fetch(VALIDATION_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'text/plain',
},
body: modelResponse,
});

const data = await response.json();
return data;
} catch (error) {
throw error;
}
}

async function main(output, context) {
const success = await evaluate(output);
console.log(`success: ${testResult}`);
return success;
}

module.exports = main;

你也可以返回完整的 GradingResult 对象。例如:

module.exports = (output, context) => {
console.log('提示:', context.prompt);
console.log('变量', context.vars.topic);

// 你可以返回一个布尔值...
// return output.toLowerCase().includes('香蕉');

// 一个分数(其中0 = 失败)...
// return 0.5;

// 或者返回一个完整的评分结果,可以很简单...
let result = {
pass: output.toLowerCase().includes('香蕉'),
score: 0.5,
reason: '包含香蕉',
};

// 或者包含嵌套的断言...
result = {
pass: true,
score: 0.75,
reason: '看起来不错',
componentResults: [
{
pass: output.toLowerCase().includes('香蕉'),
score: 0.5,
reason: '包含香蕉',
namedScores: {
'使用香蕉': 1.0,
},
},
{
pass: output.toLowerCase().includes('黄色'),
score: 0.5,
reason: '包含黄色',
namedScores: {
'略带黄色': 0.66,
},
},
],
};

return result;
};

ES 模块

ES 模块受支持,但必须具有 .mjs 文件扩展名。或者,如果您正在转译 JavaScript 或 TypeScript,我们建议将 promptfoo 指向转译后的普通 JavaScript 输出。

其他断言类型

有关断言的更多信息,请参阅 测试断言