提示是引导AI模型生成特定输出的输入。这些提示的设计和措辞会显著影响模型的反应。
在Spring AI中与AI模型交互的最低级别,处理Spring AI中的提示与管理Spring MVC中的“视图”有些相似。这涉及为动态内容创建带有占位符的广泛文本。然后根据用户请求或应用程序中的其他代码替换这些占位符。另一个类比是包含某些表达式占位符的SQL语句。
随着Spring AI的发展,它将为与AI模型的交互引入更高层次的抽象。本节中描述的基础类在角色和功能方面可以比作JDBC。例如,ChatModel类类似于JDK中的核心JDBC库。ChatClient类可以比作JdbcClient,它构建在ChatModel之上,通过Advisor提供更高级的构造,以考虑过去与模型的交互,用额外的上下文文档增强提示,并引入代理行为。
提示的结构在人工智能领域随着时间的推移而演变。最初,提示是简单的字符串。随着时间的推移,它们逐渐包含了特定输入的占位符,比如AI模型识别的“USER:”。OpenAI通过在人工智能模型处理多个消息字符串之前将其分类为不同的角色,为提示引入了更多的结构。
通常使用ChatModel的call()方法,该方法接受Prompt实例并返回ChatResponse。
Prompt类充当一系列有组织的Message对象和请求ChatOptions的容器。每条消息在提示中都体现了一个独特的角色,其内容和意图各不相同。这些角色可以包含各种元素,从用户查询到人工智能生成的对相关背景信息的响应。这种安排使得与人工智能模型的复杂和详细的交互成为可能,因为提示是由多条消息构建的,每条消息在对话中都被分配了一个特定的角色。
下面是Prompt类的截断版本,为简洁起见省略了构造函数和实用方法:
public class Prompt implements ModelRequest> {
private final List messages;
private ChatOptions chatOptions;
}
Message接口封装了Prompt文本内容、元数据属性集合和称为MessageType的分类。
public interface Content {
String getContent();
Map getMetadata();
}
public interface Message extends Content {
MessageType getMessageType();
}
多模式消息类型还实现了提供媒体内容对象列表的MediaContent接口。
public interface MediaContent extends Content {
Collection getMedia();
}
Message接口的各种实现对应于AI模型可以处理的不同类别的消息。这些模型根据会话角色区分消息类别。
如下所述,MessageType有效地映射了这些角色。
每条消息都被分配了一个特定的角色。这些角色对消息进行分类,阐明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> {
@Override
String apply(String template, Map variables);
}
Spring AI使用TemplateRenderer接口来处理变量到模板字符串中的实际替换。默认实现使用[StringTemplate]。如果需要自定义逻辑,您可以提供自己的TemplateRenderer实现。对于不需要模板渲染的场景(例如,模板字符串已经完成),您可以使用提供的NoOpTemplateRenderer。
使用带有“<”and“>”分隔符的自定义StringTemplate呈现器的示例
PromptTemplate promptTemplate = PromptTemplate.builder()
.renderer(StTemplateRenderer.builder().startDelimiterToken('<').endDelimiterToken('>').build())
.template("""
Tell me the names of 5 movies whose soundtrack was composed by .
""")
.build();
String prompt = promptTemplate.render(Map.of("composer", "John Williams"));
此类实现的接口支持提示创建的不同方面:
PromptTemplateStringActions专注于创建和呈现提示字符串,代表最基本的提示生成形式。
PromptTemplateMessageActions是为通过生成和操作Message对象进行提示创建而定制的。
PromptTemplateActions旨在返回Prompt对象,该对象可以传递给ChatModel以生成响应。
虽然这些接口可能不会在许多项目中广泛使用,但它们展示了提示创建的不同方法。
已实现的接口包括
public interface PromptTemplateStringActions {
String render();
String render(Map model);
}
String render()方法:将提示模板渲染为最终的字符串格式,无需外部输入,适用于没有占位符或动态内容的模板。
方法String render(Map
public interface PromptTemplateMessageActions {
Message createMessage();
Message createMessage(List mediaList);
Message createMessage(Map model);
}
Message createMessage()方法:创建一个不含额外数据的Message对象,用于静态或预定义的消息内容。
方法Message-createMessage(List
Message-createMessage(Map
public interface PromptTemplateActions extends PromptTemplateStringActions {
Prompt create();
Prompt create(ChatOptions modelOptions);
Prompt create(Map model);
Prompt create(Map model, ChatOptions modelOptions);
}
Prompt create()方法:在没有外部数据输入的情况下生成Prompt对象,非常适合静态或预定义的提示。
Prompt create(ChatOptions modelOptions)方法:在没有外部数据输入的情况下生成Prompt对象,并为聊天请求提供特定选项。
Prompt-create(Map
Prompt-create方法(Map
下面显示了一个来自PromptTemplates人工智能研讨会的简单示例。
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();
下面显示了人工智能角色研讨会的另一个例子。
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 response = chatModel.call(prompt).getResults();
这显示了如何使用SystemPromptTemplate创建一个消息,其中系统角色传递占位符值,从而构建Prompt实例。然后,角色用户的消息与角色系统的消息相结合,形成提示。然后将提示传递给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 .
""")
.build();
String prompt = promptTemplate.render(Map.of("composer", "John Williams"));
Spring AI支持org.springframework.core.io.资源抽象,因此您可以将提示数据放在一个文件中,该文件可以直接在PromptTemplate中使用。例如,您可以在Spring托管组件中定义一个字段来检索资源。
@Value("classpath:/prompts/system-message.st")
private Resource systemResource;
在生成式人工智能中,创建提示是开发人员的一项关键任务。这些提示的质量和结构显著影响了人工智能输出的有效性。投入时间和精力设计深思熟虑的提示可以大大提高人工智能的结果。
分享和讨论提示是人工智能社区的一种常见做法。这种协作方法不仅创造了一个共享的学习环境,还导致了高效提示的识别和使用。
该领域的研究通常涉及分析和比较不同的提示,以评估其在各种情况下的有效性。例如,一项重要的研究表明,以“深呼吸,一步一步地解决这个问题”作为提示,可以显著提高解决问题的效率。这突显了精心选择的语言对生成式人工智能系统性能的影响。
掌握提示的最有效使用,特别是随着人工智能技术的快速发展,是一个持续的挑战。你应该认识到快速工程的重要性,并考虑利用社区和研究的见解来改进快速创作策略。
在开发提示时,整合几个关键组件以确保清晰性和有效性非常重要:
指令:向人工智能提供清晰直接的指令,类似于你如何与人沟通。这种清晰度对于帮助人工智能“理解”预期是至关重要的。
外部环境:必要时,包括相关背景信息或人工智能响应的具体指导。这种“外部背景”构建了提示,并帮助人工智能掌握整体场景。
用户输入:这是最直接的部分——用户的直接请求或问题构成了提示的核心。
输出指标:这方面可能很棘手。它涉及为AI的响应指定所需的格式,例如JSON。然而,请注意,人工智能可能并不总是严格遵守这种格式。例如,它可能会在实际的JSON数据之前添加一个类似“这是你的JSON”的短语,或者有时会生成一个不准确的类似JSON的结构。
在制作提示时,为人工智能提供预期问答格式的示例非常有益。这种做法有助于人工智能“理解”查询的结构和意图,从而得到更精确和相关的响应。虽然本文档没有深入探讨这些技术,但它们为人工智能快速工程的进一步探索提供了起点。
以下是进一步调查的资源列表。
文本摘要:
将大量文本简化为简洁的摘要,捕捉关键点和主要思想,同时省略不太关键的细节。
问题解答:
重点是根据用户提出的问题,从提供的文本中得出具体的答案。它是关于根据查询精确定位和提取相关信息。
文本分类:
系统地将文本分类到预定义的类别或组中,分析文本并根据其内容将其分配到最合适的类别。
对话:
创建交互式对话,人工智能可以与用户进行来回交流,模拟自然的对话流程。
代码生成:
根据特定的用户需求或描述生成功能代码片段,将自然语言指令翻译成可执行代码。
先进技术
零射击,少射击学习:
使模型能够使用最少或没有特定问题类型的先前示例进行准确的预测或响应,使用学习到的概括来理解和执行新任务。
思维链:
将多个AI响应链接起来,以创建连贯且具有情境意识的对话。它有助于人工智能保持讨论的线索,确保相关性和连续性。
重新行动(理由+行动):
在这种方法中,人工智能首先分析输入(原因),然后确定最合适的行动或响应过程。它将理解与决策相结合。
快速创建和优化框架:
微软提供了一种结构化的方法来开发和改进提示。该框架指导用户创建有效的提示,从人工智能模型中获得所需的响应,优化交互以提高清晰度和效率。
令牌在人工智能模型处理文本的方式中至关重要,它充当了一座桥梁,将单词(如我们所理解的)转换为人工智能模型可以处理的格式。这种转换分为两个阶段:单词在输入时转换为标记,然后这些标记在输出中转换回单词。
标记化是将文本分解为标记的过程,是人工智能模型理解和处理语言的基础。AI模型使用这种标记化格式来理解和响应提示。
为了更好地理解标记,请将它们视为单词的一部分。通常,一个标记代表一个单词的四分之三。例如,莎士比亚的完整作品,总计约90万字,将翻译成约120万个代币。
使用OpenAI Tokenizer UI进行实验,看看单词是如何转换为令牌的。
代币除了在人工智能处理中的技术作用外,还有实际意义,特别是在计费和模型功能方面:
计费:人工智能模型服务通常根据令牌使用情况计费。输入(提示)和输出(响应)都有助于总令牌计数,使更短的提示更具成本效益。
模型限制:不同的AI模型有不同的令牌限制,定义了它们的“上下文窗口”——它们一次可以处理的最大信息量。例如,GPT-3的限制是4K代币,而Claude 2和Meta Llama 2等其他模型的限制是10万个代币,一些研究模型可以处理多达100万个代币。
上下文窗口:模型的令牌限制决定了其上下文窗口。超出此限制的输入不被模型处理。只发送最基本的有效信息集进行处理至关重要。例如,在询问《哈姆雷特》时,不需要包括莎士比亚所有其他作品的象征。
响应元数据:来自AI模型的响应元数据包括使用的令牌数量,这是管理使用和成本的重要信息。