Prompt Engineering for LLMs — 本课题摘录
读了哪几章: 第 5 章(提示内容)、第 6 章(组装提示)、第 8 章(对话式能动性)。 全书十一章,其余本轮没读。
本课题第一个决定("一轮的输入怎么拼")到这里才算有了一份系统的材料。前面各家给的是"我们是这么排的",这本给的是"为什么排在那里会有效"。
它对本课题回答了什么
决定一最重要的一条:位置效应叠出一个"凹陷区"
两个效应同时存在:
| 效应 | 说的是 |
|---|---|
| 上下文学习 | 越靠近提示末尾的信息,影响越大 |
| 中间迷失 | 开头和末尾都好回忆,塞在中间的容易被略过 |
两者叠加,在提示的前中段形成一个低效区——作者管它叫"凹陷区"。
深浅与确切位置因模型而异,但所有模型都有。 (依据:书 · Prompt Engineering for LLMs §Assembling —— in-context learning(越靠近 prompt 末尾影响越大)与 lost middle(开头末尾好回忆、中间容易被略过)两个效应叠加出作者称为 Valley of Meh 的低效区,位于 prompt 的前中段;深浅与位置因模型而异但所有模型都有)
这一条把前面所有关于"排在哪儿"的经验串起来了:
- aider 的段落顺序、hermes 的三层、lobehub 的四个插槽——排的是"稳定性";
- onyx 的"换个位置遵从率从九成掉到三成"、shen-ru 的"打乱组织掉三成"——测的是"效果";
- 这一本给的是那个效果背后的机制。
合起来是一条完整的因果: 前缀要稳定是为了省钱;末尾要放关键内容是为了有效。这两条约束方向不同,所以中段成了两头不讨好的地方。
对付它的两条办法,作者明说没有完美解法:
- 把关键的、高质量的内容放在凹陷区之外;
- 过滤上下文,让提示尽量短。
第二条对本课题很重要:压缩不只是为了"塞得下",还是为了"别把好东西埋 进凹陷区"。 这跟 dexter 那条"塞太满会注意力稀释,而且不会报错"是同一件事的两种说法。
决定一:三明治写法与"重新聚焦"
开头和结尾各说一遍你要模型做什么。结尾那次叫"重新聚焦"。
长提示里必要——铺垫了很久之后,要把注意力拉回问题上。 (依据:书 · Prompt Engineering for LLMs §Assembling —— sandwich 写法是在 prompt 的开头与结尾各陈述一次要模型做什么,结尾那次称为 refocus,在铺垫了大量 context 的长 prompt 里必要;introduction 负责搭台、refocus 给出明确细节)
分工:开头那次搭台("我在想给某人推荐书"),结尾那次给明确细节("到底该推荐哪一本,限定在某个范围")。
对我们的最小原型:这条可以直接用。任务说明写两遍不是冗余,是把它同时放进两个高效区。
还有一条关于"开头"的解释很有意思:模型每个词的"思考预算"是固定的,不能停下来多想一会儿。所以早点把它的注意力引导到对的方向上,能改善输出。
这跟"让它先想一想"是同一个机制的两种用法:一个是给它更多词来想,一个是让它一开始就想对方向。
决定一:提示 的最后一部分要"硬转弯"
最后一段必须从"说明问题"坚决转到"解决问题"。
否则模型不会作答,而是继续往下编更多(很可能是它自己编的)上下文。 (依据:书 · Prompt Engineering for LLMs §Assembling —— prompt 的最后一部分必须从「解释问题」硬转到「解决问题」,否则模型会继续往下添加更多(很可能是编造的)上下文而不作答;对话式接口里这一转弯常常简单到只是一个问号)
这是一条我们很容易忽略的失败模式:模型不是答错了,是它根本没意识到该答了。 对话式接口里这一转弯常常简单到只是一个问号,但自己拼提示时就得显式做。
决定一:静态与动态的分界,以及它为什么不总是干净
静态内容解释任务、澄清问题、给精确指令;动态内容提供这一次的具体情境。
它明说两者不总能干净分开,分在哪一边取决于这句话是写死的还是从可变来源取来的。 (依据:书 · Prompt Engineering for LLMs §Content —— 静态内容解释一般任务、澄清问题、给精确指令,动态内容提供这一次的具体情境;两者不总能干净分开,判据是这段文字是硬编码的还是从可变来源取来的)
这条判据很实用:"是不是写死的"决定了它属于哪一段,也就决定了它能不能进缓存前缀。 同一句话,写死就是静态、从用户档案里取来就是动态——即便内容一模一样。
决定二:工具调用在底层不是新机制
它把这件事讲穿了:跟对话一样,工具调用也是"微调过的模型 + 接口层的语法糖"。
工具定义被放进系统消息、用 markdown 组织、并按类型化函数声明的样子表示。 (依据:书 · Prompt Engineering for LLMs §Conversational —— 工具调用是「微调过的模型 + API 层语法糖」,工具定义被放进 system 消息、用 markdown 组织、按 TypeScript 函数声明的样子表示;作者声明官方没有内部格式文档,这是他们「拷问模型」还原出来的)
按类型化函数声明表示的三条好处:
- 类型词汇更丰富,能引导模型用对参数类型;
- 文档能直接写进定义里,而且参数也能各自带说明;
- 这种写法在训练数据里常见,模型天然认得。
这一条对本课题第二个决定有实质影响: 我们以为"工具定义"是走一个独立通道的结 构化数据,其实它最后还是变成了提示里的一段文字。
推论一:工具定义要占词元预算——书专门提醒要把它的表示大小算进账。 推论二:工具描述怎么写会直接影响效果,因为模型看到的就是那段文字。 推论三:"照着训练数据里常见的样子写"这条原则同样适用于工具定义。
作者诚实地声明:官方没有内部格式的文档,这是他们"拷问模型"还原出来的。
引用这一条时必须带上这个限定。
决定二:工具设计的几条具体建议
两条底层直觉:人更容易懂的,模型也更容易懂;照着训练数据里常见的样子写,效果最好。
| 建议 | 说的是 |
|---|---|
| 限制同时可见的工具数 | 工具越多,模型越容易混 |
| 工具之间要划分领域 | 尽量覆盖全,但避免功能相似的工具 |
| 别把网页接口原样搬进提示 | 网页接口参数多、响应复杂,描述它要占大量篇幅,而模型调用复杂工具的成功率更低 |
| 名字要自解释 | 模型会像人读接口文档一样,从名字建立对用途的预期 |
| 别用全小写连写的名字 | 更难被切分理解 |
| 如果模型本来就熟悉某个公开接口,就沿用它的命名与风格 | 作者的实例:他们发现模型能把某个平台的检索语法背出来,于是就照那套文档来命名参数 |
(依据:书 · Prompt Engineering for LLMs §Conversational —— 工具设计建议包括限制同时可见的工具数、工具之间划分领域避免功能相似、不要把 web API 原样搬进提示(参数多响应复杂、占篇幅且模型调用成功率低)、名字要自解释且避免全小写连写、以及沿用模型已经熟悉的公开 API 的命名与风格)
最后一条跟 open-interpreter 的"按模型伪装成它熟悉的外壳"、oh-my-pi 的"方言层"是同一条原则用在工具命名上。 这已经是第四次撞上它了,可以写成定则:凡是要模型认的东西,都该长成它见过的样子。
它没回答什么
- 循环本身——什么时候停、结果怎么回填、并发怎么处理,这三章都没讲。
- 具体的压缩机制——讲了"过滤上下文让提示更短",没给办法。
- 其余各章——本轮没读。
坑与代价
- 内部提示格式那一段是作者反推的,不是官方文档。 引用要带限定。
- 凹陷区的深浅与位置因模型而异,所以"把关键内容放在凹陷区之外"这条实操起来没有 确切坐标。
判断(无锚): 可操作的近似是:关键内容放开头和末尾,中段只放"可有可无但有更好"的背景。 如果错,会错在: 如果提示本来就短(几百词),整段都在高效区,没有凹陷区可言,这条规划是多余的。
- 它是 2024 年的书,写在"工具定义按需披露"这类接口能力出现之前。 它说"限制同时可见的工具数",今天的答案已经变成"折叠成目录按需取"——方向一致,手段更新了。