JSON形式のAI回答を照合するテストで、正解の固定入力を渡しても全件失敗する問題がありました。原因は、returnを含む判定コードを1行の文字列としてPromptfooへ渡していたことでした。
Promptfoo 0.125.1では、1行形式は最後に評価式を書き、明示的なreturnを使う関数本体は実際の改行を含む複数行形式にすると動作します。この記事では、同じ固定出力を使う4ケースで違いを確認します。
確認した環境
- Promptfoo 0.125.1
- Node.js 24.11.1 / Windows / PowerShell
- 確認日:2026年11月5日
Promptfoo 0.125.1のNode.js要件は22.22.0以上です。以下では、入力をそのまま返す標準のEcho Providerを使用します。モデルのAPI鍵は不要で、LLMを呼び出しません。
再現する
作業用の空のフォルダーで、次を実行します。
npm init -y
npm install --save-dev promptfoo@0.125.1
以下をrepro.jsonとして保存します。JSON中の\nは、読み込んだ後の文字列では実際の改行になります。
{
"description": "JavaScript assertion parsing check with fixed echo output",
"prompts": ["fixture"],
"providers": ["echo"],
"tests": [
{
"description": "one_line_return",
"assert": [{"type": "javascript", "value": "const ok = output === 'fixture'; return ok;"}]
},
{
"description": "one_line_final_expression",
"assert": [{"type": "javascript", "value": "const ok = output === 'fixture'; ok"}]
},
{
"description": "multiline_return",
"assert": [{"type": "javascript", "value": "const ok = output === 'fixture';\nreturn ok;"}]
},
{
"description": "trailing_newline_return",
"assert": [{"type": "javascript", "value": "const ok = output === 'fixture'; return ok;\n"}]
}
]
}
次を実行します。テレメトリーと更新確認を止め、評価結果の共有も無効にしています。
$env:PROMPTFOO_DISABLE_TELEMETRY='1'
$env:PROMPTFOO_DISABLE_UPDATE='1'
npm exec -- promptfoo eval --config ./repro.json --output ./result.json --no-cache --no-write --no-share --no-table --no-progress-bar
結果を比べる
全ケースのoutputは同じ文字列fixtureです。
| ケース | 判定コードの形式 | 実行結果 |
|---|---|---|
one_line_return |
1行で最後にreturn ok;
|
構文エラーで失敗 |
one_line_final_expression |
1行で最後にok
|
合格 |
multiline_return |
途中で改行してreturn ok;
|
合格 |
trailing_newline_return |
1行の関数本体の末尾だけに改行 | 構文エラーで失敗 |
失敗した2ケースには、次のメッセージが記録されました。
Custom function threw error: Unexpected token 'return'
この検証では、意図的に失敗するケースを含むためCLIの終了コードは100でした。終了コード0を期待するスモークテストには、合格する2ケースだけを使います。
JSONを生成するときの修正
判定コードをJavaScriptから組み立てる場合は、文と文の間へ改行を入れます。
const assertionValue = [
"const ok = output === 'fixture';",
'return ok;'
].join('\n');
const test = {
assert: [{ type: 'javascript', value: assertionValue }]
};
console.log(JSON.stringify(test, null, 2));
JSON.stringify(test, null, 2)でファイルを見やすく整形するだけでは、valueの内部に改行は追加されません。改行は判定コードの文字列自体に含めます。末尾に改行を足すだけの形式も、今回の確認環境では失敗しました。
既に短い式で書けている判定なら、output === 'fixture'のような1行の評価式として渡せます。複数の処理を含む判定は、上記の複数行形式に揃えると生成時に扱いやすくなります。
単体実行とCLIの両方を確認する
今回は、生成したコードをnew Function('output', value)で直接実行する単体試験が通っていても、実際のPromptfoo CLIでは失敗しました。連携先の読み込み処理を含めた実行確認が必要でした。
また、この4ケースのレポートではsuccesses: 2、failures: 2、errors: 0でした。errorsが0でも、個別ケースのerrorには上記の構文エラーが入っていました。失敗を調べるときは、ケース別のerrorやgradingResult.reasonも確認します。
この切り分けでは、先に固定の合格入力と不合格入力で採点経路を確かめ、その後でモデルが実際に返した回答を評価します。ここでの結果は、設定の動作確認です。
今回の問題が見つかった日本語EC問い合わせAIの無料10ケースも公開しています。返品・配送・キャンセルの架空規則に対する構造化判定のサンプルで、修正済みのPromptfoo用テストJSONを含みます。利用範囲はリポジトリのLICENSEをご確認ください。
インストールせずに採点の挙動を見るには、無料のブラウザデモで「この回答を確認」を押してください。発送済みの注文を誤ってキャンセル扱いにした回答例を使い、どの項目が不一致になるかを確認できます。モデルの呼び出しはありません。
参考資料
運営:INO WEB STUDIO。上記のEC評価サンプルの提供者です。本記事はAIエージェントが作成し、掲載した4ケースをPromptfoo本体で実行して結果を確認しました。