首页 / 文章

从零样本到自我一致性:实用的提示技巧进阶路径

提示工程作为攀登阶梯:零样本、少样本、分解法、批判循环与推理提示,附辅助机器人示例及何时使用纯代码。

发布者:REACTAPP.TOP阅读约 16 分钟3623 词

来源: Prompt Engineering for LLMs: Zero-Shot, Few-Shot, Reasoning, Decomposition & ReAct

一旦应用程序确定了模型可以查看的内容、需要获取的文档、哪些内容需要简化以及哪些内容应被忽略,另一个问题就会出现:如何表述具体的请求。并没有一种提示方法能适用于所有情况。一个合理的做法是先使用最简单的可行指令,只有在任务确实需要时才加入示例或分步指导。

下面的示例场景是客户支持助手。

完全不使用示例

零样本提示仅描述任务要求,而不展示理想输出的样子。对于支持助手而言,这可能是一条用于总结投诉的简短指令,投诉内容则附在指令下方:

Summarize the following customer complaint in one sentence.
<complaint>
The package arrived three days late and the box was damaged.
</complaint>

模型只会收到任务内容,除此之外别无其他。正是这种简洁性使得人们首先愿意尝试它。在提示语中添加的任何内容都会带来代价:示例会占用上下文空间,额外的指令会增加复杂性,而每新增一部分都会让两条规则产生更多冲突的可能。如果直接给出的指令就能产生可靠的结果,那么复杂的结构设计就相当于治疗一种根本不存在的病症。

优质指令应满足的要求

一个结构完善的任务描述需要明确四点:需要执行的动作、可参考的素材、适用的限制条件,以及答案应有的形式。改进后的提示语版本如下:

Task:
Summarize the customer complaint.

Source:
<complaint>
The package arrived three days late and the box was damaged.
</complaint>

Constraints:
- Use only the information in the complaint.
- Do not infer the cause of the damage.
- Use one sentence.

Output:
Return only the summary.

它比简单的“总结此内容”要求更详细,但每多出一行要求就能减少猜测的空间。模型不再需要考虑是否要推测原因、该写多长,或是是否需要添加评论。大型模型供应商发布的指南也指向同一个方向:明确说明任务是什么、输出应为何样、有哪些约束条件以及哪些背景信息重要,而非指望模型自行推断。简而言之,应用所关心的任何要求都应明确写下来。

具体的目标优于模糊的指引

“提供帮助”这一指令几乎没有给模型明确的行动方向,而“说出客户描述的问题,并用一句话概括”则给了它明确的目标。对比一下用于支持工具的两类指令:较弱的指令只是要求帮助客户,而较强的指令则要求明确客户描述的认证问题,再加上最多三条基于所提供的文档的故障排除步骤。

这一点很重要,因为模型可以沿着多种合理的方向继续处理提示内容。模糊的目标会让模型产生与开发者本意不同的理解,而明确的目标则能缩小这种差异空间。

限制应体现在任务本身之中

假设助手绝不能凭空编造文档中未提及的解决方案。这是产品规则,因此提示语必须明确说明:只能使用所提供的文档,如果文档无法涵盖相关问题,则应表明现有信息不足。这与“准确无误”相比,后者虽然指出了期望的结果,但并未给出应对不确定性的操作指引。

这种模式具有普遍性。不仅要描述理想的结果,还要说明当无法安全地得到该结果时模型应如何处理。在后续的工具调用和结构化输出环节,这一点更为重要。

何时零样本即可

当任务简单、行为易于用语言描述、模型已了解任务类型、输出规则较为有限且输入没有异常边界情况时,简单的指令通常就足够了。在消息中仅要求提供产品版本号就是这类任务之一,将句子翻译成法语也是另一例。而一次性提供五个示例则几乎没什么作用。

因此,提示词优化的第一条规则出奇地保守:先从零样本开始,只有在评估显示有需求时才添加额外机制。

零样本方法失效的方式

会出现几种常见的失败类型。

歧义性。“让这个更好”这个要求本身就存在疑问:是更简短、更有说服力、更准确,还是更正式?模型必须自行猜测。与之相比,要求重写客服回复时,则需要做到简洁、专业、让非技术背景的客户也能理解,同时还要保留所有事实陈述——这样的要求界限要明确得多。

缺失的上下文。模型无法依赖那些从未被提供也无法获取的事实。如果要求它解释客户为何无法通过认证,却又不提供错误信息或系统详情,那么再怎么重新措辞也无法补充缺失的证据。这种情况下,解决办法是提供更多上下文,而非更完善的指令。这虽是显而易见的一点,但也正是提示工程的实际局限。

相互矛盾的要求。要求用恰好十个词给出完整解释的提示,实际上同时提出了两种难以同时妥善满足的条件。优秀的提示设计应避免此类冲突,而非依赖模型去逐一解决。

未明示的假设。编写“总结投诉内容”这样的指令的开发者,其意图可能是“仅列出客户陈述的事实”。但模型却可能会生成包含合理推断的流畅总结。如果这种差异很重要,就必须在指令中明确说明。对系统而言重要的假设应转化为明确的、机器可读的要求。

添加示例

当普通指令无法满足需求时,下一个可用工具是少样本提示:将该任务的已完成示例放入上下文中。用于将消息分类为账单、技术及账户类别的分类器,可能会在实际消息之前展示几条已标注的示例消息:

Task:
Classify the customer message as BILLING, TECHNICAL, or ACCOUNT.

Example 1:
"My invoice contains an unexpected charge."
→ BILLING

Example 2:
"The application crashes when I upload a file."
→ TECHNICAL

Example 3:
"I cannot reset my password."
→ ACCOUNT

Now classify:
"I was charged twice for my subscription."

通过这些示例,模型可以推断出对应的映射关系。这被称为上下文学习,因为模型会利用窗口中的示例来调整其对当前请求的处理方式,而其底层参数保持不变。本质上,这些示例是在说明“实际任务的具体表现形式”,并且能够传达那些用文字描述起来较为困难的细节。

示例用于教授任务本身,而不仅仅是格式

许多开发者将少量示例视为格式辅助工具,但实际上它们的作用远不止于此。以“应用程序运行缓慢”与标签“技术问题”这样的示例组合为例,它不仅展示了输出格式,还体现了该应用程序对“技术问题”类别的理解方式。示例有助于塑造模型对任务本身的认知。

正因如此,劣质示例具有风险。不一致的标签、意外的偏见或违反政策的边缘情况都可能被模型复制回去。

选择要包含的示例

鉴于手头有10,000个历史工单,将它们全部放入提示语中并不现实,因此必须挑选一部分。随机选择是一种简单的做法,而更好的方法是刻意选取具有代表性的案例:

Example 1: straightforward billing issue
Example 2: straightforward technical issue
Example 3: ambiguous issue
Example 4: boundary case
Example 5: short, poorly written request

什么算作良好的示例选择取决于具体任务。分类任务需要体现主要类别及其边界;格式化任务则需要展示所需结构的示例;而依赖推理的任务则受益于能展示如何拆解问题或进行验证的示例。在所有情况下,示例的价值都源于其所包含的信息,而非仅仅因为其存在。

数量多少

数量越多并不一定越好。如果一个精心挑选的示例就能让行为特征清晰可见,那么再多三十个示例也可能只会增加数千个标记而毫无益处,还可能引入相互矛盾的模式。因此,少样本提示也面临着与其他方法相同的上下文资源限制,必须通过测试来确定合适的数量。

此时,提示工程开始呈现出实验性工作的特征。问题不再在于提示语是否更动听,而在于该版本在典型测试用例中的表现是否更好。一旦引入评估机制,这种转变就变得至关重要。

示例的多样性

如果每个演示都是简短、清晰、表述良好的请求,模型可能会学到真实用户并不遵循的狭隘模式。真实的消息通常是这样的:

"can't login"
"I've been locked out since yesterday"
"Password reset isn't sending me anything"
"login broken after changing phone"

这些描述都是用截然不同的语言来表达相同的故障问题。一个优质的少样本数据集能够体现应用程序所期望的多样性。这并不意味着随意添加示例,而是要有意识地涵盖具有实际意义的差异。

展示应避免的情况

对于某些任务而言,将正确的输出与错误的输出配对有助于模型明确边界。在支持性案例中,关于包裹送达延迟的消息可以搭配一个合理的总结和一个有缺陷的总结:

Input:
"The customer says the package arrived late."
Good output:
"The customer reports that the package arrived late."
Bad output:
"The courier lost the package."
Reason:
The customer did not state that the courier lost it.

糟糕的示例设定了一个界限:不得推断输入中未提及的事实。不过,负面示例也需要谨慎处理。一个被标记为错误的示例可能会意外地教会它本应防止的行为,尤其是当两者之间的差异很微妙时。应用程序应测试这些负面示例是否真的能提升效果,而不能想当然地认为如此。

结构示例

当输出布局难以描述时,示例会很有帮助。假设助手需要用三行分别标注问题、证据和解决方案:

Issue: ...
Evidence: ...
Action: ...

一个实际演示就能立刻让该布局变得具体可见:

Input:
"The login token expired after 30 days."
Output:
Issue: Expired authentication token
Evidence: Token expiration is reported after 30 days
Action: Regenerate the authentication token

它既能修正内容格式,也能优化呈现方式。不过,示例并不总是最佳解决方案。如果软件需要格式正确、可被机器读取的JSON,采用受模式约束的输出方式可能比向模型展示样本更为可靠。

保持示例一致性

少样本提示对矛盾信息反应敏感。以相同输入“无法登录”为例,若一个标记为ACCOUNT类别,另一个标记为TECHNICAL类别,就会出现问题:

Example 1:
"Can't log in" → ACCOUNT
Example 2:
"Can't log in" → TECHNICAL

该模型没有明确的方法来判断应使用哪种映射方式。细微的不一致也会造成问题。如果某些示例使用标签“BILLING”,而其他示例则使用短语“Billing issue”,那么输出结果就会变得模糊不清。所有示例中的标签、格式、术语、详细程度以及边缘情况的处理方式都应保持一致。演示内容也是规范的一部分,同样需要得到妥善处理。

窗口内的学习

上下文学习是少样本提示法背后的核心理念:示例位于当前上下文中,模型的行为会因这次交互而发生变化。但这并不意味着模型会永久记住这些示例。如果应用程序先发送一个带标签的示例,随后又收到用户关于无法访问账户的消息:

Example:
"Password reset email never arrived." → ACCOUNT
User:
"I can't access my account."

该模型可以使用此请求的示例。其参数不会被更新,该示例也不会被纳入其长期知识中。这反映了之前所提到的上下文与记忆之间的区别。那些会修改参数的方法,比如在额外训练数据上进行微调,属于另一种机制,与提示技术的比较则要晚得多。目前,少样本提示法最好被视为通过上下文提供的临时任务条件。

两者之间的选择

一个可行的决策流程首先是要明确输出出错的原因。任务表述模糊时需要更清晰的措辞,信息缺失时则需要更好的上下文。当模型忽略了某些细微的惯例时,示例或许能起到帮助作用。如果任务需要精确的数学运算或数据库访问,那么在提示中添加更多文字可能完全不是正确的解决办法。

最后一个案例涉及更复杂的情形。有些任务过于繁琐,无法仅通过一条指令和一次回复就能可靠处理。这类任务需要被拆分成更小的操作步骤,进行逐一检查,或借助外部计算来完成。一旦超出一定复杂度,面临的挑战就不再是寻找完美的句子,而是为模型设计一套可遵循的简单流程。

以这样一例工单为例:有客户在更改密码后立即无法登录,系统要求助手查阅历史记录,找出可能的原因并给出回复。这看起来像是一项任务,但实际上它隐藏着多个子任务:弄清发生了什么、查找相关证据、区分事实与假设、推理可能的原因、决定哪些建议是安全的、验证这些建议,以及撰写最终回复。认识到这一点,就是进行任务分解的起点。

将一项任务拆分为多项

通过分解,原本复杂的任务会被替换为若干边界明确的较小任务。应用无需一次性处理所有内容,而可以按阶段逐步处理请求:

Task:
Analyze this customer support case.

Step 1:
Extract the relevant facts.

Step 2:
Identify the customer's actual problem.

Step 3:
List plausible causes supported by the evidence.

Step 4:
Select the safest supported resolution.

Step 5:
Draft the customer-facing response.

该模型实际上并不需要“步骤”这个词。重要的是,一个模糊的目标已被转化为一系列可操作的步骤。当各部分性质不同时,这种方式尤为有效:提取事实属于信息处理任务,选择诊断结果属于推理过程,而撰写消息则属于沟通行为。若将它们混为一谈,给出单一的模糊指令,就会使得结果更难掌控和评估。

分解后的系统还提供了更多测试点。如果最终答案有误,就可以判断是事实提取、诊断还是回复撰写出了问题。这种思维方式的转变在于,提示词可以像流水线一样构建,而不仅仅是以问题的形式书写。

先规划,再行动

一种相关技术要求模型在执行复杂任务之前先制定计划。当模型需要在回答问题前确定需要哪些操作时,这种技术能提供帮助。辅助系统可以从目标及有序计划开始:

Goal:
Resolve the customer's login problem using only supported evidence.
Plan:
1. Read the latest customer message.
2. Check the relevant conversation history.
3. Identify authentication-related evidence.
4. Compare the evidence with the known troubleshooting guidance.
5. Produce a response that does not claim unsupported facts.

规划将决定如何解决问题与实际解决问题分开。一旦涉及工具,这种分离的重要性就更加凸显,因为模型可能需要先判断是否应该搜索知识库、查看账户记录或进行计算。提示功能可以在工作开始前就确定工作的结构。

这也有其代价。分解会增加提示语的长度,而当每个阶段都需单独调用模型时,还会产生额外的模型调用次数和延迟。一个五阶段的处理流程所花费的成本可能远高于单次调用。只有当额外的控制能力和可靠性能够弥补这些成本时,这种做法才有价值,而非因为阶段越多就一定越好。

生成、评估、修改

另一种有效的模式能让模型再次审视自己的初稿。第一个答案并不被视为最终结果,会通过第二次审核来依据明确的标准进行检验。对于支持系统而言,这意味着先拟写回复,然后再根据列出的问题清单来检查该初稿:

First:
Draft the response.

Then:
Check the draft for:
- unsupported claims,
- missing evidence,
- incorrect troubleshooting steps,
- promises the support team cannot make,
- failure to answer the customer's actual question.

Finally:
Revise the response to correct any problems.

这种方法有效是因为生成与评估是不同的任务。生成意味着构造出看似合理的内容,而审核现有答案则能让模型查找是否符合特定清单的要求。明确列出标准通常比单纯要求模型更努力思考更为有效。

这种模式可适用于不同深度的任务:草稿、审核、最终回复;对于结构更复杂的任务,则包括提取信息、验证提取结果、分类、验证分类结果以及最终生成内容。第二种形式更易于调试,因为每个阶段都有明确的规范。

有一个重要限制:被要求自我批评的模型并非独立的真理来源。如果原始答案基于错误的假设,批评者也可能继承这一错误。自我批评虽能提升一致性,但无法保证正确性;在涉及重大决策时,值得参考模型之外的信息,如数据库、既定规则、计算结果、检索到的文档或确定性代码。

能揭示推理结构的提示词

关于思维链提示词的研究表明,为模型提供包含中间推理步骤的示例,可在某些多步骤问题中提升解题效果,且在算术、常识和符号化测试中均有改进。其工程意义远不止于此:当提示词能明确展示任务的中间结构时,复杂任务也能从中受益。

Identify the relevant facts.
Determine which facts support each possible conclusion.
Eliminate conclusions that require unsupported assumptions.
Select the conclusion supported by the evidence.

这是一种以推理为导向的提示方式:通过设计任务,使中间决策足够清晰,从而引导模型得出所需结果。它并不要求应用程序向用户展示模型的内部推理过程。通常,更好的界面会直接询问验证结果,而非冗长的解释。应用程序可以要求保留类似下面的简洁内部记录,然后再单独生成简短的客户回复:

classification: password_reset_issue
evidence_supported: true
recommended_action: resend_reset_link
confidence: high

推理结构与面向用户的解释是相互独立的要求。将二者分开还能避免一个常见错误,即认为更直观的推理就能让答案更可靠。中间步骤同样可能包含错误。对思维链提示法的研究表明,演示内容的关联性和顺序等特性至关重要,因此仅仅增加冗长的推理过程并不能成为万能的解决方案。

多次尝试后再投票

文本生成属于概率性过程,因此同一个问题在不同运行中可能会产生不同的答案。自一致性方法通过采样多种推理路径并选择其中大多数支持的答案,而非依赖某一条采样路径,来利用这一特性。

假设支持系统无法确定某个问题属于密码重置问题还是账户锁定问题。它不必只接受一种分类结果,而是可以生成多种分析结果并对比这些分类结论。

即便各种分析结果一致,也未必代表真相。如果模型始终无法正确判断情况,多次独立分析仍可能得出相同的错误答案。一致性只能说明系统的稳定性,而非正确性。此外,这种方式还会增加计算量并导致延迟,因此仅适用于那些可靠性提升所带来的好处足以抵消成本的高难度任务。

提示词应在何时交由代码处理

这就是越来越复杂的提示词与良好的系统设计之间的界限。试想,要求计算一张包含17项、每项价格为1500卢比的发票的总金额。模型或许能够算出这个总数,但当精确的财务数值至关重要时,就没有必要通过越来越长的指令让模型来模拟运算。计算器或普通程序则能以确定性的方式完成乘法运算。

同样的逻辑也适用于其他任务:

  • 账户数据应来自数据库查询,而非模型的内存。
  • 当前事实应从数据库中获取,而非从训练数据中回忆。
  • 运算工作应由计算器或程序来完成。
  • 架构校验则是解析器和验证器的职责。
  • 授权功能则由应用程序代码和访问控制规则负责。
  • 在可行的情况下,关键的业务规则应以确定性的方式编码。

有一条实用的规则:利用提示词来引导语言模型的行为;而在任务确实需要确定性计算或执行时,则应使用确定性软件。

外部操作能进一步强化这一观点。一种著名的研究方法ReAct将推理与操作相结合,使模型能够参考外部资源或环境,而不仅仅依赖内部知识,实践表明这种交互方式有助于解决某些任务中的幻觉和错误传播问题。

那就是通往下一步的桥梁。该支持系统最初只是简单的提示,如今已发展成类似小型程序的存在。一旦验证过程需要数据库、知识库、API或其他外部功能,模型就不再仅依赖文本运行,此时问题就转向了上下文工程:不仅要决定编写哪些指令,还要确定模型应接收哪些信息。

相关阅读

  • 使用 Ollama 和 LangChain 在本地 LLM 上运行的 QuickBooks 财务智能体 — 基于 Qwen 3.5 9B 模型与 RTX 4070 的 ReAct 智能体,可无需依赖云端即可实时读取 QuickBooks 数据。查看相关代码、输出结果以及已知限制。
  • 实用指南:Vite + TypeScript 是 2026 年的标准,为何你应该停止使用它 — 详细讲解实用指南内容:Vite + TypeScript 是 2026 年的标准,为何你应该停止使用它,包括相关契约、检查机制以及供采用该架构的团队直接使用的代码片段。
  • 实用笔记:从提示工程到AI系统设计——RAG、内存与工具 — 详细讲解实用笔记内容:从提示工程到AI系统设计:RAG、内存与工具,包括适用于采用该模式的团队的契约、检查项以及可直接插入的代码片段。
  • 提示、上下文、整合与循环:构建AI智能体的四层架构 — 四个相互嵌套的层次决定了智能体的行为方式。了解每一层的作用,查看一个实际的GitHub问题分类处理示例,以及为何应先构建整合层和循环层。