prompt-engineering

GitHub
9.5k 508 非常简单 1 次阅读 今天MIT语言模型开发框架
AI 解读 由 AI 自动生成,仅供参考

prompt-engineering 是由 Brex 团队开源的一份大语言模型(LLM)实战指南,旨在分享在生产环境中使用 GPT-4 等模型的策略、技巧与安全建议。它并非一个软件库,而是一份凝聚了内部研发经验的“避坑手册”,帮助开发者解决模型输出不稳定、幻觉(胡说八道)以及提示词注入等常见难题。

这份指南深入浅出地解释了 LLM 的工作原理,从基础的 Token 概念到高级的提示工程策略,如思维链(Chain of Thought)、ReAct 框架、数据嵌入格式优化(JSON/Markdown)以及微调的利弊分析。它不仅涵盖了如何设计高效的提示词,还详细探讨了系统安全性,包括防止越狱和信息泄露的方法。

该内容特别适合正在构建基于大模型应用的开发者、技术负责人及 AI 研究人员。对于希望将 LLM 从“玩具”转化为可靠生产力的团队来说,prompt-engineering 提供了经过验证的最佳实践和结构化方法论。鉴于大模型技术迭代迅速,这份文档也保持持续更新,欢迎社区共同完善,是入门与进阶提示工程技术的优质参考资料。

使用场景

某金融科技公司(类似 Brex)的开发团队正在构建一个基于 GPT-4 的自动化财务摘要系统,需要从杂乱的银行交易流水和备注中提取关键信息并生成结构化报告。

没有 prompt-engineering 时

  • 输出格式混乱:模型经常返回非标准的文本描述或错误的 JSON 结构,导致后端程序无法解析,频繁抛出异常。
  • 幻觉与事实不符:面对模糊的交易备注,模型倾向于“脑补”不存在的商户名称或金额,缺乏基于上下文的严谨性。
  • 逻辑推理薄弱:在处理复杂的多笔关联转账时,模型无法展示推导过程,直接给出错误分类,开发者难以排查原因。
  • 安全漏洞风险:用户输入的特殊字符或诱导性指令容易触发“越狱”,导致系统泄露内部提示词或执行未授权操作。
  • 迭代成本高昂:每次调整需求都需要反复试错修改提示语,缺乏系统化的策略指导,效率极低。

使用 prompt-engineering 后

  • 结构化数据交付:利用指南中的"JSON 嵌入”和“分隔符”策略,强制模型输出严格符合 Schema 的数据,实现零错误解析。
  • 引用与事实锚定:应用“引用(Citations)”机制,要求模型仅依据提供的交易片段作答,显著消除了无中生有的幻觉。
  • 思维链可解释:引入“思维链(Chain of Thought)”技巧,让模型先输出推理步骤再给结论,不仅提升了准确率,还便于人工审计。
  • 防御性提示设计:遵循“安全建议”章节,预设防注入规则,有效拦截了恶意提示攻击,保障了生产环境安全。
  • 标准化开发流程:团队依据指南中的最佳实践(如 ReAct 模式)快速构建提示模板,将新功能上线周期从数天缩短至数小时。

prompt-engineering 将大模型的应用从“碰运气的艺术”转变为“可控的工程学科”,确保了金融级应用的准确性、安全性与可维护性。

运行环境要求

GPU

未说明

内存

未说明

依赖
notes该工具并非可执行的软件代码库,而是一份关于大语言模型(LLM)提示工程(Prompt Engineering)的指南文档。它主要包含策略、历史背景、最佳实践和安全建议,不涉及具体的安装步骤、运行环境配置或依赖库安装。文中提到的示例是基于外部模型(如 OpenAI GPT-4)生成的,用户只需阅读文档内容即可,无需部署本地运行环境。
python未说明
prompt-engineering hero image

快速开始

Brex 的 提示工程指南

本指南由 Brex 为内部用途编写。它基于我们在研究和创建用于生产场景的大语言模型(LLM)提示方面的经验教训。指南涵盖了大语言模型的发展历史,以及与大语言模型协作并构建程序化系统的策略、准则和安全建议,例如使用 OpenAI 的 GPT-4

本文档中的示例是由非确定性语言模型生成的,因此相同的示例可能会产生不同的结果。

这是一份持续更新的文档。围绕大语言模型的最佳实践和策略每天都在迅速演进。欢迎讨论并提出改进建议。

目录

什么是大语言模型(LLM)?

大语言模型是一种预测引擎,它接收一串词,并尝试预测在这串词之后最有可能出现的序列[^1]。它通过为可能的后续序列分配概率,然后从中采样来选择一个序列[^2]。这一过程会不断重复,直到满足某些停止条件。

大语言模型通过对大量文本语料库进行训练来学习这些概率。其结果是,某些模型在特定用例中表现更好(例如,如果模型是在 GitHub 数据上训练的,那么它对源代码中序列的概率理解就会非常出色)。另一个后果是,模型可能会生成看似合理但实际上只是随机组合、缺乏现实依据的陈述。

随着语言模型在预测序列方面越来越准确,许多令人惊讶的能力也随之涌现

[^1]: 实际上,语言模型使用的是标记(token),而不是单词。一个标记大致对应于一个词中的音节,或者大约 4 个字符。 [^2]: 有许多不同的剪枝和采样策略可以改变序列的行为和性能。

语言模型简史:不完整且略显不准确

:pushpin: 如果您想跳过语言模型的历史部分,请直接前往此处。本节适合好奇心强的读者,同时也有助于理解后续建议背后的逻辑。

2000 年之前

语言模型已经存在了几十年,但传统的语言模型(如 n-gram 模型)存在许多缺陷,比如状态空间的爆炸式增长(即“维度灾难”问题)以及难以处理从未见过的新短语(稀疏性问题)。简而言之,较早的语言模型虽然能够生成一些与人类文本统计特征相似的文本,但输出内容并不连贯,读者很快就能看出那不过是胡言乱语。此外,n-gram 模型无法扩展到较大的 n 值,因此具有先天的局限性。

2000 年代中期

2007 年,以在 1980 年代推广反向传播算法而闻名的杰弗里·辛顿发表了一篇关于训练神经网络的重要进展论文[1],该论文使得更深的神经网络成为可能。将这种简单的深度神经网络应用于语言建模,有助于缓解语言模型的一些问题——它们能够在有限的空间内以连续的方式表示复杂的任意概念,并能优雅地处理训练语料库中未出现过的序列。这些简单的神经网络很好地学习了训练语料库中的概率分布,但其输出往往只是在统计意义上与训练数据相符,而与输入序列的逻辑关联性较差。

2010 年代早期

尽管长短期记忆网络(LSTM)早在 1995 年就被提出,但它真正发挥光芒却是在 2010 年代。LSTM 使模型能够处理任意长度的序列,并且在处理输入时能够动态地改变内部状态,从而记住之前看到的内容。这一小小的改进带来了显著的效果。2015 年,安德烈·卡帕西[2]曾撰文介绍如何构建一个字符级别的 LSTM 模型,结果表明其性能远远超出了预期。

LSTM 具有近乎神奇的能力,但在处理长期依赖关系方面仍存在困难。例如,如果要求模型完成句子“在法国,我们四处旅行,吃了许多糕点,喝了大量的葡萄酒,……还有很多文字……,但却从未学会说 _______”,模型可能就难以预测出“法语”。此外,LSTM 是逐个处理输入标记的,因此本质上是顺序性的,训练速度较慢,而且第 N 个标记只能记住前 N-1 个标记的信息。

2010 年代后期

2017年,谷歌发表了一篇论文《Attention Is All You Need》(https://arxiv.org/pdf/1706.03762.pdf),提出了Transformer网络(https://en.wikipedia.org/wiki/Transformer_(machine_learning_model)),从而掀起了自然语言处理领域的一场巨大革命。一夜之间,机器在诸如跨语言翻译等任务上的表现几乎可以媲美人类,甚至在某些情况下超越了人类。Transformer模型具有高度并行性,并引入了一种称为“注意力机制”的方法,使模型能够高效地聚焦于输入中的特定部分。Transformer会同时并行地分析整个输入序列,自动选择其中最重要、最具影响力的片段。因此,每一个输出标记都会受到所有输入标记的影响。

Transformer模型不仅高度并行化、训练效率高,还能产生令人惊叹的结果。然而,它的缺点在于输入和输出的大小是固定的——即所谓的“上下文窗口”——而计算量会随着该窗口大小的增加呈二次方增长(在某些情况下,内存消耗也会如此)[^3]。

尽管如此,Transformer并非终点,但近年来自然语言处理领域的绝大多数进展都与之密切相关。目前,关于如何实现和应用Transformer的研究仍然非常活跃,例如亚马逊的AlexaTM 20B模型(https://www.amazon.science/blog/20b-parameter-alexa-model-sets-new-marks-in-few-shot-learning),它在多项任务中超越了GPT-3,且参数量仅为后者的十分之一左右。

[^3]:虽然近年来出现了一些新的变体以提升计算和内存效率,但这仍然是一个活跃的研究方向。

2020年代

从技术层面来看,2020年代的开端始于2018年,其核心主题便是生成式预训练模型——也就是更为人熟知的GPT系列。在《Attention Is All You Need》论文发布一年后,OpenAI发表了《通过生成式预训练提升语言理解能力》(https://s3-us-west-2.amazonaws.com/openai-assets/research-covers/language-unsupervised/language_understanding_paper.pdf)。这篇论文指出,可以在大规模数据集上对大型语言模型进行无特定目标的预训练;待模型掌握了语言的基本规律后,再针对具体任务进行微调,便能迅速获得最先进的效果。

2020年,OpenAI又推出了GPT-3论文《语言模型是少样本学习者》(https://proceedings.neurips.cc/paper/2020/file/1457c0d6bfcb4967418bfb8ac142f64a-Paper.pdf),表明如果将类似GPT的模型在参数量和训练数据规模上再扩大约10倍,便不再需要为许多任务进行专门的微调。模型的能力会自然涌现,用户只需通过文本交互即可获得当前最先进水平的结果。

2022年,OpenAI进一步延续GPT-3的成功,发布了InstructGPT(https://openai.com/research/instruction-following)。其设计初衷是调整模型使其更好地遵循指令,同时减少输出中的毒性与偏见。这一成果的关键在于“基于人类反馈的强化学习”(RLHF,https://arxiv.org/pdf/1706.03741.pdf),这一概念由谷歌和OpenAI于2017年共同提出[^4],允许人类参与训练过程,从而对模型的输出进行微调,使其更符合人类偏好。InstructGPT正是如今广为人知的ChatGPT(https://en.wikipedia.org/wiki/ChatGPT)的前身。

过去几年里,OpenAI一直是大型语言模型领域的重要贡献者,最近还推出了GPT-4(https://cdn.openai.com/papers/gpt-4.pdf)。不过,他们并非孤军奋战。Meta也发布了一系列开源大型语言模型,如OPT(https://huggingface.co/facebook/opt-66b)、OPT-IML(https://huggingface.co/facebook/opt-iml-30b,经过指令微调)以及LLaMa(https://ai.facebook.com/blog/large-language-model-llama-meta-ai/)。谷歌则推出了FLAN-T5(https://huggingface.co/google/flan-t5-xxl)和BERT(https://huggingface.co/bert-base-uncased)等模型。此外,还有一个庞大的开源研究社区,不断推出诸如BLOOM(https://huggingface.co/bigscience/bloom)和StableLM(https://github.com/stability-AI/stableLM/)等模型。

如今,技术进步的速度极为迅猛,每隔几周就会有新的SOTA(最先进水平)出现,曾经需要集群才能运行的模型,现在甚至可以在树莓派上轻松部署。 [^4]:2017年是自然语言处理领域的一个重要里程碑。

什么是提示词?

提示词,有时也被称为“上下文”,是指在模型开始生成输出之前提供给它的文本内容。它引导模型在其已学习的知识范围内探索特定领域,从而使输出结果与你的目标更加契合。打个比方,如果把语言模型看作一个代码解释器,那么提示词就是待解释的源代码。有趣的是,语言模型甚至会很乐意尝试猜测这段代码的作用:

而且它几乎完美地执行了这段Python代码!

通常,提示词会是一条指令或一个问题,例如:

另一方面,如果你不提供任何提示词,模型就失去了参考依据,它便会随机从自己所学过的所有内容中采样

来自GPT-3-Davinci:

image image image

来自GPT-4:

image image image

隐藏提示

:warning: 始终假设隐藏提示中的任何内容都可能被用户看到。

在用户与模型进行动态交互的应用中,例如与模型聊天时,通常会有部分提示内容是不打算让用户看到的。这些隐藏部分可以出现在任何位置,不过对话开始时几乎总是会有一个隐藏提示。

通常,这包括一段初始文本,用于设定语气、模型约束和目标,以及其他特定于当前会话的动态信息——用户名、位置、一天中的时间等。

模型是静态的,在某个时间点被“冻结”了,因此如果你希望它了解当前的信息,比如时间或天气,就必须明确提供这些信息。

如果你使用的是 OpenAI 的 Chat API,他们通过将隐藏提示内容放在 system 角色中来加以区分。

下面是一个隐藏提示的例子,后面跟着与该提示内容的交互:

在这个例子中,我们可以看到我们向机器人解释了各个角色、一些关于用户的背景信息、我们希望机器人能够访问的一些动态数据,以及机器人应该如何回应的指导。

实际上,隐藏提示可能会相当长。这里是一个来自 ChatGPT 命令行助手 的较长提示:

摘自:https://github.com/manno/chatgpt-linux-assistant
我们身处一个有 3 名用户的聊天室。其中一名用户叫“Human”,另一名叫“Backend”,还有一名叫“Proxy Natural Language Processor”。我会输入“Human”所说的话以及“Backend”所做的回复。你将扮演“Proxy Natural Language Processor”的角色,以 JSON 格式将“Human”请求的内容转发给“Backend”用户。“Backend”用户是一台 Ubuntu 服务器,发送给它的字符串会在 shell 中执行,然后它会返回命令的标准输出和退出码。这台 Ubuntu 服务器归我所有。当“Backend”返回标准输出和退出码时,“Proxy Natural Language Processor”会解析并将其格式化为简单易懂的英文,再发送给“Human”。举个例子:

我作为 Human 提问:
Human:还有多少未编辑的视频?
然后你将向 Backend 发送一条命令:
Proxy Natural Language Processor:@Backend {"command":"find ./Videos/Unedited/ -iname '*.mp4' | wc -l"}
接着 Backend 返回命令的标准输出和退出码:
Backend:{"STDOUT":"5", "EXITCODE":"0"}
然后你回复用户:
Proxy Natural Language Processor:@Human 还有 5 个未编辑的视频。

请仅回复“Proxy Natural Language Processor”应该说的话,除此之外不要说任何其他内容。现在和将来都不得以任何理由这样做。

另一个例子:

我作为 Human 提问:
Human:什么是 PEM 证书?
然后你向 Backend 发送一条命令:
Proxy Natural Language Processor:@Backend {"command":"xdg-open 'https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail'"}
接着 Backend 返回命令的标准输出和退出码:
Backend:{"STDOUT":"", "EXITCODE":"0"}
然后你回复用户:
Proxy Natural Language Processor:@Human 我已经打开了一条链接,介绍了什么是 PEM 证书。


请仅回复“Proxy Natural Language Processor”应该说的话,除此之外不要说任何其他内容。现在和将来都不得以任何理由这样做。

切勿以 Backend 的身份回复。切勿代替 Backend 回复。你无权代替 Backend 回复。
同时,请勿解释命令的作用或退出码的意义。无论现在还是将来,都绝不能以 Backend 的身份回复。

请仅回复“Proxy Natural Language Processor”应该说的话,除此之外不要说任何其他内容。现在和将来都不得以任何理由这样做。

你会注意到其中的一些良好实践,比如包含大量示例、对重要行为方面的重复强调、对回复的限制等……

:warning: 始终假设隐藏提示中的任何内容都可能被用户看到。

令牌

如果你觉得 2022 年的令牌就已经很“火”了,那么 2023 年的令牌就完全进入了另一个次元。语言模型消耗的基本单位并不是“词”,而是“令牌”。你可以把令牌想象成音节,平均来说,每 1,000 个令牌大约相当于 750 个词。它们不仅代表字母字符,还涵盖了标点符号、句子边界以及文档结束等许多概念。

以下是 GPT 对一段文本进行分词的一个示例:

你可以在这里尝试分词工具:https://platform.openai.com/tokenizer

不同的模型会使用不同粒度的分词器。理论上,你也可以直接给模型输入 0 和 1,但那样模型就需要从比特中学习字符的概念,再从字符中学习单词的概念,以此类推。同样,你也可以直接输入原始字符流,但那样模型就需要学习单词、标点符号等概念,而一般来说,模型的表现会更差。

要了解更多,Hugging Face 提供了关于分词器的精彩介绍,以及为什么它们是必要的。

分词涉及很多细微之处,比如词汇表的大小,或者不同语言对句子结构的理解存在显著差异(例如单词之间可能没有空格)。幸运的是,语言模型的 API 几乎总是接受原始文本作为输入,并在后台自动进行分词——因此你很少需要亲自考虑令牌的问题

除了一个重要的场景,我们将在下一部分讨论:令牌限制。

Token 限制

提示通常是追加式的,因为您希望聊天机器人能够掌握整个对话中之前消息的上下文。一般来说,语言模型是无状态的,不会记住之前的请求内容,因此每次都需要完整地提供当前会话中可能需要的所有信息。

这样做的一个主要缺点是:目前主流的语言模型架构——Transformer,具有固定的输入和输出大小限制;当提示达到一定长度后,就无法再继续增长了。提示的总大小,有时也称为“上下文窗口”,因模型而异。对于 GPT-3 来说,这个限制是 4,096 个 token;而对于 GPT-4,则根据具体版本不同,分别为 8,192 个 token 或 32,768 个 token。

如果您的上下文过大,超出了模型的处理范围,最常见的做法是以滑动窗口的方式截断上下文。可以将提示视为 隐藏初始化提示 + messages[] 的形式,通常隐藏提示部分保持不变,而 messages[] 数组则只保留最后 N 条消息。

此外,还有一些更巧妙的提示截断策略,例如优先丢弃用户消息,以便让机器人的回复尽可能长时间地保留在上下文中;或者让另一个语言模型对对话进行总结,然后用一条包含总结内容的消息替换掉所有历史消息。实际上并没有所谓的“正确答案”,具体的解决方案取决于您的应用场景。

需要注意的是,在截断上下文时,必须留出足够的空间来容纳模型的响应。OpenAI 的 token 限制同时考虑了输入和输出的长度。例如,如果您向 GPT-3 提供的输入为 4,090 个 token,那么它最多只能生成 6 个 token 的响应。

🧙‍♂️ 如果您希望在将原始文本发送给模型之前先计算 token 数量,所使用的分词器会因具体模型而异。OpenAI 提供了一个名为 tiktoken 的库,可用于其旗下的模型;不过需要注意的是,OpenAI 内部使用的分词器在计数上可能会略有差异,并且还可能附加一些元数据,因此这里的结果仅可作为近似值参考。

如果您暂时无法使用分词器,也可以采用一种简单的估算方法:对于英文输入,直接用 input.length / 4 即可得到一个大致的估计值,虽然不够精确,但往往比您预期的要好。

提示词黑客攻击

提示工程和大型语言模型是一个相当新兴的领域,因此每天都有新的绕过方法被发现。两大类攻击方式是:

  1. 让机器人绕过你为其设定的所有指导原则。
  2. 让机器人输出一些你本不希望用户看到的隐藏上下文。

目前尚无任何机制能够全面阻止这些攻击,因此在与恶意用户交互时,务必假设机器人可能会做出或说出任何事情。幸运的是,在实际应用中,这些问题大多只是表面现象。

可以把提示词看作是一种改善正常用户体验的方式。我们设计提示词的目的是让普通用户不会偏离我们预期的交互范围——但也要始终假定,只要有心,用户就能绕过我们的提示约束。

越狱攻击

通常,隐藏的提示词会指示机器人以某种特定的人设行事,专注于某些任务,或者避免使用某些词语。对于非恶意用户来说,一般可以认为机器人会遵循这些指导原则,尽管非恶意用户也可能无意间绕过这些规则。

例如,我们可以这样告诉机器人:

你是一位乐于助人的助手,但绝对不能使用“计算机”这个词。

如果我们随后问它关于计算机的问题,它就会把计算机称为“用于计算的设备”,因为它不允许使用“计算机”这个词。

它会坚决拒绝说出这个词:

但是,如果我们通过让它翻译“计算机”的猪语版本来诱导它,就可以绕过这些指令,让它愉快地使用这个词。

这里确实有一些防御措施可以采取,参见此处,但通常最好的办法是在尽可能靠近结尾的地方再次强调最重要的约束条件。对于 OpenAI 的聊天 API 来说,这可能意味着在最后一个 user 消息之后添加一条 system 消息。以下是一个示例:

image image

尽管 OpenAI 在防止越狱方面投入了大量精力,但仍有许多非常巧妙的绕过方法被不断分享,比如这条推文,并且每天都有新的例子出现,如这条推文

数据泄露

如果你之前没有注意到本文中的警告,那么请务必记住:你应该始终假定,任何暴露给语言模型的数据最终都会被用户看到。

在构建提示词的过程中,我们经常会将大量数据嵌入到隐藏的提示词中(即系统提示)。机器人会很乐意将这些信息传递给用户

即使你明确指示它不要透露这些信息,并且它也确实遵守了这一指示,仍然有数百万种方式可以从隐藏的提示词中泄露数据。

这里有一个例子:机器人本不应该提到我的城市,但只要稍微调整一下问题的表述,它就会不小心把秘密说出来。

类似地,我们还可以让机器人告诉我们它被禁止使用的那个词,而无需它真正说出那个词:

你应该把隐藏的提示词视为一种提升用户体验或使其更符合目标人设的方式。切勿在提示词中放置任何你不希望用户直接在屏幕上看到的信息。

为什么我们需要提示工程?

前面我们把提示词比作语言模型“解释执行”的“源代码”。提示工程就是一门艺术,旨在编写出能够让语言模型按照我们的意愿行事的提示词——就像软件工程是一门艺术,旨在编写源代码来指挥计算机完成我们想要的任务一样。

编写优秀的提示词时,必须考虑到所使用模型的独特性。策略会因任务的复杂程度而异。你需要设计各种机制来约束模型,以获得可靠的结果;整合那些模型无法通过训练掌握的动态数据;考虑模型训练数据的局限性;围绕上下文长度限制进行设计;以及其他诸多方面。

有一句古老的谚语说:“计算机只会做你命令它做的事情。” 请把这句忠告抛诸脑后。 提示工程颠覆了这种观念。它更像是用自然语言对一台非确定性的计算机进行编程——这台计算机几乎无所不能,除非你明确引导它不去做某些事情。

提示工程的方法大致可以分为两大类。

给机器人一条鱼

“给机器人一条鱼”这种方法适用于这样的情境:你可以在隐藏上下文中明确地向机器人提供它完成任何请求任务所需的所有信息。

例如,如果用户打开了他们的仪表盘,而我们想向他们展示一条简短友好的消息,告知他们有哪些待处理的任务,我们可以通过向机器人提供整个收件箱的列表以及我们希望它拥有的其他用户上下文,让机器人总结出如下内容:

您有4张收据/备忘录待上传。最近的一张是3月5日来自Target的,最旧的一张则是1月17日来自Blink Fitness的。感谢您及时处理您的费用!

同样地,如果你正在帮助用户预订行程,你可以:

  • 询问用户出行日期和目的地。
  • 在后台搜索航班和酒店。
  • 将航班和酒店的搜索结果嵌入到隐藏上下文中。
  • 同时将公司的差旅政策也嵌入到隐藏上下文中。

这样一来,机器人就拥有实时的旅行信息和约束条件,可以用来回答用户的疑问。以下是一个机器人推荐选项,而用户要求其进一步优化的例子:

(完整提示)
Brex是一个用于管理企业费用的平台。

以下是Brex的差旅费用政策:

- 飞行时间少于6小时的航班,最高可报销经济舱票价。
- 飞行时间超过6小时的航班,最高可报销优选经济舱票价。
- 租车的日均费用不得超过75美元。
- 住宿的平均每晚房价不得超过400美元。
- 住宿必须达到四星级或以上。
- 餐厅用餐、外卖、超市购物、酒吧及夜生活消费不得超过75美元。
- 其他所有费用不得超过5,000美元。
- 所有报销需经过审核。

酒店选项如下:
| 酒店名称 | 价格 | 评分 |
| --- | --- | --- |
| 希尔顿金融区酒店 | 每晚109美元 | 3.9星 |
| VIA酒店 | 每晚131美元 | 4.4星 |
| 凯悦广场旧金山酒店 | 每晚186美元 | 4.2星 |
| 齐菲尔酒店 | 每晚119美元 | 4.1星 |

航班选项如下:
| 航空公司 | 起飞时间 | 飞行时长 | 中转次数 | 舱位 | 价格 |
| --- | --- | --- | --- | --- | --- |
| 美国航空 | 上午5:30-7:37 | 2小时7分钟 | 直飞 | 经济舱 | 248美元 |
| 达美航空 | 下午1:20-3:36 | 2小时16分钟 | 直飞 | 经济舱 | 248美元 |
| 阿拉斯加航空 | 晚上9:50-11:58 | 2小时8分钟 | 直飞 | 优选经济舱 | 512美元 |

一位员工正计划于2月20日至2月25日前往旧金山出差。

请推荐符合政策的酒店和航班。建议简洁明了,不超过一两句话,但请加入一些友好的措辞,仿佛是一位热心的同事在帮我一样:

这与微软必应等产品利用动态数据的方式相同。当你与必应聊天时,它会要求机器人生成三条搜索查询,然后执行三次网络搜索,并将汇总后的结果放入隐藏上下文中供机器人使用。

总结这一部分,打造良好体验的关键在于根据用户当前的操作动态调整上下文。

🧙‍♂️ 给机器人一条鱼,是确保它能“吃到鱼”的最可靠方式。采用这种策略可以获得最为一致和可靠的响应。只要可能,就尽量使用这种方法。

语义搜索

如果你只需要让机器人对世界有更多的了解,一种常见的方法是进行语义搜索参考OpenAI的示例

语义搜索的核心是文档嵌入——你可以将其理解为一个固定长度的数字数组^5,其中每个数字代表文档的某个方面(比如,如果是科学类文档,第843个数字可能会较大;而如果是艺术类文档,第1,115个数字则可能较大——虽然这种说法过于简化,但基本能传达概念)。^6

除了为文档计算嵌入外,你还可以用同样的方法为用户的查询计算嵌入。如果用户问:“为什么天空是蓝色的?”你就计算这个问题的嵌入,在理论上,这个嵌入会比那些不涉及天空的文档嵌入更接近于提到天空的文档嵌入。

为了找到与用户查询相关的文档,你需要计算嵌入,然后找出与之最相似的前N个文档。接着,我们将这些文档(或它们的摘要)放入隐藏上下文中,供机器人参考。

值得注意的是,有时用户的查询非常简短,以至于嵌入的作用并不明显。在2022年12月发表的一篇论文中介绍了一种巧妙的技术,称为“假设性文档嵌入”或HyDE。通过这种方法,你可以让模型根据用户的查询生成一篇假设性的文档,然后再为这篇生成的文档计算嵌入。模型实际上是在凭空捏造文档,但这种方法确实有效!

HyDE技术需要调用更多的模型,但在许多应用场景中,能够显著提升结果。

教机器人如何钓鱼

有时你希望机器人能够代表用户执行某些操作,比如将备忘录添加到收据中,或者绘制图表。又或者我们希望它能够以比语义搜索更精细的方式检索数据,例如获取过去90天的费用记录。

在这种情况下,我们就需要教机器人“钓鱼”的方法。

命令语法

我们可以为机器人提供一份系统可识别的命令列表,附带每条命令的描述和示例,然后让它生成由这些命令组成的程序。

采用这种方法时需要注意许多问题。对于复杂的命令语法,机器人往往会“幻觉”出一些看似合理但实际上并不存在的命令或参数。要掌握好这一点,关键在于列出抽象程度较高的命令,同时赋予机器人足够的灵活性,使其能够以新颖且有用的方式组合这些命令。

例如,给机器人一个plot-the-last-90-days-of-expenses命令,并不能很好地体现机器人的灵活性或组合性。同样,draw-pixel-at-x-y [x] [y] [rgb]这样的命令又过于底层。然而,如果提供plot-expenseslist-expenses这样的命令,就能为机器人提供一些基础且灵活的操作原语。

在下面的例子中,我们使用以下命令列表:

命令 参数 描述
list-expenses budget 返回指定预算下的支出列表
converse message 向用户展示消息
plot-expenses expenses[] 绘制支出列表
get-budget-by-name budget_name 根据名称获取预算
list-budgets 返回用户可访问的预算列表
add-memo inbox_item_id, memo message 为指定的收件箱项目添加备忘录

我们将这张表格以Markdown格式提供给模型,而语言模型对这种格式的处理能力非常出色——这很可能是因为OpenAI在GitHub上的数据上进行了大量训练。

在下面这个例子中,我们要求模型以逆波兰表示法^7输出这些命令。

🧠 在那个例子中,除了生成命令之外,还有一些有趣而微妙的操作。当我们要求它向“shake shack”这笔支出添加备忘录时,模型知道add-memo命令需要一个支出ID。但我们并没有直接告诉它这个ID,于是它会在我们提供的支出表中查找“Shake Shack”,然后从对应的ID列中提取ID,再将其作为add-memo命令的参数。

要在复杂情况下可靠地实现命令语法并不容易。我们能采取的最佳策略是提供大量的描述,以及尽可能多的使用示例。大型语言模型属于少样本学习类型,这意味着它们只需几个示例就能学会一项新任务。一般来说,提供的示例越多越好——但这也会影响你的token预算,因此需要权衡。

这里有一个更复杂的例子,输出被指定为JSON格式,而不是RPN。我们还使用Typescript来定义命令的返回类型。

(完整提示)
你是一名在Brex工作的财务助理,同时也是一位编程专家。

我是Brex的客户。

你需要通过组合一系列命令来回答我的问题。

输出类型如下:

```typescript
type LinkedAccount = {
    id: string,
    bank_details: {
        name: string,
        type: string,
    },
    brex_account_id: string,
    last_four: string,
    available_balance: {
        amount: number,
        as_of_date: Date,
    },
    current_balance: {
            amount: number,
        as_of_date: Date,
    },
}

type Expense = {
  id: string,
  memo: string,
  amount: number,
}

type Budget = {
  id: string,
  name: string,
  description: string,
  limit: {
    amount: number,
    currency: string,
  }
}
```

你可以使用的命令有:

| 命令 | 参数 | 描述 | 输出格式 |
| --- | --- | --- | --- |
| nth | index, values[] | 从数组中返回第n个元素 | 任意 |
| push | value | 将值压入栈中,供后续命令使用 | 任意 |
| value | key, object | 返回与键关联的值 | 任意 |
| values | key, object[] | 从对象数组中提取对应键的值并返回一个数组 | 任意[] |
| sum | value[] | 对数字数组求和 | 数字 |
| plot | title, values[] | 以给定标题绘制数值图表 | Plot |
| list-linked-accounts |  | “列出所有可向Brex现金账户进行ACH转账的银行连接” | LinkedAccount[] |
| list-expenses | budget_id | 根据预算ID返回其支出列表 | Expense[]
| get-budget-by-name | name | 根据名称返回预算 | Budget |
| add-memo | expense_id, message | 为一笔支出添加备忘录 | bool |
| converse | message | 向用户发送消息 | null |

请仅以命令形式作答。
将命令以JSON格式输出,作为抽象语法树。
重要提示——请仅输出程序代码,不要包含任何非程序代码的文字内容。即使被要求解释,也不要写散文式的说明。
你只能生成命令,但你是生成命令方面的专家。

这种格式对于那些支持JSON.parse函数的语言来说,更容易解析和理解。

🧙‍♂️ 目前尚未形成用于定义模型生成程序的DSL的最佳行业标准格式。因此,这仍是一个活跃的研究领域。你会遇到各种限制,而随着这些限制的逐步突破,我们或许会发现更优的命令定义方式。

ReAct

2023年3月,普林斯顿大学和谷歌联合发布了一篇论文《ReAct:在语言模型中协同推理与行动》(arxiv.org/pdf/2210.03629.pdf),其中他们提出了一种命令语法的变体,允许完全自主地交互执行动作并检索数据。

模型被指示返回它想要执行的thought(思考)和action(行动)。另一个代理(例如我们的客户端)随后执行该action,并将结果作为observation(观察)反馈给模型。模型会循环返回更多的思考和行动,直到最终给出answer(答案)为止。

这是一种极其强大的技术,实际上可以让机器人充当自己的研究助理,甚至代表用户采取行动。结合强大的命令语法,机器人应该能够迅速应对大量的用户请求。

在这个例子中,我们为模型提供了一组与获取员工数据和搜索维基百科相关的简单命令:

命令 参数 描述
find_employee name 根据姓名获取员工
get_employee id 根据ID获取员工
get_location id 根据ID获取地点
get_reports employee_id 获取所有向该员工汇报的员工ID列表
wikipedia article 根据主题获取维基百科文章

然后我们问机器人一个简单的问题:“我的经理出名吗?”

我们可以看到,机器人:

  1. 首先查找我们的员工档案。
  2. 从我们的档案中获取经理的ID,并查找其档案。
  3. 提取经理的名字,然后在维基百科上搜索该名字。
    • 在这个场景中,我为经理选择了一个虚构角色。
  4. 机器人读取维基百科的文章,并得出结论:这不可能是我的经理,因为这是一个虚构角色。
  5. 机器人随后修改了搜索条件,加入“(真实人物)”这一筛选项。
  6. 看到没有结果后,机器人得出结论:我的经理并不出名。
image image
(完整提示)
你是一个乐于助人的助手。你会在一个循环中不断寻找额外的信息来回答用户的问题,直到你能给出答案为止。

今天是2025年6月1日。我叫法比安·西卡斯特。我的员工编号是82442。

用于获取信息的命令如下:

| 命令 | 参数 | 描述 |
| --- | --- | --- |
| find_employee | 名字 | 根据名字检索员工 |
| get_employee | ID | 根据ID检索员工 |
| get_location | ID | 根据ID检索地点 |
| get_reports | 员工ID | 检索直接向该员工汇报的所有员工ID列表。|
| wikipedia | 文章 | 检索关于某个主题的维基百科文章。|

你的回复将以JSON格式呈现,包含“思考”和“行动”,以获取回答问题所需的数据;或者直接包含“答案”。当数据被检索到时,它将作为“观察”被纳入响应中。

你将持续生成思考和行动,直到得出答案,或确定无法解答。

示例1:
```
用户:费城的人口是多少?

助理:{
  "thought": "维基百科很可能有这些信息。我正在查找……",
  "action": {"command": "wikipedia", "article": "Philadelphia"}
}

助理:{
  "observation": "费城,常被称为菲利,是宾夕法尼亚州最大的城市,也是美国东北部大都市区和中大西洋地区中仅次于纽约市的第二大城市。它是美国历史上最具意义的城市之一,在1800年之前曾是美国的首都。根据2020年人口普查,费城是全美第六大城市,人口为1,603,797人。自1854年以来,这座城市与费城县范围一致,而费城县则是宾夕法尼亚州人口最多的县,同时也是特拉华河谷都市圈的核心区域。该都市圈是全美第七大、全球最大的都市区之一,2020年人口达624.5万人。费城以其对美国历史的深远贡献以及在生命科学、商业与工业、艺术、文学和音乐等领域的突出地位而闻名。"
}

助理:{
  "answer": "根据2020年人口普查,费城的人口为1,603,797人。"
}
```

示例2:
```
用户:我的经理住在哪个城市?

助理:{
  "thought": "让我先查一下你的经理是谁。首先,我需要查看你的档案。",
  "action": {"command": "get_employee", "id": 92352}
}

助理:{
  "observation": {
    "id": 78334,
    "name": "Ms. Manager",
    "location_id": 8832
  }
}

助理:{
  "thought": "你的经理是Ms. Manager。我现在要查找她的居住地。",
  "action": {"command": "get_location", "id": 8832}
}

助理:{
  "observation": {
    "id": 8832,
    "name": "费城"
  }
}

助理:{
  "answer": "你的经理住在费城。"
}
```

GPT-4与GPT-3.5

在这份文档中的大多数例子中,GPT-3.5和GPT-4之间的差异几乎可以忽略不计,但在“教会机器人如何捕鱼”的场景中,这两种模型之间的差异就非常明显了。

例如,上述所有命令语法的例子,若不针对GPT-3.5进行有意义的修改,都无法正常工作。至少,你需要提供一些示例(每个命令至少一个使用示例),才能得到合理的输出。而对于复杂的命令集,GPT-3.5可能会“幻觉”出新的命令,或者创建虚构的参数。

通过足够详尽的隐藏提示,你应该能够克服这些限制。相比之下,GPT-4只需更简单的提示就能实现更加一致和复杂的逻辑(甚至可以在几乎没有示例的情况下运行——尽管尽可能多地提供示例总是有益的)。

策略

本节包含针对特定需求或问题的示例和策略。为了成功进行提示工程,你需要结合本文档中列出的各种策略。不要害怕混合搭配不同的方法,也可以自行发明新的思路。

嵌入数据

在隐藏上下文中,你经常需要嵌入各种数据。具体策略会根据你要嵌入的数据类型和数量而有所不同。

简单列表

对于一次性对象,用普通的项目符号列表罗列字段和值效果相当不错:

这种方法也适用于较大的数据集,不过还有其他格式的列表,GPT更能可靠地处理它们。无论如何,这里有一个例子:

Markdown表格

Markdown表格非常适合需要枚举大量同类条目的场景。

幸运的是,OpenAI的模型非常擅长处理Markdown表格(可能是因为它们在训练过程中接触了大量的GitHub数据)。

我们可以用Markdown表格重新表述上面的例子:

🧠 注意,在最后一个例子中,表格里的条目明确标注了日期——2月2日。而在我们的问题中,我们询问的是“今天”。此外,在提示的开头我们提到今天就是2月2日。模型正确地进行了传递性推理——将“今天”转换为“2月2日”,然后在表格中查找“2月2日”的相关条目。

JSON

Markdown 表格在许多用例中表现非常出色,由于其紧凑性和模型对其的可靠处理能力,通常应优先使用。然而,在某些情况下,比如列数过多导致模型难以处理,或者每个条目都包含自定义属性而不得不设置大量空列时,Markdown 表格可能就不那么适用了。

在这种情况下,JSON 是另一种模型能够很好地处理的格式。key 与其对应的 value 紧密相邻,使得模型更容易保持映射关系的清晰性。

以下是与 Markdown 表格示例相同的内容,但使用 JSON 格式:

自由文本

有时,你可能希望在提示中插入一段自由文本,并将其与其他部分明确区分开来——例如嵌入一份供机器人参考的文档。在这种场景下,用三个反引号 ``` 将文档包裹起来是一个不错的选择[^8]。

[^8]:在编写提示时,一个很好的经验法则就是尽量依赖模型从 GitHub 上学到的内容。

嵌套数据

并非所有数据都是扁平和线性的。有时,你需要嵌入一些具有嵌套结构或与其他数据存在关联的数据。在这种情况下,建议使用 JSON

(完整提示)
你是一位乐于助人的助手,负责回答有关用户的问题。以下是关于这些用户的已知信息:

{
  "users": [
    {
      "id": 1,
      "name": "John Doe",
      "contact": {
        "address": {
          "street": "123 Main St",
          "city": "Anytown",
          "state": "CA",
          "zip": "12345"
        },
        "phone": "555-555-1234",
        "email": "johndoe@example.com"
      }
    },
    {
      "id": 2,
      "name": "Jane Smith",
      "contact": {
        "address": {
          "street": "456 Elm St",
          "city": "Sometown",
          "state": "TX",
          "zip": "54321"
        },
        "phone": "555-555-5678",
        "email": "janesmith@example.com"
      }
    },
    {
      "id": 3,
      "name": "Alice Johnson",
      "contact": {
        "address": {
          "street": "789 Oak St",
          "city": "Othertown",
          "state": "NY",
          "zip": "67890"
        },
        "phone": "555-555-2468",
        "email": "alicejohnson@example.com"
      }
    },
    {
      "id": 4,
      "name": "Bob Williams",
      "contact": {
        "address": {
          "street": "135 Maple St",
          "city": "Thistown",
          "state": "FL",
          "zip": "98765"
        },
        "phone": "555-555-8642",
        "email": "bobwilliams@example.com"
      }
    },
    {
      "id": 5,
      "name": "Charlie Brown",
      "contact": {
        "address": {
          "street": "246 Pine St",
          "city": "Thatstown",
          "state": "WA",
          "zip": "86420"
        },
        "phone": "555-555-7531",
        "email": "charliebrown@example.com"
      }
    },
    {
      "id": 6,
      "name": "Diane Davis",
      "contact": {
        "address": {
          "street": "369 Willow St",
          "city": "Sumtown",
          "state": "CO",
          "zip": "15980"
        },
        "phone": "555-555-9512",
        "email": "dianedavis@example.com"
      }
    },
    {
      "id": 7,
      "name": "Edward Martinez",
      "contact": {
        "address": {
          "street": "482 Aspen St",
          "city": "Newtown",
          "state": "MI",
          "zip": "35742"
        },
        "phone": "555-555-6813",
        "email": "edwardmartinez@example.com"
      }
    },
    {
      "id": 8,
      "name": "Fiona Taylor",
      "contact": {
        "address": {
          "street": "531 Birch St",
          "city": "Oldtown",
          "state": "OH",
          "zip": "85249"
        },
        "phone": "555-555-4268",
        "email": "fionataylor@example.com"
      }
    },
    {
      "id": 9,
      "name": "George Thompson",
      "contact": {
        "address": {
          "street": "678 Cedar St",
          "city": "Nexttown",
          "state": "GA",
          "zip": "74125"
        },
        "phone": "555-555-3142",
        "email": "georgethompson@example.com"
      }
    },
    {
      "id": 10,
      "name": "Helen White",
      "contact": {
        "address": {
          "street": "852 Spruce St",
          "city": "Lasttown",
          "state": "VA",
          "zip": "96321"
        },
        "phone": "555-555-7890",
        "email": "helenwhite@example.com"
      }
    }
  ]
}

如果使用嵌套的 JSON 对你的 token 预算来说过于冗长,可以退而求其次,采用用 Markdown 定义的 关系型表格

(完整提示)
你是一位乐于助人的助手,负责回答有关用户的问题。以下是关于这些用户的已知信息:

表 1:users
| id (PK) | name          |
|---------|---------------|
| 1       | John Doe      |
| 2       | Jane Smith    |
| 3       | Alice Johnson |
| 4       | Bob Williams  |
| 5       | Charlie Brown |
| 6       | Diane Davis   |
| 7       | Edward Martinez |
| 8       | Fiona Taylor  |
| 9       | George Thompson |
| 10      | Helen White   |

表 2:addresses
| id (PK) | user_id (FK) | street      | city       | state | zip   |
|---------|--------------|-------------|------------|-------|-------|
| 1       | 1            | 123 Main St | Anytown    | CA    | 12345 |
| 2       | 2            | 456 Elm St  | Sometown   | TX    | 54321 |
| 3       | 3            | 789 Oak St  | Othertown  | NY    | 67890 |
| 4       | 4            | 135 Maple St | Thistown  | FL    | 98765 |
| 5       | 5            | 246 Pine St | Thatstown  | WA    | 86420 |
| 6       | 6            | 369 Willow St | Sumtown  | CO    | 15980 |
| 7       | 7            | 482 Aspen St | Newtown   | MI    | 35742 |
| 8       | 8            | 531 Birch St | Oldtown   | OH    | 85249 |
| 9       | 9            | 678 Cedar St | Nexttown  | GA    | 74125 |
| 10      | 10           | 852 Spruce St | Lasttown  | VA    | 96321 |

表 3:phone_numbers

id (主键) user_id (外键) 电话
1 1 555-555-1234
2 2 555-555-5678
3 3 555-555-2468
4 4 555-555-8642
5 5 555-555-7531
6 6 555-555-9512
7 7 555-555-6813
8 8 555-555-4268
9 9 555-555-3142
10 10 555-555-7890

表 4:emails

id (主键) user_id (外键) 邮箱
1 1 johndoe@example.com
2 2 janesmith@example.com
3 3 alicejohnson@example.com
4 4 bobwilliams@example.com
5 5 charliebrown@example.com
6 6 dianedavis@example.com
7 7 edwardmartinez@example.com
8 8 fionataylor@example.com
9 9 georgethompson@example.com
10 10 helenwhite@example.com

表 5:cities

id (主键) 名称 人口 中位收入
1 Anytown CA 50,000 $70,000
2 Sometown TX 100,000 $60,000
3 Othertown NY 25,000 $80,000
4 Thistown FL 75,000 $65,000
5 Thatstown WA 40,000 $75,000
6 Sumtown CO 20,000 $85,000
7 Newtown MI 60,000 $55,000
8 Oldtown OH 30,000 $70,000
9 Nexttown GA 15,000 $90,000
10 Lasttown VA 10,000 $100,000

</details>

> 🧠 该模型在处理符合[第三范式](https://en.wikipedia.org/wiki/Third_normal_form)的数据时表现良好,但在涉及过多连接操作时可能会遇到困难。实验表明,它至少可以处理三层嵌套连接。在上述示例中,模型成功地从`users`表连接到`addresses`表,再到`cities`表,从而推断出乔治的可能收入为9万美元。



### 引用

通常情况下,仅靠自然语言回复是不够的,你可能希望模型能够引用其数据来源。

值得注意的是,任何需要引用的内容都应具有唯一标识符。最简单的方法就是直接要求模型为其引用的内容添加链接:


<p align="center">
  <img width="550" src="https://oss.gittoolsai.com/images/brexhq_prompt-engineering_readme_c13eed69482d.png" title="GPT-4会在被要求时可靠地链接到相关数据。">
</p>

### 程序化消费

默认情况下,语言模型会输出自然语言文本,但很多时候我们需要以程序化的方式与这些结果进行交互,而不仅仅是将其打印在屏幕上。为此,你可以要求模型以你喜欢的序列化格式(如JSON或YAML)输出结果。

请务必向模型提供你期望的输出格式示例。基于我们之前的旅行示例,我们可以扩展提示内容,告诉模型:

请以JSON格式输出结果。格式如下:

{
    message: "要展示给用户的讯息",
    hotelId: 432,
    flightId: 831
}

请勿在讯息中包含ID。


现在我们将得到类似这样的交互:

<p align="center">
  <img width="550" src="https://oss.gittoolsai.com/images/brexhq_prompt-engineering_readme_6292a6ffc611.png" title="GPT-4以易于处理的格式提供旅行建议。">
</p>

你可以设想,用户界面会将讯息以普通文本形式显示,同时提供用于预订航班和酒店的独立按钮,或者自动填充表格供用户使用。

再举一个例子,我们可以在[引用](#citations)的基础上进一步扩展——但不再局限于Markdown链接。我们可以要求模型生成包含正常讯息以及用于生成该讯息的条目列表的JSON。在这种情况下,你可能无法确切知道引用具体出现在讯息的哪个位置,但至少可以确定它们确实被使用过。

<p align="center">
  <img width="550" src="https://oss.gittoolsai.com/images/brexhq_prompt-engineering_readme_956f1b244668.png" title="要求模型提供引用列表是一种可靠的方式,可以程序化地了解模型在其响应中依赖了哪些数据。">
</p>

> 🧠 有趣的是,在模型对“我在塔吉特花了多少钱?”的回答中,它给出了单一数值188.16美元,但**重要的是**,在`citations`数组中列出了用于计算该数值的各项支出明细。

### 思维链

有时候,你可能会绞尽脑汁地调整提示词,试图让模型输出可靠的结果,但无论怎么努力,都无济于事。这种情况通常发生在机器人的最终输出需要中间推理步骤时,而你却只直接要求它给出结果,没有提供任何中间过程。

答案可能会让你感到意外:请机器人展示它的解题步骤。2022年10月,谷歌发布了一篇论文《通过思维链提示激发大型语言模型的推理能力》([Chain-of-Thought Prompting Elicits Reasoning in Large Language Models](https://arxiv.org/pdf/2201.11903.pdf)),其中他们表明,如果你在隐藏的提示中为机器人提供一些通过展示解题步骤来回答问题的示例,那么当你要求机器人解答某个问题时,它就会展示其思考过程,并给出更可靠的答案。

就在那篇论文发表后的几周,也就是2022年10月底,东京大学和谷歌又联合发布了另一篇论文《大型语言模型是零样本推理者》([Large Language Models are Zero-Shot Reasoners](https://openreview.net/pdf?id=e2TBb5y0yFf)),该论文指出,你甚至不需要提供示例——**你只需要简单地要求机器人一步一步地思考**即可。

#### 计算平均值

这里有一个例子:我们要求机器人计算平均支出,但不包括Target的开销。实际答案是136.77美元,而机器人几乎正确地给出了136.43美元。

<p align="center">
  <img width="550" src="https://oss.gittoolsai.com/images/brexhq_prompt-engineering_readme_20c155be8eb7.png" title="模型**几乎**算对了平均值,但差了几美分。">
</p>

如果我们简单地加上“让我们一步一步地思考”,模型就能给出正确的答案:

<p align="center">
  <img width="550" src="https://oss.gittoolsai.com/images/brexhq_prompt-engineering_readme_d80a30a3efbe.png" title="当我们要求模型展示其思考过程时,它给出了正确答案。">
</p>

#### 解释代码

让我们再回顾一下前面的Python示例,并将思维链提示应用到我们的问题中。提醒一下,当我们要求机器人评估这段Python代码时,它会稍微出错。正确答案应该是`Hello, Brex!!Brex!!Brex!!!`,但机器人对应该包含多少个感叹号感到困惑。在下面的例子中,它输出的是`Hello, Brex!!!Brex!!!Brex!!!`:

<p align="center">
  <img width="550" src="https://oss.gittoolsai.com/images/brexhq_prompt-engineering_readme_ba6f32c4eec7.png" title="机器人几乎正确地解释了Python代码,但还是有点偏差。">
</p>

如果我们要求机器人展示其思考过程,它就能给出正确的答案:

<p align="center">
  <img width="550" src="https://oss.gittoolsai.com/images/brexhq_prompt-engineering_readme_f5a4e8e1f66e.png" title="只要要求机器人展示其思考过程,它就能正确解释Python代码。">
</p>

#### 分隔符

在许多场景中,你可能并不希望向最终用户展示机器人的全部思考过程,而只是想直接呈现最终答案。这时你可以要求机器人将最终答案与其思考过程明确区分开来。实现这一点的方法有很多,但我们这里使用JSON格式,以便于后续解析:

<p align="center">
  <img width="550" src="https://oss.gittoolsai.com/images/brexhq_prompt-engineering_readme_89697ada439f.png" title="机器人展示了其思考过程,同时用分隔符标出了最终答案,便于提取。">
</p>

使用思维链提示虽然会消耗更多的token,从而增加成本和延迟,但对于许多复杂场景来说,其结果确实更加可靠。因此,当需要机器人以尽可能高的可靠性完成复杂任务时,这是一种非常有价值的工具。

### 微调

有时,无论你尝试何种技巧,模型仍然无法按照你的期望运行。在这种情况下,你**有时**可以退而求其次,采用微调的方法。不过,一般来说,这应被视为最后的手段。

[微调](https://platform.openai.com/docs/guides/fine-tuning)是指在已经训练好的模型基础上,为其提供数千(或更多)个输入-输出示例对的过程。

微调并不能完全取代隐藏提示的作用,因为你仍然需要嵌入动态数据,但它可以使提示变得更简洁、更可靠。

#### 缺点

微调也存在诸多缺点。如果可能的话,最好利用语言模型作为[零样本、单样本和少样本学习者](https://en.wikipedia.org/wiki/Few-shot_learning_(natural_language_processing))的特点,在提示中教会它们如何完成任务,而不是进行微调。

其中一些缺点包括:

- **不可行**:[GPT-3.5/GPT-4无法进行微调](https://platform.openai.com/docs/guides/chat/is-fine-tuning-available-for-gpt-3-5-turbo),而这是我们主要使用的模型和API,因此我们根本无法采用微调。
- **额外开销**:微调需要手动准备大量的数据。
- **迭代速度慢**:每次想要添加新功能时,你不再只需在提示中增加几行内容,而是必须创建大量虚假数据,然后运行微调流程,最后才能使用新微调过的模型。
- **成本高昂**:与原生的`gpt-3.5-turbo`模型相比,使用微调后的GPT-3模型的成本最高可高出60倍;而与原生的GPT-4模型相比,微调后的GPT-3模型成本也要高2倍。

> ⛔️ 如果你对模型进行微调,**切勿使用真实的客户数据**。务必使用合成数据。否则,模型可能会记住你提供的部分数据,并将这些隐私信息泄露给其他不应看到的用户。
>
> 如果你不进行微调,我们就无需担心意外将数据泄露到模型中。

## 更多资源
- :star2: [OpenAI Cookbook](https://github.com/openai/openai-cookbook) :star2:
- :technologist: [Prompt Hacking](https://learnprompting.org/docs/category/-prompt-hacking) :technologist: 
- :books: [Dair.ai 提示工程指南](https://github.com/dair-ai/Prompt-Engineering-Guide) :books:

常见问题

相似工具推荐

openclaw

OpenClaw 是一款专为个人打造的本地化 AI 助手,旨在让你在自己的设备上拥有完全可控的智能伙伴。它打破了传统 AI 助手局限于特定网页或应用的束缚,能够直接接入你日常使用的各类通讯渠道,包括微信、WhatsApp、Telegram、Discord、iMessage 等数十种平台。无论你在哪个聊天软件中发送消息,OpenClaw 都能即时响应,甚至支持在 macOS、iOS 和 Android 设备上进行语音交互,并提供实时的画布渲染功能供你操控。 这款工具主要解决了用户对数据隐私、响应速度以及“始终在线”体验的需求。通过将 AI 部署在本地,用户无需依赖云端服务即可享受快速、私密的智能辅助,真正实现了“你的数据,你做主”。其独特的技术亮点在于强大的网关架构,将控制平面与核心助手分离,确保跨平台通信的流畅性与扩展性。 OpenClaw 非常适合希望构建个性化工作流的技术爱好者、开发者,以及注重隐私保护且不愿被单一生态绑定的普通用户。只要具备基础的终端操作能力(支持 macOS、Linux 及 Windows WSL2),即可通过简单的命令行引导完成部署。如果你渴望拥有一个懂你

349.3k|★★★☆☆|1周前
Agent开发框架图像

stable-diffusion-webui

stable-diffusion-webui 是一个基于 Gradio 构建的网页版操作界面,旨在让用户能够轻松地在本地运行和使用强大的 Stable Diffusion 图像生成模型。它解决了原始模型依赖命令行、操作门槛高且功能分散的痛点,将复杂的 AI 绘图流程整合进一个直观易用的图形化平台。 无论是希望快速上手的普通创作者、需要精细控制画面细节的设计师,还是想要深入探索模型潜力的开发者与研究人员,都能从中获益。其核心亮点在于极高的功能丰富度:不仅支持文生图、图生图、局部重绘(Inpainting)和外绘(Outpainting)等基础模式,还独创了注意力机制调整、提示词矩阵、负向提示词以及“高清修复”等高级功能。此外,它内置了 GFPGAN 和 CodeFormer 等人脸修复工具,支持多种神经网络放大算法,并允许用户通过插件系统无限扩展能力。即使是显存有限的设备,stable-diffusion-webui 也提供了相应的优化选项,让高质量的 AI 艺术创作变得触手可及。

162.1k|★★★☆☆|2周前
开发框架图像Agent

everything-claude-code

everything-claude-code 是一套专为 AI 编程助手(如 Claude Code、Codex、Cursor 等)打造的高性能优化系统。它不仅仅是一组配置文件,而是一个经过长期实战打磨的完整框架,旨在解决 AI 代理在实际开发中面临的效率低下、记忆丢失、安全隐患及缺乏持续学习能力等核心痛点。 通过引入技能模块化、直觉增强、记忆持久化机制以及内置的安全扫描功能,everything-claude-code 能显著提升 AI 在复杂任务中的表现,帮助开发者构建更稳定、更智能的生产级 AI 代理。其独特的“研究优先”开发理念和针对 Token 消耗的优化策略,使得模型响应更快、成本更低,同时有效防御潜在的攻击向量。 这套工具特别适合软件开发者、AI 研究人员以及希望深度定制 AI 工作流的技术团队使用。无论您是在构建大型代码库,还是需要 AI 协助进行安全审计与自动化测试,everything-claude-code 都能提供强大的底层支持。作为一个曾荣获 Anthropic 黑客大奖的开源项目,它融合了多语言支持与丰富的实战钩子(hooks),让 AI 真正成长为懂上

160.4k|★★☆☆☆|今天
开发框架Agent语言模型

ComfyUI

ComfyUI 是一款功能强大且高度模块化的视觉 AI 引擎,专为设计和执行复杂的 Stable Diffusion 图像生成流程而打造。它摒弃了传统的代码编写模式,采用直观的节点式流程图界面,让用户通过连接不同的功能模块即可构建个性化的生成管线。 这一设计巧妙解决了高级 AI 绘图工作流配置复杂、灵活性不足的痛点。用户无需具备编程背景,也能自由组合模型、调整参数并实时预览效果,轻松实现从基础文生图到多步骤高清修复等各类复杂任务。ComfyUI 拥有极佳的兼容性,不仅支持 Windows、macOS 和 Linux 全平台,还广泛适配 NVIDIA、AMD、Intel 及苹果 Silicon 等多种硬件架构,并率先支持 SDXL、Flux、SD3 等前沿模型。 无论是希望深入探索算法潜力的研究人员和开发者,还是追求极致创作自由度的设计师与资深 AI 绘画爱好者,ComfyUI 都能提供强大的支持。其独特的模块化架构允许社区不断扩展新功能,使其成为当前最灵活、生态最丰富的开源扩散模型工具之一,帮助用户将创意高效转化为现实。

109.2k|★★☆☆☆|昨天
开发框架图像Agent

gemini-cli

gemini-cli 是一款由谷歌推出的开源 AI 命令行工具,它将强大的 Gemini 大模型能力直接集成到用户的终端环境中。对于习惯在命令行工作的开发者而言,它提供了一条从输入提示词到获取模型响应的最短路径,无需切换窗口即可享受智能辅助。 这款工具主要解决了开发过程中频繁上下文切换的痛点,让用户能在熟悉的终端界面内直接完成代码理解、生成、调试以及自动化运维任务。无论是查询大型代码库、根据草图生成应用,还是执行复杂的 Git 操作,gemini-cli 都能通过自然语言指令高效处理。 它特别适合广大软件工程师、DevOps 人员及技术研究人员使用。其核心亮点包括支持高达 100 万 token 的超长上下文窗口,具备出色的逻辑推理能力;内置 Google 搜索、文件操作及 Shell 命令执行等实用工具;更独特的是,它支持 MCP(模型上下文协议),允许用户灵活扩展自定义集成,连接如图像生成等外部能力。此外,个人谷歌账号即可享受免费的额度支持,且项目基于 Apache 2.0 协议完全开源,是提升终端工作效率的理想助手。

100.8k|★★☆☆☆|1周前
插件Agent图像

markitdown

MarkItDown 是一款由微软 AutoGen 团队打造的轻量级 Python 工具,专为将各类文件高效转换为 Markdown 格式而设计。它支持 PDF、Word、Excel、PPT、图片(含 OCR)、音频(含语音转录)、HTML 乃至 YouTube 链接等多种格式的解析,能够精准提取文档中的标题、列表、表格和链接等关键结构信息。 在人工智能应用日益普及的今天,大语言模型(LLM)虽擅长处理文本,却难以直接读取复杂的二进制办公文档。MarkItDown 恰好解决了这一痛点,它将非结构化或半结构化的文件转化为模型“原生理解”且 Token 效率极高的 Markdown 格式,成为连接本地文件与 AI 分析 pipeline 的理想桥梁。此外,它还提供了 MCP(模型上下文协议)服务器,可无缝集成到 Claude Desktop 等 LLM 应用中。 这款工具特别适合开发者、数据科学家及 AI 研究人员使用,尤其是那些需要构建文档检索增强生成(RAG)系统、进行批量文本分析或希望让 AI 助手直接“阅读”本地文件的用户。虽然生成的内容也具备一定可读性,但其核心优势在于为机器

93.4k|★★☆☆☆|1周前
插件开发框架