此版本仍在开发中,尚未被视为稳定版。为了获取最新的快照版本,请使用Spring AI 1.1.3spring-doc.cadn.net.cn

提示

提示是引导AI模型生成特定输出的输入信息。这些提示的设计和措辞极大地影响着模型的响应。spring-doc.cadn.net.cn

在Spring AI中与AI模型进行交互的最低层级,处理提示的方式有点类似于在Spring MVC中管理“视图”。 这包括创建包含动态内容占位符的大量文本。 这些占位符随后会根据用户请求或应用程序中的其他代码进行替换。 另一个类比是包含某些表达式占位符的SQL语句。spring-doc.cadn.net.cn

随着Spring AI的发展,它将为与AI模型的交互引入更高级别的抽象。 本节中描述的基础类在角色和功能上可类比于JDBC。 例如,ChatModel类类似于JDK中的核心JDBC库。 ChatClient类则可类比于构建在ChatModel之上的JdbcClient,通过Advisor 来考虑与模型的过往交互,为提示添加额外的上下文文档,并引入代理行为构造。spring-doc.cadn.net.cn

AI领域中提示的结构随着时间的推移而发展。 起初,提示仅为简单的字符串。 随着时间的推移,它们开始包含特定输入的占位符,如 "USER:",AI模型能够识别这些占位符。 OpenAI进一步引入了更为结构化的提示处理方式,在AI模型处理之前,将多条消息字符串划分为不同的角色类别。spring-doc.cadn.net.cn

API概述

提示

在使用 call() 方法时很常见,该方法属于 ChatModel,它接受一个 Prompt 实例并返回一个 ChatResponsespring-doc.cadn.net.cn

Prompt 类作为一系列有序的 Message 对象和请求 ChatOptions 的容器发挥作用。 每个 Message 在提示中承担着独特角色,其内容和目的各不相同。 这些角色可以包括多种元素,从用户查询到AI生成的响应,再到相关背景信息等。 这种安排使得与AI模型的交互变得复杂而详尽,因为提示由多个消息构建而成,每个消息在对话中被分配了特定的角色。spring-doc.cadn.net.cn

以下是Prompt类的简化版本,为了简洁起见,省略了构造器和实用方法:spring-doc.cadn.net.cn

public class Prompt implements ModelRequest<List<Message>> {

    private final List<Message> messages;

    private ChatOptions chatOptions;
}

便捷方法

Prompt 类提供了几种通过角色访问消息的便捷方法:spring-doc.cadn.net.cn

单消息访问:spring-doc.cadn.net.cn

  • getUserMessage(): 返回提示中的最后一条用户消息,如果不存在则返回空的UserMessagespring-doc.cadn.net.cn

  • getSystemMessage(): 返回提示中的第一条系统消息,如果不存在则返回空的SystemMessagespring-doc.cadn.net.cn

  • getLastUserOrToolResponseMessage(): 返回最后一个用户或工具响应消息,有助于保持对话连贯性spring-doc.cadn.net.cn

多消息访问:spring-doc.cadn.net.cn

这些方法在处理多轮对话或需要按角色处理消息时特别有用。spring-doc.cadn.net.cn

消息

Message 接口封装了一个Prompt文本内容、一组元数据属性及一个称为MessageType的分类。spring-doc.cadn.net.cn

接口定义如下:spring-doc.cadn.net.cn

public interface Content {

	String getContent();

	Map<String, Object> getMetadata();
}

public interface Message extends Content {

	MessageType getMessageType();
}

多模态消息类型也实现了MediaContent接口,提供了Media内容对象的列表。spring-doc.cadn.net.cn

public interface MediaContent extends Content {

	Collection<Media> getMedia();

}

Message 接口的不同实现对应于AI模型可以处理的不同类别消息。 模型根据对话角色来区分消息类别。spring-doc.cadn.net.cn

Spring AI Message API

这些角色由MessageType有效地映射,如下所述。spring-doc.cadn.net.cn

角色

每条消息都被赋予了一个特定的角色。 这些角色对消息进行分类,明确了提示中各部分的上下文和目的,以便AI模型理解。 这种结构化的方法增强了与AI沟通的细微度和有效性,因为提示的每一部分都在交互中扮演着独特而明确的角色。spring-doc.cadn.net.cn

主要角色包括:spring-doc.cadn.net.cn

  • 系统角色:指导AI的行为和回应风格,为AI如何解释和回复输入设定参数或规则。这类似于在开始对话前向AI提供指导说明。spring-doc.cadn.net.cn

  • 用户角色:代表用户的输入——他们向AI提出的问题、命令或陈述。此角色至关重要,因为它构成了AI响应的基础。spring-doc.cadn.net.cn

  • 助手角色:AI针对用户输入的回应。 它不仅仅是一个答案或反应,对于维持对话的流畅性至关重要。 通过追踪AI之前的回应(即其'助手角色'消息),系统确保了互动的一致性和上下文相关性。 助手消息中还可能包含功能工具调用请求信息。 这就像AI中的一项特殊功能,在需要执行特定功能时使用,如计算、获取数据或其他超出简单对话的任务。spring-doc.cadn.net.cn

  • 工具/功能角色:工具/功能角色专注于在响应工具调用助手消息时返回额外信息。spring-doc.cadn.net.cn

在Spring AI中,角色通过枚举表示,如下所示spring-doc.cadn.net.cn

public enum MessageType {

	USER("user"),

	ASSISTANT("assistant"),

	SYSTEM("system"),

	TOOL("tool");

    ...
}

提示模板

Spring AI中用于快速模板化的核心组件是PromptTemplate类,旨在简化结构化提示的创建,这些提示随后被发送给AI模型进行处理spring-doc.cadn.net.cn

public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {

    // Other methods to be discussed later
}

此类使用TemplateRenderer API来渲染模板。默认情况下,Spring AI采用基于Terence Parr开发的开源StringTemplate引擎的StTemplateRenderer实现。模板变量通过{}语法标识,但您也可以配置分隔符以使用其他语法。spring-doc.cadn.net.cn

public interface TemplateRenderer extends BiFunction<String, Map<String, Object>, String> {

	@Override
	String apply(String template, Map<String, Object> variables);

}

Spring AI 通过使用 TemplateRenderer 接口来处理将变量实际替换到模板字符串中的操作。 默认实现使用了 [StringTemplate]。 如果您需要自定义逻辑,可以提供自己的 TemplateRenderer 实现。 对于无需模板渲染的场景(例如,模板字符串已经是完整的),您可以使用提供的 NoOpTemplateRendererspring-doc.cadn.net.cn

使用自定义StringTemplate渲染器的示例,其中 '<' 和 '>' 用作定界符
PromptTemplate promptTemplate = PromptTemplate.builder()
    .renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
    .template("""
            Tell me the names of 5 movies whose soundtrack was composed by <composer>.
            """)
    .build();

String prompt = promptTemplate.render(Map.of("composer", "John Williams"));

此类实现的接口支持提示创建的不同方面:spring-doc.cadn.net.cn

PromptTemplateStringActions 专注于创建和渲染提示字符串,代表了最基础的提示生成形式。spring-doc.cadn.net.cn

PromptTemplateMessageActions 专为通过生成和操作 Message 对象来创建提示而设计。spring-doc.cadn.net.cn

PromptTemplateActions 被设计为返回 Prompt 对象,该对象可传递给 ChatModel 以生成响应。spring-doc.cadn.net.cn

尽管这些接口在许多项目中可能不会被广泛使用,但它们展示了创建提示的不同方法。spring-doc.cadn.net.cn

实现的接口有spring-doc.cadn.net.cn

public interface PromptTemplateStringActions {

	String render();

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

}

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

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

public interface PromptTemplateMessageActions {

	Message createMessage();

    Message createMessage(List<Media> mediaList);

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

}

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

方法 Message createMessage(List<Media> mediaList): 使用静态文本和媒体内容创建一个 Message 对象。spring-doc.cadn.net.cn

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

public interface PromptTemplateActions extends PromptTemplateStringActions {

	Prompt create();

	Prompt create(ChatOptions modelOptions);

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

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

}

方法 Prompt create(): 生成一个 Prompt 对象,无需外部数据输入,适用于静态或预定义的提示。spring-doc.cadn.net.cn

方法 Prompt create(ChatOptions modelOptions): 生成一个 Prompt 对象,无需外部数据输入,并为聊天请求提供特定选项。spring-doc.cadn.net.cn

方法 Prompt create(Map<String, Object> model): 扩展了提示创建功能,以包含动态内容,接受一个 Map<String, Object>,其中每个映射条目都是提示模板中的占位符及其关联的动态值。spring-doc.cadn.net.cn

方法 Prompt create(Map<String, Object> model, ChatOptions modelOptions): 扩展了提示创建功能,以包含动态内容,接受一个 Map<String, Object>,其中每个映射条目都是提示模板中的占位符及其关联的动态值,以及聊天请求的具体选项。spring-doc.cadn.net.cn

示例用法

一个简单的示例,取自AI工作坊中的PromptTemplates,如下所示。spring-doc.cadn.net.cn

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

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

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

另一个来自AI角色工作坊的例子如下所示。spring-doc.cadn.net.cn

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 = chatModel.call(prompt).getResults();

这展示了如何使用Prompt实例,通过SystemPromptTemplate来创建一个带有系统角色的Message,并传入占位符值。 接着,具有角色user的消息与角色system的消息结合,形成提示语。 该提示语随后被传递给ChatModel以获得生成式响应。spring-doc.cadn.net.cn

使用自定义模板渲染器

可以通过实现TemplateRenderer接口并将它传递给PromptTemplate构造器来使用自定义的模板渲染器。您也可以继续使用默认的StTemplateRenderer,但采用自定义配置。spring-doc.cadn.net.cn

默认情况下,模板变量通过 {} 语法来标识。如果您计划在提示中包含JSON,可能需要使用不同的语法以避免与JSON语法冲突。例如,您可以使用 <> 作为分隔符。spring-doc.cadn.net.cn

PromptTemplate promptTemplate = PromptTemplate.builder()
    .renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
    .template("""
            Tell me the names of 5 movies whose soundtrack was composed by <composer>.
            """)
    .build();

String prompt = promptTemplate.render(Map.of("composer", "John Williams"));

使用资源而非原始字符串

Spring AI 支持 org.springframework.core.io.Resource 抽象,因此您可以将提示数据放入一个文件中,该文件可直接在 PromptTemplate 中使用。 例如,您可以在 Spring 管理的组件中定义一个字段来检索 Resourcespring-doc.cadn.net.cn

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

然后将该资源直接传递给SystemPromptTemplatespring-doc.cadn.net.cn

SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);

提示工程

在生成式AI中,提示的创建是开发者的一项关键任务。 这些提示的质量和结构极大地影响着AI输出的有效性。 投入时间和精力设计周到的提示,可以大大提高AI产生的结果。spring-doc.cadn.net.cn

在AI领域,分享和讨论提示是一种普遍做法。 这种合作方式不仅创建了共享的学习环境,还促进了高效提示的识别与应用。spring-doc.cadn.net.cn

该领域的研究常常涉及分析和比较不同的提示语,以评估它们在不同情境下的有效性。 例如,一项重要研究表明,以“深呼吸,一步一步解决这个问题”开始的提示语显著提高了问题解决效率。 这凸显了精心挑选的语言对生成式AI系统性能的影响。spring-doc.cadn.net.cn

掌握提示的有效使用方法,特别是在人工智能技术的快速发展下,是一个持续的挑战。 您应当认识到提示工程的重要性,并考虑利用社区和研究的洞见来改进提示创建策略。spring-doc.cadn.net.cn

创建有效提示

在设计提示时,整合以下几个关键要素以确保清晰度和有效性至关重要:spring-doc.cadn.net.cn

  • 指示: 向AI提供清晰直接的指示,就像与人沟通一样。这种清晰度对于帮助AI“理解”期望的内容至关重要。spring-doc.cadn.net.cn

  • 外部上下文: 根据需要包含相关的背景信息或对AI响应的具体指导。这个“外部上下文”构建了提示的框架,帮助AI理解整体场景。spring-doc.cadn.net.cn

  • 用户输入: 这是直接的部分——用户的直接请求或问题,构成了提示的核心。spring-doc.cadn.net.cn

  • 输出指示器: 此方面可能较为棘手。它涉及指定AI响应的期望格式,如JSON。但请注意,AI并不总是严格遵守此格式。例如,它可能会在实际的JSON数据前添加诸如“这是您的JSON”之类的短语,或者有时生成并非完全准确的类JSON结构。spring-doc.cadn.net.cn

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

以下是进一步研究的资源列表。spring-doc.cadn.net.cn

简单技巧

高级技术

Microsoft 指导原则

token

Tokens在AI模型处理文本的方式中至关重要,它们充当桥梁,将我们理解的词汇转换为AI模型可以处理的格式。 这一转换过程分为两个阶段:输入时,词汇被转换为Tokens;输出时,这些Tokens再被转换回词汇。spring-doc.cadn.net.cn

分词,即将文本拆分为词语的过程,是AI模型理解和处理语言的基础。 AI模型借助这种分词格式来理解并响应提示。spring-doc.cadn.net.cn

为了更好地理解Tokens(tokens),可以将它们视为单词的部分。通常,一个Tokens大约代表了一个单词的四分之三。例如,莎士比亚的全部作品,总共有大约90万字,转换成Tokens后将约为120万个。spring-doc.cadn.net.cn

试验OpenAI分词器UI,了解单词是如何转换为分词的。spring-doc.cadn.net.cn

Tokens在AI处理中的技术角色之外还有实际意义,特别是在计费和模型能力方面:spring-doc.cadn.net.cn

  • 计费:AI模型服务通常根据Tokens使用量进行计费。输入(提示)和输出(响应)都会计入总的Tokens数量,因此更简短的提示在成本效益上更为划算。spring-doc.cadn.net.cn

  • 模型限制:不同的AI模型具有不同的Tokens限制,这些限制定义了它们的“上下文窗口”——即它们一次能处理的最大信息量。例如,GPT-3的限制是4千个Tokens,而其他模型如Claude 2和Meta Llama 2的限制为10万个Tokens,一些研究型模型甚至能处理多达100万个Tokens。spring-doc.cadn.net.cn

  • 上下文窗口:模型的Tokens限制决定了其上下文窗口的大小。超过此限制的输入将不会被模型处理。因此,只发送最有效的、必要的信息集进行处理至关重要。例如,在询问关于“哈姆雷特”的信息时,无需包含莎士比亚其他所有作品的Tokens。spring-doc.cadn.net.cn

  • 响应元数据:来自AI模型的响应元数据包括使用的Tokens数量,这是管理使用量和成本的重要信息。spring-doc.cadn.net.cn