提示词(Prompt)

所谓的提示词,就是告诉大模型的一些话,分为系统提示词、用户提示词和助理提示词:

  • 系统提示词(System):定义模型的整体行为框架,包括角色定位、对话风格、知识范围等。例如设定模型为”专业医疗顾问”,需基于医学研究提供建议但不可替代诊断。
  • 用户提示词(User):明确用户的具体需求或问题,如”解释人工智能”。通过背景信息、限制条件等帮助模型精准回应。
  • 助理提示词(Assistant):基于用户和系统提示词生成回答,需保持风格一致。例如模型根据用户提问”什么是人工智能”生成解释性内容。

三者共同作用确保输出符合预期:系统设定基调,用户提供具体指令,助理完成内容生成。

系统提示词

系统提示词,即使用@SystemMessage注解来设定角色,塑造AI助手的专业身份,明确助手的能力范围:

1
2
3
4
5
6
7
8
9
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface SystemMessage {
String[] value() default {""}; //系统提示词

String delimiter() default "\n"; //分隔符

String fromResource() default ""; //从资源中加载系统提示词
}

配置@SystemMessage

回到config包内,修改之前SeparateChatAssistant类中的代码为如下所示:

1
2
3
4
5
6
7
8
9
10
11
@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "ollamaChatModel", chatMemoryProvider = "chatMemoryProvider")
public interface SeparateChatAssistant {
/**
* 分离聊天记录
* @param memoryId 聊天id
* @param userMessage 用户消息
*/
@SystemMessage("你是我的好朋友,请用四川话回答问题。") //系统消息提示词
String chat(@MemoryId int memoryId , @UserMessage String userMessage);
}

@SystemMessage注解里配置的内容将在后台转换为SystemMessage对象,并与UserMessage一起发送给大语言模型(LLM)。请注意,@SystemMessage注解里的内容只会发送给大模型一次,如果开发者修改了SystemMessage的内容,那么新的SystemMessage会被发送给大模型,同时之前的聊天记忆将会失效(持久化的除外)。

创建测试接口

在controller包内创建一个名为PromptController的类,里面的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/prompt")
public class PromptController {
@Autowired
private SeparateChatAssistant separateChatAssistant;

/**
* 测试系统提示词
*/
@GetMapping("/systemPrompt")
public String systemPrompt(){
return separateChatAssistant.chat(3,"吃啥子嘛?");
}
}

此时请求体如下:

1
2
3
4
5
6
7
8
9
10
11
[{
"model" : "deepseek-r1",
"messages" : [ {
"role" : "system",
"content" : "你是我的好朋友,请用四川话回答问题。"
}, {
"role" : "user",
"content" : "吃啥子嘛?"
} ],
"stream" : false
}]

启动项目进行测试

启动项目,访问如下地址:

1
http://localhost:8080/prompt/systemPrompt

结果如下所示:

查看一下数据库,可以发现也存有这条记录了,同时显示了提示词的类型:

添加当前时间

如果希望显示今天的日期,那么需要在提示词中添加当前日期的占位符。修改SeparateChatAssistant类中的代码为如下所示:

1
2
3
4
5
6
7
8
9
10
11
@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "ollamaChatModel", chatMemoryProvider = "chatMemoryProvider")
public interface SeparateChatAssistant {
/**
* 分离聊天记录
* @param memoryId 聊天id
* @param userMessage 用户消息
*/
@SystemMessage("你是我的好朋友,请用四川话回答问题。今天是{{current_date}}") //系统消息提示词
String chat(@MemoryId int memoryId , @UserMessage String userMessage);
}

同时PromptController类中的systemPrompt方法也修改为如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/prompt")
public class PromptController {
@Autowired
private SeparateChatAssistant separateChatAssistant;

/**
* 测试系统提示词
*/
@GetMapping("/systemPrompt")
public String systemPrompt(){
return separateChatAssistant.chat(3,"今天几号?应该吃啥子嘛?");
}
}

从资源中加载提示模板

@SystemMessage注解还可以从资源中加载提示模板。在SeparateChatAssistant中新建一个名为chatFromResource的方法,里面的代码如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "ollamaChatModel", chatMemoryProvider = "chatMemoryProvider")
public interface SeparateChatAssistant {
/**
* 分离聊天记录
* @param memoryId 聊天id
* @param userMessage 用户消息
*/
@SystemMessage("你是我的好朋友,请用四川话回答问题。今天是{{current_date}}")
String chat(@MemoryId int memoryId , @UserMessage String userMessage);

@SystemMessage(fromResource = "prompts/assistant.txt")
String chatFromResource(@MemoryId int memoryId , @UserMessage String userMessage);
}

然后创建 resources/prompts/assistant.txt 文件,里面的内容如下:

1
2
你是我的好朋友,请用四川话回答问题,回答问题可以调皮一些。
{{current_date}}表示当前的日期

接着在PromptController类中定义一个名为systemPromptV2的方法,里面的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/prompt")
public class PromptController {
@Autowired
private SeparateChatAssistant separateChatAssistant;

/**
* 测试系统提示词
*/
@GetMapping("/systemPromptV2")
public String systemPromptV2(){
return separateChatAssistant.chatFromResource(3,"今天几号?应该吃啥子嘛?");
}
}

启动项目,访问如下地址:

1
http://localhost:8080/prompt/systemPromptV2

结果如下所示:

用户提示词

用户提示词,即使用@UserMessage注解来获取用户的输入,代码和之前的SystemMessage注解一样:

1
2
3
4
5
6
7
8
9
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD, ElementType.PARAMETER})
public @interface UserMessage {
String[] value() default {""};

String delimiter() default "\n";

String fromResource() default "";
}

配置@UserMessage

回到config包内,修改之前SeparateChatAssistant类中的代码为如下所示:

1
2
3
4
5
6
@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "ollamaChatModel", chatMemoryProvider = "chatMemoryProvider")
public interface SeparateChatAssistant {
@UserMessage("你是我的好朋友,请用四川话回答问题。我的名字叫:{{myName}}")
String chatUser(@MemoryId int memoryId, @V("myName")String userMessage);
}

@UserMessage注解里配置的内容将在后台转换为UserMessage并发送给大语言模型(LLM)。这里我们在用户提示词中使用了myName变量,然后在chatUser方法参数中使用@V(“myName”)String userMessage)注解指定了属性名称为myName,表示使用当前userMessage变量的值来自动替换用户提示词模板中的对应占位符变量myName。

创建测试接口

接着在PromptController类中定义一个名为userPrompt的方法,里面的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/prompt")
public class PromptController {
@Autowired
private SeparateChatAssistant separateChatAssistant;

/**
* 测试用户提示词
*/
@GetMapping("/userPrompt")
public String userPrompt(){
return separateChatAssistant.chatUser(4,"张三");
}
}

此时请求体如下:

1
2
3
4
5
6
7
8
[{
"model" : "deepseek-r1",
"messages" : [ {
"role" : "user",
"content" : "你是我的好朋友,请用四川话回答问题。我的名字叫:张三"
}],
"stream" : false
}]

启动项目进行测试

启动项目,访问如下地址:

1
http://localhost:8080/prompt/userPrompt

结果如下所示:

查看一下数据库,可以发现也存有这条记录了,同时显示了提示词的类型:

指定参数名称

当需要指定传递参数的名称,那么需要使用@V注解:

1
2
@UserMessage("你是我的好朋友,请用四川话回答问题。我的名字叫:{{myName}}")
String chat(@V("message") String userMessage);

如果只有一个参数,那么可以不添加@V注解,但是变量名称要一样:

1
2
@UserMessage("你是我的好朋友,请用四川话回答问题。我的名字叫:{{myName}}")
String chatUser(String myName);

如果有两个或两个以上的参数,那么必须使用@V注解来显示指定传递参数的名称:

1
2
@UserMessage("你是我的好朋友,请用四川话回答问题。我的名字叫:{{myName}}")
String chatUser(@MemoryId int memoryId, @V("myName")String userMessage);

请注意,@UserMessage注解中的内容每次都会和用户的问题组织在一起发送给大模型。

@SystemMessage和@V结合使用

接下来我们通过一个例子,来综合使用系统提示词和用户提示词。

配置注解信息

回到config包内,修改之前SeparateChatAssistant类中的代码为如下所示:

1
2
3
4
5
6
7
8
@AiService(wiringMode = AiServiceWiringMode.EXPLICIT,
chatModel = "ollamaChatModel", chatMemoryProvider = "chatMemoryProvider")
public interface SeparateChatAssistant {

@SystemMessage(fromResource = "prompts/assistantV1.txt")
String chatComplex(@MemoryId int memoryId, @UserMessage String userMessage,
@V("username")String userName, @V("age")int age);
}

@SystemMessage注解表示当前系统提示词来源于prompts/assistantV1.txt文件,然后使用@V(“username”)注解作用在userName变量上,@V(“age”)作用在age变量上,意思就是使用当前的userName和age变量的值来替换prompts/assistantV1.txt文中占位用的username和age变量。

创建资源文件

在resources目录下创建prompts/assistantV1.txt文件:

1
2
3
你是我的好朋友,我叫{{username}},我的年龄是{{age}},
请用四川话回答问题,回答问题可以调皮一些。
今天是:{{current_date}}

创建测试接口

接着在PromptController类中定义一个名为promptAll的方法,里面的代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@RestController
@RequestMapping("/prompt")
public class PromptController {
@Autowired
private SeparateChatAssistant separateChatAssistant;


/**
* 测试提示词综合使用
*/
@GetMapping("/promptAll")
public String promptAll(){
return separateChatAssistant.chatComplex(5,"我是谁,多大了?","王五",20);
}
}

启动项目进行测试

启动项目,访问如下地址:

1
http://localhost:8080/prompt/promptAll

结果如下所示:

查看一下数据库,可以发现也存有这条记录了,同时显示了提示词的类型: