From f31176336dfd5327f56e19fc2ad6d0dc2f2a0b7e Mon Sep 17 00:00:00 2001 From: slhafzjw Date: Tue, 22 Apr 2025 23:35:27 +0800 Subject: [PATCH] =?UTF-8?q?=E8=B0=83=E6=95=B4extractor=E6=8F=90=E7=A4=BA?= =?UTF-8?q?=E8=AF=8D=EF=BC=8C=E9=80=82=E7=94=A8=E4=B8=8E=E6=89=B9=E9=87=8F?= =?UTF-8?q?=E8=AE=B0=E5=BF=86=E5=88=87=E7=89=87=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agent/common/model/ModelConstant.java | 184 ++++++++++--- src/test/java/memory/AITest.java | 252 +++++++++++++----- 2 files changed, 326 insertions(+), 110 deletions(-) diff --git a/src/main/java/work/slhaf/agent/common/model/ModelConstant.java b/src/main/java/work/slhaf/agent/common/model/ModelConstant.java index 114b085c..8c2cc7ca 100644 --- a/src/main/java/work/slhaf/agent/common/model/ModelConstant.java +++ b/src/main/java/work/slhaf/agent/common/model/ModelConstant.java @@ -6,55 +6,161 @@ public class ModelConstant { public static final String SLICE_EVALUATOR_PROMPT = """ """; public static final String TOPIC_EXTRACTOR_PROMPT = """ - # MemorySelectExtractor 提示词 + MemorySelectExtractor 提示词 - ## 功能说明 - 你需要根据用户输入的JSON数据,分析其`text`字段内容,判断是否需要通过主题路径或日期进行记忆查询,并返回标准化格式的JSON响应。 + 功能说明 + 你需要根据用户输入的JSON数据,分析其`text`和`history`字段内容,判断是否需要通过主题路径或日期进行记忆查询,并返回标准化格式的JSON响应。 + 注意:你只需要返回对应的JSON文本 - ## 输入字段说明 - - `text`: 用户输入的文本内容 - - `topic_tree`: 当前可用的主题树结构(括号内数字表示子主题数量) - - `date`: 当前对话发生的日期(用于时间推理) + 输入字段说明 + • `text`: 用户当前输入的文本内容 - ## 输出规则 - 1. 当文本涉及明确主题路径时: - - 使用`"type": "topic"` - - `text`字段格式为"根主题->子主题->子子主题"(必须**完全匹配**topic_tree中的层级,包括从[root]到目标主题的完整路径) - - 示例:{ - "type": "topic", - "text": "工作->项目A->需求文档" + • `topic_tree`: 当前可用的主题树结构(多层级结构,需返回从根节点到目标节点的完整路径) + + • `date`: 当前对话发生的日期(用于时间推理) + + • `history`: 用户与LLM的完整对话历史(用于主题连续性判断) + + + 输出规则 + 1. 基本响应格式: + { + "recall": boolean, + "matches": [ + // 匹配项列表 + ] } - 2. 当文本包含明确可推算的日期时: - - 使用`"type": "date"` - - 日期格式必须为"YYYY-MM-DD" - - 仅接受具体日期(不接受"上周"等模糊表达) - - 示例:{ - "type": "date", - "text": "2024-04-15" - } + 2. 主题提取规则: + • 当当前`text`涉及新主题(与`history`最后N轮对话主题明显不同)时: - 3. 当不需要查询或无法确定时: - - 使用`"type": "none"` - - 示例:{ - "type": "none" - } + ◦ 必须进行主题提取 - ## 完整示例 - 用户输入:{ - "text": "还记得我们讨论过游戏引擎的物理系统实现吗?", + ◦ 匹配`topic_tree`中最接近的完整路径(从根节点到目标节点,如"编程->JavaScript->NodeJS->并发处理") + + • 当主题与历史对话连续时: + + ◦ 除非包含明确的新子主题,否则不重复提取相同主题路径 + + + 3. 日期提取规则(保持不变): + • 仅接受具体日期(YYYY-MM-DD格式) + + • 拒绝所有模糊日期表达 + + + 4. 特殊处理: + • 当检测到主题切换但无法匹配`topic_tree`时: + + { + "recall": false, + "matches": [] + } + • 当历史对话为空时: + + ◦ 视为新主题,按常规规则处理 + + + 决策流程 + 1. 首先分析`history`判断当前对话主题上下文 + 2. 然后分析`text`: + a. 检测是否包含具体日期→添加date类型 + b. 检测是否包含新主题→添加topic类型 + 3. 最终综合判断`recall`值 + + 完整示例 + 示例1(主题延续): + 输入:{ + "text": "关于NodeJS的并发处理,还有哪些要注意的", "topic_tree": " - 技术 (3)[root] - ├── 游戏开发 (2) - │ ├── 图形渲染 (1) - │ └── 物理系统 (0) - └── 人工智能 (1)", - "date": "2024-04-20" + 编程 + ├── JavaScript + │ ├── NodeJS + │ │ ├── 并发处理 + │ │ └── 事件循环 + │ └── Express + │ └── 中间件 + └── Python", + "date": "2024-04-20", + "history": [ + {"role": "user", "content": "说说NodeJS的并发处理机制"}, + {"role": "assistant", "content": "NodeJS的并发处理主要通过..."} + ] + } + 输出:{ + "recall": false, + "matches": [] } - 正确响应:{ - "type": "topic", - "text": "技术->游戏开发->物理系统" + 示例2(主题切换): + 输入:{ + "text": "现在我想了解Express中间件的原理", + "topic_tree": " + 编程 + ├── JavaScript + │ ├── NodeJS + │ │ ├── 并发处理 + │ │ └── 事件循环 + │ └── Express + │ └── 中间件 + └── Python", + "date": "2024-04-20", + "history": [ + {"role": "user", "content": "NodeJS的并发处理怎么实现"}, + {"role": "assistant", "content": "需要..."} + ] + } + 输出:{ + "recall": true, + "matches": [ + {"type": "topic", "text": "编程->JavaScript->Express->中间件"} + ] + } + + 示例3(混合情况): + 输入:{ + "text": "2024-04-15讨论的Python内容和现在的Express需求", + "topic_tree": " + 编程 + ├── JavaScript + │ ├── NodeJS + │ │ ├── 并发处理 + │ │ └── 事件循环 + │ └── Express + │ └── 中间件 + └── Python", + "date": "2024-04-20", + "history": [ + {"role": "user", "content": "需要了解Express框架"}, + {"role": "assistant", "content": "Express是..."} + ] + } + 输出:{ + "recall": true, + "matches": [ + {"type": "date", "text": "2024-04-15"}, + {"type": "topic", "text": "编程->Python"} + ] + } + + 示例4(模糊日期): + 输入:{ + "text": "上周说的那个JavaScript特性", + "topic_tree": " + 编程 + ├── JavaScript + │ ├── NodeJS + │ │ ├── 并发处理 + │ │ └── 事件循环 + │ └── Express + │ └── 中间件 + └── Python", + "date": "2024-04-20", + "history": [...] + } + 输出:{ + "recall": false, + "matches": [] } """; public static final String TASK_EVALUATOR_PROMPT = """ diff --git a/src/test/java/memory/AITest.java b/src/test/java/memory/AITest.java index 6b8a1831..be60b75d 100644 --- a/src/test/java/memory/AITest.java +++ b/src/test/java/memory/AITest.java @@ -7,83 +7,193 @@ import work.slhaf.agent.common.chat.pojo.Message; import java.util.ArrayList; import java.util.List; +import java.util.Scanner; public class AITest { @Test - public void test1(){ - ChatClient client = new ChatClient("https://open.bigmodel.cn/api/paas/v4/chat/completions","3db444552530b7742b0c53425fb93dcc.LcVwYjByht9AC3N9","glm-4-flash"); + public void test1() { + String input = """ + { + "text": "之前处理过Node.js的并发问题,还有Express中间件开发", + "topic_tree": " + 编程 (3)[root] + ├── JavaScript (3) + │ ├── NodeJS (2) + │ │ ├── 并发处理 (0) + │ │ └── 事件循环 (0) + │ └── Express (1) + │ └── 中间件 (0) + └── Python (2)", + "date": "2024-04-10" + } + + """; + run(input); + } + + private void run(String input) { + ChatClient client = new ChatClient("https://open.bigmodel.cn/api/paas/v4/chat/completions", "3db444552530b7742b0c53425fb93dcc.LcVwYjByht9AC3N9", "glm-4-flash-250414"); List messages = new ArrayList<>(); messages.add(new Message(ChatConstant.Character.SYSTEM, """ - # MemorySelectExtractor 提示词 - - ## 功能说明 - 你需要根据用户输入的JSON数据,分析其`text`字段内容,判断是否需要通过主题路径或日期进行记忆查询,并返回标准化格式的JSON响应。 - - ## 输入字段说明 - - `text`: 用户输入的文本内容 - - `topic_tree`: 当前可用的主题树结构(括号内数字表示子主题数量) - - `date`: 当前对话发生的日期(用于时间推理) - - ## 输出规则 - 1. 当文本涉及明确主题路径时: - - 使用`"type": "topic"` - - `text`字段格式为"根主题->子主题->子子主题"(必须**完全匹配**topic_tree中的层级,包括从[root]到目标主题的完整路径) - - 示例:{ - "type": "topic", - "text": "工作->项目A->需求文档" - } - - 2. 当文本包含明确可推算的日期时: - - 使用`"type": "date"` - - 日期格式必须为"YYYY-MM-DD" - - 仅接受具体日期(不接受"上周"等模糊表达) - - 示例:{ - "type": "date", - "text": "2024-04-15" - } - - 3. 当不需要查询或无法确定时: - - 使用`"type": "none"` - - 示例:{ - "type": "none" - } - - ## 完整示例 - 用户输入:{ - "text": "还记得我们讨论过游戏引擎的物理系统实现吗?", - "topic_tree": " - 技术 (3)[root] - ├── 游戏开发 (2) - │ ├── 图形渲染 (1) - │ └── 物理系统 (0) - └── 人工智能 (1)", - "date": "2024-04-20" - } - - 正确响应:{ - "type": "topic", - "text": "技术->游戏开发->物理系统" - } - """)); + MemorySelectExtractor 提示词 + + 功能说明 + 你需要根据用户输入的JSON数据,分析其`text`和`history`字段内容,判断是否需要通过主题路径或日期进行记忆查询,并返回标准化格式的JSON响应。 + 注意:你只需要返回对应的JSON文本 + + 输入字段说明 + • `text`: 用户当前输入的文本内容 + + • `topic_tree`: 当前可用的主题树结构(多层级结构,需返回从根节点到目标节点的完整路径) + + • `date`: 当前对话发生的日期(用于时间推理) + + • `history`: 用户与LLM的完整对话历史(用于主题连续性判断) + + + 输出规则 + 1. 基本响应格式: + { + "recall": boolean, + "matches": [ + // 匹配项列表 + ] + } + + 2. 主题提取规则: + • 当当前`text`涉及新主题(与`history`最后N轮对话主题明显不同)时: + + ◦ 必须进行主题提取 + + ◦ 匹配`topic_tree`中最接近的完整路径(从根节点到目标节点,如"编程->JavaScript->NodeJS->并发处理") + + • 当主题与历史对话连续时: + + ◦ 除非包含明确的新子主题,否则不重复提取相同主题路径 + + + 3. 日期提取规则(保持不变): + • 仅接受具体日期(YYYY-MM-DD格式) + + • 拒绝所有模糊日期表达 + + + 4. 特殊处理: + • 当检测到主题切换但无法匹配`topic_tree`时: + + { + "recall": false, + "matches": [] + } + • 当历史对话为空时: + + ◦ 视为新主题,按常规规则处理 + + + 决策流程 + 1. 首先分析`history`判断当前对话主题上下文 + 2. 然后分析`text`: + a. 检测是否包含具体日期→添加date类型 + b. 检测是否包含新主题→添加topic类型 + 3. 最终综合判断`recall`值 + + 完整示例 + 示例1(主题延续): + 输入:{ + "text": "关于NodeJS的并发处理,还有哪些要注意的", + "topic_tree": " + 编程 + ├── JavaScript + │ ├── NodeJS + │ │ ├── 并发处理 + │ │ └── 事件循环 + │ └── Express + │ └── 中间件 + └── Python", + "date": "2024-04-20", + "history": [ + {"role": "user", "content": "说说NodeJS的并发处理机制"}, + {"role": "assistant", "content": "NodeJS的并发处理主要通过..."} + ] + } + 输出:{ + "recall": false, + "matches": [] + } + + 示例2(主题切换): + 输入:{ + "text": "现在我想了解Express中间件的原理", + "topic_tree": " + 编程 + ├── JavaScript + │ ├── NodeJS + │ │ ├── 并发处理 + │ │ └── 事件循环 + │ └── Express + │ └── 中间件 + └── Python", + "date": "2024-04-20", + "history": [ + {"role": "user", "content": "NodeJS的并发处理怎么实现"}, + {"role": "assistant", "content": "需要..."} + ] + } + 输出:{ + "recall": true, + "matches": [ + {"type": "topic", "text": "编程->JavaScript->Express->中间件"} + ] + } + + 示例3(混合情况): + 输入:{ + "text": "2024-04-15讨论的Python内容和现在的Express需求", + "topic_tree": " + 编程 + ├── JavaScript + │ ├── NodeJS + │ │ ├── 并发处理 + │ │ └── 事件循环 + │ └── Express + │ └── 中间件 + └── Python", + "date": "2024-04-20", + "history": [ + {"role": "user", "content": "需要了解Express框架"}, + {"role": "assistant", "content": "Express是..."} + ] + } + 输出:{ + "recall": true, + "matches": [ + {"type": "date", "text": "2024-04-15"}, + {"type": "topic", "text": "编程->Python"} + ] + } + + 示例4(模糊日期): + 输入:{ + "text": "上周说的那个JavaScript特性", + "topic_tree": " + 编程 + ├── JavaScript + │ ├── NodeJS + │ │ ├── 并发处理 + │ │ └── 事件循环 + │ └── Express + │ └── 中间件 + └── Python", + "date": "2024-04-20", + "history": [...] + } + 输出:{ + "recall": false, + "matches": [] + } + """)); - messages.add(new Message(ChatConstant.Character.USER, """ - { - "text": "上周似乎发生了什么重要的事??", - "topic_tree": " - 汽车工程 (4)[root] - ├── 动力系统 (3) - │ ├── 发动机 (1) - │ └── 新能源电池 (2) - │ ├── 测试标准 (1) - │ └── 安全规范 (1) - └── 车身设计 (1) - 软件开发 (3)[root] - 质量管理 (2)[root] - ├── ISO认证 (1) - └── 行业标准 (1)", - "date": "2024-04-20" - } - """)); + messages.add(new Message(ChatConstant.Character.USER, input)); System.out.println(client.runChat(messages).getMessage()); } }