memcore-sdk 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.
- memcore_sdk-0.3.0/.gitignore +86 -0
- memcore_sdk-0.3.0/PKG-INFO +162 -0
- memcore_sdk-0.3.0/README.md +144 -0
- memcore_sdk-0.3.0/example.py +60 -0
- memcore_sdk-0.3.0/memcore/__init__.py +15 -0
- memcore_sdk-0.3.0/memcore/client.py +338 -0
- memcore_sdk-0.3.0/memcore/integrations/__init__.py +36 -0
- memcore_sdk-0.3.0/memcore/integrations/langchain.py +180 -0
- memcore_sdk-0.3.0/memcore/integrations/llama_index.py +198 -0
- memcore_sdk-0.3.0/memcore/models.py +131 -0
- memcore_sdk-0.3.0/pyproject.toml +26 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# 密钥:绝不入库。真实 key 曾被误粘进 .env.example(模板),教训见 backend/README
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
|
|
6
|
+
# 依赖与缓存
|
|
7
|
+
.venv/
|
|
8
|
+
__pycache__/
|
|
9
|
+
*.pyc
|
|
10
|
+
*.egg-info/
|
|
11
|
+
|
|
12
|
+
# 他人仓库:5.4GB,各自带 .git 与不同许可证(含 AGPL / CC-NC),不纳入本仓库
|
|
13
|
+
reference/
|
|
14
|
+
|
|
15
|
+
# 评测数据:体积大且多为 CC-NC 许可,不可随代码分发(见 evals/benchmarks/DATASET_LICENSES.md)
|
|
16
|
+
backend/evals/benchmarks/data/*.json
|
|
17
|
+
backend/evals/benchmarks/results/
|
|
18
|
+
backend/evals/results/
|
|
19
|
+
# b47cacc 之后 backend/ → backend/v1/,上面几条只留作历史;实际生效的是这几条
|
|
20
|
+
backend/v1/evals/results/
|
|
21
|
+
backend/v1/evals/benchmarks/results/
|
|
22
|
+
backend/v1/var/
|
|
23
|
+
|
|
24
|
+
# Next 构建产物。website/.gitignore 已经挡了 website/.next/,
|
|
25
|
+
# 但在仓库根跑错目录的 next build 会在这里落一个 .next/trace,那个挡不住。
|
|
26
|
+
.next/
|
|
27
|
+
|
|
28
|
+
# 运行产物
|
|
29
|
+
*.log
|
|
30
|
+
|
|
31
|
+
# 上面的 `.env` / `.env.*` 漏掉了 `<名字>.env` 这种写法 —— 实测
|
|
32
|
+
# `backend/evals/benchmarks/samemodel.env` 带真实 API key 却处于未跟踪状态,
|
|
33
|
+
# 一次 `git add -A` 就会入库。改用后缀匹配兜住全部(`.env.example` 不以 .env 结尾,不受影响)
|
|
34
|
+
*.env
|
|
35
|
+
|
|
36
|
+
# memos 运行数据:sqlite 库、日志、锁文件。是机器本地状态,不是代码。
|
|
37
|
+
# 注意 `*.log` 匹配不到 `memos.log.2026-08-27` 这种带日期后缀的
|
|
38
|
+
.memos/
|
|
39
|
+
.venv-memos/
|
|
40
|
+
|
|
41
|
+
# 画像/日记等每主体记忆产物:运行时生成,归宿是对象存储而非代码仓库(见 TECH_DESIGN §3.3)。
|
|
42
|
+
# 初始提交曾误纳入 115 个文件,且是多租户重构**之前**的扁平布局(var/memory/<subject>/),
|
|
43
|
+
# 重构后的布局是 var/memory/<tenant>/<project>/<subject>/,旧数据已不会再被读到
|
|
44
|
+
backend/var/
|
|
45
|
+
|
|
46
|
+
# TS SDK 构建产物与依赖
|
|
47
|
+
sdk/typescript/dist/
|
|
48
|
+
sdk/typescript/node_modules/
|
|
49
|
+
|
|
50
|
+
# 小程序 demo 里的内核拷贝:由 `cd sdk/typescript && npm run build:mp` 生成
|
|
51
|
+
clients/miniprogram/lib/memcore/
|
|
52
|
+
|
|
53
|
+
# LongMemEval 各臂的逐题产物(体积大;数据集 MIT,但产物是本地生成物)
|
|
54
|
+
backend/evals/results/lme_arms/
|
|
55
|
+
|
|
56
|
+
#
|
|
57
|
+
node_modules
|
|
58
|
+
out
|
|
59
|
+
|
|
60
|
+
# 竞品调研的本地抓取产物:含**别家用户的真实凭据 / 会话 token**(明文 API key、
|
|
61
|
+
# Bearer token 等)。绝不入库 —— 一个 git add -A 就会把它们连同活凭据一起提交。
|
|
62
|
+
# 需要复现时在本地重新抓,不要留在版本库里。
|
|
63
|
+
.chrome-debug-profile/
|
|
64
|
+
|
|
65
|
+
# 竞品 APK 本地留档:Rokid 612MB + Looki 109MB,且是别人的闭源商业应用,
|
|
66
|
+
# 提交进会推送的仓库等于再分发。解读文档与证据摘录(cmd 输出)才是可入库的部分,
|
|
67
|
+
# 二进制只用于本地复核 —— 需要时按各文档「复现步骤」一章重新 adb pull。
|
|
68
|
+
# 按后缀匹配而非 `apk/`,否则会把目录里说明用途的 README 一起挡掉。
|
|
69
|
+
*.apk
|
|
70
|
+
*.xapk
|
|
71
|
+
|
|
72
|
+
# 竞品截图:含真实账号信息(用户名、头像、设备列表),绝不入库。
|
|
73
|
+
# 需要复现时在本地重新用 adb 抓,不要留在版本库里。
|
|
74
|
+
docs/competitors/*/截图/
|
|
75
|
+
|
|
76
|
+
# macOS Finder 目录元数据:无内容价值,且每次打开目录就会变动制造噪声提交。
|
|
77
|
+
# 按文件名匹配(任意层级),不要写成 `docs/.DS_Store` 这种单点写法。
|
|
78
|
+
.DS_Store
|
|
79
|
+
|
|
80
|
+
# 搬来的 kbflow 服务的 Rust 构建产物(与 backend/auth/target 同理)
|
|
81
|
+
backend/kbflow/target/
|
|
82
|
+
|
|
83
|
+
# kbflow 的上传落盘目录(KB_UPLOAD_ROOT)—— 里面是用户上传的文档,绝不入库
|
|
84
|
+
backend/kbflow/var/
|
|
85
|
+
# 小程序里的内核是 sdk/typescript 的构建产物(npm run build:mp 拷进去),clients/ 已改名 app/
|
|
86
|
+
app/miniprogram/lib/
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: memcore-sdk
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Python SDK for memcore — a universal memory kernel with explainable, auditable retrieval
|
|
5
|
+
Project-URL: Homepage, https://reglos.ai
|
|
6
|
+
License: Proprietary
|
|
7
|
+
Keywords: agents,llm,memory,rag
|
|
8
|
+
Requires-Python: >=3.10
|
|
9
|
+
Requires-Dist: httpx>=0.27
|
|
10
|
+
Provides-Extra: all
|
|
11
|
+
Requires-Dist: langchain-core>=0.3; extra == 'all'
|
|
12
|
+
Requires-Dist: llama-index-core>=0.12; extra == 'all'
|
|
13
|
+
Provides-Extra: langchain
|
|
14
|
+
Requires-Dist: langchain-core>=0.3; extra == 'langchain'
|
|
15
|
+
Provides-Extra: llamaindex
|
|
16
|
+
Requires-Dist: llama-index-core>=0.12; extra == 'llamaindex'
|
|
17
|
+
Description-Content-Type: text/markdown
|
|
18
|
+
|
|
19
|
+
# memcore Python SDK
|
|
20
|
+
|
|
21
|
+
给你的 AI 应用加一层**可解释、可审计**的长期记忆。
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install memcore-sdk
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## 10 分钟上手
|
|
28
|
+
|
|
29
|
+
```python
|
|
30
|
+
from memcore import Memcore
|
|
31
|
+
|
|
32
|
+
mc = Memcore(api_key="mk_live_...") # tenant/project 由 key 决定,你不用管
|
|
33
|
+
user = mc.subject("your-user-42") # 绑定记忆主体,后续调用不必再传
|
|
34
|
+
|
|
35
|
+
# 1. 记住
|
|
36
|
+
user.remember("我叫 Richard,住在上海,在做数据库产品,周末喜欢爬山。")
|
|
37
|
+
|
|
38
|
+
# 2. 想起来 —— 直接拼进你的 prompt
|
|
39
|
+
hits = user.recall("他住在哪里")
|
|
40
|
+
system_prompt = "你是一个助手。\n" + hits.as_prompt()
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
就这样。抽取、去重、冲突消解、时效管理都在服务端完成。
|
|
44
|
+
|
|
45
|
+
## 五个动词
|
|
46
|
+
|
|
47
|
+
| 动词 | 用途 |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `remember` | 写入:自然语言 / 对话消息 / 直接写事实 / 文档与图片 |
|
|
50
|
+
| `recall` | 检索:多路融合 + 过滤 + **解释** |
|
|
51
|
+
| `profile` / `ask` | 画像:结构化槽位 + 自然语言问答 |
|
|
52
|
+
| `forget` | 遗忘:否决单条 / 删会话 / 全清(带删除回执) |
|
|
53
|
+
| `explain` / `audit` | 溯源:这条记忆怎么来的 + 审计账本 |
|
|
54
|
+
|
|
55
|
+
## 写入的三种形态
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
# 自然语言(最常用)
|
|
59
|
+
user.remember("我下个月要去日本出差")
|
|
60
|
+
|
|
61
|
+
# 对话消息 —— `at` 用于回灌历史,相对时间("三年前")才能被正确解析
|
|
62
|
+
user.remember(messages=[
|
|
63
|
+
{"role": "user", "content": "我三年前搬到杭州", "at": "2023-05-01T10:00:00Z"},
|
|
64
|
+
{"role": "assistant", "content": "杭州挺好的"},
|
|
65
|
+
])
|
|
66
|
+
|
|
67
|
+
# 你已有自己的抽取,直接写结构化事实
|
|
68
|
+
user.remember(facts=[{"statement": "用户的租约 2027 年 8 月到期",
|
|
69
|
+
"topic": "lifestyle", "confidence": 0.95}])
|
|
70
|
+
|
|
71
|
+
# 文档与图片:PDF / Word / 文本直接解析;图片走 VLM 双路(描述 + OCR)
|
|
72
|
+
user.remember_file("contract.pdf")
|
|
73
|
+
user.remember_file("whiteboard.png")
|
|
74
|
+
|
|
75
|
+
# 需要"写完立刻可查"?
|
|
76
|
+
user.remember("...", sync=True) # 默认异步:落库即返回,抽取在后台
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## 检索与解释
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
hits = user.recall("他住在哪里", explain=True)
|
|
83
|
+
|
|
84
|
+
for m in hits:
|
|
85
|
+
print(m.statement, m.is_current) # is_current=False 表示已被更新的事实取代
|
|
86
|
+
print(m.why.matched_paths) # {'vector': {'rank': 1}, 'keyword': {'rank': 3}}
|
|
87
|
+
print(m.why.rrf_contribution) # 各路对最终排名的贡献
|
|
88
|
+
print(m.why.validity) # current / superseded + 有效期
|
|
89
|
+
|
|
90
|
+
print(hits.budget) # 考虑了多少条、返回多少、裁掉多少、用了多少 token
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
**为什么要 explain**:调试召回质量时你能看到"为什么是这条";合规审查时你能证明答案有据可依。
|
|
94
|
+
|
|
95
|
+
过滤:
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
user.recall("最近的工作", topic="work", since=datetime(2026, 1, 1),
|
|
99
|
+
source="document", min_confidence=0.8, limit=20)
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## 记忆是有时间的
|
|
103
|
+
|
|
104
|
+
同一件事变了,旧记忆**不会被覆盖**,而是标记失效并保留:
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
user.remember("我搬到上海了")
|
|
108
|
+
user.recall("住在哪里") # → 上海(当前有效)
|
|
109
|
+
# 历史仍在:m.is_current == False 的那条记录着"曾经住在杭州"
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
这让"我 2023 年住哪"这类问题也答得出来,也让画像的每次变化都有据可查。
|
|
113
|
+
|
|
114
|
+
## 遗忘的三种语义
|
|
115
|
+
|
|
116
|
+
```python
|
|
117
|
+
user.forget(memory_id, reason="抽错了") # 作废:查询不再命中,留痕可回溯
|
|
118
|
+
user.forget(session_id="...") # 级联:消息 + 派生事实 + 向量一起清
|
|
119
|
+
receipt = user.forget(everything=True) # 全清:返回可存档的删除回执(合规举证)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## 溯源与审计
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
lineage = user.explain(memory_id)
|
|
126
|
+
# → 原始消息原文、生成记录(模型 + prompt 哈希)、被哪条新事实取代
|
|
127
|
+
|
|
128
|
+
for e in user.audit(since=last_week):
|
|
129
|
+
print(e["at"], e["action"], e["record_id"])
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## 异步
|
|
133
|
+
|
|
134
|
+
方法名完全一致:
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from memcore import AsyncMemcore
|
|
138
|
+
|
|
139
|
+
async with AsyncMemcore(api_key="...") as mc:
|
|
140
|
+
user = mc.subject("user-42")
|
|
141
|
+
await user.remember("...")
|
|
142
|
+
hits = await user.recall("...")
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
## 记忆主体不只是"用户"
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
mc.subject("user-42") # 终端用户
|
|
149
|
+
mc.subject("agent-researcher", "agent") # 给 Agent 的记忆
|
|
150
|
+
mc.subject("team-growth", "team") # 团队共享记忆
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
## 错误处理
|
|
154
|
+
|
|
155
|
+
```python
|
|
156
|
+
from memcore import MemcoreError
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
user.remember("...")
|
|
160
|
+
except MemcoreError as e:
|
|
161
|
+
print(e.status, e.message) # 401 鉴权 / 400 参数 / 404 不存在
|
|
162
|
+
```
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# memcore Python SDK
|
|
2
|
+
|
|
3
|
+
给你的 AI 应用加一层**可解释、可审计**的长期记忆。
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
pip install memcore-sdk
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## 10 分钟上手
|
|
10
|
+
|
|
11
|
+
```python
|
|
12
|
+
from memcore import Memcore
|
|
13
|
+
|
|
14
|
+
mc = Memcore(api_key="mk_live_...") # tenant/project 由 key 决定,你不用管
|
|
15
|
+
user = mc.subject("your-user-42") # 绑定记忆主体,后续调用不必再传
|
|
16
|
+
|
|
17
|
+
# 1. 记住
|
|
18
|
+
user.remember("我叫 Richard,住在上海,在做数据库产品,周末喜欢爬山。")
|
|
19
|
+
|
|
20
|
+
# 2. 想起来 —— 直接拼进你的 prompt
|
|
21
|
+
hits = user.recall("他住在哪里")
|
|
22
|
+
system_prompt = "你是一个助手。\n" + hits.as_prompt()
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
就这样。抽取、去重、冲突消解、时效管理都在服务端完成。
|
|
26
|
+
|
|
27
|
+
## 五个动词
|
|
28
|
+
|
|
29
|
+
| 动词 | 用途 |
|
|
30
|
+
| --- | --- |
|
|
31
|
+
| `remember` | 写入:自然语言 / 对话消息 / 直接写事实 / 文档与图片 |
|
|
32
|
+
| `recall` | 检索:多路融合 + 过滤 + **解释** |
|
|
33
|
+
| `profile` / `ask` | 画像:结构化槽位 + 自然语言问答 |
|
|
34
|
+
| `forget` | 遗忘:否决单条 / 删会话 / 全清(带删除回执) |
|
|
35
|
+
| `explain` / `audit` | 溯源:这条记忆怎么来的 + 审计账本 |
|
|
36
|
+
|
|
37
|
+
## 写入的三种形态
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
# 自然语言(最常用)
|
|
41
|
+
user.remember("我下个月要去日本出差")
|
|
42
|
+
|
|
43
|
+
# 对话消息 —— `at` 用于回灌历史,相对时间("三年前")才能被正确解析
|
|
44
|
+
user.remember(messages=[
|
|
45
|
+
{"role": "user", "content": "我三年前搬到杭州", "at": "2023-05-01T10:00:00Z"},
|
|
46
|
+
{"role": "assistant", "content": "杭州挺好的"},
|
|
47
|
+
])
|
|
48
|
+
|
|
49
|
+
# 你已有自己的抽取,直接写结构化事实
|
|
50
|
+
user.remember(facts=[{"statement": "用户的租约 2027 年 8 月到期",
|
|
51
|
+
"topic": "lifestyle", "confidence": 0.95}])
|
|
52
|
+
|
|
53
|
+
# 文档与图片:PDF / Word / 文本直接解析;图片走 VLM 双路(描述 + OCR)
|
|
54
|
+
user.remember_file("contract.pdf")
|
|
55
|
+
user.remember_file("whiteboard.png")
|
|
56
|
+
|
|
57
|
+
# 需要"写完立刻可查"?
|
|
58
|
+
user.remember("...", sync=True) # 默认异步:落库即返回,抽取在后台
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## 检索与解释
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
hits = user.recall("他住在哪里", explain=True)
|
|
65
|
+
|
|
66
|
+
for m in hits:
|
|
67
|
+
print(m.statement, m.is_current) # is_current=False 表示已被更新的事实取代
|
|
68
|
+
print(m.why.matched_paths) # {'vector': {'rank': 1}, 'keyword': {'rank': 3}}
|
|
69
|
+
print(m.why.rrf_contribution) # 各路对最终排名的贡献
|
|
70
|
+
print(m.why.validity) # current / superseded + 有效期
|
|
71
|
+
|
|
72
|
+
print(hits.budget) # 考虑了多少条、返回多少、裁掉多少、用了多少 token
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
**为什么要 explain**:调试召回质量时你能看到"为什么是这条";合规审查时你能证明答案有据可依。
|
|
76
|
+
|
|
77
|
+
过滤:
|
|
78
|
+
|
|
79
|
+
```python
|
|
80
|
+
user.recall("最近的工作", topic="work", since=datetime(2026, 1, 1),
|
|
81
|
+
source="document", min_confidence=0.8, limit=20)
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
## 记忆是有时间的
|
|
85
|
+
|
|
86
|
+
同一件事变了,旧记忆**不会被覆盖**,而是标记失效并保留:
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
user.remember("我搬到上海了")
|
|
90
|
+
user.recall("住在哪里") # → 上海(当前有效)
|
|
91
|
+
# 历史仍在:m.is_current == False 的那条记录着"曾经住在杭州"
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
这让"我 2023 年住哪"这类问题也答得出来,也让画像的每次变化都有据可查。
|
|
95
|
+
|
|
96
|
+
## 遗忘的三种语义
|
|
97
|
+
|
|
98
|
+
```python
|
|
99
|
+
user.forget(memory_id, reason="抽错了") # 作废:查询不再命中,留痕可回溯
|
|
100
|
+
user.forget(session_id="...") # 级联:消息 + 派生事实 + 向量一起清
|
|
101
|
+
receipt = user.forget(everything=True) # 全清:返回可存档的删除回执(合规举证)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## 溯源与审计
|
|
105
|
+
|
|
106
|
+
```python
|
|
107
|
+
lineage = user.explain(memory_id)
|
|
108
|
+
# → 原始消息原文、生成记录(模型 + prompt 哈希)、被哪条新事实取代
|
|
109
|
+
|
|
110
|
+
for e in user.audit(since=last_week):
|
|
111
|
+
print(e["at"], e["action"], e["record_id"])
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## 异步
|
|
115
|
+
|
|
116
|
+
方法名完全一致:
|
|
117
|
+
|
|
118
|
+
```python
|
|
119
|
+
from memcore import AsyncMemcore
|
|
120
|
+
|
|
121
|
+
async with AsyncMemcore(api_key="...") as mc:
|
|
122
|
+
user = mc.subject("user-42")
|
|
123
|
+
await user.remember("...")
|
|
124
|
+
hits = await user.recall("...")
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## 记忆主体不只是"用户"
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
mc.subject("user-42") # 终端用户
|
|
131
|
+
mc.subject("agent-researcher", "agent") # 给 Agent 的记忆
|
|
132
|
+
mc.subject("team-growth", "team") # 团队共享记忆
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## 错误处理
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
from memcore import MemcoreError
|
|
139
|
+
|
|
140
|
+
try:
|
|
141
|
+
user.remember("...")
|
|
142
|
+
except MemcoreError as e:
|
|
143
|
+
print(e.status, e.message) # 401 鉴权 / 400 参数 / 404 不存在
|
|
144
|
+
```
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"""SDK 快速上手 —— 也是端到端测试。
|
|
2
|
+
|
|
3
|
+
前置:后端在 localhost:8000 运行。
|
|
4
|
+
python example.py
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import uuid
|
|
8
|
+
|
|
9
|
+
from memcore import Memcore
|
|
10
|
+
|
|
11
|
+
mc = Memcore(base_url="http://localhost:8000") # 生产环境传 api_key=
|
|
12
|
+
user = mc.subject(f"demo-{uuid.uuid4().hex[:6]}") # 绑定主体,后续调用不必再传
|
|
13
|
+
|
|
14
|
+
print("1) 写入记忆(sync:写完立刻可查)")
|
|
15
|
+
out = user.remember("我叫 Richard,住在上海,在做数据库产品,周末喜欢爬山。", sync=True)
|
|
16
|
+
print(f" 抽出 {out.get('facts', 0)} 条记忆\n")
|
|
17
|
+
|
|
18
|
+
print("2) 检索 + explain")
|
|
19
|
+
hits = user.recall("他住在哪里", explain=True)
|
|
20
|
+
for m in hits:
|
|
21
|
+
paths = list(m.why.matched_paths) if m.why else []
|
|
22
|
+
print(f" · {m} ← 命中路径 {paths}")
|
|
23
|
+
if hits.budget:
|
|
24
|
+
b = hits.budget
|
|
25
|
+
print(f" 预算:返回 {b['items_returned']}/{b['items_considered']} 条,"
|
|
26
|
+
f"用了 {b['tokens_used']}/{b['token_budget']} token\n")
|
|
27
|
+
|
|
28
|
+
print("3) 直接拼进你的 prompt(最常见用法)")
|
|
29
|
+
print(" " + (hits.as_prompt().replace("\n", "\n ") or "(空)") + "\n")
|
|
30
|
+
|
|
31
|
+
print("4) 画像")
|
|
32
|
+
p = user.profile()
|
|
33
|
+
for s in p.slots[:5]:
|
|
34
|
+
print(f" [{s.topic}/{s.sub_topic}] {s.projection}")
|
|
35
|
+
print()
|
|
36
|
+
|
|
37
|
+
print("5) 溯源:这条记忆怎么来的")
|
|
38
|
+
if hits.facts:
|
|
39
|
+
lin = user.explain(hits.facts[0].id)
|
|
40
|
+
src = lin.get("source_messages") or []
|
|
41
|
+
gen = lin.get("generations") or []
|
|
42
|
+
print(f" 来源消息 {len(src)} 条;生成记录 {len(gen)} 条"
|
|
43
|
+
+ (f",模型 {gen[0]['model']},prompt 哈希 {gen[0]['prompt_sha256'][:12]}…" if gen else ""))
|
|
44
|
+
print()
|
|
45
|
+
|
|
46
|
+
print("6) 遗忘(抽错了 → 作废但留痕)")
|
|
47
|
+
if hits.facts:
|
|
48
|
+
user.forget(hits.facts[0].id, reason="示例:这条抽错了")
|
|
49
|
+
after = user.recall("他住在哪里")
|
|
50
|
+
print(f" 否决后再查:{len(after)} 条(原 {len(hits)} 条)")
|
|
51
|
+
print()
|
|
52
|
+
|
|
53
|
+
print("7) 审计账本")
|
|
54
|
+
for e in user.audit(limit=5):
|
|
55
|
+
print(f" {e['at'][:19]} {e['action']} {e['layer']}")
|
|
56
|
+
|
|
57
|
+
print("\n清理:")
|
|
58
|
+
receipt = user.forget(everything=True, reason="示例结束")
|
|
59
|
+
print(f" 删除回执:{receipt['receipt']['deleted']}")
|
|
60
|
+
mc.close()
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
"""memcore — 通用记忆内核的 Python SDK。
|
|
2
|
+
|
|
3
|
+
from memcore import Memcore
|
|
4
|
+
mc = Memcore(api_key="mk_live_...")
|
|
5
|
+
user = mc.subject("user-42")
|
|
6
|
+
user.remember("我住在上海")
|
|
7
|
+
print(user.recall("我住在哪").as_prompt())
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from memcore.client import AsyncMemcore, AsyncSubject, Memcore, Subject
|
|
11
|
+
from memcore.models import MemcoreError, Memory, Profile, ProfileSlot, RecallResult, Why
|
|
12
|
+
|
|
13
|
+
__version__ = "0.3.0"
|
|
14
|
+
__all__ = ["Memcore", "AsyncMemcore", "Subject", "AsyncSubject", "Memory", "Profile",
|
|
15
|
+
"ProfileSlot", "RecallResult", "Why", "MemcoreError"]
|