掌握语义内核(Semantic Kernel):如何精进你的提示词工程
在人工智能的海洋里,大型语言模型(LLM AI)是高速发展的一艘巨轮,而有效地与其沟通和指导其行为的锚,正是提示语(prompts)。提示语是我们提供给模型的输入或查询,以期获取特定的响应。当今,提示语工程(prompt engineering)已成为涌现的领域,它需要创造力和对细节的关注。接下来,我将带大家一同深入这个话题,探索怎样有效地设计提示语,成为一名出色的提示语工程师,并借助一个强大工具——Semantic Kernel——提高我们的能力。
提示语的微妙之处在于选词拼句,这就如同是为模型拟定一条生成高质量且相关文本的轨迹。比如,当你利用ChatGPT时,可以观察到基于你提供的不同输入,模型的行为会怎样剧烈变化。演示一下,以下两个提示语产生的输出截然不同:
提示语1:
Prompt:请给我讲述人类的历史。
提示语2:
Prompt:用三句话给我讲述人类的历史。
第一个提示语给出了一份长篇报告,而第二个提示语则给出了一个简洁的回答。设计提示语时要在具体性和相关性之间找到平衡点。
不仅如此,直接与LLM模型互动时,还可以利用如温度参数来控制模型输出的随机性,以及利用top-k、top-p、截断采样和截尾采样等参数来影响模型行为。
提示语工程:新兴的职业前景 由于提示语工程对于操作LLM AI模型的影响力,它已经成为任何从事此领域工作人员的关键技能,并且随着越来越多的组织采用LLM AI模型以自动化任务和提高生产力,这个技能也越发受到追捧。一个优秀的提示语工程师能帮助组织通过精心设计的提示语来发挥出LLM AI模型的最大价值。
利用Semantic Kernel成为优秀的提示语工程师 Semantic Kernel是一个宝贵的提示语工程工具,因为它允许你通过一个通用界面在不同的模型上试验不同的提示语和参数,让你快速比较各种模型和参数的输出,以及对提示语进行迭代以达到预期结果。
熟悉了提示语工程后,你也可以利用Semantic Kernel将你的技能应用于真实场景。将你的提示语与原生函数和连接器结合起来,你可以构建出强大的AI驱动的应用程序。
此外,Semantic Kernel和Visual Studio Code的深度集成更是简化了将提示语工程纳入现有开发流程的过程。
-
直接在你偏好的代码编辑器中创建提示语。
-
使用现有的测试框架为它们编写测试。
-
使用现有的CI/CD流程将它们部署到生产环境。
提示语工程的额外技巧 要成为一名熟练的提示语工程师,需要结合技术知识、创造力和实验。这里有一些卓越的提示语工程技巧:
-
充分了解LLM AI模型:深入理解LLM AI模型的工作原理,包括它们的架构、训练过程和行为。
-
领域知识:获取领域特定知识以便设计符合预期输出和任务要求的提示语。
-
实验性:探索不同的参数和设置,以微调提示语,并优化模型在特定任务或领域中的行为。
-
反馈与迭代:持续分析模型生成的输出,并根据用户反馈迭代提示语,以提高它们的质量与相关性。
-
保持更新:跟上提示语工程技术、研究和最佳实践的最新进展,以增强你的技能并在该领域保持领先。
提示语工程是一个动态发展的领域,其中,熟练的提示语工程师在有效利用LLM AI模型的能力方面起着关键作用。提示语是从AI模型中获取正确结果的核心。在本文中,我们演示了如何使用Semantic Kernel时共通的提示语工程技巧。
想看到这个教程的最终解决方案,你可以在公共文档存储库中查看以下的示例。创建一个检测用户意图的提示语 如果您曾经使用过ChatGPT或Microsoft Copilot,您已经熟悉提示语的概念。在接收到请求后,LLM会尝试预测最可能的响应。例如,如果发送了提示语"I want to go to the ",AI服务可能会返回"beach"来完成句子。这是一个非常简单的例子,但它演示了文本生成提示语工作的基本概念。
有了Semantic Kernel SDK,你可以轻松地在自己的应用程序中运行提示语。这允许你在你自己的应用程序中利用AI模型的能力。
一个常见的场景是检测用户的意图,以便之后可以运行一些自动化操作,所以在本文中,我们将展示如何创建一个检测用户意图的提示语。此外,我们将演示如何使用提示语工程技术逐步改进提示语。
本文中的许多建议都基于《提示语工程指南》。如果您想成为撰写提示语的专家,我们强烈建议您阅读这份指南,并利用他们的提示语工程技术。
通过Semantic Kernel运行你的第一个提示语 如果我们想让AI检测用户输入的意图,我们可以简单地询问这个意图是什么。在Semantic Kernel中,我们可以创建一个执行该操作的字符串,如下所示:
Console.Write("你的请求: ");string request = Console.ReadLine()!;
string prompt = $"这个请求的意图是什么? {request}";
要运行这个提示语,我们现在需要创建一个具有AI服务的kernel。
using Microsoft.Extensions.DependencyInjection;using Microsoft.Extensions.Logging;using Microsoft.SemanticKernel;
// Create a kernelvar builder = Kernel.CreateBuilder();// Add a text or chat completion service using either:// builder.Services.AddAzureOpenAIChatCompletion()// builder.Services.AddAzureOpenAITextGeneration()// builder.Services.AddOpenAIChatCompletion()// builder.Services.AddOpenAITextGeneration()
最后,我们可以使用我们的新kernel来调用我们的提示语。
Console.WriteLine(await kernel.InvokePromptAsync(prompt));
如果我们用输入"I want to send an email to the marketing team celebrating their recent milestone."运行这段代码,我们应该会获得以下类似的输出:
这个请求的意图是寻求指导或澄清如何有效地编写一封邮件,以庆祝市场营销团队最近的里程碑。
通过提示语工程改进提示语 虽然这个提示语“可行”,但由于你无法使用结果来可预测地触发自动化,所以并不实用。每次运行提示语,你可能会得到非常不同的响应。
为了使结果更为可预测,我们可以进行以下改进:
1)使提示语更具体 我们可以做的第一件事是让我们的提示语更具体。与其仅仅询问“这个请求的意图是什么?”不如我们向AI提供一系列可选择的意图。这将使提示语更可预测,因为AI只能从我们提供的意图列表中进行选择。
prompt = @$"这个请求的意图是什么? {request}你可以在SendEmail、SendMessage、CompleteTask、CreateDocument之间进行选择。"
现在,当您用相同的输入运行提示语时,您应该会得到一个更有用的结果,但它仍然不完美,因为AI会以额外的信息作出回应。
这个请求的意图是发送一封电子邮件。因此,合适的行动将是使用SendEmail功能。
2)通过格式化添加结构到输出 虽然结果更可预测,但如果LLM以一种你不能轻易解析的结果进行响应,就有可能遇到问题。例如,如果LLM响应“意图是SendEmail”,你可能很难提取意图,因为它不在一个可预测的位置。
为了使结果更可预测,我们可以通过使用格式化来给提示语添加结构。在这种情况下,我们可以这样定义我们的提示语的不同部分:
prompt = @$"说明:此请求的意图是什么?选择: SendEmail, SendMessage, CompleteTask, CreateDocument.用户输入: {request}意图:";
通过使用这种格式,AI不太可能响应一个结果,而只是意图。
在其他提示语中,您也可能想要尝试使用Markdown、XML、JSON、YAML或其他格式来添加结构到您的提示语及其输出。由于LLMs倾向于生成看起来像提示语的文本,因此建议您对于提示以及输出都使用相同的格式。
例如,如果您希望LLM生成一个JSON对象,您可以使用以下提示语:
prompt = @$"## 说明使用以下格式提供请求的意图:
```json{ "intent": {intent}}你可以在以下意图之间进行选择:json["SendEmail", "SendMessage", "CompleteTask", "CreateDocument"]用户输入是:{ "request": "{request}"}
这将会产生以下输出:
{ "intent": "SendEmail"}
3)使用少数样本提示提供示例 到目前为止,我们一直在使用零样本提示,这意味着我们没有给AI提供任何示例。虽然这对于入门是可以的,但对于更复杂的场景并不推荐,因为AI可能没有足够的训练数据来产生正确的结果。
为了添加示例,我们可以使用少数样本提示。通过少数样本提示,我们提供给AI一些我们希望它做到的例子。例如,我们可以提供以下例子来帮助AI区分发送电子邮件和发送即时消息。
prompt = @$"说明:此请求的意图是什么?选项:SendEmail、SendMessage、CompleteTask、CreateDocument
用户输入:你能很快向营销团队发送批准吗?意图:SendMessage
用户输入:你能将完整的更新发送给营销团队吗?意图:SendEmail
用户输入:{request}意图:";
4)告诉AI应该做什么以避免做错事 通常当AI开始错误响应时,我们的直觉是让AI停止做某些事情。不幸的是,这往往会导致AI做出更糟的事情。例如,如果你告诉AI停止返回一个幻想出的意图,它可能开始返回与用户请求完全无关的意图。
相反,我们推荐你告诉AI它应该做什么。例如,如果你想让AI停止返回幻想出的意图,你可能会写出如下提示语。
prompt = @$"说明:此请求的意图是什么?如果你不知道其意图,不要猜测;而是以“未知”作为响应。选项:SendEmail、SendMessage、CompleteTask、CreateDocument、Unknown。用户输入:你能很快向营销团队发送批准吗?意图:发送消息
用户输入:你能将完整的更新发送给营销团队吗?意图:发送电子邮件
用户输入:{request}意图:";
5)为AI提供上下文 在某些情况下,你可能想要给AI提供上下文,这样它可以更好地理解用户的请求。这对于长时间运行的聊天场景尤为重要,在这些场景中,用户的意图可能需要从前面的消息中获取上下文。
例如,以下对话:
用户:我讨厌发送电子邮件,没有人会读它们。AI:我很抱歉听到这一点。使用消息可能是一种更好的沟通方式。用户:我同意,你可以那样发送市场营销团队的全面状态更新吗?
如果AI只被给予最后一条消息,它可能错误地回应"SendEmail"而不是"SendMessage"。但是,如果AI被给予整个对话,它可能能够理解用户的意图。
为了提供这种上下文,我们可以简单地将之前的消息添加到提示语中。例如,我们可以更新我们的提示语使其看起来如下:
string history = @"用户输入:我讨厌发送电子邮件,没有人会读它们。AI回应:我很抱歉听到这一点。使用消息可能是一种更好的沟通方式。";
prompt = @$"说明:此请求的意图是什么?如果你不知道其意图,不要猜测;而是以"Unknown"作为响应。选项:SendEmail、SendMessage、CompleteTask、CreateDocument、Unknown。
用户输入:你能很快给营销团队发一份批准书吗?意图:发送消息
用户输入:你能把最新消息发给营销团队吗?意图:发送电子邮件
{history}
用户输入:{request}意图:";
6)在聊天完成提示语中使用消息角色 随着你的提示语变得越来越复杂,你可能会想要使用消息角色来帮助AI区分系统指令、用户输入和AI响应。这在我们开始将聊天历史添加到提示语时尤为重要。AI应该知道,一些先前的消息是由自己发送的,而非用户。
在Semantic Kernel中,使用特殊语法来定义消息角色。要定义消息角色,你只需用<message>标签包裹消息,并将角色名作为属性。这目前仅在C# SDK中可用。
history = @"<message role="user">我讨厌发电子邮件,从来没有人读过。</message><message role="assistant">听到这个消息我很难过。信息可能是更好的沟通方式。</message>";
prompt = @$"<message role="system">说明:此请求的意图是什么?如果你不知道其意图,不要猜测;而是以"Unknown"作为响应。选项:SendEmail、SendMessage、CompleteTask、CreateDocument、Unknown。</message>
<message role="user">你能很快给营销团队发一份批准书吗?</message><message role="system">意图:</message><message role="assistant">SendMessage</message>
<message role="user">你能将完整的更新发送给营销团队吗?</message><message role="system">意图:</message><message role="assistant">SendEmail</message>
{history}<message role="user">{request}</message><message role="system">意图:</message>";
7)鼓励你的AI 最后,研究表明,给AI鼓励能帮助其表现得更好。
就是夸它,说他棒!给他带高帽,比如你是某某领域的专家之类的。
另外也可以和博主一样,不断学习提示词工程,提升自己的提示词工程能力
- 点赞
- 收藏
- 关注作者
评论(0)