此版本仍在开发中,尚不被认为是稳定的。对于最新的快照版本,请使用 Spring AI 1.0.1! |
提示
提示是指导人工智能模型生成特定输出的输入。 这些提示的设计和措辞会显着影响模型的响应。
在 Spring AI 中与 AI 模型交互的最低级别,在 Spring AI 中处理提示有点类似于管理 Spring MVC 中的“View”。 这涉及为动态内容创建带有占位符的大量文本。 然后根据用户请求或应用程序中的其他代码替换这些占位符。 另一个类比是包含某些表达式的占位符的 SQL 语句。
随着 Spring AI 的发展,它将引入更高级别的抽象来与 AI 模型交互。
本节中描述的基础类在角色和功能方面可以与 JDBC 类似。
这ChatModel
类类似于 JDK 中的核心 JDBC 库。
这ChatClient
类可以比作JdbcClient
,建立在ChatModel
并通过Advisor
考虑过去与模型的交互,使用额外的上下文文档增强提示,并引入代理行为。
人工智能领域内提示的结构随着时间的推移而演变。 最初,提示是简单的字符串。 随着时间的推移,它们逐渐包括特定输入的占位符,例如人工智能模型识别的“USER:”。 OpenAI 通过在人工智能模型处理多个消息字符串之前将多个消息字符串分类为不同的角色,为提示引入了更多的结构。
API 概述
提示
通常使用call()
方法ChatModel
这需要一个Prompt
实例并返回一个ChatResponse
.
这Prompt
class 函数作为有组织的一系列Message
对象和请求ChatOptions
.
每Message
在提示中体现了独特的作用,其内容和意图不同。
这些角色可以涵盖各种元素,从用户查询到人工智能生成的响应,再到相关背景信息。
这种安排可以与人工智能模型进行复杂而详细的交互,因为提示是由多条消息构建的,每条消息都被分配了在对话中扮演的特定角色。
下面是 Prompt 类的截断版本,为简洁起见,省略了构造函数和实用程序方法:
public class Prompt implements ModelRequest<List<Message>> {
private final List<Message> messages;
private ChatOptions chatOptions;
}
消息
这Message
接口封装了一个Prompt
文本内容、元数据属性的集合以及称为MessageType
.
接口定义如下:
public interface Content {
String getContent();
Map<String, Object> getMetadata();
}
public interface Message extends Content {
MessageType getMessageType();
}
多模态消息类型还实现了MediaContent
接口提供列表Media
content 对象。
public interface MediaContent extends Content {
Collection<Media> getMedia();
}
的各种实现Message
接口对应于 AI 模型可以处理的不同类别的消息。
模型根据对话角色区分消息类别。

这些角色由MessageType
,如下所述。
角色
每条消息都分配了一个特定的角色。 这些角色对消息进行分类,阐明 AI 模型提示的每个部分的上下文和目的。 这种结构化方法增强了与人工智能沟通的细微差别和有效性,因为提示的每个部分在交互中都发挥着独特且明确的作用。
主要角色是:
-
系统角色:指导 AI 的行为和响应风格,设置 AI 如何解释和回复输入的参数或规则。这类似于在开始对话之前向人工智能提供指令。
-
用户角色:代表用户的输入——他们对人工智能的问题、命令或陈述。这个角色是至关重要的,因为它构成了人工智能响应的基础。
-
助理角色:人工智能对用户输入的响应。 它不仅仅是一个答案或反应,对于保持对话的流畅性至关重要。 通过跟踪人工智能之前的响应(其“助理角色”消息),系统确保了连贯且与上下文相关的交互。 助手消息也可能包含函数工具调用请求信息。 它就像人工智能中的一项特殊功能,在需要执行特定功能时使用,例如计算、获取数据或不仅仅是说话之外的其他任务。
-
工具/功能角色:工具/功能角色侧重于返回其他信息以响应工具调用助手消息。
角色在 Spring AI 中表示为枚举,如下所示
public enum MessageType {
USER("user"),
ASSISTANT("assistant"),
SYSTEM("system"),
TOOL("tool");
...
}
提示模板
Spring AI 中提示模板的一个关键组件是PromptTemplate
类,旨在促进结构化提示的创建,然后将其发送到 AI 模型进行处理
public class PromptTemplate implements PromptTemplateActions, PromptTemplateMessageActions {
// Other methods to be discussed later
}
此类使用TemplateRenderer
API 来渲染模板。默认情况下,Spring AI 使用StTemplateRenderer
实现,它基于 Terence Parr 开发的开源 StringTemplate 引擎。模板变量由语法标识,但您也可以将分隔符配置为使用其他语法。{}
public interface TemplateRenderer extends BiFunction<String, Map<String, Object>, String> {
@Override
String apply(String template, Map<String, Object> variables);
}
Spring AI 使用TemplateRenderer
接口来处理变量对模板字符串的实际替换。
默认实现使用 [StringTemplate]。
您可以提供自己的实现TemplateRenderer
如果您需要自定义逻辑。
对于不需要模板渲染的场景(例如,模板字符串已经完成),可以使用提供的NoOpTemplateRenderer
.
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"));
此类实现的接口支持提示创建的不同方面:
PromptTemplateStringActions
专注于创建和渲染提示字符串,代表提示生成的最基本形式。
PromptTemplateMessageActions
是为通过生成和作Message
对象。
PromptTemplateActions
旨在返回Prompt
对象,可以传递给ChatModel
用于生成响应。
虽然这些接口可能不会在许多项目中广泛使用,但它们显示了提示创建的不同方法。
实现的接口是
public interface PromptTemplateStringActions {
String render();
String render(Map<String, Object> model);
}
方法String render()
:将提示模板渲染为最终字符串格式,无需外部输入,适用于没有占位符或动态内容的模板。
方法String render(Map<String, Object> model)
:增强渲染功能以包含动态内容。它使用Map<String, Object>
其中 map 键是提示模板中的占位符名称,值是要插入的动态内容。
public interface PromptTemplateMessageActions {
Message createMessage();
Message createMessage(List<Media> mediaList);
Message createMessage(Map<String, Object> model);
}
方法Message createMessage()
:创建一个Message
对象,没有其他数据,用于静态或预定义的消息内容。
方法Message createMessage(List<Media> mediaList)
:创建一个Message
具有静态文本和媒体内容的对象。
方法Message createMessage(Map<String, Object> model)
:扩展消息创建以集成动态内容,接受Map<String, Object>
其中每个条目表示消息模板中的占位符及其相应的动态值。
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
对象,无需外部数据输入,非常适合静态或预定义提示。
方法Prompt create(ChatOptions modelOptions)
:生成一个Prompt
对象,没有外部数据输入,并且具有聊天请求的特定选项。
方法Prompt create(Map<String, Object> model)
:扩展提示创建功能以包括动态内容,将Map<String, Object>
其中,每个地图条目都是提示模板中的占位符及其关联的动态值。
方法Prompt create(Map<String, Object> model, ChatOptions modelOptions)
:扩展提示创建功能以包括动态内容,将Map<String, Object>
其中,每个地图条目都是提示模板中的占位符及其关联的动态值,以及聊天请求的特定选项。
用法示例
下面显示了 PromptTemplates 上 AI 研讨会的一个简单示例。
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 角色研讨会中的另一个示例。
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 以获得生成响应。
使用自定义模板渲染器
您可以通过实现TemplateRenderer
接口并将其传递给PromptTemplate
构造 函数。您也可以继续使用默认值StTemplateRenderer
,但具有自定义配置。
默认情况下,模板变量由语法标识。如果计划在提示中包含 JSON,则可能需要使用不同的语法来避免与 JSON 语法冲突。例如,您可以使用 和 分隔符。{}
<
>
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 托管组件中定义一个字段来检索Resource
.
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
然后将该资源传递给SystemPromptTemplate
径直。
SystemPromptTemplate systemPromptTemplate = new SystemPromptTemplate(systemResource);
提示工程
在生成式人工智能中,提示的创建是开发人员的一项至关重要的任务。 这些提示的质量和结构显着影响人工智能输出的有效性。 投入时间和精力来设计深思熟虑的提示可以大大改善人工智能的结果。
分享和讨论提示是人工智能社区的常见做法。 这种协作方法不仅创造了一个共享的学习环境,而且还导致识别和使用高效的提示。
该领域的研究通常涉及分析和比较不同的提示,以评估它们在各种情况下的有效性。 例如,一项重要的研究表明,以“深呼吸,一步一步解决这个问题”开始提示可以显着提高解决问题的效率。 这凸显了精心选择的语言对生成式人工智能系统性能的影响。
掌握提示的最有效使用,特别是随着人工智能技术的快速发展,是一项持续的挑战。 您应该认识到提示工程的重要性,并考虑利用社区和研究的见解来改进提示创建策略。
创建有效的提示
开发提示时,集成几个关键组件以确保清晰度和有效性非常重要:
-
说明:向人工智能提供清晰直接的指令,类似于您与人交流的方式。这种清晰度对于帮助人工智能“理解”预期内容至关重要。
-
外部背景:必要时包括相关背景信息或人工智能响应的具体指导。这种“外部上下文”构建了提示并帮助人工智能掌握整体场景。
-
用户输入:这是简单的部分 - 用户的直接请求或问题构成了提示的核心。
-
输出指标:这方面可能很棘手。它涉及指定人工智能响应所需的格式,例如 JSON。但是,请注意,人工智能可能并不总是严格遵守这种格式。例如,它可能会在实际 JSON 数据之前添加诸如“这是您的 JSON”之类的短语,或者有时会生成不准确的类似 JSON 的结构。
在制作提示时,向人工智能提供预期问答格式的示例可能非常有益。这种做法有助于人工智能“理解”查询的结构和意图,从而获得更精确和相关的响应。虽然本文档没有深入研究这些技术,但它们为进一步探索人工智能提示工程提供了起点。
以下是供进一步调查的资源列表。
先进技术
-
零样本、少样本学习:
使模型能够做出准确的预测或响应,只需很少或没有特定问题类型的先前示例,使用学习的泛化来理解新任务并采取行动。 -
思维链:
链接多个 AI 响应,以创建连贯且上下文感知的对话。它可以帮助人工智能保持讨论的线索,确保相关性和连续性。 -
ReAct(理由+行动):
在这种方法中,人工智能首先分析(关于)输入的原因,然后确定最合适的行动方案或响应。它将理解与决策相结合。
Microsoft 指南
-
提示创建和优化框架:
Microsoft 提供了一种结构化的方法来开发和完善提示。该框架指导用户创建有效的提示,从 AI 模型中引出所需的响应,优化交互以提高清晰度和效率。
Tokens
标记在人工智能模型处理文本的方式中至关重要,充当桥梁,将单词(正如我们所理解的那样)转换为人工智能模型可以处理的格式。这种转换分两个阶段进行:单词在输入时转换为标记,然后这些标记在输出中转换回单词。
标记化是将文本分解为标记的过程,是人工智能模型如何理解和处理语言的基础。人工智能模型使用这种标记化格式来理解和响应提示。
为了更好地理解标记,请将它们视为单词的一部分。通常,一个标记代表大约一个单词的四分之三。例如,莎士比亚的完整作品,总计大约 900,000 个单词,可以翻译成大约 120 万个Tokens。
尝试使用 OpenAI Tokenizer UI,看看单词是如何转换为标记的。
Tokens除了在人工智能处理中的技术作用之外,还具有实际意义,特别是在计费和模型功能方面:
-
计费:AI 模型服务通常根据Tokens使用情况计费。输入(提示)和输出(响应)都会影响Tokens总数,使较短的提示更具成本效益。
-
模型限制:不同的人工智能模型有不同的Tokens限制,定义了它们的“上下文窗口”——它们一次可以处理的最大信息量。例如,GPT-3 的限制是 4K Tokens,而其他模型如 Claude 2 和 Meta Llama 2 的限制是 100K Tokens,一些研究模型最多可以处理 100 万个Tokens。
-
上下文窗口:模型的Tokens限制决定了其上下文窗口。超过此限制的输入不会由模型处理。仅发送最小有效信息集进行处理至关重要。例如,在询问“哈姆雷特”时,无需包含莎士比亚所有其他作品的标记。
-
响应元数据:来自 AI 模型的响应元数据包括使用的Tokens数量,这是管理使用和成本的重要信息。