跳转到内容

2. 把需求交给 AI

约 30 分钟 难度:新手 动手章

一句请求要交给 AI 去实现,通常要包含三样东西:数据从哪里来、结果长什么样、遇到特殊情况怎么办。这三样东西不说清楚,AI 只能自己猜。猜对了看不出问题,猜错了要重新说一遍,说清楚一次就能省掉这一轮来回。

「帮我整理报价」这句话读起来已经是一个完整的要求,拆开看却缺着好几处:

  • 报价文本长什么样,字段之间用什么分隔?
  • 「整理」之后,结果应该是什么形状:一张表、一行摘要,还是别的?
  • 缺价格、缺单位这类情况该怎么处理:跳过,还是标出来?

这些空白没有唯一答案,答案在提出需求的人手里,不在 AI 手里。没写清楚时,AI 会按最常见的猜测往下走,猜测和实际情况不一致,结果就会跑偏。

示范项目「供应商报价整理器」要处理的第一批输入是这样的,三个字段用英文逗号分隔,第三行故意缺一个单位:

input.txt
M6 螺母,个,0.18
M8 螺栓,个,0.55
不锈钢垫片,,1.20

把「帮我整理报价」原样交给 AI,不说明分隔符和缺失情况的处理方式,AI 只能挑一种常见格式去猜。拿到的实现类似这样:

parse-guessed.js
// 只凭一句"帮我整理报价"猜出来的实现,猜的是 Tab 分隔
function parseQuotesGuessed(text) {
const lines = text.trim().split('\n').filter(Boolean);
return lines.map((line) => {
const [name, unit, price] = line.split('\t');
return { name, unit, price: Number(price) };
});
}

用上面那份 input.txt 的内容跑一遍这个函数:三行都没有 Tab 字符,split('\t') 切不出第二、第三段,结果是整行原文被塞进了 name,unit 完全丢失,price 变成 Number(undefined),也就是 NaN。三行输入,三行都不对。

这句请求确实没告诉它字段用逗号分隔,跟 AI「做得不够好」无关。换一句猜测(比如猜逗号、猜空格),结果会不一样,但换哪种猜测由 AI 决定,不由实际数据决定。

北极星给出的最小模板只有三段,负责把上面那几处空白填上:

输入是……,输出是……,规则是……

把「帮我整理报价」换成这样一句话再交给 AI:

输入是:每行一条报价,字段用英文逗号分隔,顺序是品名、单位、含税价。输出是:一张表,每行对应一条报价。规则是:单位或价格缺失的行,对应字段标记为「缺失」,其余行照常显示数字。

这一次 AI 拿到的实现类似这样:

parse-templated.js
// 按模板说清楚分隔符和缺失规则之后得到的实现
function parseQuotesWithTemplate(text) {
const lines = text.trim().split('\n').filter(Boolean);
return lines.map((line) => {
const [name, unit, price] = line.split(',').map((cell) => cell.trim());
const missingUnit = !unit;
const missingPrice = price === undefined || price === '';
return {
name,
unit: missingUnit ? '缺失' : unit,
price: missingPrice ? '缺失' : Number(price),
missing: missingUnit || missingPrice,
};
});
}

同一份 input.txt 跑一遍:前两行品名、单位、价格全部对上;第三行「不锈钢垫片」缺单位,unit 字段被标成「缺失」,价格 1.2 正常显示。三行输入,这一次三行都对。

两版代码唯一的差别是分隔符和缺失处理这两处空白有没有被填上,跟哪一次 AI 更用心无关。

模板里的「规则是」这一段可以继续加条件。价格是 0 该不该也算缺失?「不锈钢垫片,个,0」这一行按现在的规则会显示价格 0,不会被标成缺失,因为 price === '' 不成立。

把这条规则加进模板里再试一次:「价格等于 0 时,也标记为缺失」。把这句加进上面那段请求,重新交给 AI,看这一行的 missing 字段有没有变成 true。

同一个模板可以套进第 0 章留下的那句问题陈述。报价整理器的版本是:

输入是:粘贴进网页的报价文本。输出是:一张统一格式的汇总表,标出缺失的行。规则是:品名、规格、单位不同写法要能对上同一列。

第 0 章「游戏灯光」那个念头例子,套进同一个模板会变成:

输入是:游戏发出的血量下降信号。输出是:桌面灯在收到信号后的颜色变化。规则是:信号在一秒内没有收到确认,灯自动恢复原色。

模板的三段位置不变,填进去的内容来自各自的问题陈述,不是套用同一个答案。

把「换一个模板」那一节的实现存成一个能直接打开的页面,不需要先装运行环境:

  • 文件夹quote-tool/
    • index.html
quote-tool/index.html
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="utf-8" />
<title>报价整理器</title>
</head>
<body>
<!-- 粘贴报价文本:每行一条,品名、单位、含税价用英文逗号分隔 -->
<textarea id="input" rows="6" cols="50"></textarea>
<br />
<button id="run">整理</button>
<table id="output"></table>
<script>
// 按模板里说清楚的规则解析:逗号分隔,缺失字段标记出来
function parseQuotes(text) {
const lines = text.trim().split('\n').filter(Boolean);
return lines.map((line) => {
const [name, unit, price] = line.split(',').map((cell) => cell.trim());
const missingUnit = !unit;
const missingPrice = price === undefined || price === '';
return {
name,
unit: missingUnit ? '缺失' : unit,
price: missingPrice ? '缺失' : Number(price),
missing: missingUnit || missingPrice,
};
});
}
// 点击「整理」后,把解析结果渲染成表格,缺失的行标红
document.getElementById('run').addEventListener('click', () => {
const rows = parseQuotes(document.getElementById('input').value);
document.getElementById('output').innerHTML =
'<tr><th>品名</th><th>单位</th><th>含税价</th></tr>' +
rows
.map(
(row) =>
`<tr style="color:${row.missing ? 'red' : 'black'}"><td>${row.name}</td><td>${row.unit}</td><td>${row.price}</td></tr>`
)
.join('');
});
</script>
</body>
</html>

双击打开这个文件,粘贴 input.txt 里的三行,点击「整理」,能看到一张三行的表格,第三行标红。这个文件本身就是这一章的产物:不需要服务器,不需要提前装 Node.js,直接在浏览器里打开就能用。

另一份产物是两次请求的步骤对比,不靠秒表计时,靠往返次数:

请求方式需要说明分隔符需要说明缺失规则跑通所需轮数
「帮我整理报价」中途补充中途补充至少两轮
套用输入/输出/规则模板一次说清一次说清一轮

这张表格记录的是刚才发生的事。模板不保证永远只需要一轮,规则本身写漏一处,一样要补第二轮,比如上一节故意漏掉的「价格等于 0」。

我要一个程序。输入是……,输出是……,规则是……

这一节有错或讲不清? 提个 Issue 直接改文档 请作者催更