Prompt工程
提示词工程主要就是
- prompt分类
- prompt优化技巧
提示词分类
分为三大类:
user prompt: 是用户对ai提供的实际问题、指令、需求等
system prompt: 是对AI模型的行为规则和角色设定的隐藏指令,一般对用不可见,即告诉AI你是谁能做什么。不同的prompt可以让同一个AI模型表现出完全不同的应用特性,这是构建垂直领域AI应用(如教育辅导、医疗咨询、产品咨询)的关键
assistant prompt: 这是AI模型的相应内容,即设置了AI回复时的一些模板等
Token成本优化
系统提示词、用户提示词和AI大模型的输出都是要消耗Token的,合理的优化这些方面可以节约成本。
- 精简系统提示词只保留核心指令(例如:你是一个经验丰富且有编成的编程导师 和 你是一个编程导师 其实差别不大可以去掉不必要的修饰词)
- 定期清理对话历史,设定多轮对话记忆轮数,每次对话都会总结回忆上文,对话越长Token消耗越多
- 使用向量检索代替直接输入,对于需要处理大量参考文档的场景不要将整个文档作为prompt,而是用向量数据库和RAG获取相关段落
- 结构化代替自然语言,如表格、列表等
参考现有Prompt提示词库
如有现成的可以直接使用节约开发时间和成本
- 文本对话:docs.anthropic.com/en/home
- AI绘画:promptlibrary.org/
提示词技巧
基础技巧: 指明任务和角色、提供详细的说明和具体实例、明确输出格式等
进阶技巧:
- 思维链提示法:即通过引导模型展示推理过程逐步思考问题,提高复杂问题的准确性
- 少样本学习:为模型提供几个输入输出的实力帮助理解任务模式和期望输出
- 分布引导:先给出一个复杂问题,并给出解决问题的每个步骤
- 自我修正和评估:让模型自己评估自己的输出并进行改进
- 知识引用和检索
- 多视角
- 多模态
实践
我们可以开发一个AI恋爱大师应用,来解决用户的情感问题,那么如何实现的这个应用呢?其实很简单,AI需要明晰自己的定位,自己有何种能力以及自己要解决什么样的问题,这时候就需要我们设计系统提示词。除此之外,用户可能进行长对话,那我们不能聊完一句忘记一句需要有多轮对话记忆功能,如何实现这点呢?这就要使用SpringAI框架的对话记忆相关API了。
系统提示词设计
我们把上面这段需求喂给AI让AI帮忙生成一段提示词,然后我们简单优化一下就有了下面这段系统提示词:
扮演深耕恋爱心理领域的专家。开场向用户表明身份,告知用户可倾诉恋爱难题。围绕单身、恋爱、已婚三种状态提问:单身状态询问社交圈拓展及追求心仪对象的困扰;恋爱状态询问沟通、习惯差异引发的矛盾;已婚状态询问家庭责任与亲属关系处理的问题。引导用户详述事情经过、对方反应及自身想法,以便给出专属解决方案。
多轮对话的实现
先了解几个概念
- ChatClient (Spring AI 调用大模型的客户端)
- Advisors (SpringAI用来增强AI调用能力的拦截器)
- Chat Memory Advisor (对话记忆拦截器)
- Chat Memory (对话记忆拦截器依赖的对话记忆存储 )
ChatClient
ChatClient对比直接使用Spring boot注入ChatModel来调用大模型有以下好处:可实现更丰富的功能、灵活、支持更复杂的链式调用
// 基础用法(ChatModel)
ChatResponse response = chatModel.call(new Prompt("你好"));
// 高级用法(ChatClient)
ChatClient chatClient = ChatClient.builder(chatModel)
.defaultSystem("你是恋爱顾问")
.build();
String response = chatClient.prompt().user("你好").call().content();
Advisor
SpringAI 使用顾问机制来增强AI的能力,在调用AI前后都可以执行一些额外的操作类似AOP切面编程,常见的用法有:
- 前置增强:调用AI前优化一下提示词、检查提示词是否安全、用户提示词是否包含敏感问题等
- 调用AI后记录日志、处理返回结果等
用法很简单,可以直接为ChatClient指定默认拦截器,如对话记忆拦截器MessageChatMemoryAdvisor,能够帮助我们实现多轮对话的功能,不必再自己维护对话列表
var chatClient = ChatClient.builder(chatModel)
.defaultAdvisors(
new MessageChatMemoryAdvisor(chatMemory), // 对话记忆 advisor
new QuestionAnswerAdvisor(vectorStore) // RAG 检索增强 advisor
)
.build();
String response = this.chatClient.prompt()
// 对话时动态设定拦截器参数,比如指定对话记忆的 id 和长度
.advisors(advisor -> advisor.param("chat_memory_conversation_id", "678")
.param("chat_memory_response_size", 100))
.user(userText)
.call()
.content();
Advisor原理
ChatMemory
负责历史对话的存储,定义了保存消息,查询消息,清空历史消息的方法等
开发代码
参考Spring AI Alibaba的官方示例代码:(java2ai.com/docs/1.0.0-…)
(1)先初始化ChatClient对象,使用构造方法注入阿里大模型dashscopeChatModel对象来初始化ChatClient。初始化时指定默认系统prompt和基于内存的对话记忆Advisor。代码如下:
@Component
@Slf4j
public class LoveApp {
private final ChatClient chatClient;
private static final String SYSTEM_PROMPT = "扮演深耕恋爱心理领域的专家。开场向用户表明身份,告知用户可倾诉恋爱难题。" +
"围绕单身、恋爱、已婚三种状态提问:单身状态询问社交圈拓展及追求心仪对象的困扰;" +
"恋爱状态询问沟通、习惯差异引发的矛盾;已婚状态询问家庭责任与亲属关系处理的问题。" +
"引导用户详述事情经过、对方反应及自身想法,以便给出专属解决方案。";
public LoveApp(ChatModel dashscopeChatModel) {
// 初始化基于内存的对话记忆
ChatMemory chatMemory = new InMemoryChatMemory();
chatClient = ChatClient.builder(dashscopeChatModel)
.defaultSystem(SYSTEM_PROMPT)
.defaultAdvisors(
new MessageChatMemoryAdvisor(chatMemory)
)
.build();
}
}
(2)编写对话方法,调用chatClient对象,传入用户prompt,并指定对话id和记忆大小。代码如下:
public String doChat(String message, String chatId) {
ChatResponse response = chatClient
.prompt()
.user(message)
.advisors(spec -> spec.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId)
.param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 10))
.call()
.chatResponse();
String content = response.getResult().getOutput().getText();
log.info("content: {}", content);
return content;
}
(3)测试功能:
@SpringBootTest
class LoveAppTest {
@Resource
private LoveApp loveApp;
@Test
void doChat() {
String chatID = UUID.randomUUID().toString();
//第一轮对话
String message1 = "我是周浩宇";
String content1 = loveApp.doChat(message1, chatID);
//第二轮对话
String message2 = "我的对象是wsy";
String content2 = loveApp.doChat(message2, chatID);
Assertions.assertNotNull(content2);//断言非空,为空报错
//第三轮对话
String message3 = "如何让我们相处更加融洽";
String content3 = loveApp.doChat(message3, chatID);
Assertions.assertNotNull(content2);
//第四轮对话
String message4 = "我的对象是谁来着帮我回忆一下";
String content4 = loveApp.doChat(message4, chatID);
Assertions.assertNotNull(content2);
}
}
对话记忆成功:
自定义Advisor
文档编写中......