amrita_plugin_memory 0.2.8__tar.gz → 0.3.0__tar.gz
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.
- amrita_plugin_memory-0.3.0/PKG-INFO +437 -0
- amrita_plugin_memory-0.3.0/README.md +420 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/config.py +36 -22
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/matchers.py +24 -7
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/rethinking/__init__.py +1 -2
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/rethinking/_state.py +27 -4
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/rethinking/backend.py +1 -1
- amrita_plugin_memory-0.3.0/amrita_plugin_memory/rethinking/consts.py +243 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/rethinking/hooks.py +8 -13
- amrita_plugin_memory-0.3.0/amrita_plugin_memory/rethinking/knowledge.py +450 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/rethinking/nodes.py +0 -21
- amrita_plugin_memory-0.3.0/amrita_plugin_memory/rethinking/runner.py +567 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/rethinking/schemas.py +175 -7
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/rethinking/tools.py +230 -12
- amrita_plugin_memory-0.3.0/amrita_plugin_memory/rethinking/types.py +79 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/tools.py +4 -1
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/vector.py +7 -12
- amrita_plugin_memory-0.3.0/amrita_plugin_memory.egg-info/PKG-INFO +437 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory.egg-info/SOURCES.txt +2 -1
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/pyproject.toml +1 -1
- amrita_plugin_memory-0.2.8/PKG-INFO +0 -222
- amrita_plugin_memory-0.2.8/README.md +0 -205
- amrita_plugin_memory-0.2.8/amrita_plugin_memory/rethinking/consts.py +0 -88
- amrita_plugin_memory-0.2.8/amrita_plugin_memory/rethinking/runner.py +0 -387
- amrita_plugin_memory-0.2.8/amrita_plugin_memory/rethinking/workflow.py +0 -34
- amrita_plugin_memory-0.2.8/amrita_plugin_memory.egg-info/PKG-INFO +0 -222
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/LICENSE +0 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/__init__.py +0 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory/embed.py +0 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory.egg-info/dependency_links.txt +0 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory.egg-info/requires.txt +0 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/amrita_plugin_memory.egg-info/top_level.txt +0 -0
- {amrita_plugin_memory-0.2.8 → amrita_plugin_memory-0.3.0}/setup.cfg +0 -0
|
@@ -0,0 +1,437 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: amrita_plugin_memory
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Amrita长期记忆插件
|
|
5
|
+
Requires-Python: <3.14,>=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Requires-Dist: aiohttp>=3.13.3
|
|
9
|
+
Requires-Dist: aiologic>=0.16.0
|
|
10
|
+
Requires-Dist: amrita-core>=0.8.5
|
|
11
|
+
Requires-Dist: amrita>=1.3
|
|
12
|
+
Requires-Dist: chromadb>=1.5.8
|
|
13
|
+
Requires-Dist: nonebot-plugin-amrita>=0.2.2
|
|
14
|
+
Requires-Dist: nonebot-plugin-apscheduler>=0.5.0
|
|
15
|
+
Requires-Dist: nonebot-plugin-localstore>=0.7.4
|
|
16
|
+
Dynamic: license-file
|
|
17
|
+
|
|
18
|
+
# amrita_plugin_memory
|
|
19
|
+
|
|
20
|
+
基于向量数据库与 Loop Engineering 的长期记忆与知识库插件 — 双层架构:表层 Function Calling 记忆工具 + 底层事件驱动潜意识推理。
|
|
21
|
+
|
|
22
|
+
- **表层** — LLM 对话中按需调用记忆工具(读写删改列),ChromaDB 语义检索。
|
|
23
|
+
- **底层** — 用户发消息时触发后台 Agent 整理记忆库,基于 Core Agent 框架复用 ChatObject 管线。
|
|
24
|
+
|
|
25
|
+
## 安装
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
ambot plugin add amrita_plugin_memory
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
前置依赖:Python 3.11+ / AmritaBot 实例 / Ollama 或 OpenAI 嵌入服务 / ChromaDB。
|
|
32
|
+
|
|
33
|
+
## 快速开始
|
|
34
|
+
|
|
35
|
+
### 1. 配置环境变量(`.env`)
|
|
36
|
+
|
|
37
|
+
```env
|
|
38
|
+
VECTOR_DB_TYPE=local
|
|
39
|
+
EMBEDDING_MODEL_URL=http://127.0.0.1:11434
|
|
40
|
+
EMBEDDING_MODEL_NAME=auto
|
|
41
|
+
EMBEDDING_PROCTOL=ollama-embed
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 2. 开启表层记忆
|
|
45
|
+
|
|
46
|
+
表层记忆开箱即用,无需额外配置。LLM 会在需要时自动调用 `write_memory` / `read_memory` 等工具。
|
|
47
|
+
|
|
48
|
+
### 3. 开启潜意识推理(可选)
|
|
49
|
+
|
|
50
|
+
编辑 `config/amrita_plugin_memory/config.toml`:
|
|
51
|
+
|
|
52
|
+
```toml
|
|
53
|
+
[subconscious]
|
|
54
|
+
enabled = true
|
|
55
|
+
target_user_id = "你的QQ号"
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
设置 `target_user_id` 为目标用户的 QQ 号,重启 Bot 即可。用户每次发消息后,后台 Agent 会在 30 分钟后自动整理记忆库。
|
|
59
|
+
|
|
60
|
+
> **适用场景**:潜意识推理专为**个人助理**场景设计——单个 Bot 服务单个用户。它会在后台持续调用 LLM 进行记忆整理,**每轮推理可能消耗数万 tokens**。如果 Bot 服务于大量用户或对 token 成本敏感,建议保持 `enabled = false`。
|
|
61
|
+
|
|
62
|
+
如需允许 Agent 主动给用户发私聊消息,额外开启:
|
|
63
|
+
|
|
64
|
+
```toml
|
|
65
|
+
allow_send_to_user = true
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
如需关闭全局知识库以节省 token:
|
|
69
|
+
|
|
70
|
+
```toml
|
|
71
|
+
enable_knowledge = false
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
### 4. 验证
|
|
75
|
+
|
|
76
|
+
观察日志中 `[Subconscious]` 前缀的输出:
|
|
77
|
+
|
|
78
|
+
```text
|
|
79
|
+
[Subconscious] Starting for user=你的QQ号
|
|
80
|
+
[Subconscious] Idle — waiting for user chat to trigger first run
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
用户发消息后约 30 分钟,会看到 `Cycle #1` 开始执行。
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
## 双层架构
|
|
88
|
+
|
|
89
|
+
```mermaid
|
|
90
|
+
flowchart TB
|
|
91
|
+
subgraph Surface["表层:Long-Term Memory Tools"]
|
|
92
|
+
S_LLM["对话 LLM"] -->|"write_memory"| S_Write["写入记忆"]
|
|
93
|
+
S_LLM -->|"read_memory"| S_Read["语义检索"]
|
|
94
|
+
S_LLM -->|"update/delete/list"| S_Mut["更新 / 删除 / 列表"]
|
|
95
|
+
S_Write --> ChromaDB[("ChromaDB<br/>向量数据库")]
|
|
96
|
+
S_Read --> ChromaDB
|
|
97
|
+
S_Mut --> ChromaDB
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
subgraph Subconscious["底层:Subconscious Reasoning"]
|
|
101
|
+
UserChat["用户发消息"] --> Hook["on_precompletion hook"]
|
|
102
|
+
Hook -->|"cancel_and_reschedule"| Scheduler["APScheduler<br/>指数惩罚延迟"]
|
|
103
|
+
Scheduler --> Runner["SubconsciousRunner"]
|
|
104
|
+
Runner --> ChatObject["ChatObject<br/>(容器)"]
|
|
105
|
+
ChatObject --> WF["Workflow 管线"]
|
|
106
|
+
WF --> LM["LIMITING_MEMORY<br/>Core MemoryLimiter"]
|
|
107
|
+
LM --> Build["BUILD_MESSAGE"]
|
|
108
|
+
Build --> AgentLoop["ReAct Agent Loop"]
|
|
109
|
+
AgentLoop -->|"工具调用"| STools["subconscious_* 工具"]
|
|
110
|
+
STools --> ChromaDB
|
|
111
|
+
AgentLoop --> KB["KnowledgeBaseManager<br/>文件 + JSON + ChromaDB"]
|
|
112
|
+
AgentLoop --> Profile["用户画像<br/>行级增量更新"]
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
Surface -->|"knowledge_* 工具"| KB
|
|
116
|
+
Surface -.->|"共享 ChromaDB"| Subconscious
|
|
117
|
+
Runner -->|"持久化状态"| CachedRepo["CachedUserDataRepository"]
|
|
118
|
+
Runner -->|"usage 统计"| Insights["InsightsModel<br/>全局 Token 统计"]
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## 功能
|
|
122
|
+
|
|
123
|
+
### 表层:长期记忆
|
|
124
|
+
|
|
125
|
+
| 功能 | 说明 |
|
|
126
|
+
| -------- | ---------------------------------------------- |
|
|
127
|
+
| 语义检索 | ChromaDB 嵌入向量相似度搜索 |
|
|
128
|
+
| 分区隔离 | `scope="user"` 个人 / `scope="group"` 群共享 |
|
|
129
|
+
| 重要性 | low / medium / high 三级,支持过滤 |
|
|
130
|
+
| 标签分类 | 自定义标签(preference、project、personal 等) |
|
|
131
|
+
| 过期清理 | 短期 7 天 / 长期 90 天 |
|
|
132
|
+
| 并发安全 | 用户 ID 粒度 `aiologic.Lock` |
|
|
133
|
+
|
|
134
|
+
### 底层:潜意识推理
|
|
135
|
+
|
|
136
|
+
| 功能 | 说明 |
|
|
137
|
+
| ------------ | --------------------------------------------------------- |
|
|
138
|
+
| 事件驱动 | 用户发消息触发,无活动则永远空闲 |
|
|
139
|
+
| 惩罚退避 | 连续触发时指数延长延迟(30min→45min→...→1440min) |
|
|
140
|
+
| 自动整理 | LLM 后台去重、合并、标签补全、低质清理 |
|
|
141
|
+
| 记忆压缩 | Core `MemoryLimiter` 截断超限 + 自动摘要 |
|
|
142
|
+
| 去重辅助 | `subconscious_duplicate_helper` 返回待整理记忆 + 合并指导 |
|
|
143
|
+
| 统计概览 | `subconscious_get_memory_stats` 总量/重要性/标签分布 |
|
|
144
|
+
| 膨胀感知 | ChromaDB 超 `memory_warn_threshold` 时注入压缩提示 |
|
|
145
|
+
| 滑动窗口 | `max_abstracts` 轮摘要保留,跨轮传递进度 |
|
|
146
|
+
| 用户画像 | 行级增量更新,Markdown 文件持久化 |
|
|
147
|
+
| Session 摘要 | MemoryLimiter 全量摘要 + LRU 缓存 |
|
|
148
|
+
| 主动消息 | LLM 向用户发起主动问候(需 `allow_send_to_user`) |
|
|
149
|
+
| Token 统计 | 复用 Bot `InsightsModel` 全局统计 |
|
|
150
|
+
|
|
151
|
+
### 共享:全局知识库
|
|
152
|
+
|
|
153
|
+
知识库是**表层和潜意识双层共享**的资源——知识工具通过双重 `@on_tools` 注册,对话 LLM 和后台 Agent 均可调用。
|
|
154
|
+
|
|
155
|
+
每条知识由三个组件共同管理:
|
|
156
|
+
|
|
157
|
+
```mermaid
|
|
158
|
+
flowchart LR
|
|
159
|
+
subgraph File["Markdown 文件"]
|
|
160
|
+
direction TB
|
|
161
|
+
Title["# 标题"]
|
|
162
|
+
Summary["摘要文本"]
|
|
163
|
+
Sep["---"]
|
|
164
|
+
Body["正文内容"]
|
|
165
|
+
Title --> Summary --> Sep --> Body
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
subgraph Index["JSON 索引"]
|
|
169
|
+
KnowledgeIndex["knowledge_index.json<br/>[{kid, title, summary, ...}]"]
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
subgraph Vector["ChromaDB"]
|
|
173
|
+
Embedding["{kid → embedding(summary)}"]
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
File <-->|"解析/写入"| Index
|
|
177
|
+
File <-->|"向量化/搜索"| Vector
|
|
178
|
+
Index <-->|"校验/修复"| Vector
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**文件格式**:第一行 `# 标题`,然后摘要文本,`---` 之后是正文。框架自动管理分割——LLM 只需传 `title`/`summary`/`body` 三个字段,无需手动处理 `---`。摘要被向量化存入 ChromaDB 用于语义搜索,正文存在文件中支持按行分段读取。
|
|
182
|
+
|
|
183
|
+
**启动自修复**(`validate_on_startup`):启动时计算三方 ID 集合的差集,自动修复四种不一致:
|
|
184
|
+
|
|
185
|
+
| 场景 | 检测 | 修复 |
|
|
186
|
+
| -------- | ---------------------------- | --------------------------- |
|
|
187
|
+
| 孤文件 | 文件在,JSON 索引无 | 解析文件追加到索引 + 向量化 |
|
|
188
|
+
| 孤索引 | JSON 在,文件无 | 从索引中删除 + 清理向量 |
|
|
189
|
+
| 缺向量 | JSON+文件都在,ChromaDB 缺失 | 从摘要重新向量化写入 |
|
|
190
|
+
| 悬空向量 | 向量在,JSON 索引无 | 从 ChromaDB 删除 |
|
|
191
|
+
|
|
192
|
+
**行级读取**:`knowledge_read` 支持 `start_line`/`end_line` 参数——LLM 可以用滑动窗口分段读取长知识,避免一次加载超长内容。`knowledge_search` 只匹配摘要向量,找到相关条目后再用 `knowledge_read` 按需拉取正文。
|
|
193
|
+
|
|
194
|
+
## 工具参考
|
|
195
|
+
|
|
196
|
+
### 表层工具(`tools.py`)
|
|
197
|
+
|
|
198
|
+
| 工具 | 参数 |
|
|
199
|
+
| ------------------ | -------------------------------------------- |
|
|
200
|
+
| `write_memory` | content, tags, importance(enum), scope(enum) |
|
|
201
|
+
| `read_memory` | query, top_k(5), importance?, scope(enum) |
|
|
202
|
+
| `update_memory` | id, scope, content?, tags?, importance? |
|
|
203
|
+
| `delete_memory` | id, scope |
|
|
204
|
+
| `list_memory` | limit, scope |
|
|
205
|
+
| `knowledge_list` | — |
|
|
206
|
+
| `knowledge_read` | kid, start_line?, end_line? |
|
|
207
|
+
| `knowledge_create` | title, summary, body |
|
|
208
|
+
| `knowledge_update` | kid, title?, summary?, body? |
|
|
209
|
+
| `knowledge_delete` | kid |
|
|
210
|
+
| `knowledge_search` | query, top_k? |
|
|
211
|
+
|
|
212
|
+
### 潜意识工具(`rethinking/tools.py`)
|
|
213
|
+
|
|
214
|
+
记忆和 session/画像工具注册在隔离的 `_SUBCONSCIOUS_TOOLS` 上;知识工具通过双重注册同时暴露给表层和潜意识:
|
|
215
|
+
|
|
216
|
+
| 工具 | 用途 |
|
|
217
|
+
| -------------------------------- | -------------------------------------- |
|
|
218
|
+
| `subconscious_read_memory` | 语义检索 |
|
|
219
|
+
| `subconscious_write_memory` | 写入新记忆 |
|
|
220
|
+
| `subconscious_update_memory` | 更新指定 ID 记忆 |
|
|
221
|
+
| `subconscious_delete_memory` | 删除指定 ID 记忆 |
|
|
222
|
+
| `subconscious_list_memory` | 列出全部记忆 |
|
|
223
|
+
| `subconscious_iter_stop` | 结束本轮推理 |
|
|
224
|
+
| `subconscious_send_to_user` | 主动向用户发消息 |
|
|
225
|
+
| `subconscious_read_chat_context` | 读取最近聊天记录 |
|
|
226
|
+
| `subconscious_duplicate_helper` | 去重辅助(返回记忆 + 合并指导 prompt) |
|
|
227
|
+
| `subconscious_get_memory_stats` | 统计概览 |
|
|
228
|
+
| `subconscious_knowledge_list` | 列出全局知识条目 |
|
|
229
|
+
| `subconscious_knowledge_read` | 读取知识条目(支持行滑动) |
|
|
230
|
+
| `subconscious_knowledge_create` | 创建知识条目 |
|
|
231
|
+
| `subconscious_knowledge_update` | 更新知识条目 |
|
|
232
|
+
| `subconscious_knowledge_delete` | 删除知识条目 |
|
|
233
|
+
| `subconscious_knowledge_search` | 语义搜索知识库 |
|
|
234
|
+
| `subconscious_read_sessions` | 读取归档 sessions(LLM 摘要) |
|
|
235
|
+
| `subconscious_get_profile` | 读取用户画像(行滑动窗口) |
|
|
236
|
+
| `subconscious_update_profile` | 增量更新用户画像 |
|
|
237
|
+
|
|
238
|
+
---
|
|
239
|
+
|
|
240
|
+
## 持久化与状态恢复
|
|
241
|
+
|
|
242
|
+
潜意识推理的状态跨重启持久化,确保 Bot 重启后不丢失进度。
|
|
243
|
+
|
|
244
|
+
### 持久化存储
|
|
245
|
+
|
|
246
|
+
| 存储 | 技术 | 存什么 |
|
|
247
|
+
| ---------------- | ----------------------------------------------------- | ------------------------------------------------------------------------------------- |
|
|
248
|
+
| Runner 元状态 | `CachedUserDataRepository`(uid=`amrita_memory`) | `total_runs`、`last_abstracts`(最近 N 轮摘要)、`pending_messages`(待发送消息队列) |
|
|
249
|
+
| 当前摘要 | 同上 `memory_json.abstract` | 最新一轮 MemoryLimiter 产出的摘要,注入 Jinja2 模板 `<SUMMARY>` |
|
|
250
|
+
| Session 摘要缓存 | `LRUCache[int, str]`(最大 128 条) | session DB id → LLM 生成的摘要文本,避免重复调用 MemoryLimiter |
|
|
251
|
+
| 惩罚计数器 | 内存(不持久化) | `_penalty_count`:重启后从 0 开始,等价于"新鲜启动" |
|
|
252
|
+
| 用户画像 | `data/user_profile.md` | Markdown 文件,`summary---body` 格式,行级增量更新 |
|
|
253
|
+
| 全局知识库 | `data/knowledge/` + `knowledge_index.json` + ChromaDB | 三方同步管理 |
|
|
254
|
+
| Token 统计 | `InsightsModel`(复用 Bot ORM) | 全局 prompt/completion token 累加 |
|
|
255
|
+
|
|
256
|
+
### 生命周期
|
|
257
|
+
|
|
258
|
+
```mermaid
|
|
259
|
+
flowchart TD
|
|
260
|
+
Startup["Bot 启动"] --> Load["_load_from_repo()<br/>恢复 total_runs / last_abstracts / pending_messages"]
|
|
261
|
+
Load --> KB["KnowledgeBaseManager<br/>init() + validate_on_startup()"]
|
|
262
|
+
KB --> Idle["进入空闲<br/>等待用户聊天触发"]
|
|
263
|
+
Idle -->|用户发消息| Cancel["cancel_and_reschedule()"]
|
|
264
|
+
Cancel -->|延迟到达| Run["_run() ReAct 循环"]
|
|
265
|
+
Run --> Save1["_save_to_repo()"]
|
|
266
|
+
Run --> Save2["_save_pending_to_repo()"]
|
|
267
|
+
Save1 & Save2 --> Check{"都成功?"}
|
|
268
|
+
Check -->|Yes| Reset["reset_penalty()"]
|
|
269
|
+
Check -->|No| Keep["惩罚不重置<br/>(重试保护)"]
|
|
270
|
+
Reset --> Idle
|
|
271
|
+
Keep --> Idle
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
**跨重启连续性**:`last_abstracts` 通过 Jinja2 模板 `{{ last_abstracts }}` 和 `{{ last_run }}` 注入 prompt,让 Agent 知道"上一轮做了什么"——即使 Bot 重启,推理上下文也能部分延续。
|
|
275
|
+
|
|
276
|
+
**惩罚计数器不持久化**:重启后从 0 开始。设计意图:重启本身就是一次完整的"冷启动",已有的记忆整理结果已经通过 ChromaDB 持久化了,不需要保留旧的退避状态。
|
|
277
|
+
|
|
278
|
+
---
|
|
279
|
+
|
|
280
|
+
## 调度策略
|
|
281
|
+
|
|
282
|
+
**事件驱动 + 指数惩罚退避**。不使用定时自循环——只有目标用户发消息时才触发推理。
|
|
283
|
+
|
|
284
|
+
用户每次聊天 → 取消现有计划 → 惩罚计数 +1 → 重新计算延迟:
|
|
285
|
+
|
|
286
|
+
$$\text{delay} = \min(\text{base} \times \text{multiplier}^{\text{penalty}-1},\ \text{cap})$$
|
|
287
|
+
|
|
288
|
+
默认参数:`base=30min`,`multiplier=1.5`,`cap=1440min`。推理成功后惩罚重置为 0。用户连续聊天会自动推开推理,长时间沉默后恢复正常频率。
|
|
289
|
+
|
|
290
|
+
## Workflow 管线
|
|
291
|
+
|
|
292
|
+
`SubconsciousRunner` 将 ChatObject 作为数据容器,注入自定义 `SubconsciousBackend` + Core `ReActAgentStrategy`:
|
|
293
|
+
|
|
294
|
+
```
|
|
295
|
+
LOAD_STATE → JINJA2_RENDER → LIMITING_MEMORY → BUILD_MESSAGE → REACT_BLOCK
|
|
296
|
+
```
|
|
297
|
+
|
|
298
|
+
`LIMITING_MEMORY` 在 Agent Loop 之前运行 Core `MemoryLimiter`:消息截断 → 摘要生成。`_build_config()` 将 `enable_memory_compress` 和 `loop_detect_threshold` 注入 `AmritaConfig`。
|
|
299
|
+
|
|
300
|
+
## 技术栈
|
|
301
|
+
|
|
302
|
+
| 组件 | 技术 |
|
|
303
|
+
| ---------- | -------------------------------------------------- |
|
|
304
|
+
| 后端框架 | Python 3.10+ / NoneBot2 / AmritaCore / AmritaSense |
|
|
305
|
+
| 向量数据库 | ChromaDB(PersistentClient / HttpClient) |
|
|
306
|
+
| 嵌入模型 | OpenAI Embedding / Ollama Embedding |
|
|
307
|
+
| 调度引擎 | nonebot_plugin_apscheduler(date trigger) |
|
|
308
|
+
| 持久化 | CachedUserDataRepository |
|
|
309
|
+
| Token 统计 | InsightsModel(复用 Bot 全局 usage) |
|
|
310
|
+
| 缓存 | nonebot_plugin_amrita.cache.LRUCache |
|
|
311
|
+
| 配置管理 | Pydantic + TOML |
|
|
312
|
+
| 代码质量 | Ruff + Pyright |
|
|
313
|
+
|
|
314
|
+
## 配置详解
|
|
315
|
+
|
|
316
|
+
### `config/amrita_plugin_memory/config.toml`
|
|
317
|
+
|
|
318
|
+
```toml
|
|
319
|
+
# 记忆过期
|
|
320
|
+
short_term_expiry_days = 7
|
|
321
|
+
long_term_expiry_days = 90
|
|
322
|
+
per_session_memory_limit = 50
|
|
323
|
+
|
|
324
|
+
# 常驻推理循环
|
|
325
|
+
[subconscious]
|
|
326
|
+
enabled = false
|
|
327
|
+
target_user_id = ""
|
|
328
|
+
allowed_tools = []
|
|
329
|
+
max_iterations = 10
|
|
330
|
+
loop_detect_threshold = 3
|
|
331
|
+
rethink_base_delay_minutes = 30
|
|
332
|
+
rethink_penalty_multiplier = 1.5
|
|
333
|
+
rethink_max_delay_minutes = 1440
|
|
334
|
+
prompt_file = "prompt/subconscious_main.md.jinja2"
|
|
335
|
+
prompt_send_file = "prompt/subconscious_send.md.jinja2"
|
|
336
|
+
prompt_knowledge_file = "prompt/knowledge_guide.md.jinja2"
|
|
337
|
+
prompt_profile_file = "prompt/profile_guide.md.jinja2"
|
|
338
|
+
enable_memory_compress = true
|
|
339
|
+
allow_send_to_user = false
|
|
340
|
+
memory_warn_threshold = 100
|
|
341
|
+
max_abstracts = 5
|
|
342
|
+
knowledge_max_chars = 10000
|
|
343
|
+
knowledge_collection_name = "amrita_global_knowledge"
|
|
344
|
+
enable_knowledge = true
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
| 字段 | 默认值 | 说明 |
|
|
348
|
+
| ---------------------------- | -------------------------------------- | ---------------------------------- |
|
|
349
|
+
| `enabled` | `false` | 是否启用潜意识循环 |
|
|
350
|
+
| `target_user_id` | `""` | 目标用户 ID,为空则不启动 |
|
|
351
|
+
| `allowed_tools` | `[]` | 额外可用工具(从全局拉取) |
|
|
352
|
+
| `max_iterations` | `10` | 单轮 ReAct 最大步数(预留) |
|
|
353
|
+
| `loop_detect_threshold` | `3` | 传入 Core `loop_reasoning_trigger` |
|
|
354
|
+
| `rethink_base_delay_minutes` | `30` | 惩罚退避基数 |
|
|
355
|
+
| `rethink_penalty_multiplier` | `1.5` | 惩罚指数倍率 |
|
|
356
|
+
| `rethink_max_delay_minutes` | `1440` | 惩罚延迟上限(1 天) |
|
|
357
|
+
| `prompt_file` | `"prompt/subconscious_main.md.jinja2"` | 主推理提示词模板 |
|
|
358
|
+
| `prompt_send_file` | `"prompt/subconscious_send.md.jinja2"` | 主动消息生成模板 |
|
|
359
|
+
| `prompt_knowledge_file` | `"prompt/knowledge_guide.md.jinja2"` | 知识库使用指南 |
|
|
360
|
+
| `prompt_profile_file` | `"prompt/profile_guide.md.jinja2"` | 画像构建指南 |
|
|
361
|
+
| `enable_memory_compress` | `true` | 传入 Core `enable_memory_abstract` |
|
|
362
|
+
| `allow_send_to_user` | `false` | 允许 Agent 主动发私聊消息 |
|
|
363
|
+
| `memory_warn_threshold` | `100` | ChromaDB 超此数量注入压缩提示 |
|
|
364
|
+
| `max_abstracts` | `5` | 摘要滑动窗口大小 |
|
|
365
|
+
| `knowledge_max_chars` | `10000` | 知识条目单条正文上限 |
|
|
366
|
+
| `knowledge_collection_name` | `"amrita_global_knowledge"` | ChromaDB 知识库 collection |
|
|
367
|
+
| `enable_knowledge` | `true` | 是否启用全局知识库 |
|
|
368
|
+
|
|
369
|
+
### 提示词模板
|
|
370
|
+
|
|
371
|
+
4 个 Jinja2 模板文件位于 `config/amrita_plugin_memory/prompt/`,首次缺失时自动从默认值创建:
|
|
372
|
+
|
|
373
|
+
| 文件 | 用途 | 变量 |
|
|
374
|
+
| ----------------------------- | ------------ | ------------------------------------------------------------------------------------------------ |
|
|
375
|
+
| `subconscious_main.md.jinja2` | 主推理提示词 | `character_prompt`, `last_run`, `last_abstracts`, `current_time`, `target_user_id`, `total_runs` |
|
|
376
|
+
| `subconscious_send.md.jinja2` | 主动消息生成 | `character_prompt`, `intent`, `memory_context`, `current_time` |
|
|
377
|
+
| `knowledge_guide.md.jinja2` | 知识库指南 | 无(纯静态文本,注入主 prompt 末尾) |
|
|
378
|
+
| `profile_guide.md.jinja2` | 画像构建指南 | 无(纯静态文本,注入主 prompt 末尾) |
|
|
379
|
+
|
|
380
|
+
### 环境变量(`.env`)
|
|
381
|
+
|
|
382
|
+
| 变量 | 类型 | 默认值 | 说明 |
|
|
383
|
+
| -------------------------- | ------------------- | ---------------------- | ------------- |
|
|
384
|
+
| `VECTOR_DB_TYPE` | local/remote | local | ChromaDB 类型 |
|
|
385
|
+
| `VECTOR_DB_SERVER` | string | 127.0.0.1 | 远程地址 |
|
|
386
|
+
| `VECTOR_DB_PORT` | int | 8000 | 远程端口 |
|
|
387
|
+
| `VECTOR_DB_SERVER_SSL` | bool | false | 远程 SSL |
|
|
388
|
+
| `VECTOR_DB_REMOTE_HEADERS` | dict | {} | 远程请求头 |
|
|
389
|
+
| `VECTOR_DB_TENANT` | string | default | 租户 |
|
|
390
|
+
| `VECTOR_DB_DATABASE` | string | default | 数据库 |
|
|
391
|
+
| `EMBEDDING_MODEL_URL` | string | http://127.0.0.1:11434 | 嵌入模型地址 |
|
|
392
|
+
| `EMBEDDING_MODEL_NAME` | string | auto | 模型名 |
|
|
393
|
+
| `EMBEDDING_PROCTOL` | openai/ollama-embed | ollama-embed | 协议 |
|
|
394
|
+
| `EMBEDDING_MODEL_API_KEY` | string | (空) | API Key |
|
|
395
|
+
|
|
396
|
+
## 项目结构
|
|
397
|
+
|
|
398
|
+
```
|
|
399
|
+
amrita_plugin_memory/
|
|
400
|
+
├── config.py # 配置模型(SubconsciousConfig / ConfigFile / EnvConfig)
|
|
401
|
+
├── tools.py # 表层记忆工具(write/read/update/delete/list)
|
|
402
|
+
├── vector.py # ChromaDB 封装(AsyncUserMemory / 锁池)
|
|
403
|
+
├── embed.py # 嵌入模型
|
|
404
|
+
├── matchers.py # 匹配器
|
|
405
|
+
├── rethink/ # 潜意识推理子系统
|
|
406
|
+
│ ├── _state.py # 模块级状态(runner / penalty / pending / 隔离工具管理器)
|
|
407
|
+
│ ├── types.py # TypedDict 定义(7 个数据结构)
|
|
408
|
+
│ ├── consts.py # 默认 Prompt 模板 / ensure_prompt_file / load_character_prompt
|
|
409
|
+
│ ├── backend.py # SubconsciousBackend — 隔离的工具 + memory 后端
|
|
410
|
+
│ ├── nodes.py # LIMITING_MEMORY 工作流节点
|
|
411
|
+
│ ├── runner.py # SubconsciousRunner — 核心编排器
|
|
412
|
+
│ ├── hooks.py # on_precompletion hook / 生命周期管理
|
|
413
|
+
│ ├── tools.py # 19 个潜意识工具 handler
|
|
414
|
+
│ ├── schemas.py # 19 个 FunctionDefinitionSchema
|
|
415
|
+
│ └── knowledge.py # KnowledgeBaseManager — 三方同步知识库
|
|
416
|
+
config/amrita_plugin_memory/
|
|
417
|
+
├── config.toml # 插件配置文件
|
|
418
|
+
└── prompt/ # Jinja2 提示词模板
|
|
419
|
+
├── subconscious_main.md.jinja2
|
|
420
|
+
├── subconscious_send.md.jinja2
|
|
421
|
+
├── knowledge_guide.md.jinja2
|
|
422
|
+
├── profile_guide.md.jinja2
|
|
423
|
+
└── README.md
|
|
424
|
+
data/amrita_plugin_memory/
|
|
425
|
+
├── vector_db.chroma/ # ChromaDB 持久化
|
|
426
|
+
├── knowledge/ # 知识文件(KNOWLEDGE_*.md)
|
|
427
|
+
├── knowledge_index.json # 知识索引
|
|
428
|
+
└── user_profile.md # 用户画像
|
|
429
|
+
```
|
|
430
|
+
|
|
431
|
+
## 开发
|
|
432
|
+
|
|
433
|
+
```bash
|
|
434
|
+
uv sync # 安装依赖
|
|
435
|
+
ruff check . # 代码检查
|
|
436
|
+
pyright # 类型检查
|
|
437
|
+
```
|