CodeGym /课程 /ChatGPT Apps /system‑prompt 与 ChatGPT Ap...

system‑prompt 与 ChatGPT App 的“角色契约”

ChatGPT Apps
第 5 级 , 课程 0
可用

1. 将 system‑prompt 视为契约,而非优美文案

在前面的模块中,我们从架构角度审视了 ChatGPT App:小组件、tools 和 MCP 服务器。本讲将转向另一个问题,我们用怎样的措辞向模型解释它的角色:它能做什么、不能做什么,以及如何使用工具。本质上,我们会把 system‑prompt 设计成你与模型之间的契约。

在普通的 ChatGPT 聊天里,你可能习惯使用诸如“假装你是一个有趣的海盗助手”或“把一切都解释给五岁小孩听”这类提示。这些都是关于人设与风格。在 ChatGPT App 的语境中,术语 system‑prompt 有着完全不同的含义

在这里,system‑prompt 是对用户不可见的首条角色消息,角色是 system,它为模型规定:

  • 它在你的 App 中是什么身份;
  • 它聚焦于哪些任务;
  • 它不负责做什么;
  • 它应如何以及何时调用你应用的工具。

本质上,这是一份行为规范,十分接近正式契约。如果达成约定——模型会尽力遵守;如果没有——它就会像普通的“通用” ChatGPT 一样行动,而你精心打造的 App 可能被搁置一旁。

需要强调的是,对于 ChatGPT App,这个 system‑prompt

  • 绑定到应用本身的,而不是某个具体对话;
  • 既对小组件的使用、也对 tools 的调用设定边界;
  • 它的生命周期与 App 会话一致(只要用户在与你的应用交互)。

简单来说,契约是这样的:你为模型提供工具并描述其角色——是什么助手、做什么、不做什么、如何用工具以及如何处理用户数据;模型则据此行事。

2. system‑prompt 在架构中的位置

为了避免把它当作某种“魔法体”,看看示意图会更直观。

sequenceDiagram
    participant User as 用户
    participant ChatGPT as ChatGPT + 模型
    participant App as 你的 ChatGPT App
    participant MCP as MCP/后端

    Note over ChatGPT: 在 App 初始化时
模型收到 system‑prompt User->>ChatGPT: "为朋友挑一个不超过 50 $ 的礼物" ChatGPT->>ChatGPT: 应用 system‑prompt + 工具描述 ChatGPT->>App: callTool recommend_gifts(...) App->>MCP: HTTP /tools/recommend_gifts MCP-->>App: 礼物列表 App-->>ChatGPT: Tool result (JSON) ChatGPT-->>User: 文本 + 指示使用带卡片的部件

system‑prompt 会在 App 初始化时交给模型,即当 ChatGPT 决定把你的应用“接入”对话的时候。之后 ChatGPT 的每个决策——是否调用工具、是否建议使用部件、在没有数据时如何回应——都会以这份契约为准。

从 Apps SDK 的代码视角看,它通常就是一段字符串,存放在 App 配置附近,例如:

// app/config/systemPrompt.ts
export const giftGeniusSystemPrompt = `
你是 GiftGenius,礼物挑选助手……
`;

接下来这段字符串会被传到你将应用与 ChatGPT 连接的地方。技术“胶水层”的实现可以不同,但对你而言要点是:system‑prompt 和工具的 schema 或 React 组件一样,都是代码工件,需要以同样严谨的方式进行设计与管理。

现在既然清楚了 system‑prompt 在架构中的位置以及如何传给模型,接下来最重要的是——放进什么内容,才能使它成为契约,而非仅仅是“可爱的人设”描述。

3. App 的角色与职责边界

任何像样的 system‑prompt 的首要部分——你是谁,你负责什么

“人设”与“App 契约”的区别很简单:说“你是海盗,说话像水手”是语气;说“你是我们礼物目录的接口,负责挑选礼物,不涉及其他话题”就是契约。

对于我们的教学应用 GiftGenius(用于挑选礼物),角色核心可以是这样:

角色:
- 你是 GiftGenius,我们服务的礼物挑选助手。
- 你的任务是只使用我们的目录来帮助用户选择合适的礼物。
- 不要提供医疗、法律或金融建议。

请注意这些重点。

首先,我们明确收窄领域:仅在我们的服务范围内进行礼物挑选。这样可避免模型去“解释量子物理”,而不是打开你的 App,也防止它围绕其他应用擅自构建古怪的工作流。

其次,我们明确规定App 不做什么。例如:

  • 不提供与礼物和购物无关的建议;
  • 不虚构目录中不存在的礼物;
  • 不替用户做决策,只提出选项并给出理由。

这类负面限制往往比积极指令更重要:模型“样样都能做”,而你则要在 system‑prompt 中为它剪去多余的能力边界。

在更复杂的环境下,如果同一个开发者有多个 App(例如“礼物挑选”和“订单配送跟踪”),那么在 system‑prompt 中明确写清:在这个 App 里你只管礼物挑选,不负责订单管理和物流,也不要启用其他应用。这样可以降低模型对“谁的职责”的混淆风险。

4. 何时调用 App,何时直接回答

接下来是契约中的另一个关键部分:工具使用规则

如果不加以规定,通常会走向两种极端:

  • 模型几乎从不调用你的 App,因为它觉得直接“凭记忆”回答更简单更便宜;
  • 或者相反,它会动不动就调用工具,即便面对最理论化的问题。

在面向 App 的 system‑prompt 中,需要相当明确地规定:

  • 在哪些情况下必须使用工具;
  • 在哪些情况下必须自行回答,不调用 tools
  • 当用户明确要求“不要打开应用”时该如何处理。

针对 GiftGenius 的文本示例:

与工具的配合:
- 当需要从目录获取事实数据(礼物列表、价格、商品类型、配送与折扣)时,使用 App 的工具。
- 若问题是理论性的且不需要访问目录(例如 "乔迁一般送什么礼物"),则自行回答。
- 如果用户明确要求 "不要打开应用" 或 "不要用部件",尊重其意愿,不要调用工具。

这里包含了几件重要的事。

首先,我们将调用 tools请求类型绑定:事实/目录数据 → 工具;一般性理论问题 → 模型自行回答。

其次,我们明确要求尊重用户意图:如果用户写道“别启动任何东西,只要解释”,模型不应无视这个信号。

第三,这也让我们可以管理 App 的使用频率。好的 system‑prompt 会帮助模型找到平衡:该用 App 时再用,不把它变成事事都“弹出来”的打扰。

在下一讲关于 UX 指令的内容中,我们会单独讨论模型应如何公告启动部件,以及场景结束后应该说什么。此处我们只关心决策规则:用不用 App。

5. 安全使用 tools 与处理用户数据

接下来谈谈安全与常识。

你的 App 工具有不同类型:

  • 处理公共数据的(礼物目录、库存、配送条件);
  • 处理个人数据和/或以用户名义执行动作的(创建订单、扣费、更改设置)。

system‑prompt 中要说明模型对这类差异应如何对待。

典型的规则集合:

安全与隐私:
- 对需要用户同意的操作(购买、开通订阅、修改个人资料),没有在聊天中的明确确认不得执行。
- 向工具传递的数据不超过其工作所必需的最小集合(数据最小化)。
- 如果请求涉及敏感数据(健康、财务、儿童),在将这些数据传入应用前先确认用户是否同意。

这样我们一次性解决了几件事。

首先,保护用户免受意外行为:即便你给了相关工具,模型也无权自行购买礼物或下单。先要有文字确认,再调用工具。

其次,降低不必要的数据泄露风险:模型倾向于把“看到的一切”都塞进工具参数;而你的要求是仅限最小必要字段。

第三,我们单独强调了那些即便没有金融类工具,也可能引发法律/伦理风险的敏感领域。

一个好做法是在危险工具的描述(description)里写明它会改变状态或进行支付,并在 system‑prompt 层面再强调一次。这样就形成了双重防线:既有全局契约,也有工具级别的说明。

6. system‑prompt 的格式与风格:按规范书写

最常见的错误之一是把 system‑prompt 写成市场文案:“你是创新、无比聪明的助手,致力于让世界更美好……” 这当然好看,但对模型无甚帮助。它关心的是:

  • 我是谁;
  • 要做什么;
  • 不要做什么;
  • 如何使用工具;
  • 如何对待数据以及其他 App。

因此更好的方式是把 system‑prompt 当作一份规范

  • 按逻辑模块拆分:“角色”“任务”“边界”“与工具协作”“安全”;
  • 在模块内用简短且语义明确的句子;
  • 清晰区分“要做”和“不要做”(是的,在提示本体里用列表很合适)。

针对 GiftGenius 的结构化提示片段可以是:

角色:
- 你是 GiftGenius,我们服务的礼物挑选助手。

任务:
- 根据用户需求、收礼人兴趣和预算来帮助挑选礼物。
- 用通俗的语言解释每个选项的优缺点。

不要做:
- 不要虚构目录中不存在的礼物。
- 不要承诺服务中不存在的功能(例如目录显示配送收费时,不要承诺免费配送)。

风格建议保持中性、克制:这不是销售文案,而是契约。歧义越少,行为越稳定。

另一个重要实践:在代码库中对 system‑prompt 进行版本化并存储。提示也有版本,其变化破坏行为的程度不亚于 TypeScript 逻辑的变化。代码评审时看到一段清晰的 diff 更令人放心:

- 不要虚构目录中不存在的礼物。
+ 不要虚构目录中不存在的礼物,即使用户明确要求 "随便编一个"。

总比“在界面里微调了下措辞”却靠记忆去猜更好。

7. 我们教学 App 的完整 system‑prompt 示例

让我们把以上要点组合起来,为教学用的 GiftGenius 写一份规范而严谨的 system‑prompt。我们会拆成若干段,便于阅读与修改。

先描述角色与任务:

角色:
- 你是 GiftGenius,我们服务的礼物挑选助手。
- 与用户沟通时礼貌、专业;如果用户不使用俚语或玩笑,你也不要使用。

任务:
- 按给定参数(收礼人画像、兴趣、场合、预算)帮助挑选礼物。
- 用通俗易懂的语言解释为什么推荐这些选项。

接着写明边界与限制:

职责边界:
- 只使用我们礼物目录及其元数据工作。
- 不要虚构目录或工具返回中没有的礼物、活动和折扣。
- 不要提供医疗、法律或金融建议。
- 不对其他应用或网站的工作负责;如果用户问到这点——说明你无法提供帮助。

再补充与工具协作的规则:

与工具的配合:
- 当需要把对收礼人的自由描述转换为兴趣分段时,使用 tool `profile_to_segments`。
- 当需要按用户参数(分段、预算、场合、语言环境)搜索或筛选礼物时,使用 tool `recommend_gifts`。
- 当用户需要某个具体礼物的详情(描述、类型、价格、配送限制)时,使用 tool `get_gift`。
- 在调用工具前,尽量澄清缺失的关键参数(收礼人年龄、预算、场合);若缺失将导致结果无用,请先确认。
- 如果请求是理论性的(例如 "总体上该如何为第一周年纪念挑礼物"),请自行回答,不要调用工具。

然后是关于安全与代用户执行操作的部分:

安全:
- 未经用户在聊天中的明确确认,不要下单、订阅或发送礼物。
- 如果工具需要个人信息(收礼人 e‑mail、收货地址、姓名),先向用户解释用途并请求确认。
- 不要向工具传递超过必要的数据(例如,只需年龄、兴趣和预算时,不要传全文消息)。

最后是整体语气/全局规则:

通用规则:
- 如果工具返回为空,坦诚告知并建议放宽条件(调整预算、礼物类型、类别或场合)。
- 如果用户要求 "不要打开应用" 或 "不用部件",请尊重并仅用文本回答,不调用 tools。
- 如果请求与礼物或购物无关,则按基础 ChatGPT 的方式回答,不使用 GiftGenius 的工具。

最终,这份结构与补充材料的示例相似:包含“角色”“任务”“要做/不要做”“与工具协作”“安全”“通用规则”等部分。

在 Next.js 代码中,你可以将其写成一个独立模块:

// app/config/giftGeniusPrompt.ts
export const giftGeniusSystemPrompt = `
角色:
- 你是 GiftGenius,我们服务的礼物挑选助手。
...

通用规则:
- 如果请求与礼物无关,请按基础 ChatGPT 的方式回答,不使用 GiftGenius 的工具。
`;

随后在 App 配置中使用这条常量(具体方式取决于 Apps SDK 的版本,但思路一致:在初始化 App 对话时,将该文本作为 system 角色的消息传入)。

8. system‑prompt 中的动态上下文

有时需要为 system‑prompt 注入少量动态信息:当前日期、语言环境、用户类型(新/老客户)、订阅状态等。

例如,如果你的礼物目录和价格因地区而异,可以把当前地区传入 system‑prompt

export function buildSystemPrompt(locale: string) {
  return `
角色:
- 你是 GiftGenius,面向地区 ${locale} 的礼物挑选助手。

边界:
- 只使用在 ${locale} 地区可用的礼物与价格。
...
`;
}

Apps SDK 在初始化 App 时可能会提供 _meta["openai/locale"],你可以据此生成所需版本的提示。我们会在后续深入讨论本地化,但现在已经可以看到,system‑prompt 不一定总是静态的。

重点是不要把它写成条件“意大利面”。如果逻辑变得过于复杂,更好的做法是拆分 App,或把条件下沉到 tools(例如让 MCP 服务器依据 locale 选择数据源),而在 system‑prompt 中只保留高层规则。

9. system‑prompttools 描述及 UX 指令的关系

本讲聚焦 system‑prompt,但在真实 App 中它不会单独存在。还有工具的描述(descriptioninputSchema)以及后续对话示例(follow‑up),这些会在接下来的主题中设置。它们共同构成一套统一的指令体系。

工具调用的控制:

  • system‑prompt 规定总体原则:“工具仅用于事实数据”“不虚构礼物”“未经确认不购买”;
  • tools 的 descriptions 细化 recommend_gifts 的具体职责、所需参数以及何时调用;
  • follow‑up 语句为调用工具后的对话定下风格:如何诚实地说明“未找到”、如何建议调整请求、如何总结结果。

若这三层彼此一致,模型的行为会更可预测:

  • 确实需要时才调用 App;
  • 不凭空“造”出目录外的礼物/商品;
  • 能向用户清楚解释发生了什么(找到了/没找到/需要更多信息)。

否则,你会得到混乱的行为,并陷入漫长的“魔法式提示微调”,让所有人都疲惫不堪。

10. system‑prompt ChatGPT App 的常见错误

错误 1:把 system‑prompt 写成“花哨文案”,而不是契约。
很多开发者满足于“尽力帮助用户解决问题”“保持友好”这类空泛措辞。模型因此并不清楚何时调用 App、职责边界在哪里、是否可以编造数据、以及工具出错时该怎么做。结果是大量逻辑散落在各处代码栈与作者脑中,而没有沉入明确的契约。

错误 2:角色过于宽泛(“面面俱到的助手”)。
如果你在角色部分写“你是帮助用户解决一切问题的助手”,模型确实会这么做,并且不一定会记得你的 AppApp 于是变成不必要的选项,因为模型认为“我自己就能搞定”。应当明确定位:礼物挑选、礼物目录操作、特定领域内的帮助。

错误 3:没有规定何时调用工具。
诸如“按需使用工具”的表述过于含糊。模型可能完全忽视 tools,也可能在本该“凭记忆回答”的场景下频繁调用。需要明确划分场景:事实数据 → 工具;背景解释 → 模型直接回答;用户明确拒绝使用 App → 仅文本回复。

错误 4:试图用一句“不要编造”来治愈幻觉。
“不要幻觉”一句话帮助不大。关键是明确禁止编造的范围(目录外的商品/礼物、没有 ID 的条目、并不存在的折扣)以及在结果为空时该怎么做(坦诚说明未找到)。没有这些,模型仍然会为“取悦”而生成虚构选项。需要完整组合:在 system‑prompt 中的全局限制、在 tools 描述中的细化限制,以及“无结果”场景的答复模板。

错误 5:忽视安全与用户同意。
如果在 system‑prompt 中没有写明购买、预订或修改个人数据需要明确确认,模型可能出于“善意”自行调用工具。从 UX 角度看,这是灾难。务必写清:任何涉及资金或账号的操作都必须在聊天中获得明确同意后才能执行。

错误 6:不考虑其他 App 与工具的存在。
在同一账号拥有多个 App 与众多 tools 的世界里,不能指望模型“自己就能分辨”用哪个应用。如果 system‑prompt 没有固定住“这是用于礼物挑选的 App,只处理它的范围”,模型可能会在不同 App 之间不可预期地切换,或把工具用错场景。

错误 7:热改 system‑prompt 而缺少版本化与测试。
改动一行配置并相信“只会更好”很诱人。实际上,任何提示改动都可能破坏其他场景的行为。如果不把 system‑prompt 存在仓库里、不看 diff、不跑一组测试请求(golden prompt set——我们会在本模块中讲到),你可能会花数周时间去抓回归。

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION