mirror of
https://github.com/slhaf/Partner.git
synced 2026-05-12 16:53:04 +08:00
- 修复了 MemoryUpdater 中正则表达式提取问题,应先调用matcher.find()进行匹配
- 在 MemorySelector 和 CoreModel 中添加lod.debug()输出模块响应内容 - 修复了某些细节问题 - 调整了 CoreModel 对应的提示词,添加了输入输出示例 - MemoryGraph 中 dialogMap 和 dateIndex 的更新机制存在问题,需要修复
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -46,3 +46,4 @@ build/
|
|||||||
/src/test/java/memory/result/total_input.json
|
/src/test/java/memory/result/total_input.json
|
||||||
/src/test/java/memory/result/input3.json
|
/src/test/java/memory/result/input3.json
|
||||||
/src/test/java/memory/result/input4.json
|
/src/test/java/memory/result/input4.json
|
||||||
|
/src/test/java/memory/result/primary_input.json
|
||||||
|
|||||||
@@ -55,7 +55,6 @@ public class Agent implements TaskCallback, InputReceiver {
|
|||||||
* 向用户返回输出内容
|
* 向用户返回输出内容
|
||||||
*/
|
*/
|
||||||
public void sendToUser(String userInfo,String output){
|
public void sendToUser(String userInfo,String output){
|
||||||
System.out.println(output);
|
|
||||||
messageSender.sendMessage(new InteractionOutputData(output,userInfo));
|
messageSender.sendMessage(new InteractionOutputData(output,userInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,23 +3,14 @@ package work.slhaf.agent.common.model;
|
|||||||
public class ModelConstant {
|
public class ModelConstant {
|
||||||
public static final String CORE_MODEL_PROMPT = """
|
public static final String CORE_MODEL_PROMPT = """
|
||||||
CoreModel 提示词
|
CoreModel 提示词
|
||||||
|
|
||||||
功能说明
|
功能说明
|
||||||
你需要根据用户的当前输入(text)生成恰当的回复。每条用户输入都采用以下格式:
|
你需要根据当前输入的JSON文本生成恰当的回复。
|
||||||
|
|
||||||
```
|
|
||||||
[用户昵称(用户uuid)] 实际输入内容
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
你需要只基于最新一条消息中的用户(即最后一条user类型消息中括号内的uuid)进行回应,仅参考该用户的历史上下文内容。
|
你需要只基于最新一条消息中的用户(即最后一条user类型消息中括号内的uuid)进行回应,仅参考该用户的历史上下文内容。
|
||||||
|
如果其他用户的对话历史中提到的信息能**明确补充该用户的信息背景**(如他人提及该用户、与其对话、对其信息进行补全等),你可以将其作为当前用户的新知识补充。否则,完全忽略其
|
||||||
如果其他用户的对话历史中提到的信息能**明确补充该用户的信息背景**(如他人提及该用户、与其对话、对其信息进行补全等),你可以将其作为当前用户的新知识补充。否则,完全忽略其他用户的内容。
|
|
||||||
|
|
||||||
注意,历史消息中将只包含带有前缀 `[用户昵称(用户uuid)]` 的完整输入文本,不会带有下文提到的额外字段。
|
注意,历史消息中将只包含带有前缀 `[用户昵称(用户uuid)]` 的完整输入文本,不会带有下文提到的额外字段。
|
||||||
|
|
||||||
字段说明
|
字段说明
|
||||||
- text:指的是“原始输入内容”,包含带有前缀 `[用户昵称(用户uuid)]` 的完整输入文本
|
- text:指的是"原始输入内容",包含带有前缀 `[用户昵称(用户uuid)]` 的完整输入文本
|
||||||
- datetime:当text包含时间相关语义时使用
|
- datetime:当text包含时间相关语义时使用
|
||||||
- character:当需要根据角色设定调整语气时使用
|
- character:当需要根据角色设定调整语气时使用
|
||||||
- user_nick:当text中包含对用户的称呼或个性化需求时使用
|
- user_nick:当text中包含对用户的称呼或个性化需求时使用
|
||||||
@@ -32,7 +23,7 @@ public class ModelConstant {
|
|||||||
• datetime:仅当text包含时间表达时生效
|
• datetime:仅当text包含时间表达时生效
|
||||||
• character:仅当角色设定会影响回复风格时生效
|
• character:仅当角色设定会影响回复风格时生效
|
||||||
• user_nick:仅当需要个性化称呼时生效
|
• user_nick:仅当需要个性化称呼时生效
|
||||||
3. 其他所有扩展字段(如memory_slices/static_memory等):
|
3. 其他所有扩展字段(如memory_slices、static_memory等):
|
||||||
- 必须与text内容有明确关联时才参考
|
- 必须与text内容有明确关联时才参考
|
||||||
- 且只考虑当前用户的字段内容,忽略其他用户相关内容
|
- 且只考虑当前用户的字段内容,忽略其他用户相关内容
|
||||||
|
|
||||||
@@ -41,7 +32,7 @@ public class ModelConstant {
|
|||||||
- 禁止引用与当前text无关的历史内容
|
- 禁止引用与当前text无关的历史内容
|
||||||
- 若角色设定与当前对话无关,应自动忽略
|
- 若角色设定与当前对话无关,应自动忽略
|
||||||
- 上文中你的回应可能并没有符合这个格式,但那是经过裁剪后的结果,你需要严格确保本次回应的格式正确
|
- 上文中你的回应可能并没有符合这个格式,但那是经过裁剪后的结果,你需要严格确保本次回应的格式正确
|
||||||
- 输出格式严格为:
|
- 输出格式为:
|
||||||
{
|
{
|
||||||
"text": "响应内容"
|
"text": "响应内容"
|
||||||
}
|
}
|
||||||
@@ -49,21 +40,34 @@ public class ModelConstant {
|
|||||||
核心生成逻辑
|
核心生成逻辑
|
||||||
1. 主内容优先原则
|
1. 主内容优先原则
|
||||||
- 独立分析text字段的语义
|
- 独立分析text字段的语义
|
||||||
- 仅在其他字段能直接辅助理解text的前提下引用(如text中提及“上次说的那个”)
|
- 仅在其他字段能直接辅助理解text的前提下引用(如text中提及"上次说的那个")
|
||||||
- 若text表达独立完整(如新话题),忽略所有非核心字段
|
- 若text表达独立完整(如新话题),忽略所有非核心字段
|
||||||
|
|
||||||
2. 多用户隔离机制
|
2. 多用户隔离机制
|
||||||
- 每条消息都带有格式 `[用户昵称(用户uuid)]`
|
- 每条消息都带有格式 `[用户昵称(用户uuid)]`
|
||||||
- 所有分析仅基于最后一条user消息中的用户进行处理
|
- 所有分析仅基于最后一条user消息中的用户进行处理
|
||||||
- memory_slices/static_memory等内容只会包含该用户的相关信息
|
- memory_slices/static_memory等内容只会包含该用户的相关信息
|
||||||
- 如果历史中其他用户提到了当前用户的信息,可用于补充理解;否则忽略
|
- 如果历史中其他用户提到了当前用户的信息,可用于补充理解;否则忽略
|
||||||
|
|
||||||
3. 无关字段过滤机制
|
3. 无关字段过滤机制
|
||||||
- text短于5个字符(如“在”、“好的”)
|
- text短于5个字符(如"在"、"好的")
|
||||||
- text开启新话题(如“量子计算是什么”)
|
- text开启新话题(如"量子计算是什么")
|
||||||
- text为独立句子,无引用上下文指代
|
- text为独立句子,无引用上下文指代
|
||||||
→ 此类情况强制忽略所有扩展字段
|
→ 此类情况强制忽略所有扩展字段
|
||||||
|
|
||||||
|
输入输出示例
|
||||||
|
|
||||||
|
示例:
|
||||||
|
输入:
|
||||||
|
{
|
||||||
|
"text": "[小王(5gHj)] 上次说的周三会议改到几点了?",
|
||||||
|
"datetime": "2024-03-15 14:30:00",
|
||||||
|
"character": "客服系统",
|
||||||
|
"user_nick": "小王",
|
||||||
|
"user_id": "5gHj"
|
||||||
|
}
|
||||||
|
输出:
|
||||||
|
{
|
||||||
|
"text": "根据系统记录,周三会议已调整为15:00(原14:30),调整通知已于2024-03-14发送。"
|
||||||
|
}
|
||||||
|
|
||||||
最终注意事项
|
最终注意事项
|
||||||
1. 回应内容必须紧扣用户输入,确保基于当前用户的语境
|
1. 回应内容必须紧扣用户输入,确保基于当前用户的语境
|
||||||
@@ -73,6 +77,7 @@ public class ModelConstant {
|
|||||||
5. 若text与memory_slices等扩展字段无关,应完全忽略
|
5. 若text与memory_slices等扩展字段无关,应完全忽略
|
||||||
6. 请确保你对每一轮对话都只针对当前输入用户作出回应,保持多用户上下文隔离的准确性
|
6. 请确保你对每一轮对话都只针对当前输入用户作出回应,保持多用户上下文隔离的准确性
|
||||||
|
|
||||||
|
> 注意!
|
||||||
> 以下模块可能会追加更多内容限制或上下文提示,请确保你的回答能够自然兼容这些后续拼接的内容,并调整输出格式。
|
> 以下模块可能会追加更多内容限制或上下文提示,请确保你的回答能够自然兼容这些后续拼接的内容,并调整输出格式。
|
||||||
|
|
||||||
""";
|
""";
|
||||||
@@ -220,11 +225,12 @@ public class ModelConstant {
|
|||||||
|
|
||||||
|
|
||||||
决策流程
|
决策流程
|
||||||
|
0. 若主题树为空或者未提供主题树,则直接将recall设置为null, 不进行后续判定
|
||||||
1. 首先分析`history`判断当前对话主题上下文
|
1. 首先分析`history`判断当前对话主题上下文
|
||||||
2. 然后分析`text`:
|
2. 然后分析`text`:
|
||||||
a. 检测是否包含具体日期→添加date类型
|
a. 检测是否包含具体日期→添加date类型
|
||||||
b. 检测是否包含新主题→添加topic类型
|
b. 检测是否包含新主题→添加topic类型
|
||||||
3. 最终综合判断`recall`值
|
3. 最终综合判断`recall`值, 如果找到了对应的主题路径,则recall值为true; 否则为false
|
||||||
|
|
||||||
完整示例
|
完整示例
|
||||||
示例1(主题延续):
|
示例1(主题延续):
|
||||||
|
|||||||
@@ -126,6 +126,9 @@ public class MemoryGraph extends PersistableObject {
|
|||||||
this.userDialogMap = new ConcurrentHashMap<>();
|
this.userDialogMap = new ConcurrentHashMap<>();
|
||||||
// this.currentCompressedSessionContext = new ArrayList<>();
|
// this.currentCompressedSessionContext = new ArrayList<>();
|
||||||
this.dialogMap = new HashMap<>();
|
this.dialogMap = new HashMap<>();
|
||||||
|
this.character = """
|
||||||
|
实话实说,不做糖衣炮弹。 采取前瞻性的观点。 始终保持尊重。 乐于分享明确的观点。 保持轻松、随和。 直奔主题。 务实至上。 勇于创新,打破常规思维。使用中文回答所有问题。
|
||||||
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static MemoryGraph getInstance(String id) throws IOException, ClassNotFoundException {
|
public static MemoryGraph getInstance(String id) throws IOException, ClassNotFoundException {
|
||||||
@@ -401,9 +404,10 @@ public class MemoryGraph extends PersistableObject {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void checkCacheDate() {
|
private void checkCacheDate() {
|
||||||
if (cacheDate.isBefore(LocalDate.now())) {
|
if ( cacheDate == null || cacheDate.isBefore(LocalDate.now())) {
|
||||||
memorySliceCache.clear();
|
memorySliceCache.clear();
|
||||||
memoryNodeCacheCounter.clear();
|
memoryNodeCacheCounter.clear();
|
||||||
|
cacheDate = LocalDate.now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ public class CoreModel extends Model implements InteractionModule {
|
|||||||
coreModel = new CoreModel();
|
coreModel = new CoreModel();
|
||||||
coreModel.memoryManager = MemoryManager.getInstance();
|
coreModel.memoryManager = MemoryManager.getInstance();
|
||||||
coreModel.messages = coreModel.memoryManager.getChatMessages();
|
coreModel.messages = coreModel.memoryManager.getChatMessages();
|
||||||
|
coreModel.sessionManager = SessionManager.getInstance();
|
||||||
setModel(config, coreModel, MODEL_KEY, ModelConstant.CORE_MODEL_PROMPT);
|
setModel(config, coreModel, MODEL_KEY, ModelConstant.CORE_MODEL_PROMPT);
|
||||||
log.info("CoreModel注册完毕...");
|
log.info("CoreModel注册完毕...");
|
||||||
}
|
}
|
||||||
@@ -62,6 +63,7 @@ public class CoreModel extends Model implements InteractionModule {
|
|||||||
try {
|
try {
|
||||||
ChatResponse chatResponse = this.chat();
|
ChatResponse chatResponse = this.chat();
|
||||||
response = JSONObject.parse(extractJson(chatResponse.getMessage()));
|
response = JSONObject.parse(extractJson(chatResponse.getMessage()));
|
||||||
|
log.debug("CoreModel 响应内容: {}",response.toString());
|
||||||
this.messages.removeLast();
|
this.messages.removeLast();
|
||||||
this.messages.add(new Message(ChatConstant.Character.USER, interactionContext.getCoreContext().getString("text")));
|
this.messages.add(new Message(ChatConstant.Character.USER, interactionContext.getCoreContext().getString("text")));
|
||||||
Message assistantMessage = new Message(ChatConstant.Character.ASSISTANT, response.getString("text"));
|
Message assistantMessage = new Message(ChatConstant.Character.ASSISTANT, response.getString("text"));
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package work.slhaf.agent.modules.memory.selector;
|
package work.slhaf.agent.modules.memory.selector;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import work.slhaf.agent.core.interaction.InteractionModule;
|
import work.slhaf.agent.core.interaction.InteractionModule;
|
||||||
import work.slhaf.agent.core.interaction.data.InteractionContext;
|
import work.slhaf.agent.core.interaction.data.InteractionContext;
|
||||||
import work.slhaf.agent.core.memory.MemoryManager;
|
import work.slhaf.agent.core.memory.MemoryManager;
|
||||||
@@ -19,6 +20,7 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
|
@Slf4j
|
||||||
public class MemorySelector implements InteractionModule {
|
public class MemorySelector implements InteractionModule {
|
||||||
|
|
||||||
private static MemorySelector memorySelector;
|
private static MemorySelector memorySelector;
|
||||||
@@ -68,7 +70,8 @@ public class MemorySelector implements InteractionModule {
|
|||||||
String userId =interactionContext.getUserId();
|
String userId =interactionContext.getUserId();
|
||||||
//获取主题路径
|
//获取主题路径
|
||||||
ExtractorResult extractorResult = memorySelectExtractor.execute(interactionContext);
|
ExtractorResult extractorResult = memorySelectExtractor.execute(interactionContext);
|
||||||
if (extractorResult.isRecall()) {
|
log.debug("主题路径: {}",extractorResult);
|
||||||
|
if (extractorResult.isRecall() || extractorResult.getMatches().isEmpty()) {
|
||||||
//查找切片
|
//查找切片
|
||||||
List<MemoryResult> memoryResultList = new ArrayList<>();
|
List<MemoryResult> memoryResultList = new ArrayList<>();
|
||||||
setMemoryResultList(memoryResultList, extractorResult.getMatches(),userId);
|
setMemoryResultList(memoryResultList, extractorResult.getMatches(),userId);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public class SliceSelectEvaluator extends Model {
|
|||||||
Config config = Config.getConfig();
|
Config config = Config.getConfig();
|
||||||
sliceSelectEvaluator = new SliceSelectEvaluator();
|
sliceSelectEvaluator = new SliceSelectEvaluator();
|
||||||
sliceSelectEvaluator.setMemoryManager(MemoryManager.getInstance());
|
sliceSelectEvaluator.setMemoryManager(MemoryManager.getInstance());
|
||||||
|
sliceSelectEvaluator.setExecutor(InteractionThreadPoolExecutor.getInstance());
|
||||||
setModel(config, sliceSelectEvaluator, MODEL_KEY, ModelConstant.SLICE_EVALUATOR_PROMPT);
|
setModel(config, sliceSelectEvaluator, MODEL_KEY, ModelConstant.SLICE_EVALUATOR_PROMPT);
|
||||||
log.info("SliceEvaluator注册完毕...");
|
log.info("SliceEvaluator注册完毕...");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -115,12 +115,17 @@ public class MemoryUpdater implements InteractionModule {
|
|||||||
try {
|
try {
|
||||||
//以第一条user对应的id为发起用户
|
//以第一条user对应的id为发起用户
|
||||||
Pattern pattern = Pattern.compile(USERID_REGEX);
|
Pattern pattern = Pattern.compile(USERID_REGEX);
|
||||||
Matcher matcher = pattern.matcher(memoryManager.getChatMessages().getFirst().getContent());
|
Matcher matcher = pattern.matcher(memoryManager.getChatMessages().get(1).getContent());
|
||||||
|
if (!matcher.find()){
|
||||||
|
throw new RuntimeException("未匹配到 userId!");
|
||||||
|
}
|
||||||
String userId = matcher.group(1);
|
String userId = matcher.group(1);
|
||||||
SummarizeResult summarizeResult = memorySummarizer.execute(new SummarizeInput(memoryManager.getChatMessages(), memoryManager.getTopicTree()));
|
SummarizeResult summarizeResult = memorySummarizer.execute(new SummarizeInput(memoryManager.getChatMessages(), memoryManager.getTopicTree()));
|
||||||
MemorySlice memorySlice = getMemorySlice(userId, summarizeResult, memoryManager.getChatMessages());
|
MemorySlice memorySlice = getMemorySlice(userId, summarizeResult, memoryManager.getChatMessages());
|
||||||
//设置involvedUserId
|
//设置involvedUserId
|
||||||
setInvolvedUserId(userId, memorySlice, memoryManager.getChatMessages());
|
List<Message> messages = new ArrayList<>(memoryManager.getChatMessages());
|
||||||
|
messages.removeFirst();
|
||||||
|
setInvolvedUserId(userId, memorySlice, messages);
|
||||||
memoryManager.insertSlice(memorySlice, summarizeResult.getTopicPath());
|
memoryManager.insertSlice(memorySlice, summarizeResult.getTopicPath());
|
||||||
//更新总dialogMap
|
//更新总dialogMap
|
||||||
singleMemorySummary.put("total", summarizeResult.getSummary());
|
singleMemorySummary.put("total", summarizeResult.getSummary());
|
||||||
@@ -147,6 +152,7 @@ public class MemoryUpdater implements InteractionModule {
|
|||||||
if (userId.equals(startUserId)) {
|
if (userId.equals(startUserId)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
memorySlice.setInvolvedUserIds(new ArrayList<>());
|
||||||
memorySlice.getInvolvedUserIds().add(userId);
|
memorySlice.getInvolvedUserIds().add(userId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ public class MemorySummarizer extends Model {
|
|||||||
private SummarizeResult multiSummarizeExecute(String prompt, String messageStr) {
|
private SummarizeResult multiSummarizeExecute(String prompt, String messageStr) {
|
||||||
ChatResponse response = chatClient.runChat(List.of(new Message(ChatConstant.Character.SYSTEM, prompt),
|
ChatResponse response = chatClient.runChat(List.of(new Message(ChatConstant.Character.SYSTEM, prompt),
|
||||||
new Message(ChatConstant.Character.USER, messageStr)));
|
new Message(ChatConstant.Character.USER, messageStr)));
|
||||||
return JSONObject.parseObject(response.getMessage(), SummarizeResult.class);
|
return JSONObject.parseObject(extractJson(response.getMessage()), SummarizeResult.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void singleMessageSummarize(List<Message> chatMessages) {
|
private void singleMessageSummarize(List<Message> chatMessages) {
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ public class PreprocessExecutor {
|
|||||||
|
|
||||||
context.setModulePrompt(new JSONObject());
|
context.setModulePrompt(new JSONObject());
|
||||||
|
|
||||||
|
context.setSingle(inputData.isSingle());
|
||||||
|
context.setFinished(false);
|
||||||
|
|
||||||
return context;
|
return context;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ public class RegexTest {
|
|||||||
@Test
|
@Test
|
||||||
public void regexTest(){
|
public void regexTest(){
|
||||||
String[] examples = {
|
String[] examples = {
|
||||||
"[小明(userId)] 我在开会] (te[]st)",
|
"[小明(abc)] 我在开会] (te[]st)",
|
||||||
"[用户(昵)称(userId)] 你好[呀]",
|
"[用户(昵)称(userId)] 你好[呀]",
|
||||||
"[测试账号(userId)] 这是一个(test(123))消息"
|
"[测试账号(userId)] 这是一个(test(123))消息"
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user