dsh-tdai-memory 0.3.1 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/client.js +4 -3
- package/index.js +436 -436
- package/package.json +1 -1
- package/vendor/tdai/adapters/standalone/llm-runner.js +274 -274
- package/vendor/tdai/config.js +366 -366
- package/vendor/tdai/core/hooks/auto-recall.js +13 -13
- package/vendor/tdai/core/prompts/l1-dedup.js +64 -64
- package/vendor/tdai/core/prompts/l1-extraction.js +98 -98
- package/vendor/tdai/core/prompts/persona-generation.js +125 -125
- package/vendor/tdai/core/prompts/scene-extraction.js +224 -224
- package/vendor/tdai/core/scene/scene-navigation.js +3 -3
- package/vendor/tdai/core/seed/seed-runtime.js +318 -318
- package/vendor/tdai/core/store/sqlite.js +190 -190
- package/vendor/tdai/core/tdai-core.js +450 -450
- package/vendor/tdai/utils/session-header-fetch.js +88 -88
|
@@ -24,19 +24,19 @@ const RECALL_LINE_SEPARATOR = "\n";
|
|
|
24
24
|
* Memory tools usage guide — injected at the end of memory context so the
|
|
25
25
|
* main agent knows how to actively retrieve deeper information.
|
|
26
26
|
*/
|
|
27
|
-
const MEMORY_TOOLS_GUIDE = `<memory-tools-guide>
|
|
28
|
-
## 记忆工具调用指南
|
|
29
|
-
|
|
30
|
-
当上方注入的记忆片段不足以回答用户问题时,可主动调用以下工具获取更多信息:
|
|
31
|
-
|
|
32
|
-
- **tdai_memory_search**:搜索结构化记忆(L1),适用于回忆用户偏好、历史事件节点、规则等关键信息。
|
|
33
|
-
- **tdai_conversation_search**:搜索原始对话(L0),适用于查找具体消息原文、时间线、上下文细节;也可用于补充或校验 memory_search 的结果。
|
|
34
|
-
- **read_file**(Scene Navigation 中的路径):当已定位到相关情境,且需要该场景的完整画像、事件经过或阶段结论时使用。
|
|
35
|
-
|
|
36
|
-
### ⚠️ 调用次数限制
|
|
37
|
-
每轮对话中,tdai_memory_search 和 tdai_conversation_search **合计最多调用 3 次**。
|
|
38
|
-
- 首次搜索无结果时,可换关键词或换工具重试,但总调用次数不要超过 3 次。
|
|
39
|
-
- 若 3 次搜索后仍无结果,说明该信息不在记忆中,请直接根据已有信息回复用户,不要继续搜索。
|
|
27
|
+
const MEMORY_TOOLS_GUIDE = `<memory-tools-guide>
|
|
28
|
+
## 记忆工具调用指南
|
|
29
|
+
|
|
30
|
+
当上方注入的记忆片段不足以回答用户问题时,可主动调用以下工具获取更多信息:
|
|
31
|
+
|
|
32
|
+
- **tdai_memory_search**:搜索结构化记忆(L1),适用于回忆用户偏好、历史事件节点、规则等关键信息。
|
|
33
|
+
- **tdai_conversation_search**:搜索原始对话(L0),适用于查找具体消息原文、时间线、上下文细节;也可用于补充或校验 memory_search 的结果。
|
|
34
|
+
- **read_file**(Scene Navigation 中的路径):当已定位到相关情境,且需要该场景的完整画像、事件经过或阶段结论时使用。
|
|
35
|
+
|
|
36
|
+
### ⚠️ 调用次数限制
|
|
37
|
+
每轮对话中,tdai_memory_search 和 tdai_conversation_search **合计最多调用 3 次**。
|
|
38
|
+
- 首次搜索无结果时,可换关键词或换工具重试,但总调用次数不要超过 3 次。
|
|
39
|
+
- 若 3 次搜索后仍无结果,说明该信息不在记忆中,请直接根据已有信息回复用户,不要继续搜索。
|
|
40
40
|
</memory-tools-guide>`;
|
|
41
41
|
export async function performAutoRecall(params) {
|
|
42
42
|
const { cfg, logger } = params;
|
|
@@ -8,60 +8,60 @@
|
|
|
8
8
|
// ============================
|
|
9
9
|
// System Prompt
|
|
10
10
|
// ============================
|
|
11
|
-
export const CONFLICT_DETECTION_SYSTEM_PROMPT = `你是记忆冲突检测器。批量比较多条【新记忆】与【统一候选记忆池】中的已有记忆,逐条决定如何处理。
|
|
12
|
-
|
|
13
|
-
**输出语言**:\`merged_content\` 使用与候选池中已有记忆相同的语言;JSON 字段名、枚举值、record_id、ISO 时间戳保持英文。
|
|
14
|
-
|
|
15
|
-
## 核心规则
|
|
16
|
-
|
|
17
|
-
- **跨 type 合并**:不同 type(persona / episodic / instruction)的记忆如果语义上描述同一事实/事件,**可以合并**。
|
|
18
|
-
- **多对多合并**:一条新记忆可以同时替换/合并候选池中的**多条**已有记忆(通过 target_ids 数组指定)。
|
|
19
|
-
- 合并后你必须判断新记忆的最佳 type(merged_type)。
|
|
20
|
-
|
|
21
|
-
## 判断逻辑
|
|
22
|
-
|
|
23
|
-
1. **分辨记忆性质**:
|
|
24
|
-
- **状态类**(persona/instruction):偏好、特质、长期设定、相对稳定的事实、行为规则
|
|
25
|
-
- **事件类**(episodic):一次性经历、带时间点的客观记录,建议合并同一件事的前因后果
|
|
26
|
-
|
|
27
|
-
2. **判断是否同一事实/事件**:主体相同、主题一致、时间接近、scene_name 相似
|
|
28
|
-
|
|
29
|
-
3. **选择动作**:
|
|
30
|
-
- "store":视为新信息,新增当前记忆。
|
|
31
|
-
- "skip":已有记忆更好,新记忆无增量或更模糊,忽略当前记忆。
|
|
32
|
-
- "update":同一事实/事件,新记忆在内容或时间上更优(更具体、更晚或纠错),以新记忆为主覆盖旧记忆,可保留旧记忆中仍正确的细节。
|
|
33
|
-
- "merge":同一事实或同一演化过程,多条记忆信息互补且不矛盾,合并成一条更完整记忆,信息尽量不冗余。
|
|
34
|
-
|
|
35
|
-
4. **策略倾向**:
|
|
36
|
-
- 状态类:多条描述同一偏好/特质 → 倾向 merge;无增量 → skip;明确更新 → update
|
|
37
|
-
- 事件类:同一事件的前因后果、不同阶段 → 倾向 merge 为一条完整叙述;完全相同 → skip
|
|
38
|
-
- 跨类型示例:一条 episodic "用户在 2018 年开始做播客" + 一条 persona "用户有播客制作经验" → 可 merge 为一条 persona 或 episodic(取决于信息侧重)
|
|
39
|
-
|
|
40
|
-
5. **timestamp 处理**:
|
|
41
|
-
- merge / update 时,merged_timestamps 应包含**所有相关记忆的时间戳并集**(去重排序)
|
|
42
|
-
- 这样可以保留事件发生的完整时间线
|
|
43
|
-
|
|
44
|
-
## 输出格式
|
|
45
|
-
|
|
46
|
-
严格输出 JSON 数组,每个元素对应一条新记忆的决策。不输出任何其他内容:
|
|
47
|
-
|
|
48
|
-
[
|
|
49
|
-
{
|
|
50
|
-
"record_id": "新记忆的 record_id",
|
|
51
|
-
"action": "store|update|skip|merge",
|
|
52
|
-
"target_ids": ["要删除的候选记忆 record_id 1", "record_id 2"],
|
|
53
|
-
"merged_content": "合并/更新后的记忆内容(merge/update 时必填)",
|
|
54
|
-
"merged_type": "合并后的最佳 type:persona|episodic|instruction(merge/update 时必填)",
|
|
55
|
-
"merged_priority": 85,
|
|
56
|
-
"merged_timestamps": ["合并后的时间戳数组,包含所有新旧记忆时间戳的并集(merge/update 时必填)"]
|
|
57
|
-
}
|
|
58
|
-
]
|
|
59
|
-
|
|
60
|
-
字段说明:
|
|
61
|
-
- target_ids:要删除替换的旧记忆 ID **数组**(可以 1 条或多条)。store/skip 时省略或为空。
|
|
62
|
-
- merged_content:merge/update 时的最终记忆文本。store/skip 时省略。
|
|
63
|
-
- merged_type:merge/update 后记忆应归属的 type。根据合并后内容本质判断。
|
|
64
|
-
- merged_priority:merge/update 后的新优先级(0-100 整数,merge/update 时必填)。合并后信息更完整、更确定,通常应**酌情提升** priority(例如两条 priority 70 的记忆合并后可提升到 80)。参考标准:80-100(核心特质/重要事件),60-79(一般偏好/普通活动),<60(次要信息)。
|
|
11
|
+
export const CONFLICT_DETECTION_SYSTEM_PROMPT = `你是记忆冲突检测器。批量比较多条【新记忆】与【统一候选记忆池】中的已有记忆,逐条决定如何处理。
|
|
12
|
+
|
|
13
|
+
**输出语言**:\`merged_content\` 使用与候选池中已有记忆相同的语言;JSON 字段名、枚举值、record_id、ISO 时间戳保持英文。
|
|
14
|
+
|
|
15
|
+
## 核心规则
|
|
16
|
+
|
|
17
|
+
- **跨 type 合并**:不同 type(persona / episodic / instruction)的记忆如果语义上描述同一事实/事件,**可以合并**。
|
|
18
|
+
- **多对多合并**:一条新记忆可以同时替换/合并候选池中的**多条**已有记忆(通过 target_ids 数组指定)。
|
|
19
|
+
- 合并后你必须判断新记忆的最佳 type(merged_type)。
|
|
20
|
+
|
|
21
|
+
## 判断逻辑
|
|
22
|
+
|
|
23
|
+
1. **分辨记忆性质**:
|
|
24
|
+
- **状态类**(persona/instruction):偏好、特质、长期设定、相对稳定的事实、行为规则
|
|
25
|
+
- **事件类**(episodic):一次性经历、带时间点的客观记录,建议合并同一件事的前因后果
|
|
26
|
+
|
|
27
|
+
2. **判断是否同一事实/事件**:主体相同、主题一致、时间接近、scene_name 相似
|
|
28
|
+
|
|
29
|
+
3. **选择动作**:
|
|
30
|
+
- "store":视为新信息,新增当前记忆。
|
|
31
|
+
- "skip":已有记忆更好,新记忆无增量或更模糊,忽略当前记忆。
|
|
32
|
+
- "update":同一事实/事件,新记忆在内容或时间上更优(更具体、更晚或纠错),以新记忆为主覆盖旧记忆,可保留旧记忆中仍正确的细节。
|
|
33
|
+
- "merge":同一事实或同一演化过程,多条记忆信息互补且不矛盾,合并成一条更完整记忆,信息尽量不冗余。
|
|
34
|
+
|
|
35
|
+
4. **策略倾向**:
|
|
36
|
+
- 状态类:多条描述同一偏好/特质 → 倾向 merge;无增量 → skip;明确更新 → update
|
|
37
|
+
- 事件类:同一事件的前因后果、不同阶段 → 倾向 merge 为一条完整叙述;完全相同 → skip
|
|
38
|
+
- 跨类型示例:一条 episodic "用户在 2018 年开始做播客" + 一条 persona "用户有播客制作经验" → 可 merge 为一条 persona 或 episodic(取决于信息侧重)
|
|
39
|
+
|
|
40
|
+
5. **timestamp 处理**:
|
|
41
|
+
- merge / update 时,merged_timestamps 应包含**所有相关记忆的时间戳并集**(去重排序)
|
|
42
|
+
- 这样可以保留事件发生的完整时间线
|
|
43
|
+
|
|
44
|
+
## 输出格式
|
|
45
|
+
|
|
46
|
+
严格输出 JSON 数组,每个元素对应一条新记忆的决策。不输出任何其他内容:
|
|
47
|
+
|
|
48
|
+
[
|
|
49
|
+
{
|
|
50
|
+
"record_id": "新记忆的 record_id",
|
|
51
|
+
"action": "store|update|skip|merge",
|
|
52
|
+
"target_ids": ["要删除的候选记忆 record_id 1", "record_id 2"],
|
|
53
|
+
"merged_content": "合并/更新后的记忆内容(merge/update 时必填)",
|
|
54
|
+
"merged_type": "合并后的最佳 type:persona|episodic|instruction(merge/update 时必填)",
|
|
55
|
+
"merged_priority": 85,
|
|
56
|
+
"merged_timestamps": ["合并后的时间戳数组,包含所有新旧记忆时间戳的并集(merge/update 时必填)"]
|
|
57
|
+
}
|
|
58
|
+
]
|
|
59
|
+
|
|
60
|
+
字段说明:
|
|
61
|
+
- target_ids:要删除替换的旧记忆 ID **数组**(可以 1 条或多条)。store/skip 时省略或为空。
|
|
62
|
+
- merged_content:merge/update 时的最终记忆文本。store/skip 时省略。
|
|
63
|
+
- merged_type:merge/update 后记忆应归属的 type。根据合并后内容本质判断。
|
|
64
|
+
- merged_priority:merge/update 后的新优先级(0-100 整数,merge/update 时必填)。合并后信息更完整、更确定,通常应**酌情提升** priority(例如两条 priority 70 的记忆合并后可提升到 80)。参考标准:80-100(核心特质/重要事件),60-79(一般偏好/普通活动),<60(次要信息)。
|
|
65
65
|
- merged_timestamps:合并后的时间戳数组。收集新记忆 + 所有被合并旧记忆的时间戳,去重排序。`;
|
|
66
66
|
/**
|
|
67
67
|
* Format the batch conflict detection prompt using a unified candidate pool.
|
|
@@ -122,15 +122,15 @@ export function formatBatchConflictPrompt(matches) {
|
|
|
122
122
|
});
|
|
123
123
|
const newMemoriesText = memoryParts.join("\n\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n\n");
|
|
124
124
|
// Step 4: Assemble final prompt
|
|
125
|
-
return `**输出语言**:\`merged_content\` 使用与候选池中已有记忆相同的语言。
|
|
126
|
-
|
|
127
|
-
${poolSection}
|
|
128
|
-
|
|
129
|
-
${"═".repeat(50)}
|
|
130
|
-
|
|
131
|
-
## 待判断的新记忆(共 ${matches.length} 条)
|
|
132
|
-
|
|
133
|
-
${newMemoriesText}
|
|
134
|
-
|
|
125
|
+
return `**输出语言**:\`merged_content\` 使用与候选池中已有记忆相同的语言。
|
|
126
|
+
|
|
127
|
+
${poolSection}
|
|
128
|
+
|
|
129
|
+
${"═".repeat(50)}
|
|
130
|
+
|
|
131
|
+
## 待判断的新记忆(共 ${matches.length} 条)
|
|
132
|
+
|
|
133
|
+
${newMemoriesText}
|
|
134
|
+
|
|
135
135
|
请逐条判断并输出决策 JSON 数组。当某条新记忆的候选列表为空时,该条直接输出 action=store。`;
|
|
136
136
|
}
|
|
@@ -9,92 +9,92 @@ import { formatForLLM, describeTimeZoneForPrompt } from "../../utils/time.js";
|
|
|
9
9
|
// ============================
|
|
10
10
|
// System Prompt
|
|
11
11
|
// ============================
|
|
12
|
-
export const EXTRACT_MEMORIES_SYSTEM_PROMPT = `你是专业的"情境切分与记忆提取专家"。
|
|
13
|
-
你的任务是分析用户的对话,判断情境切换,并从中提取结构化的核心记忆(仅限 persona, episodic, instruction 三类)。
|
|
14
|
-
|
|
15
|
-
**输出语言**:所有自由文本字段(\`scene_name\`、memory \`content\`)使用与用户消息相同的语言;JSON 字段名、枚举值、ISO 时间戳保持英文。
|
|
16
|
-
|
|
17
|
-
### 任务一:情境切分(Scene Segmentation)
|
|
18
|
-
分析【待提取的新消息】,结合【上一个情境】,判断并输出当前对话的情境。
|
|
19
|
-
- 继承:无明显切换,沿用上一个情境。
|
|
20
|
-
- 切换条件:用户发出明确指令(如"换话题")、意图转变、或提出独立新目标。
|
|
21
|
-
- 一段对话可能只有一个情境,也可能有多个情境(话题多次切换时)。
|
|
22
|
-
- 命名规则:"我(AI)在和xxx(用户身份)做xxx(目标活动)"(**使用上述输出语言**,约 30-50 个字符或等价长度,单句,全局唯一)。
|
|
23
|
-
|
|
24
|
-
---
|
|
25
|
-
|
|
26
|
-
### 任务二:核心记忆提取(Memory Extraction)
|
|
27
|
-
结合背景和当前情境,仅从【待提取的新消息】中提取核心信息。
|
|
28
|
-
|
|
29
|
-
【通用提取原则】
|
|
30
|
-
1. 宁缺毋滥:过滤琐碎闲聊、临时性指令和一次性操作(如"这次、本单");剔除不可靠的边缘信息。
|
|
31
|
-
2. 独立完整:记忆必须"跳出当前对话依然成立",无上下文也能看懂。提取主体必须以"用户(姓名)"或"AI"为核心。
|
|
32
|
-
3. 归纳合并:强关联或因果关系的多条消息,必须合并为一条完整记忆,不可碎片化。
|
|
33
|
-
|
|
34
|
-
【支持提取的三大类型】(必须严格遵守类型规则)
|
|
35
|
-
> 下面给出的"提取句式"和"触发词"仅作为中文骨架参考;**实际 \`content\` 必须按上述输出语言书写**(例如英文用户 → "The user (Maya) is a senior product manager based in Berlin")。
|
|
36
|
-
|
|
37
|
-
1. 个性化记忆 (type: "persona")
|
|
38
|
-
- 定义:用户的稳定属性、偏好、技能、价值观、习惯(如住所、职业、饮食禁忌)。
|
|
39
|
-
- 提取句式:"用户([姓名])喜欢/是/擅长..."
|
|
40
|
-
- 打分 (priority):80-100(健康/禁忌/核心特质);50-70(一般喜好/技能);<50(模糊次要,可丢弃)。
|
|
41
|
-
- 触发词:喜欢、习惯、经常、我这个人...
|
|
42
|
-
|
|
43
|
-
2. 客观事件记忆 (type: "episodic")
|
|
44
|
-
- 定义:客观发生的动作、决定、计划或达成结果。绝不包含纯主观感受。
|
|
45
|
-
- 提取句式:"用户([姓名])在 [最好是精确绝对时间] 于 [地点] [做了某事(可以包含起因、经过、结果)]"。
|
|
46
|
-
- 时间约束:尽量基于消息的 timestamp 推算绝对时间,如能确定则在 metadata 中输出 activity_start_time 和 activity_end_time(ISO 8601格式)。无法确定时可省略。
|
|
47
|
-
- 打分 (priority):80-100(重要事件/计划);60-70(一般完整活动);<60(琐碎事项,直接丢弃)。
|
|
48
|
-
|
|
49
|
-
3. 全局指令记忆 (type: "instruction")
|
|
50
|
-
- 定义:用户对 AI 提出的长期行为规则、格式偏好、语气控制。
|
|
51
|
-
- 提取句式:"用户要求/希望 AI 以后回答时..."
|
|
52
|
-
- 触发词:以后都、从现在开始、记住、必须。
|
|
53
|
-
- 打分 (priority):-1(极其严格的全局死命令);90-100(核心行为规则);70-80(重要要求);<70(临时要求,直接丢弃)。
|
|
54
|
-
|
|
55
|
-
---
|
|
56
|
-
|
|
57
|
-
### 不应该提取的内容
|
|
58
|
-
- 琐碎闲聊、问候;临时性的纯工具性请求(如"这次帮我翻译一下")
|
|
59
|
-
- 一次性操作指令(如"这次、本单"相关)
|
|
60
|
-
- 重复的内容;AI助手自身的行为或输出
|
|
61
|
-
- 不属于以上3类的信息
|
|
62
|
-
- 纯主观感受(不带客观事件的情绪表达)
|
|
63
|
-
|
|
64
|
-
---
|
|
65
|
-
|
|
66
|
-
### 任务三:输出格式规范(JSON)
|
|
67
|
-
返回且仅返回一个合法的 JSON 数组。数组的每一项是一个情境,包含该情境的消息范围和抽取到的记忆:
|
|
68
|
-
|
|
69
|
-
[
|
|
70
|
-
{
|
|
71
|
-
"scene_name": "当前生成或继承的情境名称",
|
|
72
|
-
"message_ids": ["属于该情境的消息ID列表"],
|
|
73
|
-
"memories": [
|
|
74
|
-
{
|
|
75
|
-
"content": "完整、独立的记忆陈述(按对应类型的句式要求)",
|
|
76
|
-
"type": "persona|episodic|instruction",
|
|
77
|
-
"priority": 80,
|
|
78
|
-
"source_message_ids": ["消息ID_1", "消息ID_2"],
|
|
79
|
-
"metadata": {}
|
|
80
|
-
}
|
|
81
|
-
]
|
|
82
|
-
}
|
|
83
|
-
]
|
|
84
|
-
|
|
85
|
-
metadata 字段说明:
|
|
86
|
-
- episodic 类型:如能确定活动时间,填入 {"activity_start_time": "ISO8601", "activity_end_time": "ISO8601"}
|
|
87
|
-
- 其他类型或无法确定时间:输出空对象 {}
|
|
88
|
-
|
|
89
|
-
如果整段对话无有意义的记忆,也要输出情境分割结果,memories 为空数组:
|
|
90
|
-
[
|
|
91
|
-
{
|
|
92
|
-
"scene_name": "情境名称",
|
|
93
|
-
"message_ids": ["id1", "id2"],
|
|
94
|
-
"memories": []
|
|
95
|
-
}
|
|
96
|
-
]
|
|
97
|
-
|
|
12
|
+
export const EXTRACT_MEMORIES_SYSTEM_PROMPT = `你是专业的"情境切分与记忆提取专家"。
|
|
13
|
+
你的任务是分析用户的对话,判断情境切换,并从中提取结构化的核心记忆(仅限 persona, episodic, instruction 三类)。
|
|
14
|
+
|
|
15
|
+
**输出语言**:所有自由文本字段(\`scene_name\`、memory \`content\`)使用与用户消息相同的语言;JSON 字段名、枚举值、ISO 时间戳保持英文。
|
|
16
|
+
|
|
17
|
+
### 任务一:情境切分(Scene Segmentation)
|
|
18
|
+
分析【待提取的新消息】,结合【上一个情境】,判断并输出当前对话的情境。
|
|
19
|
+
- 继承:无明显切换,沿用上一个情境。
|
|
20
|
+
- 切换条件:用户发出明确指令(如"换话题")、意图转变、或提出独立新目标。
|
|
21
|
+
- 一段对话可能只有一个情境,也可能有多个情境(话题多次切换时)。
|
|
22
|
+
- 命名规则:"我(AI)在和xxx(用户身份)做xxx(目标活动)"(**使用上述输出语言**,约 30-50 个字符或等价长度,单句,全局唯一)。
|
|
23
|
+
|
|
24
|
+
---
|
|
25
|
+
|
|
26
|
+
### 任务二:核心记忆提取(Memory Extraction)
|
|
27
|
+
结合背景和当前情境,仅从【待提取的新消息】中提取核心信息。
|
|
28
|
+
|
|
29
|
+
【通用提取原则】
|
|
30
|
+
1. 宁缺毋滥:过滤琐碎闲聊、临时性指令和一次性操作(如"这次、本单");剔除不可靠的边缘信息。
|
|
31
|
+
2. 独立完整:记忆必须"跳出当前对话依然成立",无上下文也能看懂。提取主体必须以"用户(姓名)"或"AI"为核心。
|
|
32
|
+
3. 归纳合并:强关联或因果关系的多条消息,必须合并为一条完整记忆,不可碎片化。
|
|
33
|
+
|
|
34
|
+
【支持提取的三大类型】(必须严格遵守类型规则)
|
|
35
|
+
> 下面给出的"提取句式"和"触发词"仅作为中文骨架参考;**实际 \`content\` 必须按上述输出语言书写**(例如英文用户 → "The user (Maya) is a senior product manager based in Berlin")。
|
|
36
|
+
|
|
37
|
+
1. 个性化记忆 (type: "persona")
|
|
38
|
+
- 定义:用户的稳定属性、偏好、技能、价值观、习惯(如住所、职业、饮食禁忌)。
|
|
39
|
+
- 提取句式:"用户([姓名])喜欢/是/擅长..."
|
|
40
|
+
- 打分 (priority):80-100(健康/禁忌/核心特质);50-70(一般喜好/技能);<50(模糊次要,可丢弃)。
|
|
41
|
+
- 触发词:喜欢、习惯、经常、我这个人...
|
|
42
|
+
|
|
43
|
+
2. 客观事件记忆 (type: "episodic")
|
|
44
|
+
- 定义:客观发生的动作、决定、计划或达成结果。绝不包含纯主观感受。
|
|
45
|
+
- 提取句式:"用户([姓名])在 [最好是精确绝对时间] 于 [地点] [做了某事(可以包含起因、经过、结果)]"。
|
|
46
|
+
- 时间约束:尽量基于消息的 timestamp 推算绝对时间,如能确定则在 metadata 中输出 activity_start_time 和 activity_end_time(ISO 8601格式)。无法确定时可省略。
|
|
47
|
+
- 打分 (priority):80-100(重要事件/计划);60-70(一般完整活动);<60(琐碎事项,直接丢弃)。
|
|
48
|
+
|
|
49
|
+
3. 全局指令记忆 (type: "instruction")
|
|
50
|
+
- 定义:用户对 AI 提出的长期行为规则、格式偏好、语气控制。
|
|
51
|
+
- 提取句式:"用户要求/希望 AI 以后回答时..."
|
|
52
|
+
- 触发词:以后都、从现在开始、记住、必须。
|
|
53
|
+
- 打分 (priority):-1(极其严格的全局死命令);90-100(核心行为规则);70-80(重要要求);<70(临时要求,直接丢弃)。
|
|
54
|
+
|
|
55
|
+
---
|
|
56
|
+
|
|
57
|
+
### 不应该提取的内容
|
|
58
|
+
- 琐碎闲聊、问候;临时性的纯工具性请求(如"这次帮我翻译一下")
|
|
59
|
+
- 一次性操作指令(如"这次、本单"相关)
|
|
60
|
+
- 重复的内容;AI助手自身的行为或输出
|
|
61
|
+
- 不属于以上3类的信息
|
|
62
|
+
- 纯主观感受(不带客观事件的情绪表达)
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
### 任务三:输出格式规范(JSON)
|
|
67
|
+
返回且仅返回一个合法的 JSON 数组。数组的每一项是一个情境,包含该情境的消息范围和抽取到的记忆:
|
|
68
|
+
|
|
69
|
+
[
|
|
70
|
+
{
|
|
71
|
+
"scene_name": "当前生成或继承的情境名称",
|
|
72
|
+
"message_ids": ["属于该情境的消息ID列表"],
|
|
73
|
+
"memories": [
|
|
74
|
+
{
|
|
75
|
+
"content": "完整、独立的记忆陈述(按对应类型的句式要求)",
|
|
76
|
+
"type": "persona|episodic|instruction",
|
|
77
|
+
"priority": 80,
|
|
78
|
+
"source_message_ids": ["消息ID_1", "消息ID_2"],
|
|
79
|
+
"metadata": {}
|
|
80
|
+
}
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
metadata 字段说明:
|
|
86
|
+
- episodic 类型:如能确定活动时间,填入 {"activity_start_time": "ISO8601", "activity_end_time": "ISO8601"}
|
|
87
|
+
- 其他类型或无法确定时间:输出空对象 {}
|
|
88
|
+
|
|
89
|
+
如果整段对话无有意义的记忆,也要输出情境分割结果,memories 为空数组:
|
|
90
|
+
[
|
|
91
|
+
{
|
|
92
|
+
"scene_name": "情境名称",
|
|
93
|
+
"message_ids": ["id1", "id2"],
|
|
94
|
+
"memories": []
|
|
95
|
+
}
|
|
96
|
+
]
|
|
97
|
+
|
|
98
98
|
请严格按上述 JSON 数组格式输出,不要输出任何额外的 Markdown 代码块修饰符(如 \`\`\`json)或解释文本。`;
|
|
99
99
|
// ============================
|
|
100
100
|
// Prompt Builder
|
|
@@ -116,17 +116,17 @@ export function formatExtractionPrompt(params) {
|
|
|
116
116
|
const newText = newMessages
|
|
117
117
|
.map((m) => `[${m.id}] [${m.role}] [${formatForLLM(m.timestamp)}]: ${m.content}`)
|
|
118
118
|
.join("\n\n");
|
|
119
|
-
return `**${describeTimeZoneForPrompt()}**
|
|
120
|
-
|
|
121
|
-
**输出语言**:根据下方"待提取的新消息"中 user 发言的主导语言书写 \`scene_name\` 和 memory \`content\`。
|
|
122
|
-
|
|
123
|
-
【上一个情境】:${previousSceneName}
|
|
124
|
-
|
|
125
|
-
【背景对话】(仅供理解上下文推断关系/时间,严禁从中提取记忆):
|
|
126
|
-
${bgText}
|
|
127
|
-
|
|
128
|
-
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
129
|
-
|
|
130
|
-
【待提取的新消息】(务必结合 timestamp 推算时间,只从这里提取记忆!):
|
|
119
|
+
return `**${describeTimeZoneForPrompt()}**
|
|
120
|
+
|
|
121
|
+
**输出语言**:根据下方"待提取的新消息"中 user 发言的主导语言书写 \`scene_name\` 和 memory \`content\`。
|
|
122
|
+
|
|
123
|
+
【上一个情境】:${previousSceneName}
|
|
124
|
+
|
|
125
|
+
【背景对话】(仅供理解上下文推断关系/时间,严禁从中提取记忆):
|
|
126
|
+
${bgText}
|
|
127
|
+
|
|
128
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
129
|
+
|
|
130
|
+
【待提取的新消息】(务必结合 timestamp 推算时间,只从这里提取记忆!):
|
|
131
131
|
${newText}`;
|
|
132
132
|
}
|