用 Node.js 给提示词建立回归测试
文章用 JSON 测试用例和 Node.js 脚本批量执行提示词,通过关键词保留、字数限制等规则输出通过情况。示例围绕通知摘要,建议覆盖多日期、混合语言和空输入等边界条件,并可接入不同模型 API。
AI 深度解读
提示词试两次都能用,离「改完还能稳定工作」还有一段距离。作者给 AI 学习者设计了一个很小的 Node.js 项目:固定一组输入,用规则检查模型回答,再记录每次修改后的通过率。
它的价值是让提示词修改有据可查。不过,原文给的是教学骨架,没有接好的模型 API,也没有模型对比实测。对刚开始写 AI 功能的前端和全栈开发者,这个起点足够具体,也容易看清边界。
先把「回答不错」变成能检查的条件
作者选的任务是:把大学通知压缩成一句话,同时原样保留所有日期和时间。
这个任务适合入门,因为部分要求可以直接检查。摘要是否流畅需要人判断,但「Saturday 有没有丢」「20 November 有没有被改写」可以交给程序。
cases.json 用输入和规则描述预期行为:
[
{ "input": "Library closes at 6 pm on Saturday from next week.",
"mustInclude": ["6 pm", "Saturday"], "maxWords": 25 },
{ "input": "Fee deadline for semester 5 is extended to 20 November.",
"mustInclude": ["20 November"], "maxWords": 25 }
]
要看的是 mustInclude 和 maxWords:前者要求回答包含指定文本,后者把长度限制为 25 个词。它们检查的是必要条件,还不能证明摘要完整、准确。
原文只展示了 2 条样例,要求读者补足至少 10 条,并加入两个日期、Hindi-English 混合文本、空通知等难例。这样做是为了让问题尽早暴露,避免测试集只覆盖最顺手的输入。
用一个 Node.js 脚本,把修改前后放在一起比较
下面的脚本负责读取用例、请求模型、检查回答并输出结果:
// test.mjs (Node 18+; .mjs so import and top-level await work)
import fs from "node:fs";
const PROMPT = "Summarise this college notice in one sentence. Keep every date and time exactly as written.";
const cases = JSON.parse(fs.readFileSync("cases.json", "utf8"));
async function ask(text) {
// Replace with your provider's API call. It must return the model's reply as a string.
throw new Error("connect your AI API here");
}
function check(answer, c) {
const problems = [];
for (const word of c.mustInclude || []) {
if (!answer.includes(word)) problems.push(`missing "${word}"`);
}
const words = answer.trim().split(/\s+/).length;
if (c.maxWords && words > c.maxWords) problems.push(`${words} words`);
return problems;
}
let passed = 0;
for (const c of cases) {
const answer = await ask(`${PROMPT}\n\nNotice: ${c.input}`);
const problems = check(answer, c);
if (problems.length === 0) passed++;
console.log(problems.length ? "FAIL" : "PASS", "|", c.input.slice(0, 40), "|", problems.join(", "));
}
console.log(`${passed}/${cases.length} passed`);
先看 ask():它目前会直接抛错,必须换成实际的供应商 API 调用,并返回字符串。原文要求使用 Node 18+,文件采用 .mjs,以支持 import 和顶层 await;API key 放在环境变量里,不写进文件,也不提交到 GitHub。
测试循环每次把 PROMPT 和通知拼在一起,逐条等待回答,再打印 PASS 或 FAIL、输入前 40 个字符以及失败原因,最后输出总通过数。
这里没有绑定供应商,但也没有自动完成供应商适配。请求格式、响应提取等工作仍由读者补齐。
固定测试,再改提示词,分数才有比较价值
作者建议每轮只修改 PROMPT 中的一处,查看失败项,再运行并记录新分数。经过三四轮,就能留下修改过程。
原文举了「v1 7/10,v2 9/10,增加了原样保留日期的要求」这样的记录。这是示例记录,不是作者公布的实验结果。
标题里的「改提示词,不改测试」,重点是别为了提高分数而放宽规则。若任务要求原样保留日期,就应该围绕失败样例改善提示词。当然,规则写错或需求改变时,测试也需要修订,只是要说明原因。
作者还提出三项扩展:每条用例运行 3 次,增加 mustNotInclude 检查编造细节,把结果保存成 CSV 以比较两个模型。这些都没有在给出的脚本里实现。
我的判断
这个项目最有用的地方,是把凭感觉调提示词变成可复查的迭代。对简单摘要任务,直接用 Node.js 和 JSON 起步,投入很小,也方便理解每个失败来自哪里。
但通过率只能说明规则覆盖范围内的表现。answer.includes() 区分大小写,也不理解语义;回答即使包含指定日期,仍可能把日期与事件对应错。脚本也没有检查「只有一句话」,更没有验证所有事实。
长度统计同样有前提:split(/\s+/) 适合按空白分词的文本,不能直接拿来衡量中文摘要字数。空回答在这段实现里还会被计为 1 个词。
作者没有给出修改前后的完整输出、重复运行数据或两个模型的对照结果,因此效果判断仍是教学经验。相比一开始引入完整评测框架,这个方案容易上手;需要复杂语义判断时,就得增加人工复核或更细的评测方式。
能拿来做什么
- 给正在做的通知摘要功能整理至少 10 条固定用例,把日期、时间和长度要求写清楚,并加入双日期、混合语言及空输入。
- 在 Node 项目中接好
ask(),每轮只改一处PROMPT,记录修改原因、通过数和失败回答,方便回看哪次改动有效。 - 把每条用例运行 3 次的循环和 CSV 保存补进脚本,比较两个模型时使用同一组输入与规则。
- 增加
mustNotInclude后,继续人工抽查事实对应关系;不能把命中几个字符串当成摘要正确的证明。