amrita_plugin_memory 0.1.0__tar.gz → 0.1.1__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.1.1/PKG-INFO +181 -0
- amrita_plugin_memory-0.1.1/README.md +166 -0
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory/config.py +4 -1
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory/embed.py +4 -28
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory/tools.py +85 -152
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory/vector.py +28 -7
- amrita_plugin_memory-0.1.1/amrita_plugin_memory.egg-info/PKG-INFO +181 -0
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory.egg-info/requires.txt +1 -1
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/pyproject.toml +2 -2
- amrita_plugin_memory-0.1.0/PKG-INFO +0 -98
- amrita_plugin_memory-0.1.0/README.md +0 -83
- amrita_plugin_memory-0.1.0/amrita_plugin_memory.egg-info/PKG-INFO +0 -98
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/LICENSE +0 -0
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory/__init__.py +0 -0
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory.egg-info/SOURCES.txt +0 -0
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory.egg-info/dependency_links.txt +0 -0
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory.egg-info/top_level.txt +0 -0
- {amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/setup.cfg +0 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: amrita_plugin_memory
|
|
3
|
+
Version: 0.1.1
|
|
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-localstore>=0.7.4
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# amrita_plugin_memory
|
|
17
|
+
|
|
18
|
+
Amrita 长期记忆插件 —— 基于 ChromaDB 向量数据库的智能记忆管理系统,让 AI 助手能够持久化地记住关于用户的重要信息。
|
|
19
|
+
|
|
20
|
+
## 技术栈
|
|
21
|
+
|
|
22
|
+
| 组件 | 技术 |
|
|
23
|
+
|------|------|
|
|
24
|
+
| 后端框架 | Python 3.10+ / NoneBot2 / Amrita Core |
|
|
25
|
+
| 向量数据库 | ChromaDB(支持本地 PersistentClient 与远程 HttpClient) |
|
|
26
|
+
| 嵌入模型 | OpenAI Embedding API / Ollama Embedding API |
|
|
27
|
+
| 配置管理 | Pydantic + TOML |
|
|
28
|
+
| 异步处理 | asyncio + aiologic + aiohttp |
|
|
29
|
+
| 代码质量 | Ruff + Pyright |
|
|
30
|
+
|
|
31
|
+
## 架构概览
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
amrita_plugin_memory/
|
|
35
|
+
├── __init__.py # 插件入口,注册依赖
|
|
36
|
+
├── config.py # 配置模型(ConfigFile / EnvConfig / DataManager)
|
|
37
|
+
├── embed.py # Ollama 嵌入适配器
|
|
38
|
+
├── vector.py # ChromaDB 异步封装(WrappedClientAPI / AsyncUserMemory)
|
|
39
|
+
└── tools.py # 工具函数定义与注册(write/read/update/delete/list)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- **config.py**: 定义配置文件(过期天数、记忆上限)和环境变量(数据库类型、嵌入模型地址等),通过 Pydantic 模型校验。
|
|
43
|
+
- **embed.py**: 实现 Ollama 协议的嵌入适配器,通过 HTTP API 调用 `/api/embed` 端点。
|
|
44
|
+
- **vector.py**: 对 ChromaDB 原生 API 进行 `asyncio.to_thread` 封装,提供异步的集合管理与记忆 CRUD。使用 `aiologic.Lock` 按用户粒度加锁,保证并发安全。
|
|
45
|
+
- **tools.py**: 定义 5 个 Function Calling 工具(`write_memory` / `read_memory` / `update_memory` / `delete_memory` / `list_memory`),注册到 Amrita 的工具系统中。
|
|
46
|
+
|
|
47
|
+
## 功能特点
|
|
48
|
+
|
|
49
|
+
- **长期记忆存储**:将用户偏好、项目信息等持久化存入 ChromaDB 向量数据库
|
|
50
|
+
- **语义检索**:基于嵌入向量的语义相似度检索,支持中英文关键词
|
|
51
|
+
- **智能标签**:支持使用自定义标签对记忆进行分类(如 `preference`、`project`)
|
|
52
|
+
- **重要性分级**:三级重要程度(`low` / `medium` / `high`),支持按级别过滤检索
|
|
53
|
+
- **完整 CRUD**:支持记忆的创建、查询、更新、删除和列表查看
|
|
54
|
+
- **并发安全**:按用户 ID 粒度加锁,确保同一用户的操作串行化
|
|
55
|
+
- **多租户支持**:通过 ChromaDB remote 模式支持远程向量数据库
|
|
56
|
+
|
|
57
|
+
## 工具函数
|
|
58
|
+
|
|
59
|
+
### 1. `write_memory` —— 写入记忆
|
|
60
|
+
|
|
61
|
+
将当前用户(或群组)的重要信息存入长期记忆。
|
|
62
|
+
|
|
63
|
+
| 参数 | 类型 | 必需 | 描述 |
|
|
64
|
+
|------|------|------|------|
|
|
65
|
+
| `content` | string | ✅ | 记忆内容,简洁明了 |
|
|
66
|
+
| `tags` | string | ✅ | 分类标签,如 `preference`、`project` |
|
|
67
|
+
| `importance` | `"low"` / `"medium"` / `"high"` | ✅ | 重要性等级 |
|
|
68
|
+
|
|
69
|
+
### 2. `read_memory` —— 检索记忆
|
|
70
|
+
|
|
71
|
+
从记忆库中按语义相似度检索用户相关信息。
|
|
72
|
+
|
|
73
|
+
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|
|
74
|
+
|------|------|------|--------|------|
|
|
75
|
+
| `query` | string | ✅ | — | 关键词字符串,空格分隔 |
|
|
76
|
+
| `top_k` | integer | ❌ | `5` | 返回结果数量 |
|
|
77
|
+
| `importance` | `"low"` / `"medium"` / `"high"` | ❌ | — | 按重要性过滤 |
|
|
78
|
+
|
|
79
|
+
### 3. `update_memory` —— 更新记忆
|
|
80
|
+
|
|
81
|
+
更新指定 ID 的记忆内容、标签或重要性。
|
|
82
|
+
|
|
83
|
+
| 参数 | 类型 | 必需 | 描述 |
|
|
84
|
+
|------|------|------|------|
|
|
85
|
+
| `id` | string | ✅ | 要更新的记忆 ID |
|
|
86
|
+
| `content` | string | ❌ | 新的记忆内容 |
|
|
87
|
+
| `tags` | string | ❌ | 新的标签 |
|
|
88
|
+
| `importance` | `"low"` / `"medium"` / `"high"` | ❌ | 新的重要性等级 |
|
|
89
|
+
|
|
90
|
+
### 4. `delete_memory` —— 删除记忆
|
|
91
|
+
|
|
92
|
+
删除指定 ID 的记忆。
|
|
93
|
+
|
|
94
|
+
| 参数 | 类型 | 必需 | 描述 |
|
|
95
|
+
|------|------|------|------|
|
|
96
|
+
| `id` | string | ✅ | 要删除的记忆 ID |
|
|
97
|
+
|
|
98
|
+
### 5. `list_memory` —— 列出记忆
|
|
99
|
+
|
|
100
|
+
列出当前用户的所有记忆(返回标签和 ID)。
|
|
101
|
+
|
|
102
|
+
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|
|
103
|
+
|------|------|------|--------|------|
|
|
104
|
+
| `limit` | integer | ❌ | `5` | 返回数量限制 |
|
|
105
|
+
|
|
106
|
+
## 配置选项
|
|
107
|
+
|
|
108
|
+
### 文件配置(`config/amrita_plugin_memory/config.toml`)
|
|
109
|
+
|
|
110
|
+
| 配置项 | 类型 | 默认值 | 描述 |
|
|
111
|
+
|--------|------|--------|------|
|
|
112
|
+
| `short_term_expiry_days` | int | `3` | 短期记忆过期天数 |
|
|
113
|
+
| `long_term_expiry_days` | int | `30` | 长期记忆过期天数 |
|
|
114
|
+
| `permanent_expiry_days` | int | `365` | 永久记忆过期天数 |
|
|
115
|
+
| `per_session_memory_limit` | int | `50` | 每个会话的记忆数量上限 |
|
|
116
|
+
|
|
117
|
+
### 环境变量(`.env` 或系统环境变量)
|
|
118
|
+
|
|
119
|
+
| 变量 | 类型 | 默认值 | 描述 |
|
|
120
|
+
|------|------|--------|------|
|
|
121
|
+
| `VECTOR_DB_TYPE` | `local` / `remote` | `local` | ChromaDB 数据库类型 |
|
|
122
|
+
| `VECTOR_DB_SERVER` | string | `127.0.0.1` | 远程 ChromaDB 地址 |
|
|
123
|
+
| `VECTOR_DB_PORT` | int | `8000` | 远程 ChromaDB 端口 |
|
|
124
|
+
| `VECTOR_DB_SERVER_SSL` | bool | `false` | 是否启用 SSL |
|
|
125
|
+
| `VECTOR_DB_REMOTE_HEADERS` | dict | `{}` | 远程请求头 |
|
|
126
|
+
| `VECTOR_DB_TENANT` | string | `default` | 租户名称 |
|
|
127
|
+
| `VECTOR_DB_DATABASE` | string | `default` | 数据库名称 |
|
|
128
|
+
| `EMBEDDING_MODEL_URL` | string | `http://127.0.0.1:11434` | 嵌入模型地址 |
|
|
129
|
+
| `EMBEDDING_MODEL_NAME` | string | `auto` | 嵌入模型名称 |
|
|
130
|
+
| `EMBEDDING_PROCTOL` | `openai` / `ollama-embed` | `ollama-embed` | 嵌入模型协议 |
|
|
131
|
+
|
|
132
|
+
## 安装与使用
|
|
133
|
+
|
|
134
|
+
### 前置条件
|
|
135
|
+
|
|
136
|
+
- Python 3.10 ~ 3.13
|
|
137
|
+
- 已部署的 [AmritaBot](https://github.com/AmritaBot) 实例
|
|
138
|
+
- (本地模式)无需额外组件
|
|
139
|
+
- (远程模式)已运行的 ChromaDB 服务端
|
|
140
|
+
- 已运行的嵌入模型服务(如 Ollama)
|
|
141
|
+
|
|
142
|
+
### 安装
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
ambot plugin install amrita_plugin_memory
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 配置
|
|
149
|
+
|
|
150
|
+
插件安装后会自动生成配置文件。你可以通过以下方式配置:
|
|
151
|
+
|
|
152
|
+
1. **WebUI 配置**:在 Amrita 的 Web 管理界面中直接修改
|
|
153
|
+
2. **手动编辑**:修改 `config/amrita_plugin_memory/config.toml`
|
|
154
|
+
3. **环境变量**:通过 `.env` 文件或系统环境变量设置数据库和嵌入模型参数
|
|
155
|
+
|
|
156
|
+
### 验证
|
|
157
|
+
|
|
158
|
+
启动后查看日志,确认向量数据库连接成功:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
正在尝试向量数据库连接...
|
|
162
|
+
当前向量数据库类型: local
|
|
163
|
+
创建了向量数据库客户端!
|
|
164
|
+
向量数据库版本:x.x.x
|
|
165
|
+
完成。
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## 开发
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# 安装开发依赖
|
|
172
|
+
uv sync
|
|
173
|
+
|
|
174
|
+
# 代码格式化与检查
|
|
175
|
+
ruff format .
|
|
176
|
+
ruff check .
|
|
177
|
+
|
|
178
|
+
# 类型检查
|
|
179
|
+
pyright
|
|
180
|
+
```
|
|
181
|
+
|
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
# amrita_plugin_memory
|
|
2
|
+
|
|
3
|
+
Amrita 长期记忆插件 —— 基于 ChromaDB 向量数据库的智能记忆管理系统,让 AI 助手能够持久化地记住关于用户的重要信息。
|
|
4
|
+
|
|
5
|
+
## 技术栈
|
|
6
|
+
|
|
7
|
+
| 组件 | 技术 |
|
|
8
|
+
|------|------|
|
|
9
|
+
| 后端框架 | Python 3.10+ / NoneBot2 / Amrita Core |
|
|
10
|
+
| 向量数据库 | ChromaDB(支持本地 PersistentClient 与远程 HttpClient) |
|
|
11
|
+
| 嵌入模型 | OpenAI Embedding API / Ollama Embedding API |
|
|
12
|
+
| 配置管理 | Pydantic + TOML |
|
|
13
|
+
| 异步处理 | asyncio + aiologic + aiohttp |
|
|
14
|
+
| 代码质量 | Ruff + Pyright |
|
|
15
|
+
|
|
16
|
+
## 架构概览
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
amrita_plugin_memory/
|
|
20
|
+
├── __init__.py # 插件入口,注册依赖
|
|
21
|
+
├── config.py # 配置模型(ConfigFile / EnvConfig / DataManager)
|
|
22
|
+
├── embed.py # Ollama 嵌入适配器
|
|
23
|
+
├── vector.py # ChromaDB 异步封装(WrappedClientAPI / AsyncUserMemory)
|
|
24
|
+
└── tools.py # 工具函数定义与注册(write/read/update/delete/list)
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
- **config.py**: 定义配置文件(过期天数、记忆上限)和环境变量(数据库类型、嵌入模型地址等),通过 Pydantic 模型校验。
|
|
28
|
+
- **embed.py**: 实现 Ollama 协议的嵌入适配器,通过 HTTP API 调用 `/api/embed` 端点。
|
|
29
|
+
- **vector.py**: 对 ChromaDB 原生 API 进行 `asyncio.to_thread` 封装,提供异步的集合管理与记忆 CRUD。使用 `aiologic.Lock` 按用户粒度加锁,保证并发安全。
|
|
30
|
+
- **tools.py**: 定义 5 个 Function Calling 工具(`write_memory` / `read_memory` / `update_memory` / `delete_memory` / `list_memory`),注册到 Amrita 的工具系统中。
|
|
31
|
+
|
|
32
|
+
## 功能特点
|
|
33
|
+
|
|
34
|
+
- **长期记忆存储**:将用户偏好、项目信息等持久化存入 ChromaDB 向量数据库
|
|
35
|
+
- **语义检索**:基于嵌入向量的语义相似度检索,支持中英文关键词
|
|
36
|
+
- **智能标签**:支持使用自定义标签对记忆进行分类(如 `preference`、`project`)
|
|
37
|
+
- **重要性分级**:三级重要程度(`low` / `medium` / `high`),支持按级别过滤检索
|
|
38
|
+
- **完整 CRUD**:支持记忆的创建、查询、更新、删除和列表查看
|
|
39
|
+
- **并发安全**:按用户 ID 粒度加锁,确保同一用户的操作串行化
|
|
40
|
+
- **多租户支持**:通过 ChromaDB remote 模式支持远程向量数据库
|
|
41
|
+
|
|
42
|
+
## 工具函数
|
|
43
|
+
|
|
44
|
+
### 1. `write_memory` —— 写入记忆
|
|
45
|
+
|
|
46
|
+
将当前用户(或群组)的重要信息存入长期记忆。
|
|
47
|
+
|
|
48
|
+
| 参数 | 类型 | 必需 | 描述 |
|
|
49
|
+
|------|------|------|------|
|
|
50
|
+
| `content` | string | ✅ | 记忆内容,简洁明了 |
|
|
51
|
+
| `tags` | string | ✅ | 分类标签,如 `preference`、`project` |
|
|
52
|
+
| `importance` | `"low"` / `"medium"` / `"high"` | ✅ | 重要性等级 |
|
|
53
|
+
|
|
54
|
+
### 2. `read_memory` —— 检索记忆
|
|
55
|
+
|
|
56
|
+
从记忆库中按语义相似度检索用户相关信息。
|
|
57
|
+
|
|
58
|
+
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|
|
59
|
+
|------|------|------|--------|------|
|
|
60
|
+
| `query` | string | ✅ | — | 关键词字符串,空格分隔 |
|
|
61
|
+
| `top_k` | integer | ❌ | `5` | 返回结果数量 |
|
|
62
|
+
| `importance` | `"low"` / `"medium"` / `"high"` | ❌ | — | 按重要性过滤 |
|
|
63
|
+
|
|
64
|
+
### 3. `update_memory` —— 更新记忆
|
|
65
|
+
|
|
66
|
+
更新指定 ID 的记忆内容、标签或重要性。
|
|
67
|
+
|
|
68
|
+
| 参数 | 类型 | 必需 | 描述 |
|
|
69
|
+
|------|------|------|------|
|
|
70
|
+
| `id` | string | ✅ | 要更新的记忆 ID |
|
|
71
|
+
| `content` | string | ❌ | 新的记忆内容 |
|
|
72
|
+
| `tags` | string | ❌ | 新的标签 |
|
|
73
|
+
| `importance` | `"low"` / `"medium"` / `"high"` | ❌ | 新的重要性等级 |
|
|
74
|
+
|
|
75
|
+
### 4. `delete_memory` —— 删除记忆
|
|
76
|
+
|
|
77
|
+
删除指定 ID 的记忆。
|
|
78
|
+
|
|
79
|
+
| 参数 | 类型 | 必需 | 描述 |
|
|
80
|
+
|------|------|------|------|
|
|
81
|
+
| `id` | string | ✅ | 要删除的记忆 ID |
|
|
82
|
+
|
|
83
|
+
### 5. `list_memory` —— 列出记忆
|
|
84
|
+
|
|
85
|
+
列出当前用户的所有记忆(返回标签和 ID)。
|
|
86
|
+
|
|
87
|
+
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|
|
88
|
+
|------|------|------|--------|------|
|
|
89
|
+
| `limit` | integer | ❌ | `5` | 返回数量限制 |
|
|
90
|
+
|
|
91
|
+
## 配置选项
|
|
92
|
+
|
|
93
|
+
### 文件配置(`config/amrita_plugin_memory/config.toml`)
|
|
94
|
+
|
|
95
|
+
| 配置项 | 类型 | 默认值 | 描述 |
|
|
96
|
+
|--------|------|--------|------|
|
|
97
|
+
| `short_term_expiry_days` | int | `3` | 短期记忆过期天数 |
|
|
98
|
+
| `long_term_expiry_days` | int | `30` | 长期记忆过期天数 |
|
|
99
|
+
| `permanent_expiry_days` | int | `365` | 永久记忆过期天数 |
|
|
100
|
+
| `per_session_memory_limit` | int | `50` | 每个会话的记忆数量上限 |
|
|
101
|
+
|
|
102
|
+
### 环境变量(`.env` 或系统环境变量)
|
|
103
|
+
|
|
104
|
+
| 变量 | 类型 | 默认值 | 描述 |
|
|
105
|
+
|------|------|--------|------|
|
|
106
|
+
| `VECTOR_DB_TYPE` | `local` / `remote` | `local` | ChromaDB 数据库类型 |
|
|
107
|
+
| `VECTOR_DB_SERVER` | string | `127.0.0.1` | 远程 ChromaDB 地址 |
|
|
108
|
+
| `VECTOR_DB_PORT` | int | `8000` | 远程 ChromaDB 端口 |
|
|
109
|
+
| `VECTOR_DB_SERVER_SSL` | bool | `false` | 是否启用 SSL |
|
|
110
|
+
| `VECTOR_DB_REMOTE_HEADERS` | dict | `{}` | 远程请求头 |
|
|
111
|
+
| `VECTOR_DB_TENANT` | string | `default` | 租户名称 |
|
|
112
|
+
| `VECTOR_DB_DATABASE` | string | `default` | 数据库名称 |
|
|
113
|
+
| `EMBEDDING_MODEL_URL` | string | `http://127.0.0.1:11434` | 嵌入模型地址 |
|
|
114
|
+
| `EMBEDDING_MODEL_NAME` | string | `auto` | 嵌入模型名称 |
|
|
115
|
+
| `EMBEDDING_PROCTOL` | `openai` / `ollama-embed` | `ollama-embed` | 嵌入模型协议 |
|
|
116
|
+
|
|
117
|
+
## 安装与使用
|
|
118
|
+
|
|
119
|
+
### 前置条件
|
|
120
|
+
|
|
121
|
+
- Python 3.10 ~ 3.13
|
|
122
|
+
- 已部署的 [AmritaBot](https://github.com/AmritaBot) 实例
|
|
123
|
+
- (本地模式)无需额外组件
|
|
124
|
+
- (远程模式)已运行的 ChromaDB 服务端
|
|
125
|
+
- 已运行的嵌入模型服务(如 Ollama)
|
|
126
|
+
|
|
127
|
+
### 安装
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
ambot plugin install amrita_plugin_memory
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### 配置
|
|
134
|
+
|
|
135
|
+
插件安装后会自动生成配置文件。你可以通过以下方式配置:
|
|
136
|
+
|
|
137
|
+
1. **WebUI 配置**:在 Amrita 的 Web 管理界面中直接修改
|
|
138
|
+
2. **手动编辑**:修改 `config/amrita_plugin_memory/config.toml`
|
|
139
|
+
3. **环境变量**:通过 `.env` 文件或系统环境变量设置数据库和嵌入模型参数
|
|
140
|
+
|
|
141
|
+
### 验证
|
|
142
|
+
|
|
143
|
+
启动后查看日志,确认向量数据库连接成功:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
正在尝试向量数据库连接...
|
|
147
|
+
当前向量数据库类型: local
|
|
148
|
+
创建了向量数据库客户端!
|
|
149
|
+
向量数据库版本:x.x.x
|
|
150
|
+
完成。
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## 开发
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
# 安装开发依赖
|
|
157
|
+
uv sync
|
|
158
|
+
|
|
159
|
+
# 代码格式化与检查
|
|
160
|
+
ruff format .
|
|
161
|
+
ruff check .
|
|
162
|
+
|
|
163
|
+
# 类型检查
|
|
164
|
+
pyright
|
|
165
|
+
```
|
|
166
|
+
|
|
@@ -14,6 +14,8 @@ PLUGIN_IM = "amrita_plugin_memory"
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
class ConfigFile(BaseModel):
|
|
17
|
+
"""配置文件"""
|
|
18
|
+
|
|
17
19
|
short_term_expiry_days: int = Field(
|
|
18
20
|
default=3, description="短期记忆的过期天数,默认为3天"
|
|
19
21
|
)
|
|
@@ -60,12 +62,13 @@ class EnvConfig(BaseModel):
|
|
|
60
62
|
default="http://127.0.0.1:11434", description="Embedding模型地址"
|
|
61
63
|
)
|
|
62
64
|
embedding_model_name: str = Field(default="auto", description="Embedding模型名称")
|
|
63
|
-
embedding_proctol: Literal["openai
|
|
65
|
+
embedding_proctol: Literal["openai", "ollama-embed"] = Field(
|
|
64
66
|
default="ollama-embed", description="Embedding模型协议"
|
|
65
67
|
)
|
|
66
68
|
|
|
67
69
|
|
|
68
70
|
class DataManager(BaseDataManager[ConfigFile]):
|
|
71
|
+
_owner_name = PLUGIN_IM
|
|
69
72
|
config: ConfigFile
|
|
70
73
|
|
|
71
74
|
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
from collections.abc import Iterable, Sequence
|
|
1
|
+
from collections.abc import Iterable, Sequence # noqa: I001
|
|
2
2
|
from typing import Any, Literal
|
|
3
|
+
from typing_extensions import override
|
|
3
4
|
|
|
4
5
|
import aiohttp
|
|
5
|
-
from amrita_core.
|
|
6
|
+
from amrita_core.base.adapter import ModelAdapter
|
|
6
7
|
from amrita_core.types import EmbeddingChunk
|
|
7
|
-
from openai import AsyncOpenAI
|
|
8
8
|
|
|
9
9
|
|
|
10
10
|
class OllamaEmbeddingAdapter(ModelAdapter):
|
|
11
|
+
@override
|
|
11
12
|
async def call_embed(
|
|
12
13
|
self, texts: Iterable[str], **kwargs
|
|
13
14
|
) -> Sequence[EmbeddingChunk]:
|
|
@@ -43,28 +44,3 @@ class OllamaEmbeddingAdapter(ModelAdapter):
|
|
|
43
44
|
@staticmethod
|
|
44
45
|
def get_type() -> Literal["embed"]:
|
|
45
46
|
return "embed"
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
class OpenAIEmbeddingAdapter(ModelAdapter):
|
|
49
|
-
async def call_embed(
|
|
50
|
-
self, texts: Iterable[str], **kwargs
|
|
51
|
-
) -> Sequence[EmbeddingChunk]:
|
|
52
|
-
ps = self.preset
|
|
53
|
-
client = AsyncOpenAI(
|
|
54
|
-
base_url=ps.base_url, api_key=ps.api_key, max_retries=5, timeout=60
|
|
55
|
-
)
|
|
56
|
-
if isinstance(texts, str):
|
|
57
|
-
texts = [texts]
|
|
58
|
-
texts = list(texts)
|
|
59
|
-
embedd = await client.embeddings.create(
|
|
60
|
-
input=texts, model=ps.model, **kwargs, timeout=60
|
|
61
|
-
)
|
|
62
|
-
return [EmbeddingChunk.model_validate(data) for data in embedd.data]
|
|
63
|
-
|
|
64
|
-
@staticmethod
|
|
65
|
-
def get_adapter_protocol() -> Literal["openai-embed"]:
|
|
66
|
-
return "openai-embed"
|
|
67
|
-
|
|
68
|
-
@staticmethod
|
|
69
|
-
def get_type() -> Literal["embed"]:
|
|
70
|
-
return "embed"
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import json
|
|
2
2
|
from datetime import datetime
|
|
3
|
+
from typing import Any
|
|
3
4
|
|
|
4
|
-
from amrita.plugins.chat.runtime import
|
|
5
|
+
from amrita.plugins.chat.runtime import AmritaBotContext
|
|
5
6
|
from amrita_core import (
|
|
6
7
|
FunctionDefinitionSchema,
|
|
7
8
|
FunctionParametersSchema,
|
|
@@ -15,6 +16,30 @@ from nonebot import logger
|
|
|
15
16
|
from .config import DataManager
|
|
16
17
|
from .vector import AsyncUserMemory, MemoryMetadata, get_db_conn
|
|
17
18
|
|
|
19
|
+
|
|
20
|
+
def _get_session_id(ctx: ToolContext) -> str:
|
|
21
|
+
"""从 ToolContext 中提取会话 ID"""
|
|
22
|
+
amrictx: AmritaBotContext = ctx.ctx.chat_object._hook_kwargs["amrita"]
|
|
23
|
+
return amrictx["event"].get_session_id()
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def _make_operator() -> AsyncUserMemory:
|
|
27
|
+
"""创建 AsyncUserMemory 实例"""
|
|
28
|
+
return AsyncUserMemory(get_db_conn())
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _ok(**extra: Any) -> str:
|
|
32
|
+
"""构建成功响应 JSON"""
|
|
33
|
+
return json.dumps({"status": "success", **extra}, ensure_ascii=False, indent=4)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _err(message: str) -> str:
|
|
37
|
+
"""构建错误响应 JSON"""
|
|
38
|
+
return json.dumps(
|
|
39
|
+
{"status": "error", "message": message}, ensure_ascii=False, indent=4
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
|
|
18
43
|
WRITE_MEMORY_FUN = FunctionDefinitionSchema(
|
|
19
44
|
name="write_memory",
|
|
20
45
|
description="将当前用户(或群组)的重要信息存入长期记忆",
|
|
@@ -117,34 +142,22 @@ LIST_MEMORY_FUN = FunctionDefinitionSchema(
|
|
|
117
142
|
|
|
118
143
|
@on_tools(WRITE_MEMORY_FUN, custom_run=True, strict=True)
|
|
119
144
|
async def w(ctx: ToolContext) -> str:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
ope = AsyncUserMemory(get_db_conn())
|
|
145
|
+
session_id = _get_session_id(ctx)
|
|
146
|
+
ope = _make_operator()
|
|
123
147
|
await ope.init()
|
|
124
148
|
logger.debug("开始写入记忆...")
|
|
125
|
-
logger.debug(f"会话ID: {
|
|
149
|
+
logger.debug(f"会话ID: {session_id}")
|
|
126
150
|
logger.debug(f"记忆Payload {ctx.data['content']}")
|
|
127
151
|
if (
|
|
128
|
-
await ope.count_user_notes(
|
|
129
|
-
|
|
152
|
+
await ope.count_user_notes(session_id)
|
|
153
|
+
>= (await DataManager().safe_get_config()).per_session_memory_limit
|
|
130
154
|
):
|
|
131
|
-
return
|
|
132
|
-
{
|
|
133
|
-
"status": "error",
|
|
134
|
-
"message": "当前会话的记忆数量已超过限制,请清理后再试",
|
|
135
|
-
},
|
|
136
|
-
ensure_ascii=False,
|
|
137
|
-
indent=4,
|
|
138
|
-
)
|
|
155
|
+
return _err("当前会话的记忆数量已超过限制,请清理后再试")
|
|
139
156
|
meta = MemoryMetadata(
|
|
140
157
|
importance=ctx.data["importance"],
|
|
141
158
|
tags=ctx.data["tags"],
|
|
142
159
|
)
|
|
143
|
-
await ope.add_note(
|
|
144
|
-
nb_event.get_session_id(),
|
|
145
|
-
ctx.data["content"],
|
|
146
|
-
metadata=meta,
|
|
147
|
-
)
|
|
160
|
+
await ope.add_note(session_id, ctx.data["content"], metadata=meta)
|
|
148
161
|
dmp = meta.model_dump()
|
|
149
162
|
dmp["status"] = "success"
|
|
150
163
|
return json.dumps(dmp, ensure_ascii=False, indent=4)
|
|
@@ -152,80 +165,53 @@ async def w(ctx: ToolContext) -> str:
|
|
|
152
165
|
|
|
153
166
|
@on_tools(READ_MEMORY_FUN, custom_run=True, strict=True)
|
|
154
167
|
async def r(ctx: ToolContext) -> str:
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
ope = AsyncUserMemory(get_db_conn())
|
|
168
|
+
session_id = _get_session_id(ctx)
|
|
169
|
+
ope = _make_operator()
|
|
158
170
|
await ope.init()
|
|
159
171
|
logger.debug("开始检索记忆...")
|
|
160
|
-
logger.debug(f"会话ID: {
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
172
|
+
logger.debug(f"会话ID: {session_id}")
|
|
173
|
+
try:
|
|
174
|
+
res: QueryResult = await ope.query_notes(
|
|
175
|
+
session_id,
|
|
176
|
+
ctx.data["query"],
|
|
177
|
+
top_k=ctx.data["top_k"],
|
|
178
|
+
importance=ctx.data.get("importance"),
|
|
179
|
+
)
|
|
180
|
+
return json.dumps(res, ensure_ascii=False, indent=4)
|
|
181
|
+
except Exception as e:
|
|
182
|
+
logger.error(f"检索记忆时发生错误: {e}")
|
|
183
|
+
return _err(f"检索记忆失败: {e!s}")
|
|
168
184
|
|
|
169
185
|
|
|
170
186
|
@on_tools(UPDATE_FUN, custom_run=True, strict=True)
|
|
171
187
|
async def update_memory(ctx: ToolContext) -> str:
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
ope = AsyncUserMemory(get_db_conn())
|
|
188
|
+
session_id = _get_session_id(ctx)
|
|
189
|
+
ope = _make_operator()
|
|
175
190
|
await ope.init()
|
|
176
191
|
logger.debug("开始更新记忆...")
|
|
177
|
-
logger.debug(f"会话ID: {
|
|
192
|
+
logger.debug(f"会话ID: {session_id}")
|
|
178
193
|
logger.debug(f"更新记忆ID: {ctx.data['id']}")
|
|
179
194
|
|
|
180
195
|
try:
|
|
181
|
-
result = await ope.get_all_notes(
|
|
182
|
-
nb_event.get_session_id(), include=["metadatas", "documents"]
|
|
183
|
-
)
|
|
196
|
+
result = await ope.get_all_notes(session_id, include=["metadatas", "documents"])
|
|
184
197
|
if not result or not result.get("ids"):
|
|
185
|
-
return
|
|
186
|
-
{
|
|
187
|
-
"status": "error",
|
|
188
|
-
"message": "未找到指定ID的记忆",
|
|
189
|
-
},
|
|
190
|
-
ensure_ascii=False,
|
|
191
|
-
indent=4,
|
|
192
|
-
)
|
|
198
|
+
return _err("未找到指定ID的记忆")
|
|
193
199
|
|
|
194
200
|
# 查找要更新的记忆
|
|
195
|
-
target_index = -1
|
|
196
201
|
ids = result["ids"]
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
202
|
+
try:
|
|
203
|
+
target_index = ids.index(ctx.data["id"])
|
|
204
|
+
except ValueError:
|
|
205
|
+
return _err("未找到指定ID的记忆")
|
|
201
206
|
|
|
202
|
-
|
|
203
|
-
return json.dumps(
|
|
204
|
-
{
|
|
205
|
-
"status": "error",
|
|
206
|
-
"message": "未找到指定ID的记忆",
|
|
207
|
-
},
|
|
208
|
-
ensure_ascii=False,
|
|
209
|
-
indent=4,
|
|
210
|
-
)
|
|
211
|
-
|
|
212
|
-
# 获取现有数据,处理可能为None的情况
|
|
207
|
+
# 获取现有数据
|
|
213
208
|
documents = result.get("documents") or []
|
|
214
209
|
metadatas = result.get("metadatas") or []
|
|
215
|
-
|
|
216
210
|
existing_doc = documents[target_index] if target_index < len(documents) else ""
|
|
217
211
|
existing_meta = metadatas[target_index] if target_index < len(metadatas) else {}
|
|
218
212
|
|
|
219
|
-
# 确保有必要的元数据
|
|
220
213
|
if not existing_meta:
|
|
221
|
-
return
|
|
222
|
-
{
|
|
223
|
-
"status": "error",
|
|
224
|
-
"message": "记忆元数据损坏",
|
|
225
|
-
},
|
|
226
|
-
ensure_ascii=False,
|
|
227
|
-
indent=4,
|
|
228
|
-
)
|
|
214
|
+
return _err("记忆元数据损坏")
|
|
229
215
|
|
|
230
216
|
# 构建更新后的数据
|
|
231
217
|
new_content = ctx.data.get("content", existing_doc)
|
|
@@ -234,113 +220,71 @@ async def update_memory(ctx: ToolContext) -> str:
|
|
|
234
220
|
"importance", existing_meta.get("importance", "medium")
|
|
235
221
|
)
|
|
236
222
|
|
|
237
|
-
#
|
|
223
|
+
# 保留原始创建时间
|
|
238
224
|
created_at_str = existing_meta.get("created_at", "")
|
|
239
|
-
if isinstance(created_at_str, str)
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
225
|
+
if isinstance(created_at_str, str):
|
|
226
|
+
try:
|
|
227
|
+
created_at = datetime.fromisoformat(created_at_str)
|
|
228
|
+
except ValueError:
|
|
229
|
+
created_at = datetime.now()
|
|
244
230
|
else:
|
|
245
231
|
created_at = datetime.now()
|
|
246
|
-
|
|
232
|
+
|
|
233
|
+
# 使用原生 update,原子操作,不会丢失数据
|
|
247
234
|
meta = MemoryMetadata(
|
|
248
235
|
memory_id=ctx.data["id"],
|
|
249
236
|
importance=new_importance,
|
|
250
237
|
tags=new_tags,
|
|
251
238
|
created_at=created_at,
|
|
252
239
|
)
|
|
253
|
-
await ope.
|
|
254
|
-
nb_event.get_session_id(),
|
|
255
|
-
new_content,
|
|
256
|
-
metadata=meta,
|
|
257
|
-
)
|
|
240
|
+
await ope.update_note(session_id, new_content, metadata=meta)
|
|
258
241
|
|
|
259
|
-
return
|
|
260
|
-
{"status": "success", "message": "记忆更新成功", "id": ctx.data["id"]},
|
|
261
|
-
ensure_ascii=False,
|
|
262
|
-
indent=4,
|
|
263
|
-
)
|
|
242
|
+
return _ok(message="记忆更新成功", id=ctx.data["id"])
|
|
264
243
|
except Exception as e:
|
|
265
244
|
logger.error(f"更新记忆时发生错误: {e}")
|
|
266
|
-
return
|
|
267
|
-
{
|
|
268
|
-
"status": "error",
|
|
269
|
-
"message": f"更新记忆失败: {e!s}",
|
|
270
|
-
},
|
|
271
|
-
ensure_ascii=False,
|
|
272
|
-
indent=4,
|
|
273
|
-
)
|
|
245
|
+
return _err(f"更新记忆失败: {e!s}")
|
|
274
246
|
|
|
275
247
|
|
|
276
248
|
@on_tools(DELETE_FUN, custom_run=True, strict=True)
|
|
277
249
|
async def delete_memory(ctx: ToolContext) -> str:
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
ope = AsyncUserMemory(get_db_conn())
|
|
250
|
+
session_id = _get_session_id(ctx)
|
|
251
|
+
ope = _make_operator()
|
|
281
252
|
await ope.init()
|
|
282
253
|
logger.debug("开始删除记忆...")
|
|
283
|
-
logger.debug(f"会话ID: {
|
|
254
|
+
logger.debug(f"会话ID: {session_id}")
|
|
284
255
|
logger.debug(f"删除记忆ID: {ctx.data['id']}")
|
|
285
256
|
|
|
286
257
|
try:
|
|
287
|
-
|
|
288
|
-
result = await ope.get_all_notes(
|
|
289
|
-
nb_event.get_session_id(), include=["metadatas"]
|
|
290
|
-
)
|
|
258
|
+
result = await ope.get_all_notes(session_id, include=["metadatas"])
|
|
291
259
|
if (
|
|
292
260
|
not result
|
|
293
261
|
or not result.get("ids")
|
|
294
262
|
or ctx.data["id"] not in (result.get("ids") or [])
|
|
295
263
|
):
|
|
296
|
-
return
|
|
297
|
-
{
|
|
298
|
-
"status": "error",
|
|
299
|
-
"message": "未找到指定ID的记忆",
|
|
300
|
-
},
|
|
301
|
-
ensure_ascii=False,
|
|
302
|
-
indent=4,
|
|
303
|
-
)
|
|
264
|
+
return _err("未找到指定ID的记忆")
|
|
304
265
|
|
|
305
|
-
await ope.delete_note(
|
|
306
|
-
return
|
|
307
|
-
{"status": "success", "message": "记忆删除成功", "id": ctx.data["id"]},
|
|
308
|
-
ensure_ascii=False,
|
|
309
|
-
indent=4,
|
|
310
|
-
)
|
|
266
|
+
await ope.delete_note(session_id, ctx.data["id"])
|
|
267
|
+
return _ok(message="记忆删除成功", id=ctx.data["id"])
|
|
311
268
|
except Exception as e:
|
|
312
269
|
logger.error(f"删除记忆时发生错误: {e}")
|
|
313
|
-
return
|
|
314
|
-
{
|
|
315
|
-
"status": "error",
|
|
316
|
-
"message": f"删除记忆失败: {e!s}",
|
|
317
|
-
},
|
|
318
|
-
ensure_ascii=False,
|
|
319
|
-
indent=4,
|
|
320
|
-
)
|
|
270
|
+
return _err(f"删除记忆失败: {e!s}")
|
|
321
271
|
|
|
322
272
|
|
|
323
273
|
@on_tools(LIST_MEMORY_FUN, custom_run=True, strict=True)
|
|
324
274
|
async def list_memory(ctx: ToolContext) -> str:
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
ope = AsyncUserMemory(get_db_conn())
|
|
275
|
+
session_id = _get_session_id(ctx)
|
|
276
|
+
ope = _make_operator()
|
|
328
277
|
await ope.init()
|
|
329
278
|
logger.debug("开始列出记忆...")
|
|
330
|
-
logger.debug(f"会话ID: {
|
|
279
|
+
logger.debug(f"会话ID: {session_id}")
|
|
331
280
|
|
|
332
281
|
try:
|
|
333
282
|
limit = ctx.data.get("limit", 5)
|
|
334
|
-
result = await ope.get_all_notes(
|
|
335
|
-
nb_event.get_session_id(), include=["metadatas", "documents"]
|
|
336
|
-
)
|
|
283
|
+
result = await ope.get_all_notes(session_id, include=["metadatas", "documents"])
|
|
337
284
|
|
|
338
285
|
if not result or not result.get("ids"):
|
|
339
|
-
return
|
|
340
|
-
|
|
341
|
-
ensure_ascii=False,
|
|
342
|
-
indent=4,
|
|
343
|
-
)
|
|
286
|
+
return _ok(memories=[], total=0)
|
|
287
|
+
|
|
344
288
|
memories = []
|
|
345
289
|
ids = result["ids"]
|
|
346
290
|
documents = result.get("documents") or [""] * len(ids)
|
|
@@ -361,18 +305,7 @@ async def list_memory(ctx: ToolContext) -> str:
|
|
|
361
305
|
}
|
|
362
306
|
)
|
|
363
307
|
|
|
364
|
-
return
|
|
365
|
-
{"status": "success", "memories": memories, "total": len(ids)},
|
|
366
|
-
ensure_ascii=False,
|
|
367
|
-
indent=4,
|
|
368
|
-
)
|
|
308
|
+
return _ok(memories=memories, total=len(ids))
|
|
369
309
|
except Exception as e:
|
|
370
310
|
logger.error(f"列出记忆时发生错误: {e}")
|
|
371
|
-
return
|
|
372
|
-
{
|
|
373
|
-
"status": "error",
|
|
374
|
-
"message": f"列出记忆失败: {e!s}",
|
|
375
|
-
},
|
|
376
|
-
ensure_ascii=False,
|
|
377
|
-
indent=4,
|
|
378
|
-
)
|
|
311
|
+
return _err(f"列出记忆失败: {e!s}")
|
|
@@ -7,7 +7,6 @@ from collections.abc import Awaitable, Callable, Sequence
|
|
|
7
7
|
from datetime import datetime
|
|
8
8
|
from functools import wraps
|
|
9
9
|
from inspect import iscoroutinefunction
|
|
10
|
-
from types import CoroutineType
|
|
11
10
|
from typing import Any, Literal, TypeVar, overload
|
|
12
11
|
from uuid import UUID
|
|
13
12
|
|
|
@@ -15,7 +14,7 @@ import aiologic
|
|
|
15
14
|
import chromadb
|
|
16
15
|
from amrita_core.libchat import call_embedding
|
|
17
16
|
from amrita_core.types import EmbeddingChunk
|
|
18
|
-
from
|
|
17
|
+
from amrita_sense.weakcache import WeakValueLRUCache
|
|
19
18
|
from chromadb.api import ClientAPI
|
|
20
19
|
from chromadb.api.collection_configuration import (
|
|
21
20
|
CreateCollectionConfiguration,
|
|
@@ -53,14 +52,12 @@ def get_lock(collection: str, uid: str) -> aiologic.Lock:
|
|
|
53
52
|
@overload
|
|
54
53
|
def any_to_thread(
|
|
55
54
|
func: Callable[..., Awaitable[T]], /, *args, **kwargs
|
|
56
|
-
) ->
|
|
55
|
+
) -> Awaitable[T]: ...
|
|
57
56
|
@overload
|
|
58
|
-
def any_to_thread(
|
|
59
|
-
func: Callable[..., T], /, *args, **kwargs
|
|
60
|
-
) -> CoroutineType[Any, Any, T]: ...
|
|
57
|
+
def any_to_thread(func: Callable[..., T], /, *args, **kwargs) -> Awaitable[T]: ...
|
|
61
58
|
|
|
62
59
|
|
|
63
|
-
def any_to_thread(func: Callable[..., Awaitable[T] | T], /, *args, **kwargs):
|
|
60
|
+
def any_to_thread(func: Callable[..., Awaitable[T] | T], /, *args, **kwargs) -> Any:
|
|
64
61
|
if not callable(func):
|
|
65
62
|
raise TypeError("func must be callable")
|
|
66
63
|
if iscoroutinefunction(func):
|
|
@@ -371,6 +368,30 @@ class AsyncUserMemory:
|
|
|
371
368
|
documents=[note_text],
|
|
372
369
|
)
|
|
373
370
|
|
|
371
|
+
@require_init
|
|
372
|
+
async def update_note(self, user_id: str, note_text: str, metadata: MemoryMetadata):
|
|
373
|
+
"""更新指定记忆,使用 ChromaDB 原生 update 保证原子性"""
|
|
374
|
+
async with get_lock(self._collection_name, user_id):
|
|
375
|
+
vector: Sequence[EmbeddingChunk] = await call_embedding(
|
|
376
|
+
note_text, build_preset()
|
|
377
|
+
)
|
|
378
|
+
if len(vector) == 0:
|
|
379
|
+
raise RuntimeError("No embedding returned")
|
|
380
|
+
await any_to_thread(
|
|
381
|
+
self._collection.update,
|
|
382
|
+
ids=[metadata.memory_id],
|
|
383
|
+
metadatas=[
|
|
384
|
+
{
|
|
385
|
+
"user_id": user_id,
|
|
386
|
+
"tags": metadata.tags,
|
|
387
|
+
"importance": metadata.importance,
|
|
388
|
+
"created_at": metadata.created_at.isoformat(),
|
|
389
|
+
}
|
|
390
|
+
],
|
|
391
|
+
embeddings=[vector[0].embedding],
|
|
392
|
+
documents=[note_text],
|
|
393
|
+
)
|
|
394
|
+
|
|
374
395
|
@require_init
|
|
375
396
|
async def query_notes(
|
|
376
397
|
self,
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: amrita_plugin_memory
|
|
3
|
+
Version: 0.1.1
|
|
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-localstore>=0.7.4
|
|
14
|
+
Dynamic: license-file
|
|
15
|
+
|
|
16
|
+
# amrita_plugin_memory
|
|
17
|
+
|
|
18
|
+
Amrita 长期记忆插件 —— 基于 ChromaDB 向量数据库的智能记忆管理系统,让 AI 助手能够持久化地记住关于用户的重要信息。
|
|
19
|
+
|
|
20
|
+
## 技术栈
|
|
21
|
+
|
|
22
|
+
| 组件 | 技术 |
|
|
23
|
+
|------|------|
|
|
24
|
+
| 后端框架 | Python 3.10+ / NoneBot2 / Amrita Core |
|
|
25
|
+
| 向量数据库 | ChromaDB(支持本地 PersistentClient 与远程 HttpClient) |
|
|
26
|
+
| 嵌入模型 | OpenAI Embedding API / Ollama Embedding API |
|
|
27
|
+
| 配置管理 | Pydantic + TOML |
|
|
28
|
+
| 异步处理 | asyncio + aiologic + aiohttp |
|
|
29
|
+
| 代码质量 | Ruff + Pyright |
|
|
30
|
+
|
|
31
|
+
## 架构概览
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
amrita_plugin_memory/
|
|
35
|
+
├── __init__.py # 插件入口,注册依赖
|
|
36
|
+
├── config.py # 配置模型(ConfigFile / EnvConfig / DataManager)
|
|
37
|
+
├── embed.py # Ollama 嵌入适配器
|
|
38
|
+
├── vector.py # ChromaDB 异步封装(WrappedClientAPI / AsyncUserMemory)
|
|
39
|
+
└── tools.py # 工具函数定义与注册(write/read/update/delete/list)
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
- **config.py**: 定义配置文件(过期天数、记忆上限)和环境变量(数据库类型、嵌入模型地址等),通过 Pydantic 模型校验。
|
|
43
|
+
- **embed.py**: 实现 Ollama 协议的嵌入适配器,通过 HTTP API 调用 `/api/embed` 端点。
|
|
44
|
+
- **vector.py**: 对 ChromaDB 原生 API 进行 `asyncio.to_thread` 封装,提供异步的集合管理与记忆 CRUD。使用 `aiologic.Lock` 按用户粒度加锁,保证并发安全。
|
|
45
|
+
- **tools.py**: 定义 5 个 Function Calling 工具(`write_memory` / `read_memory` / `update_memory` / `delete_memory` / `list_memory`),注册到 Amrita 的工具系统中。
|
|
46
|
+
|
|
47
|
+
## 功能特点
|
|
48
|
+
|
|
49
|
+
- **长期记忆存储**:将用户偏好、项目信息等持久化存入 ChromaDB 向量数据库
|
|
50
|
+
- **语义检索**:基于嵌入向量的语义相似度检索,支持中英文关键词
|
|
51
|
+
- **智能标签**:支持使用自定义标签对记忆进行分类(如 `preference`、`project`)
|
|
52
|
+
- **重要性分级**:三级重要程度(`low` / `medium` / `high`),支持按级别过滤检索
|
|
53
|
+
- **完整 CRUD**:支持记忆的创建、查询、更新、删除和列表查看
|
|
54
|
+
- **并发安全**:按用户 ID 粒度加锁,确保同一用户的操作串行化
|
|
55
|
+
- **多租户支持**:通过 ChromaDB remote 模式支持远程向量数据库
|
|
56
|
+
|
|
57
|
+
## 工具函数
|
|
58
|
+
|
|
59
|
+
### 1. `write_memory` —— 写入记忆
|
|
60
|
+
|
|
61
|
+
将当前用户(或群组)的重要信息存入长期记忆。
|
|
62
|
+
|
|
63
|
+
| 参数 | 类型 | 必需 | 描述 |
|
|
64
|
+
|------|------|------|------|
|
|
65
|
+
| `content` | string | ✅ | 记忆内容,简洁明了 |
|
|
66
|
+
| `tags` | string | ✅ | 分类标签,如 `preference`、`project` |
|
|
67
|
+
| `importance` | `"low"` / `"medium"` / `"high"` | ✅ | 重要性等级 |
|
|
68
|
+
|
|
69
|
+
### 2. `read_memory` —— 检索记忆
|
|
70
|
+
|
|
71
|
+
从记忆库中按语义相似度检索用户相关信息。
|
|
72
|
+
|
|
73
|
+
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|
|
74
|
+
|------|------|------|--------|------|
|
|
75
|
+
| `query` | string | ✅ | — | 关键词字符串,空格分隔 |
|
|
76
|
+
| `top_k` | integer | ❌ | `5` | 返回结果数量 |
|
|
77
|
+
| `importance` | `"low"` / `"medium"` / `"high"` | ❌ | — | 按重要性过滤 |
|
|
78
|
+
|
|
79
|
+
### 3. `update_memory` —— 更新记忆
|
|
80
|
+
|
|
81
|
+
更新指定 ID 的记忆内容、标签或重要性。
|
|
82
|
+
|
|
83
|
+
| 参数 | 类型 | 必需 | 描述 |
|
|
84
|
+
|------|------|------|------|
|
|
85
|
+
| `id` | string | ✅ | 要更新的记忆 ID |
|
|
86
|
+
| `content` | string | ❌ | 新的记忆内容 |
|
|
87
|
+
| `tags` | string | ❌ | 新的标签 |
|
|
88
|
+
| `importance` | `"low"` / `"medium"` / `"high"` | ❌ | 新的重要性等级 |
|
|
89
|
+
|
|
90
|
+
### 4. `delete_memory` —— 删除记忆
|
|
91
|
+
|
|
92
|
+
删除指定 ID 的记忆。
|
|
93
|
+
|
|
94
|
+
| 参数 | 类型 | 必需 | 描述 |
|
|
95
|
+
|------|------|------|------|
|
|
96
|
+
| `id` | string | ✅ | 要删除的记忆 ID |
|
|
97
|
+
|
|
98
|
+
### 5. `list_memory` —— 列出记忆
|
|
99
|
+
|
|
100
|
+
列出当前用户的所有记忆(返回标签和 ID)。
|
|
101
|
+
|
|
102
|
+
| 参数 | 类型 | 必需 | 默认值 | 描述 |
|
|
103
|
+
|------|------|------|--------|------|
|
|
104
|
+
| `limit` | integer | ❌ | `5` | 返回数量限制 |
|
|
105
|
+
|
|
106
|
+
## 配置选项
|
|
107
|
+
|
|
108
|
+
### 文件配置(`config/amrita_plugin_memory/config.toml`)
|
|
109
|
+
|
|
110
|
+
| 配置项 | 类型 | 默认值 | 描述 |
|
|
111
|
+
|--------|------|--------|------|
|
|
112
|
+
| `short_term_expiry_days` | int | `3` | 短期记忆过期天数 |
|
|
113
|
+
| `long_term_expiry_days` | int | `30` | 长期记忆过期天数 |
|
|
114
|
+
| `permanent_expiry_days` | int | `365` | 永久记忆过期天数 |
|
|
115
|
+
| `per_session_memory_limit` | int | `50` | 每个会话的记忆数量上限 |
|
|
116
|
+
|
|
117
|
+
### 环境变量(`.env` 或系统环境变量)
|
|
118
|
+
|
|
119
|
+
| 变量 | 类型 | 默认值 | 描述 |
|
|
120
|
+
|------|------|--------|------|
|
|
121
|
+
| `VECTOR_DB_TYPE` | `local` / `remote` | `local` | ChromaDB 数据库类型 |
|
|
122
|
+
| `VECTOR_DB_SERVER` | string | `127.0.0.1` | 远程 ChromaDB 地址 |
|
|
123
|
+
| `VECTOR_DB_PORT` | int | `8000` | 远程 ChromaDB 端口 |
|
|
124
|
+
| `VECTOR_DB_SERVER_SSL` | bool | `false` | 是否启用 SSL |
|
|
125
|
+
| `VECTOR_DB_REMOTE_HEADERS` | dict | `{}` | 远程请求头 |
|
|
126
|
+
| `VECTOR_DB_TENANT` | string | `default` | 租户名称 |
|
|
127
|
+
| `VECTOR_DB_DATABASE` | string | `default` | 数据库名称 |
|
|
128
|
+
| `EMBEDDING_MODEL_URL` | string | `http://127.0.0.1:11434` | 嵌入模型地址 |
|
|
129
|
+
| `EMBEDDING_MODEL_NAME` | string | `auto` | 嵌入模型名称 |
|
|
130
|
+
| `EMBEDDING_PROCTOL` | `openai` / `ollama-embed` | `ollama-embed` | 嵌入模型协议 |
|
|
131
|
+
|
|
132
|
+
## 安装与使用
|
|
133
|
+
|
|
134
|
+
### 前置条件
|
|
135
|
+
|
|
136
|
+
- Python 3.10 ~ 3.13
|
|
137
|
+
- 已部署的 [AmritaBot](https://github.com/AmritaBot) 实例
|
|
138
|
+
- (本地模式)无需额外组件
|
|
139
|
+
- (远程模式)已运行的 ChromaDB 服务端
|
|
140
|
+
- 已运行的嵌入模型服务(如 Ollama)
|
|
141
|
+
|
|
142
|
+
### 安装
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
ambot plugin install amrita_plugin_memory
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### 配置
|
|
149
|
+
|
|
150
|
+
插件安装后会自动生成配置文件。你可以通过以下方式配置:
|
|
151
|
+
|
|
152
|
+
1. **WebUI 配置**:在 Amrita 的 Web 管理界面中直接修改
|
|
153
|
+
2. **手动编辑**:修改 `config/amrita_plugin_memory/config.toml`
|
|
154
|
+
3. **环境变量**:通过 `.env` 文件或系统环境变量设置数据库和嵌入模型参数
|
|
155
|
+
|
|
156
|
+
### 验证
|
|
157
|
+
|
|
158
|
+
启动后查看日志,确认向量数据库连接成功:
|
|
159
|
+
|
|
160
|
+
```
|
|
161
|
+
正在尝试向量数据库连接...
|
|
162
|
+
当前向量数据库类型: local
|
|
163
|
+
创建了向量数据库客户端!
|
|
164
|
+
向量数据库版本:x.x.x
|
|
165
|
+
完成。
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
## 开发
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
# 安装开发依赖
|
|
172
|
+
uv sync
|
|
173
|
+
|
|
174
|
+
# 代码格式化与检查
|
|
175
|
+
ruff format .
|
|
176
|
+
ruff check .
|
|
177
|
+
|
|
178
|
+
# 类型检查
|
|
179
|
+
pyright
|
|
180
|
+
```
|
|
181
|
+
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "amrita_plugin_memory"
|
|
3
3
|
description = "Amrita长期记忆插件"
|
|
4
|
-
version = "0.1.
|
|
4
|
+
version = "0.1.1"
|
|
5
5
|
dependencies = [
|
|
6
6
|
"aiohttp>=3.13.3",
|
|
7
7
|
"aiologic>=0.16.0",
|
|
8
8
|
"amrita-core>=0.8.5",
|
|
9
|
-
"amrita
|
|
9
|
+
"amrita>=1.3",
|
|
10
10
|
"chromadb>=1.5.8",
|
|
11
11
|
"nonebot-plugin-localstore>=0.7.4",
|
|
12
12
|
]
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: amrita_plugin_memory
|
|
3
|
-
Version: 0.1.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[full]>=1.1.9
|
|
12
|
-
Requires-Dist: chromadb>=1.5.8
|
|
13
|
-
Requires-Dist: nonebot-plugin-localstore>=0.7.4
|
|
14
|
-
Dynamic: license-file
|
|
15
|
-
|
|
16
|
-
# amrita_plugin_memory
|
|
17
|
-
|
|
18
|
-
Amrita 长期记忆插件 - 一个智能记忆管理系统,用于帮助 AI 助手记住关于用户的长期信息。
|
|
19
|
-
|
|
20
|
-
## 技术栈
|
|
21
|
-
|
|
22
|
-
- **后端**: Python 3.x 插件架构
|
|
23
|
-
- **向量数据库**: ChromaDB (支持本地和远程模式)
|
|
24
|
-
- **嵌入模型**: 支持 OpenAI Embedding API 和 Ollama Embedding API
|
|
25
|
-
- **框架**: NoneBot2 + Amrita Core + AmritaBot
|
|
26
|
-
- **配置管理**: Pydantic + TOML
|
|
27
|
-
- **异步处理**: asyncio + aiologic + aiohttp
|
|
28
|
-
|
|
29
|
-
## 功能特点
|
|
30
|
-
|
|
31
|
-
- **长期记忆存储**:持久化存储关于用户的长期重要信息
|
|
32
|
-
- **智能标签系统**:支持使用标签对记忆进行分类管理
|
|
33
|
-
- **重要性分级**:支持设置记忆的重要程度(low/medium/high)
|
|
34
|
-
- **灵活检索**:支持按关键词检索记忆内容
|
|
35
|
-
- **完整管理**:支持记忆的增删改查和列表查看
|
|
36
|
-
|
|
37
|
-
## 工具函数
|
|
38
|
-
|
|
39
|
-
插件提供了五个主要工具函数:
|
|
40
|
-
|
|
41
|
-
### 1. write_memory
|
|
42
|
-
|
|
43
|
-
将重要信息存入长期记忆
|
|
44
|
-
|
|
45
|
-
参数:
|
|
46
|
-
|
|
47
|
-
- content: 记忆内容,简洁明了(必需)
|
|
48
|
-
- tags: 分类标签,如 `"preference"` 或 `"project"`(必需)
|
|
49
|
-
- importance: 重要性等级(必需,可选值:`"low"`, `"medium"`, `"high"`)
|
|
50
|
-
|
|
51
|
-
### 2. read_memory
|
|
52
|
-
|
|
53
|
-
从记忆库检索用户相关信息
|
|
54
|
-
|
|
55
|
-
参数:
|
|
56
|
-
|
|
57
|
-
- query: 关键词字符串,用空格分割(必需)
|
|
58
|
-
- top_k: 返回数量,默认5条(可选)
|
|
59
|
-
- importance: 重要性等级过滤(可选,可选值:`"low"`, `"medium"`, `"high"`)
|
|
60
|
-
|
|
61
|
-
### 3. update_memory
|
|
62
|
-
|
|
63
|
-
更新指定ID的记忆内容
|
|
64
|
-
|
|
65
|
-
参数:
|
|
66
|
-
|
|
67
|
-
- id: 要更新的记忆ID(必需)
|
|
68
|
-
- content: 新的记忆内容(可选)
|
|
69
|
-
- tags: 新的标签(可选)
|
|
70
|
-
- importance: 新的重要性等级(可选,可选值:`"low"`, `"medium"`, `"high"`)
|
|
71
|
-
|
|
72
|
-
### 4. delete_memory
|
|
73
|
-
|
|
74
|
-
删除指定ID的记忆
|
|
75
|
-
|
|
76
|
-
参数:
|
|
77
|
-
|
|
78
|
-
- id: 要删除的记忆ID(必需)
|
|
79
|
-
|
|
80
|
-
### 5. list_memory
|
|
81
|
-
|
|
82
|
-
列出当前用户的所有记忆
|
|
83
|
-
|
|
84
|
-
参数:
|
|
85
|
-
|
|
86
|
-
- limit: 返回数量限制,默认5条(可选)
|
|
87
|
-
|
|
88
|
-
## 配置选项
|
|
89
|
-
|
|
90
|
-
- `short_term_expiry_days`: 短期记忆的过期天数,默认为3天
|
|
91
|
-
- `long_term_expiry_days`: 长期记忆的过期天数,默认为30天
|
|
92
|
-
- `permanent_expiry_days`: 永久记忆的过期天数,默认为1年
|
|
93
|
-
- `per_session_memory_limit`: 每个会话的记忆数量限制,默认为50条
|
|
94
|
-
|
|
95
|
-
## 安装和使用
|
|
96
|
-
|
|
97
|
-
1. 安装插件:`amrita plugin install amrita_plugin_memory`
|
|
98
|
-
2. 配置插件:插件会自动生成配置文件,或者您可以在WebUI中配置。
|
|
@@ -1,83 +0,0 @@
|
|
|
1
|
-
# amrita_plugin_memory
|
|
2
|
-
|
|
3
|
-
Amrita 长期记忆插件 - 一个智能记忆管理系统,用于帮助 AI 助手记住关于用户的长期信息。
|
|
4
|
-
|
|
5
|
-
## 技术栈
|
|
6
|
-
|
|
7
|
-
- **后端**: Python 3.x 插件架构
|
|
8
|
-
- **向量数据库**: ChromaDB (支持本地和远程模式)
|
|
9
|
-
- **嵌入模型**: 支持 OpenAI Embedding API 和 Ollama Embedding API
|
|
10
|
-
- **框架**: NoneBot2 + Amrita Core + AmritaBot
|
|
11
|
-
- **配置管理**: Pydantic + TOML
|
|
12
|
-
- **异步处理**: asyncio + aiologic + aiohttp
|
|
13
|
-
|
|
14
|
-
## 功能特点
|
|
15
|
-
|
|
16
|
-
- **长期记忆存储**:持久化存储关于用户的长期重要信息
|
|
17
|
-
- **智能标签系统**:支持使用标签对记忆进行分类管理
|
|
18
|
-
- **重要性分级**:支持设置记忆的重要程度(low/medium/high)
|
|
19
|
-
- **灵活检索**:支持按关键词检索记忆内容
|
|
20
|
-
- **完整管理**:支持记忆的增删改查和列表查看
|
|
21
|
-
|
|
22
|
-
## 工具函数
|
|
23
|
-
|
|
24
|
-
插件提供了五个主要工具函数:
|
|
25
|
-
|
|
26
|
-
### 1. write_memory
|
|
27
|
-
|
|
28
|
-
将重要信息存入长期记忆
|
|
29
|
-
|
|
30
|
-
参数:
|
|
31
|
-
|
|
32
|
-
- content: 记忆内容,简洁明了(必需)
|
|
33
|
-
- tags: 分类标签,如 `"preference"` 或 `"project"`(必需)
|
|
34
|
-
- importance: 重要性等级(必需,可选值:`"low"`, `"medium"`, `"high"`)
|
|
35
|
-
|
|
36
|
-
### 2. read_memory
|
|
37
|
-
|
|
38
|
-
从记忆库检索用户相关信息
|
|
39
|
-
|
|
40
|
-
参数:
|
|
41
|
-
|
|
42
|
-
- query: 关键词字符串,用空格分割(必需)
|
|
43
|
-
- top_k: 返回数量,默认5条(可选)
|
|
44
|
-
- importance: 重要性等级过滤(可选,可选值:`"low"`, `"medium"`, `"high"`)
|
|
45
|
-
|
|
46
|
-
### 3. update_memory
|
|
47
|
-
|
|
48
|
-
更新指定ID的记忆内容
|
|
49
|
-
|
|
50
|
-
参数:
|
|
51
|
-
|
|
52
|
-
- id: 要更新的记忆ID(必需)
|
|
53
|
-
- content: 新的记忆内容(可选)
|
|
54
|
-
- tags: 新的标签(可选)
|
|
55
|
-
- importance: 新的重要性等级(可选,可选值:`"low"`, `"medium"`, `"high"`)
|
|
56
|
-
|
|
57
|
-
### 4. delete_memory
|
|
58
|
-
|
|
59
|
-
删除指定ID的记忆
|
|
60
|
-
|
|
61
|
-
参数:
|
|
62
|
-
|
|
63
|
-
- id: 要删除的记忆ID(必需)
|
|
64
|
-
|
|
65
|
-
### 5. list_memory
|
|
66
|
-
|
|
67
|
-
列出当前用户的所有记忆
|
|
68
|
-
|
|
69
|
-
参数:
|
|
70
|
-
|
|
71
|
-
- limit: 返回数量限制,默认5条(可选)
|
|
72
|
-
|
|
73
|
-
## 配置选项
|
|
74
|
-
|
|
75
|
-
- `short_term_expiry_days`: 短期记忆的过期天数,默认为3天
|
|
76
|
-
- `long_term_expiry_days`: 长期记忆的过期天数,默认为30天
|
|
77
|
-
- `permanent_expiry_days`: 永久记忆的过期天数,默认为1年
|
|
78
|
-
- `per_session_memory_limit`: 每个会话的记忆数量限制,默认为50条
|
|
79
|
-
|
|
80
|
-
## 安装和使用
|
|
81
|
-
|
|
82
|
-
1. 安装插件:`amrita plugin install amrita_plugin_memory`
|
|
83
|
-
2. 配置插件:插件会自动生成配置文件,或者您可以在WebUI中配置。
|
|
@@ -1,98 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.4
|
|
2
|
-
Name: amrita_plugin_memory
|
|
3
|
-
Version: 0.1.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[full]>=1.1.9
|
|
12
|
-
Requires-Dist: chromadb>=1.5.8
|
|
13
|
-
Requires-Dist: nonebot-plugin-localstore>=0.7.4
|
|
14
|
-
Dynamic: license-file
|
|
15
|
-
|
|
16
|
-
# amrita_plugin_memory
|
|
17
|
-
|
|
18
|
-
Amrita 长期记忆插件 - 一个智能记忆管理系统,用于帮助 AI 助手记住关于用户的长期信息。
|
|
19
|
-
|
|
20
|
-
## 技术栈
|
|
21
|
-
|
|
22
|
-
- **后端**: Python 3.x 插件架构
|
|
23
|
-
- **向量数据库**: ChromaDB (支持本地和远程模式)
|
|
24
|
-
- **嵌入模型**: 支持 OpenAI Embedding API 和 Ollama Embedding API
|
|
25
|
-
- **框架**: NoneBot2 + Amrita Core + AmritaBot
|
|
26
|
-
- **配置管理**: Pydantic + TOML
|
|
27
|
-
- **异步处理**: asyncio + aiologic + aiohttp
|
|
28
|
-
|
|
29
|
-
## 功能特点
|
|
30
|
-
|
|
31
|
-
- **长期记忆存储**:持久化存储关于用户的长期重要信息
|
|
32
|
-
- **智能标签系统**:支持使用标签对记忆进行分类管理
|
|
33
|
-
- **重要性分级**:支持设置记忆的重要程度(low/medium/high)
|
|
34
|
-
- **灵活检索**:支持按关键词检索记忆内容
|
|
35
|
-
- **完整管理**:支持记忆的增删改查和列表查看
|
|
36
|
-
|
|
37
|
-
## 工具函数
|
|
38
|
-
|
|
39
|
-
插件提供了五个主要工具函数:
|
|
40
|
-
|
|
41
|
-
### 1. write_memory
|
|
42
|
-
|
|
43
|
-
将重要信息存入长期记忆
|
|
44
|
-
|
|
45
|
-
参数:
|
|
46
|
-
|
|
47
|
-
- content: 记忆内容,简洁明了(必需)
|
|
48
|
-
- tags: 分类标签,如 `"preference"` 或 `"project"`(必需)
|
|
49
|
-
- importance: 重要性等级(必需,可选值:`"low"`, `"medium"`, `"high"`)
|
|
50
|
-
|
|
51
|
-
### 2. read_memory
|
|
52
|
-
|
|
53
|
-
从记忆库检索用户相关信息
|
|
54
|
-
|
|
55
|
-
参数:
|
|
56
|
-
|
|
57
|
-
- query: 关键词字符串,用空格分割(必需)
|
|
58
|
-
- top_k: 返回数量,默认5条(可选)
|
|
59
|
-
- importance: 重要性等级过滤(可选,可选值:`"low"`, `"medium"`, `"high"`)
|
|
60
|
-
|
|
61
|
-
### 3. update_memory
|
|
62
|
-
|
|
63
|
-
更新指定ID的记忆内容
|
|
64
|
-
|
|
65
|
-
参数:
|
|
66
|
-
|
|
67
|
-
- id: 要更新的记忆ID(必需)
|
|
68
|
-
- content: 新的记忆内容(可选)
|
|
69
|
-
- tags: 新的标签(可选)
|
|
70
|
-
- importance: 新的重要性等级(可选,可选值:`"low"`, `"medium"`, `"high"`)
|
|
71
|
-
|
|
72
|
-
### 4. delete_memory
|
|
73
|
-
|
|
74
|
-
删除指定ID的记忆
|
|
75
|
-
|
|
76
|
-
参数:
|
|
77
|
-
|
|
78
|
-
- id: 要删除的记忆ID(必需)
|
|
79
|
-
|
|
80
|
-
### 5. list_memory
|
|
81
|
-
|
|
82
|
-
列出当前用户的所有记忆
|
|
83
|
-
|
|
84
|
-
参数:
|
|
85
|
-
|
|
86
|
-
- limit: 返回数量限制,默认5条(可选)
|
|
87
|
-
|
|
88
|
-
## 配置选项
|
|
89
|
-
|
|
90
|
-
- `short_term_expiry_days`: 短期记忆的过期天数,默认为3天
|
|
91
|
-
- `long_term_expiry_days`: 长期记忆的过期天数,默认为30天
|
|
92
|
-
- `permanent_expiry_days`: 永久记忆的过期天数,默认为1年
|
|
93
|
-
- `per_session_memory_limit`: 每个会话的记忆数量限制,默认为50条
|
|
94
|
-
|
|
95
|
-
## 安装和使用
|
|
96
|
-
|
|
97
|
-
1. 安装插件:`amrita plugin install amrita_plugin_memory`
|
|
98
|
-
2. 配置插件:插件会自动生成配置文件,或者您可以在WebUI中配置。
|
|
File without changes
|
|
File without changes
|
{amrita_plugin_memory-0.1.0 → amrita_plugin_memory-0.1.1}/amrita_plugin_memory.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|