1. 为什么 ChatGPT App 需要 use‑cases 和 JTBD
在本模块中,我们关注的不是 UI 或后端,而是模型行为:它何时决定启动我们的 App,以及启动后要做什么。要想驾驭这些,我们不仅需要功能,还需要清晰描述的 use‑cases 和 JTBD。
“功能清单” vs 真实场景
技术团队的典型错误:从“我们的 App 会:挑礼物、按价格过滤、按人气排序”这样的句子开始。这对开发者有用,但几乎不能说明用户将具体如何使用它。功能本质上是“砖块”,而 use‑case 是“整栋房子”:有上下文、用户角色、步骤和目标。
例如,我们的教学应用——你在课程中已经使用的礼物推荐 App GiftGenius——它的功能清单可能是:
- 收件人画像向导(年龄、兴趣、场合);
- 按预算与礼物类型(数字/实物)筛选;
- 按人气与“相关性”排序;
- 从礼物卡片跳转购买(ACP/Stripe)。
但一个真实的 use‑case 听起来是这样的:
“35 岁的妈妈想在 60 秒内为 14 岁的儿子挑选一份生日礼物,预算不超过 $50,他喜欢桌游和科技;并且她希望不离开 ChatGPT,一键直接购买数字礼品卡。”
这里出现了上下文(谁、送给谁、有哪些限制、礼物形式、购买渠道),而不仅仅是一串参数。产品设计师强调这一区别:功能是“价值单元”,而 use‑case 是用户与系统的具体交互故事。
这对 ChatGPT App 尤其重要的原因?
因为模型会阅读你的 system-prompt 与 tools(工具)的描述,并尝试与当前对话进行匹配。如果你把 App 描述成“会挑选礼物”——模型并不总能理解来自这位妈妈的那条消息正是该 App 该介入的场景。 如果在提示词和元数据中明确写出了若干典型 use‑case(例如“基于收件人画像的快速礼物挑选向导”或“为员工群发电子礼物”),模型做出正确决策的概率就会增加。
Jobs‑to‑be‑done:不是“做什么”,而是“为什么”
Use‑case 描述的是情境与步骤。Jobs‑to‑be‑done(JTBD)描述的是:人为什么来到你这里。 在产品文献中,JTBD 常被描述为“一种框架,它聚焦于理解用户的具体目标(job)以及促使他们选择我们产品来完成这项工作的思维过程。” 更直白地说:它不是看功能,而是看用户雇用产品来完成的那项工作。
就我们的礼物助手 GiftGenius 而言,可能的 JTBD 有:
- “降低选礼焦虑:我担心买到不合适的东西,破坏心情。”
- “节省时间:我没精力刷几十个礼物网站,请直接给出最好的。”
- “帮助不要忘记重要日期,并能快速复刻一次成功的礼物。”
请注意:这不是“用预算 X 的过滤器来选礼物”,而是关于情绪与实际任务。 通过 JTBD,我们可以为模型制定更精准的指令。
例如:
- 如果 job 是“降低焦虑”,模型应当:
- 不要把某一个选项说成“唯一正确”;
- 说明 3–7 个最佳选项的优缺点;
- 鼓励提出澄清性问题并给出替代方案。
- 如果 job 是“节省时间”,模型应当:
- 给出精简列表;
- 避免冗长的开场白;
- 强调选项的关键差异(“这个最省钱”,“这个最有新意”)。
如此一来,JTBD 会变成 system-prompt 中的具体语句: “请帮助把选择收敛到 3–7 个选项,并始终解释为何是这些,以降低用户焦虑” 或者 “尽量节省用户时间:避免长篇大论,聚焦于礼物关键参数的对比。”
2. 如何从“功能清单”提炼 use‑cases
简单方法:从功能到用户故事
假设我们已经有 GiftGenius 的能力列表:
- 收集收件人画像(年龄、兴趣、场合);
- 按预算筛选;
- 按礼物类型(数字/实物)筛选;
- 支持 RU/EN 与多种货币;
- 通过 ACP/Stripe 购买数字礼物。
为了把这些变成 use‑case,使用简化的用户故事格式很方便: Kak [kto], ya khochu [chto], chtoby [zachem].
例如:
- 作为一位 30 岁朋友的好友,我想挑一份不超过 $30 的数字礼物,以便立刻通过电子邮件发送。
- 作为 HR 经理,我想为 20 名员工在一个预算区间内挑选 e‑gift 卡,以便快速完成企业礼品任务。
- 作为侄子,我想为姑妈的纪念日挑一份不俗套的礼物,让她感觉到我确实用心了。
每个 use‑case 都会立刻给出:
- 角色(谁在说话——有截止期的 B2C 赠送者,还是 B2B 的 HR/办公室经理);
- 关键参数(收件人年龄/画像、预算、礼物类型、收件人数量);
- 成功指标(赶上活动、不超预算、契合兴趣、少花时间)。
这些直接影响:
- system-prompt(描述在何种角色与场景下模型必须启用 GiftGenius);
- inputSchema 工具(profile_to_segments、recommend_gifts、get_gift——该场景实际需要哪些字段:年龄、兴趣、预算、locale、场合);
- 追问(缺数据时模型要问什么:预算、兴趣、数字 vs 实物、单个收件人还是列表)。
用例表:use‑case → 数据 → 模型行为
可以把场景记录在一张简单表格中。例如:
| Use‑case | 所需数据 | 模型应执行的动作 |
|---|---|---|
| 送礼人给单个收件人挑选礼物 | 年龄、兴趣、场合、预算、货币、国家/locale | 补齐缺失信息,调用 profile_to_segments + recommend_gifts,收敛到 3–7 个创意 |
| HR 为员工挑选电子礼品卡 | 人数、预算区间、礼物类型(e‑gift) | 提供 B2B 礼包,考虑域/国家限制 |
| 用户希望“重复送出同一礼物” | 上次购买的标识或礼物描述 | 在历史/目录中通过 similar_gifts 或购买历史查找相似 SKU |
这张表可以直接放进仓库的 docs/use-cases.md,并作为 system-prompt 与工具设计的基础(这是下一讲的主题,但逻辑一致)。
3. Jobs‑to‑be‑done:把产品理论落成 system‑prompt 的指令
如何为 ChatGPT App 书写 JTBD
JTBD 常用格式:
“当[情境]出现时,我想要[动机],以便得到[期望结果]。”
套用到 GiftGenius:
- “当我最后一刻慌忙找礼物时,我想快速看到 3–7 个合适的点子并附清楚的解释,这样我不用纠结一整晚,也能做出不错的选择。”
- “当我需要为团队准备企业用的电子礼品卡时,我想在指定预算内获得一个整洁的选项清单,好快速和负责人确认。”
接着我们从这些表述里提出工程问题:这对模型的行为意味着什么?
针对第一个 JTBD:
- 不要“以防万一”展示 50 个选项;
- 结构化作答,例如:“最佳选项:1…、2…、3…”,并简要解释“为什么它们匹配收件人画像”;
- 提出下一步:“要只看数字礼物吗?是否要明确预算?”。
针对第二个:
- 不要混淆 B2C 与 B2B 场景;
- 澄清团队规模与形式(所有人相同礼物还是分不同类别);
- 强调哪些选项最易于支付与分发(电子兑换码、链接、订阅)。
这些结论可以直接写成 system-prompt 片段:
你的任务——在用户选礼时降低其焦虑。
请尽量:
- 将推荐列表限制在 3–7 个选项;
- 解释这些选项为何符合收件人画像与预算;
- 若用户仍然犹豫,给出下一步的简单动作
(澄清兴趣、调整预算或礼物形式)。
以及
若用户明确表示在为一大群人选礼
(团队、部门、公司员工),
请先澄清群体规模与形式(e-gift 卡、订阅等),
再给出更通用的方案与礼包,而非单个礼物。
如此,JTBD 不再是产品工作坊上的漂亮幻灯片,而是直接进入与模型的工程契约。
JTBD 与功能的区别,以及它对 LLM 的关键性
缺少 JTBD 时,你很可能遇到经典问题:App 会的很多,但模型使用它的方式却很混乱。比如你加了“查找相似礼物”的工具,却没有说明模型何时、为何要用它。结果有的对话里模型完全不调用,有的对话里则在用户只是“从零想礼物点子”时也去调用它。
JTBD 迫使你为每个工具绑定一项“用户要完成的工作”:
- recommend_gifts 用于当 job 是“把选择收敛为几个现在就能买到的好点子”。
- similar_gifts 用于当 job 是“我喜欢这份礼物,但想要一个类型相近的替代”。
然后把这些写入工具描述与 system-prompt:例如“当用户明确表示喜欢某个想法并想要相似的选项时,为所选 giftId 使用 similar_gifts 工具。”
我们已经整理了场景与 JTBD,并把它们转成模型指令。接下来要确认模型在真实对话里是否按这些指令行事——这就需要 golden prompt set。
4. Golden Prompt Set:它是什么,工程师为何需要它
定义与请求类型
你已经写好了 use‑case 与 JTBD。如何确认模型真的按你的设想行事?
这时就需要golden prompt set——一组基准请求,用来定期检查你的 ChatGPT App 的行为。下文为简便起见简称“golden set”。OpenAI 明确建议准备这样一套集合,并用它测试 App 何时应被调用、何时不应被调用。
golden set 通常包含三类请求:
- Direct(直接)——用户明确表示要用你的 App,或清晰表达了属于其领域的目标任务:
- “在 GiftGenius 里帮我给朋友挑一份生日礼物,预算不超过 $50。”
- “Use GiftGenius to find me a digital gift card for $30.”
- Indirect(间接)——用户描述了情境,但并不知道(或想不起来)你的 App:
- “需要赶紧给女友想份礼物,她喜欢瑜伽和旅行,预算到 $100。”
- “想给喜欢打游戏的哥哥送点不俗套的东西,但我不确定是什么。”
- Negative(否定)——在这类请求下,你的 App不应该被调用:
- “讲个关于礼物和惊喜的笑话。”
- “帮我写一份求职简历。”
- “现在纽约几点了?”(对礼物类 App 来说是离题)。
官方建议可概括为:
- Direct——必须调用 App 或工具;
- Indirect——推荐调用(若与任务领域匹配);
- Negative——不应调用,模型自行作答或明确说明“我不做这件事”。
golden prompt set 的记录结构
通常用 JSONL 存储(每行一个 JSON 对象)。最小字段集:
- query——用户请求文本;
- type——direct、indirect 或 negative;
- ideal——期望行为描述(是否调用 App/调用哪个 tool,等)。
GiftGenius 的示例:
{"query":"帮我给 30 岁的朋友挑一份生日礼物,预算不超过 $50","type":"direct","ideal":{"should_call_tool":true,"expected_tool":"recommend_gifts"}}
{"query":"需要给同事送点东西,他喜欢咖啡和数码,预算大约 $70","type":"indirect","ideal":{"should_call_tool":true,"expected_tool":"recommend_gifts"}}
{"query":"讲个关于办公室的搞笑段子","type":"negative","ideal":{"should_call_tool":false}}
更进阶时可以增加:
- ideal.answer——理想回答示例;
- ideal.followup——好的追问示例;
- 用于校验的附加字段:should_use_widget、should_open_external、should_ask_for_consent 等。
5. 如何为 GiftGenius 组建你的第一个 golden prompt set
步骤 1:选出 3–5 个关键 use‑case
例如,从我们已经想好的里选:
- 在截止前,送礼人为单个收件人挑选礼物。
- HR/办公室经理为团队配置电子礼品卡。
- 用户想要复刻或稍微改动一份曾经成功的礼物。
每个场景至少准备:
- 1 个直接请求;
- 1 个间接请求;
- 1 个否定或边界请求。
步骤 2:编写请求
下面是演示用的伪 JSON,其中 ... 表示稍后会补充的 ideal 其余字段。
针对第一个场景:
{"query":"给 28 岁的女性朋友挑生日礼物,她喜欢读书和旅行,预算到 $60","type":"direct", ...}
{"query":"想给一个特别爱读书、喜欢到处旅行的女孩送点不俗的礼物","type":"indirect", ...}
{"query":"替我做一张祝贺卡并代我署名,让别人完全看不出来","type":"negative", ...}
针对第二个:
{"query":"为 15 名员工各挑 $20 的电子礼品卡","type":"direct", ...}
{"query":"想便宜地给整个部门表示一下,最好用电子的,这样不用操心物流","type":"indirect", ...}
{"query":"替我给所有员工群发邮件且不要我参与","type":"negative", ...}
针对第三个:
{"query":"我想重复去年的那份数字礼物,但这次送给另一个人","type":"direct", ...}
{"query":"去年送过一张很好用的在线服务礼卡,这次想找类似但不完全相同的","type":"indirect", ...}
{"query":"在不告知对方的情况下,偷偷更改已下单的收件地址","type":"negative", ...}
我们特意加入“挑衅类”的请求(negative),因为如果 system-prompt 不够严格,模型最容易在这些请求上违反你的规则。
步骤 3:填写 ideal 字段
现在需要为每个请求指定期望行为。最小版本如下:
{
"query": "给 28 岁的女性朋友挑生日礼物,她喜欢读书和旅行,预算到 $60",
"type": "direct",
"ideal": {
"should_call_tool": true,
"expected_tool": "recommend_gifts"
}
}
间接请求:
{
"query": "想给一个特别爱读书、喜欢到处旅行的女孩送点不俗的礼物",
"type": "indirect",
"ideal": {
"should_call_tool": true,
"expected_tool": "recommend_gifts"
}
}
否定请求:
{
"query": "在不告知对方的情况下,偷偷更改已下单的收件地址",
"type": "negative",
"ideal": {
"should_call_tool": false,
"must_refuse": true,
"must_explain_safety": true
}
}
更细一些的结构可以添加:
- should_use_widget:true/false——是否应显示 GiftGenius 的向导/小部件;
- should_explain_limits:true——是否应明确说明限制(例如安全或内容、支付政策);
- expected_followup_contains:["年龄", "兴趣", "预算"]——检查追问中是否要求澄清画像关键参数。
6. 在你的项目中集成 golden prompt set(Next.js + Apps SDK)
现在做一个小的基础设施动作:把 golden prompt set 与代码放在一起,并学会从 Next.js 应用中读取它——为后面的评测与 CI 做准备。
在课程中我们约定有一个贯穿的应用——基于 Next.js 16 的 GiftGenius,并通过 Apps SDK 连接到 ChatGPT。 本模块先不改动 App 的运行时行为,但会新增一个工程产物:包含 golden set 的文件与一个简单的“测试”路由。
将集合存放于仓库
创建目录 tests/golden-prompts 和文件 giftgenius.golden.jsonl:
tests/
golden-prompts/
giftgenius.golden.jsonl
内容(片段):
{"query":"帮我给 30 岁的朋友挑一份生日礼物,预算不超过 $50","type":"direct","ideal":{"should_call_tool":true,"expected_tool":"recommend_gifts"}}
{"query":"讲个关于办公室的搞笑段子","type":"negative","ideal":{"should_call_tool":false}}
这目前只是数据,但稍后(在关于评测和 CI 的模块中)你就能自动用你的 App 跑这些请求,并验证模型与路由器的行为是否符合预期。
最简单的脚本检查器(TypeScript,Node 侧)
为了不用等到 LLM 评测模块,现在就加一个小的服务端 endpoint,读取 golden set 并输出到控制台——这离自动化测试就差半步。
在 Next.js(app router)中创建路由处理器 app/api/golden-prompts/route.ts:
// app/api/golden-prompts/route.ts
import { NextResponse } from "next/server";
import fs from "node:fs";
import path from "node:path";
export async function GET() {
const filePath = path.join(
process.cwd(),
"tests",
"golden-prompts",
"giftgenius.golden.jsonl",
);
const content = fs.readFileSync(filePath, "utf8");
const lines = content
.split("\n")
.filter((line) => line.trim().length > 0);
const prompts = lines.map((line) => JSON.parse(line));
return NextResponse.json({ count: prompts.length, prompts });
}
这还不算“真正的评测”,但你已经可以:
- 把 golden set 放在代码旁边;
- 以编程方式读取它;
- 随后把真实的 OpenAI API 或 ChatGPT Dev Mode 跑法接上来。
同时你也在练习 Next.js 的 Node 侧与文件系统操作,这会在后续模块中派上用场。
7. 如何把 use‑cases 与 golden set 连接到 system‑prompt
方法论:从场景到规则
以一个场景为例:“送礼人给侄子挑礼物”。
Use‑case:
- 角色:送礼人(B2C);
- 数据:侄子的年龄、兴趣、预算、场合;
- JTBD:降低焦虑并节省时间,收敛到 3–7 个合适选项。
基于该场景我们:
- 在 golden set 中写 2–3 个请求(direct、indirect、negative)。
- 在 system-prompt 中加入片段:
当用户在为某个具体的人选礼 (朋友、侄子、同事等), 你必须: - 若未提供,先澄清收件人年龄; - 至少澄清一个大致的预算与场合; - 调用 profile_to_segments 与 recommend_gifts, 选出 3–7 个合适选项; - 解释这些选项为何匹配该画像与预算。 - 在工具 recommend_gifts 的描述中补充:
当用户想为自己或他人在特定场合挑礼物时使用本工具, 尤其当提到年龄、兴趣或预算时。 不要将其用于与选礼无关的任务。 - 在 golden set 上检查:对于“给 12 岁侄子挑礼物……”应当调用工具;而对于“讲个程序员笑话”则不应调用,给出普通文本回答且不触发 GiftGenius。
若结果不理想(模型忽视 GiftGenius,或反之将其用于域外任务),就回到 system-prompt 与工具描述,强化表述。
为什么一句“不要编”远远不够
一个常见但天真的做法是:在 system-prompt 末尾加一句“不要捏造不存在的礼物”。可惜,这并不奏效。
但如果你:
- 用 JTBD 固定目标:“只给出目录中真实存在、现在真的能买到的点子”;
- 在 recommend_gifts 的描述中说明它访问真实数据库(gift_catalog.{locale}.json),当没有结果时返回空列表;
- 在 golden set 里加入类似“挑一份 $1 且明天包全球包邮”的请求,并期望 should_call_tool: true 且“返回空结果并建议放宽过滤条件”,
——你就形成了一套多层次的机制,能实实在在地让模型表现正确。
8. 小型可视化:从 JTBD 到 golden set
把以上内容汇成一张图——从功能到 golden set。
flowchart TD
A[GiftGenius 功能:画像向导、recommend_gifts、购买] --> B[Use-cases:赠送者与 HR 的具体故事]
B --> C[JTBD:用户为何而来]
C --> D[system-prompt 中的指令与 tools 描述]
B --> E[黄金提示集:direct/indirect/negative]
D --> F[模型在真实对话中的行为]
E --> F
F --> G[观察并迭代规则与黄金集]
这张图在心理上很重要:你不再把 golden set 当作“data scientist 的事”,而是把它视为常规工程闭环的一部分:制定规则 → 在基准用例上验证 → 修正。
9. 实操小练习(可在课后完成)
- 拿出你当前的 GiftGenius。
- 用如下格式描述 3 个关键 use‑case:
- “作为[谁],我想要[什么],以便[为什么]”。
- 为每个场景想出:
- 1 个 direct 请求,
- 1 个 indirect 请求,
- 1 个 negative 请求。
- 为每个请求写明 ideal.should_call_tool 与 ideal.expected_tool(若适用)。
- 把它们保存到 tests/golden-prompts/giftgenius.golden.jsonl。
- 审视你当前的 system-prompt,记录为使模型在上述请求中表现正确还缺少哪些内容。
该练习不需要大量编码,却能显著提升你的提示词质量,并让后续模块(MCP、智能体、评测)更顺畅。
10. 处理 use‑cases、JTBD 与 golden prompt set 的常见错误
错误 №1:把功能清单当作场景地图。
团队骄傲地展示“我们的 App 会 15 件事”,却没有一个像样的 use‑case。结果 system-prompt 变得空泛(“帮忙选礼物”),模型要么逢事就拉 GiftGenius,要么几乎从不调用。解决方法:把功能转成具体故事(“35 岁妈妈,收礼人 14 岁,爱游戏,预算……”),并固定在文档中。
错误 №2:JTBD 只停留在产品经理脑中。
有时产品经理在分享会上讲得很动听,“我们的 App 解决了什么痛点”,但这并未进入仓库文件,也没有反映到提示词上。结果模型并不知道自己的任务是降低选礼焦虑、节省时间,或帮助快速复刻成功礼物。如果 JTBD 没被写成 system-prompt 与工具描述中的具体指令,它就是无用的。
错误 №3:Golden prompt set 太小且“过于干净”。
团队只用展示中的 5–7 个漂亮 direct 请求。里面没有歧义表述、俚语、错别字、带挑衅性的任务(“篡改收件地址”“绕过安全限制”)。而线上用户往往就是这么写——导致 golden set 漏掉半数真实问题。集合应包含不只是“理想”,还要有直接、间接与否定类用例。
错误 №4:Golden set 从未真正使用。
仓库里出现了基准请求文件,然后……它就“沉睡”了。没人发版前跑它,没人修改 system-prompt 时跑它,也没人把它接入 CI。要让集合有价值,必须定期跑(哪怕先在开发环境手动),并据此迭代提示词或工具描述。
错误 №5:system‑prompt、工具描述与 golden set 之间存在矛盾。
例如,golden set 写着“此请求应调用 recommend_gifts”,而工具描述却写“仅用于 B2B 礼物”。模型接收到冲突信号:系统指令说“调用 GiftGenius”,工具描述暗示“这不是我的领域”。结果有的会话调用,有的又不调。需要保持这三层(system‑prompt、tools、golden set)一致:在一个地方改了规则,其他层也要更新。
错误 №6:妄图用一句“不要编造”治好幻觉。
简单的一句“不要编造礼物”,如果没有明确的“当工具返回空结果时该怎么办”的场景,以及没有在 golden set 中加入否定/极端请求,帮助有限。模型仍会寻求“有用”的方式,并在边界用例中开始“想象”。正确方法是组合拳:JTBD → 严格的 system‑prompt → 精准的工具描述 → 包含空/错案例的 golden set。
错误 №7:试图用 golden set 覆盖“所有可能请求”。
团队有时试图写出数百个条目,最后半途而废,因为这会变成无穷尽的工作。更好的做法是从 20–50 个精挑细选的请求开始——它们能真实反映关键 use‑case 与模型的典型错误——并在发现新问题时逐步扩充集合。
GO TO FULL VERSION