Prompts

Prompts 是指导 AI 模型生成特定输出的输入。这些 Prompts 的设计和措辞会显着影响模型的响应。

在 Spring AI 中与 AI 模型交互的最低级别,Spring AI 中的提示处理有点类似于管理 Spring MVC 中的“视图”。这涉及到为动态内容创建带有占位符的大量文本。然后根据用户请求或应用程序中的其他代码替换这些占位符。另一个类比是包含某些表达式的占位符的 SQL 语句。

随着 Spring AI 的发展,它将引入更高级别的抽象来与 AI 模型交互。本节中描述的基础类在其角色和功能方面可以与 JDBC 类比。例如,该类ChatClient类似于 JDK 中的核心 JDBC 库。在此基础上,Spring AI 可以提供类似于JdbcTemplate,Spring Data Repositories 的帮助器类,并最终提供更高级的构造,例如考虑过去与模型交互的 ChatEngines 和 Agents。

提示的结构在人工智能领域随着时间的推移而不断演变。最初,提示是简单的字符串。随着时间的推移,它们逐渐包含了特定输入的占位符,例如人工智能模型可以识别的“USER:”。 OpenAI 通过在 AI 模型处理多个消息字符串之前将其分类为不同的角色,引入了更多的提示结构。

API概述

Prompt

通常使用ChatClient的generate方法,该方法获取Prompt实例并返回ChatResponse。

Prompt 类充当一系列有组织的 Message 对象的容器,每个对象形成整个提示的一部分。每条消息都体现了提示中的独特角色,其内容和意图有所不同。这些角色可以包含各种元素,从用户查询到人工智能生成的响应或相关背景信息。这种安排可以与人工智能模型进行复杂而详细的交互,因为提示是由多条消息构成的,每条消息都在对话中分配了一个特定的角色。

下面是 Prompt 类的截断版本,为简洁起见,省略了构造函数和实用方法:

public class Prompt {

    private final List<Message> messages;

    // constructors and utility methods omitted
}

Message

该 Message 接口封装了文本消息、类型为Map的属性集合、MessageType 的分类以及 多模式模型的媒体对象列表。接口定义如下:

public interface Message {

    String getContent();

    List<Media> getMedia();

    Map<String, Object> getProperties();

    MessageType getMessageType();

}

接口的各种实现Message对应于人工智能模型可以处理的不同类别的消息。一些模型(例如 OpenAI 的模型)根据对话角色区分消息类别。这些角色由 有效映射MessageType,如下所述。

Roles

人工智能提示的演变已经从基本、简单的文本转变为具有特定角色和结构的更有组织和复杂的格式。

最初,提示是简单的字符串——只是文本行。随着时间的推移,它逐渐演变为在这些字符串中包含特定的占位符,例如“USER:”,人工智能模型可以识别并相应地做出响应。这是朝着更加结构化的提示迈出的一步。

OpenAI 随后推出了一种更有组织性的方法。在他们的模型中,提示不仅仅是单个字符串,而是一系列消息。每条消息虽然仍为文本形式,但都被分配了特定的角色。这些角色对消息进行分类,阐明 AI 模型提示的每个部分的上下文和目的。这种结构化方法增强了与人工智能沟通的细微差别和有效性,因为提示的每个部分在交互中都扮演着独特且明确的角色。

主要角色是:

  • 系统角色:指导AI的行为和响应风格,设置AI如何解释和回复输入的参数或规则。这类似于在开始对话之前向人工智能提供指令。

  • 用户角色:代表用户的输入——他们对人工智能的问题、命令或陈述。这一作用至关重要,因为它构成了人工智能响应的基础。

  • 助理角色:人工智能对用户输入的响应。它不仅仅是一个答案或反应,对于维持对话的顺利进行也至关重要。通过跟踪人工智能之前的响应(其“助理角色”消息),系统可确保连贯且与上下文相关的交互。

  • 功能角色:该角色处理会话期间的特定任务或操作。系统角色设置 AI 的整体行为,而功能角色则侧重于执行用户要求的某些操作或命令。它就像人工智能中的一项特殊功能,在需要执行特定功能时使用,例如计算、获取数据或其他不仅仅是说话的任务。这一角色使得人工智能除了对话响应之外还可以提供实际帮助。

角色在 Spring AI 中表示为枚举,如下所示

public enum MessageType {

    USER("user"),

    ASSISTANT("assistant"),

    SYSTEM("system"),

    FUNCTION("function");

    private final String value;

    MessageType(String value) {
        this.value = value;
    }

    public String getValue() {
        return value;
    }

    public static MessageType fromValue(String value) {
        for (MessageType messageType : MessageType.values()) {
            if (messageType.getValue().equals(value)) {
                return messageType;
            }
        }
        throw new IllegalArgumentException("Invalid MessageType value: " + value);
    }

}

PromptTemplate

Spring AI 中提示模板的一个关键组件是PromptTemplate类。此类使用 Terence Parr 开发的 StringTemplate 引擎来构建和管理提示。这个 PromptTemplate 类 旨在帮助创建结构化提示,然后将其发送到 AI 模型进行处理

public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {

    // Other methods to be discussed later
}

此类实现的接口支持提示创建的不同方面:

  • PromptTemplateStringActions 专注于创建和渲染提示字符串,代表提示生成的最基本形式。

  • PromptTemplateMessageActions是为通过消息对象的生成和操作进行提示创建而定制的。

  • PromptTemplateActions旨在返回 Prompt 对象,该对象可以传递给 ChatClient 以生成响应。

虽然这些界面可能不会在许多项目中广泛使用,但它们显示了提示创建的不同方法。

实现的接口有

public interface PromptTemplateStringActions {

    String render();

    String render(Map<String, Object> model);

}

方法 String render():将提示模板渲染为最终的字符串格式,无需外部输入,适用于没有占位符或动态内容的模板。

该方法 String render(Map<String, Object> model):增强渲染功能以包含动态内容。它使用 Map<String, Object>,其中映射键是提示模板中的占位符名称,值是要插入的动态内容。

public interface PromptTemplateMessageActions {

    Message createMessage();

    Message createMessage(Map<String, Object> model);

}

该方法 Message createMessage():创建一个没有附加数据的 Message 对象,用于静态或预定义的消息内容。

该方法Message createMessage(Map<String, Object> model):扩展消息创建以集成动态内容,接受 Map<String, Object>,其中每个条目代表消息模板中的占位符及其相应的动态值。


public interface PromptTemplateActions extends PromptTemplateStringActions {

    Prompt create();

    Prompt create(Map<String, Object> model);

}

该方法Prompt create():生成一个 Prompt 对象,无需外部数据输入,非常适合静态或预定义提示。

该方法Prompt create(Map<String, Object> model):扩展提示创建功能以包含动态内容,采用 Map<String, Object>,其中每个映射条目都是提示模板中的占位符及其关联的动态值。

用法示例

下面显示了来自PromptTemplates 上 AI Workshop的一个简单示例。

PromptTemplate promptTemplate = new PromptTemplate("Tell me a {adjective} joke about {topic}");

Prompt prompt = promptTemplate.create(Map.of("adjective", adjective, "topic", topic));

return chatClient.call(prompt).getResult();

下面显示了来自 AI Workshop on Roles 的另一个示例。

String userText = """
    Tell me about three famous pirates from the Golden Age of Piracy and why they did.
    Write at least a sentence for each pirate.
    """;

Message userMessage = new UserMessage(userText);

String systemText = """
  You are a helpful AI assistant that helps people find information.
  Your name is {name}
  You should reply to the user's request with your name and also in the style of a {voice}.
  """;

SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemText);
Message systemMessage = systemPromptTemplate.createMessage(Map.of("name", name, "voice", voice));

Prompt prompt = new Prompt(List.of(userMessage, systemMessage));

List<Generation> response = chatClient.call(prompt).getResults();

这显示了如何通过基于 SystemPromptTemplate 使用传递占位符值的系统角色来创建实例来构建Prompt实例。然后将Message带有角色的消息user与角色的消息组合起来system形成提示。然后提示被传递到 ChatClient 以获取生成响应。

使用资源而不是原始字符串

Spring AI 支持org.springframework.core.io.Resource抽象,因此您可以将提示数据放入可 直接在 PromptTemplates 中使用的文件中。例如,您可以在 Spring 托管组件中定义一个字段来检索资源。

@Value("classpath:/prompts/system-message.st")
private Resource systemResource;

然后将该资源直接传递给SystemPromptTemplate。

SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);

提示工程(Prompt Engineering)

在生成式人工智能中,创建提示对于开发人员来说是一项至关重要的任务。这些提示的质量和结构显着影响人工智能输出的有效性。投入时间和精力来设计深思熟虑的提示可以极大地改善人工智能的结果。

分享和讨论提示是人工智能社区的常见做法。这种协作方法不仅创建了共享的学习环境,而且还可以识别和使用高效的提示。

该领域的研究通常涉及分析和比较不同的提示,以评估其在各种情况下的有效性。例如,一项重要研究表明,以“深吸一口气,逐步解决这个问题”作为提示,可以显着提高解决问题的效率。这凸显了精心选择的语言对生成人工智能系统性能的影响。

掌握最有效地使用提示,尤其是随着人工智能技术的快速发展,是一个持续的挑战。您应该认识到提示工程的重要性,并考虑利用社区和研究的见解来改进提示创建策略。

创建有效的提示

开发提示时,集成几个关键组件以确保清晰度和有效性非常重要:

  • 指令:向人工智能提供清晰、直接的指令,类似于你与人沟通的方式。这种清晰度对于帮助人工智能“理解”预期至关重要。

  • 外部背景:必要时包括相关背景信息或人工智能响应的具体指导。这种“外部背景”构成了提示并帮助人工智能掌握整体场景。

  • 用户输入:这是最简单的部分 - 用户的直接请求或问题构成提示的核心。

  • 输出指示器:这方面可能很棘手。它涉及指定 AI 响应所需的格式,例如 JSON。然而,请注意,人工智能可能并不总是严格遵守这种格式。例如,它可能会在实际 JSON 数据之前添加诸如“这是您的 JSON”之类的短语,或者有时会生成不准确的类似 JSON 的结构。

在制作提示时,向人工智能提供预期问答格式的示例非常有用。这种做法有助于人工智能“理解”您的查询的结构和意图,从而产生更精确和相关的响应。虽然本文档没有深入探讨这些技术,但它们为进一步探索 AI 提示工程提供了一个起点。

以下是供进一步调查的资源列表。

简单的技巧

  • 文本摘要:将大量文本简化为简洁的摘要,捕捉要点和主要思想,同时省略不太重要的细节。

  • 问答:重点是根据用户提出的问题从提供的文本中得出具体答案。它是为了响应查询而精确定位和提取相关信息。

  • 文本分类:系统地将文本分类为预定义的类别或组,分析文本并根据其内容将其分配到最合适的类别。

  • 对话:创建交互式对话,人工智能可以与用户进行来回通信,模拟自然的对话流程。

  • 代码生成:根据特定的用户需求或描述生成功能代码片段,将自然语言指令转换为可执行代码。

增强的技巧

  • 零样本、少样本学习:

使模型能够在很少甚至没有特定问题类型的先前示例的情况下做出准确的预测或响应,使用学习到的概括来理解新任务并采取行动。

  • 思想链:

链接多个人工智能响应以创建连贯且上下文感知的对话。它帮助人工智能保持讨论的主线,确保相关性和连续性。

  • ReAct(理性+行动)

在这种方法中,人工智能首先分析输入(原因),然后确定最合适的行动或响应方案。它将理解与决策结合起来。

微软指南

Microsoft 提供了一种结构化方法来开发和完善提示。该框架指导用户创建有效的提示,从人工智能模型中引出所需的响应,优化交互以提高清晰度和效率。

Tokens

Tokens 对于人工智能模型处理文本的方式至关重要,它充当将单词(按照我们的理解)转换为人工智能模型可以处理的格式的桥梁。这种转换分两个阶段进行:输入时单词被转换为标记,然后这些标记在输出中被转换回单词。

标记化是将文本分解为标记的过程,是人工智能模型理解和处理语言的基础。人工智能模型使用这种标记化格式来理解和响应提示。

为了更好地理解标记,请将它们视为单词的一部分。通常,一个标记代表大约四分之三的单词。例如,莎士比亚全集总计约 90 万字,可翻译为约 120 万个代币。

使用 OpenAI Tokenizer UI 进行实验,了解单词如何转换为标记。

Tokens 的实际意义超出了其在人工智能处理中的技术作用,特别是在计费和模型功能方面:

  • 计费:AI 模型服务通常根据代币使用情况进行计费。输入(提示)和输出(响应)都会对令牌总数产生影响,从而使较短的提示更具成本效益。

  • 模型限制:不同的人工智能模型有不同的令牌限制,定义它们的“上下文窗口”——它们一次可以处理的最大信息量。例如,GPT-3 的限制是 4K 代币,而 Claude 2 和 Meta Llama 2 等其他模型的限制是 100K 代币,一些研究模型最多可以处理 100 万个代币。

  • 上下文窗口:模型的令牌限制决定了其上下文窗口。模型不会处理超过此限制的输入。仅发送最少的有效信息集进行处理至关重要。例如,当查询“哈姆雷特”时,无需包含莎士比亚所有其他作品中的标记。

  • 响应元数据:人工智能模型响应的元数据包括所使用的代币数量,这是管理使用和成本的重要信息。

作者:Jeebiz  创建时间:2024-04-05 22:41
最后编辑:Jeebiz  更新时间:2024-07-06 19:00