smart_brain 0.1.2 → 0.3.0

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.
Files changed (79) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +25 -0
  3. data/MEMPAL_GUIDE.md +1074 -0
  4. data/README.en.md +206 -173
  5. data/README.md +593 -173
  6. data/config/brain.yml +69 -1
  7. data/conversation_demo.rb +438 -438
  8. data/db/migrate/002_turn_events_payload.sql +9 -0
  9. data/db/migrate/003_tiers_and_lifecycle.sql +28 -0
  10. data/db/migrate/004_kg_edges.sql +30 -0
  11. data/db/migrate/005_domains_and_memory_scopes.sql +163 -0
  12. data/docs/coding_todo.md +139 -0
  13. data/docs/context_package.md +220 -0
  14. data/docs/evidence_pack.md +190 -0
  15. data/docs/gap_vs_mempal.md +161 -0
  16. data/docs/installation.md +198 -0
  17. data/docs/mcp.md +93 -0
  18. data/docs/media_memory_schema.md +271 -0
  19. data/docs/memory_types.md +278 -0
  20. data/docs/multi_scope_memory_refactor_plan.md +483 -0
  21. data/docs/multi_scope_migration.md +65 -0
  22. data/docs/policies.md +308 -0
  23. data/docs/retrieval_plan.md +233 -0
  24. data/docs/smartbrain_design.md +299 -0
  25. data/docs/user_guide.md +547 -0
  26. data/example.rb +91 -91
  27. data/examples/01_memory_basic.rb +57 -0
  28. data/examples/02_governance.rb +63 -0
  29. data/examples/03_postgres_persistence.rb +63 -0
  30. data/examples/04_ollama_llm.rb +69 -0
  31. data/examples/05_smart_rag_integration.rb +79 -0
  32. data/examples/06_multi_scope_memory.rb +50 -0
  33. data/examples/07_media_memory.rb +53 -0
  34. data/examples/README.md +49 -0
  35. data/exe/smart_brain +168 -0
  36. data/lib/smart_brain/adapters/smart_rag/direct_client.rb +57 -5
  37. data/lib/smart_brain/adapters/smart_rag/http_client.rb +118 -5
  38. data/lib/smart_brain/adapters/smart_rag/http_transport.rb +138 -0
  39. data/lib/smart_brain/adapters/smart_rag/media_metadata_extractor.rb +255 -0
  40. data/lib/smart_brain/adapters/smart_rag/null_client.rb +44 -2
  41. data/lib/smart_brain/adapters/smart_rag/scope_filter.rb +60 -0
  42. data/lib/smart_brain/configuration.rb +60 -0
  43. data/lib/smart_brain/consolidator/working_summary.rb +80 -12
  44. data/lib/smart_brain/context_composer/composer.rb +40 -3
  45. data/lib/smart_brain/contracts/retrieval_plan.rb +10 -0
  46. data/lib/smart_brain/contracts/scope_context.rb +46 -0
  47. data/lib/smart_brain/contracts/scope_ref.rb +25 -0
  48. data/lib/smart_brain/db.rb +109 -0
  49. data/lib/smart_brain/event_store/in_memory.rb +6 -2
  50. data/lib/smart_brain/event_store/postgres.rb +199 -0
  51. data/lib/smart_brain/fusion/merger.rb +31 -2
  52. data/lib/smart_brain/governance/briefing.rb +146 -0
  53. data/lib/smart_brain/governance/fact_check.rb +110 -0
  54. data/lib/smart_brain/governance/knowledge_graph.rb +60 -0
  55. data/lib/smart_brain/governance/lifecycle.rb +225 -0
  56. data/lib/smart_brain/governance/tiers.rb +60 -0
  57. data/lib/smart_brain/memory_extractor/extractor.rb +25 -7
  58. data/lib/smart_brain/memory_store/in_memory.rb +202 -17
  59. data/lib/smart_brain/memory_store/postgres.rb +500 -0
  60. data/lib/smart_brain/model_provider/base.rb +87 -0
  61. data/lib/smart_brain/model_provider/factory.rb +49 -0
  62. data/lib/smart_brain/model_provider/ollama.rb +60 -0
  63. data/lib/smart_brain/model_provider/openai.rb +60 -0
  64. data/lib/smart_brain/model_provider/stub.rb +26 -0
  65. data/lib/smart_brain/model_provider.rb +7 -0
  66. data/lib/smart_brain/observability/tracker.rb +39 -1
  67. data/lib/smart_brain/retrievers/exact_retriever.rb +6 -0
  68. data/lib/smart_brain/retrievers/memory_retriever.rb +59 -5
  69. data/lib/smart_brain/runtime.rb +306 -16
  70. data/lib/smart_brain/scopes/conflict_resolver.rb +67 -0
  71. data/lib/smart_brain/scopes/registry.rb +133 -0
  72. data/lib/smart_brain/scopes/resolver.rb +32 -0
  73. data/lib/smart_brain/server/http_app.rb +143 -0
  74. data/lib/smart_brain/server/mcp_server.rb +385 -0
  75. data/lib/smart_brain/server/service.rb +129 -0
  76. data/lib/smart_brain/support/levenshtein.rb +35 -0
  77. data/lib/smart_brain/version.rb +5 -5
  78. data/lib/smart_brain.rb +93 -35
  79. metadata +100 -54
@@ -0,0 +1,271 @@
1
+ # 媒体记忆:契约与数据模型设计(阶段 0 定稿)
2
+
3
+ > 状态:**P0-P3、数据完整性修复和真实端到端验证已实现**(2026-08-14)
4
+ > 范围:smart_brain 在 SmartRAG 文本资源记忆之外,扩展 image / audio / video 等媒体记忆的契约与数据模型。
5
+ > 本文档是阶段 1–4 实现的对照依据。
6
+
7
+ ## 1. 设计目标与原则
8
+
9
+ 1. **载体复用,不加表**:媒体记忆 = 结构化元数据(存 `source_documents.metadata` JSONB)+ 可检索文本(存 `source_sections`)。现有文本链路零改动。
10
+ 2. **两个正交维度**:`source_type`(来源:url/file/manual)与 `media_type`(内容类别:image/audio/video/document/other)互不干扰,不能合并。
11
+ 3. **向后兼容**:`add_document` 行为不变;`retrieve` 无 `media_type` 过滤时行为不变;证据结构字段只增不改。
12
+ 4. **可降级**:LLM/whisper 依赖缺失时,仅存技术元数据 + 文件名/标签,仍有价值且不报错。
13
+
14
+ ## 2. 媒体类型清单(`media_type` 枚举)
15
+
16
+ | 值 | 含义 | 覆盖内容 | 专用入口 |
17
+ |---|---|---|---|
18
+ | `image` | 图片 | jpg/png/gif/webp/heic | `add_image` |
19
+ | `audio` | 音频 | mp3/wav/m4a/flac/ogg | `add_audio` |
20
+ | `video` | 视频 | mp4/mkv/mov/webm | `add_video` |
21
+ | `document` | 文档类 | pdf/docx/xlsx/pptx/md/txt/html/csv/json 等(即现有 `add_document` 全部覆盖面,**text 并入 document**) | `add_document` |
22
+ | `other` | 无法识别 | — | `add_media` 兜底 |
23
+
24
+ - 枚举值:`image / audio / video / document / other`。
25
+ - `add_document` 语义不变,仅显式归类为 `media_type: "document"`。
26
+ - 命名以产品语义为准,不与 IANA 的 `application` 对齐。
27
+
28
+ ### 2.1 类型推断规则(`add_media(media_type: :auto)` 时)
29
+
30
+ 1. 扩展名映射表优先(`.jpg/.png` → image,`.mp3/.wav` → audio,`.mp4/.mov` → video,其余文档扩展名 → document);
31
+ 2. 无法从扩展名判断时用 `file` 命令 MIME 兜底;
32
+ 3. 仍无法识别 → `other`。
33
+
34
+ ## 3. 数据模型:`metadata` JSONB schema
35
+
36
+ 在现有 `extract_metadata` 产物(`file_path/file_size/file_type/created_at/modified_at` + 用户覆盖)之上,新增三个键:
37
+
38
+ ```json
39
+ {
40
+ "media_type": "image",
41
+ "media": {
42
+ "format": "jpeg",
43
+ "width": 1920,
44
+ "height": 1080,
45
+ "dpi": 72,
46
+ "color_mode": "RGB",
47
+ "orientation": "landscape",
48
+ "exif": { "datetime": "2026-07-01T10:00:00Z", "camera_model": "X", "gps": { "lat": 31.2, "lon": 121.5 } },
49
+ "duration_ms": null,
50
+ "bitrate_bps": null,
51
+ "sample_rate_hz": null,
52
+ "channels": null,
53
+ "codec": null,
54
+ "fps": null,
55
+ "audio_codec": null
56
+ },
57
+ "semantic": {
58
+ "description": "产品发布会现场白板照片",
59
+ "captions": ["画面中央是需求流程图,标题为 Q3 路线图"],
60
+ "tags": ["发布会", "白板", "路线图"]
61
+ },
62
+ "content": "(截断后的转写/描述摘要,见 3.3)"
63
+ }
64
+ ```
65
+
66
+ ### 3.1 设计要点(已确认决策)
67
+
68
+ - **D1(通过)**:`media` 是**单一对象、三态共用、类型特有字段置 null**。检索与展示代码无需按类型分支。
69
+ - **D2(通过)**:`media_type` 在**顶层冗余**一份,`metadata->>'media_type'` 可直接查询/过滤,不用剥 `media` 对象。
70
+ - **D3(通过)**:`title` **只进 `document.title` 列**,不进 `semantic`,避免双写不一致。
71
+ - **D4(通过)**:`metadata.content` 存**截断后的转写/描述摘要**,全文只进 `sections`。
72
+
73
+ ### 3.2 `media` 字段说明
74
+
75
+ | 字段 | 适用 | 说明 |
76
+ |---|---|---|
77
+ | `format` | 全部 | 实际格式(jpeg/mp3/mp4/…),来自解析 |
78
+ | `width` / `height` | image/video | 像素尺寸;其他类型 null |
79
+ | `dpi` | image | 分辨率;其他类型 null |
80
+ | `color_mode` | image | RGB/CMYK/灰度等 |
81
+ | `orientation` | image/video | landscape/portrait,可推导可不存 |
82
+ | `exif` | image | 可选:拍摄时间、相机、GPS;无则 `{}` |
83
+ | `duration_ms` | audio/video | 时长(毫秒) |
84
+ | `bitrate_bps` | audio/video | 码率(bps),解析不到则 null |
85
+ | `sample_rate_hz` | audio | 采样率 |
86
+ | `channels` | audio | 声道数 |
87
+ | `codec` | audio/video | 编码(h264/mp3/…) |
88
+ | `fps` | video | 帧率 |
89
+ | `audio_codec` | video | 视频内音轨编码 |
90
+
91
+ ### 3.3 `semantic` 字段说明
92
+
93
+ - `description`:用户或 LLM 提供的整体描述(可 null)。
94
+ - `captions`:LLM 生成的描述/字幕句(数组,可空)。图片为画面描述,音频/视频为转写字幕句。
95
+ - `tags`:用户标签(数组,可空)。
96
+
97
+ ## 4. 写侧 API 契约
98
+
99
+ ### 4.1 SmartRAG 层(真实执行者)
100
+
101
+ ```ruby
102
+ rag.add_image(source, options = {}) # media_type 固定 "image"
103
+ rag.add_audio(source, options = {}) # 固定 "audio"
104
+ rag.add_video(source, options = {}) # 固定 "video"
105
+ rag.add_document(source, options = {}) # 现有,显式归类 media_type: "document"
106
+ rag.add_media(source, options = {}) # media_type: :auto | "image" | "audio" | "video" | "document"
107
+ ```
108
+
109
+ `options` 统一字典(全可选,命名对齐现有 `add_document` 的 options):
110
+
111
+ - `title:` / `description:` / `author:` / `tags:` → 语义元数据
112
+ - `media_type:` → 仅 `add_media` 使用
113
+ - `llm_caption: true` → 图片/视频帧生成描述(默认开,依赖缺失降级)
114
+ - `transcribe: true` → 音频/视频转写(默认开,依赖缺失降级)
115
+ - `generate_embeddings:` / `generate_tags:` → 透传现有 `save_sections` 选项
116
+ - `metadata: {}` → 用户覆盖(现有约定:merge 进 extract_metadata 结果)
117
+ - `source_type:` / `source_uri:` / `url:` → 透传现有 `create_or_update_document`
118
+
119
+ 统一返回结构:
120
+
121
+ ```ruby
122
+ {
123
+ document_id: 123,
124
+ media_type: "image",
125
+ status: "success", # "success" | "unsupported"
126
+ section_count: 3,
127
+ metadata: { media: {...}, semantic: {...} }, # 入库后回读的元数据
128
+ warnings: ["whisper 未安装,跳过音频转写"] # 降级说明
129
+ }
130
+ ```
131
+
132
+ ### 4.2 smart_brain 适配层(三个客户端统一契约)
133
+
134
+ ```ruby
135
+ add_document(source, options = {}) # 新增(现有客户端只有 retrieve)
136
+ add_image(source, options = {})
137
+ add_audio(source, options = {})
138
+ add_video(source, options = {})
139
+ add_media(source, options = {})
140
+ ```
141
+
142
+ - `DirectClient` → 转发 `@rag`
143
+ - `HttpClient` → `POST /v1/media`;本地文件走 multipart,URL 走 JSON。服务端 extractor 由 SmartRAG `HttpApp` 注入。
144
+ - `NullClient` → `{status: "unsupported", warnings: ["smart_rag client not configured; add_media ignored"]}`(fail closed,与现有 retrieve 降级风格一致)
145
+
146
+ ### 4.3 smart_brain 门面(阶段 4 薄封装)
147
+
148
+ ```ruby
149
+ SmartBrain.add_image(source:, options: {})
150
+ SmartBrain.add_audio(source:, options: {})
151
+ SmartBrain.add_video(source:, options: {})
152
+ SmartBrain.add_media(source:, options: {})
153
+ ```
154
+
155
+ - **不绑定 session**:媒体资源是全局资源记忆(归 SmartRAG 库),不属于某个对话会话。
156
+ - 导入动作是否记入 EventStore → 列为后续增强点,不纳入本契约。
157
+
158
+ ## 5. 读侧 / 检索契约
159
+
160
+ ### 5.1 过滤(RetrievalPlan → SmartRAG filters)
161
+
162
+ ```ruby
163
+ plan[:filters] = { media_type: "image" } # 或 ["image", "audio"]
164
+ ```
165
+
166
+ - 单值或数组皆可(对齐现有 `source_type` 的 `Array()` 归一化风格)。
167
+ - 实现落在 `candidate_passes_filters?` 新增分支:从 `candidate[:metadata][:media_type]` 取值比较。
168
+ - 不带此过滤时行为不变。
169
+
170
+ ### 5.2 证据透传(EvidencePack)
171
+
172
+ - **不新增 `kind`**:仍是 `resource_section`(媒体检索命中的就是转写/描述文本块)。
173
+ - `metadata` 透传 `media_type` + `media` + `semantic`,`source_type`/`title`/`snippet` 字段语义不变。
174
+ - 现有 merger/composer 消费代码无需改动(它们只读 title/snippet/metadata)。
175
+
176
+ ## 6. 完整示例(评审用)
177
+
178
+ ### 6.1 image
179
+
180
+ ```json
181
+ {
182
+ "media_type": "image",
183
+ "media": { "format": "jpeg", "width": 1920, "height": 1080, "dpi": 72, "color_mode": "RGB",
184
+ "orientation": "landscape", "exif": {}, "duration_ms": null, "codec": null,
185
+ "bitrate_bps": null, "sample_rate_hz": null, "channels": null, "fps": null, "audio_codec": null },
186
+ "semantic": { "description": "产品发布会白板", "captions": ["画面中央是需求流程图,标题为 Q3 路线图"], "tags": [] },
187
+ "content": "需求流程图:Q3 路线图……(LLM 描述摘要)"
188
+ }
189
+ ```
190
+
191
+ ### 6.2 audio
192
+
193
+ ```json
194
+ {
195
+ "media_type": "audio",
196
+ "media": { "format": "mp3", "duration_ms": 1870000, "bitrate_bps": 128000, "sample_rate_hz": 44100,
197
+ "channels": 2, "codec": "mp3", "width": null, "height": null, "dpi": null,
198
+ "color_mode": null, "orientation": null, "exif": {}, "fps": null, "audio_codec": null },
199
+ "semantic": { "description": null, "captions": ["……转写句子 1", "……转写句子 2"], "tags": ["会议"] },
200
+ "content": "大家好,今天我们讨论 Q3 路线图……(转写摘要)"
201
+ }
202
+ ```
203
+
204
+ ### 6.3 video
205
+
206
+ ```json
207
+ {
208
+ "media_type": "video",
209
+ "media": { "format": "mp4", "duration_ms": 452000, "width": 1920, "height": 1080, "fps": 30,
210
+ "codec": "h264", "audio_codec": "aac", "bitrate_bps": null, "sample_rate_hz": null,
211
+ "channels": null, "dpi": null, "color_mode": null, "orientation": "landscape",
212
+ "exif": {} },
213
+ "semantic": { "description": null, "captions": ["第 1 帧:界面加载中……", "字幕:点击导入按钮"], "tags": [] },
214
+ "content": "字幕与帧描述摘要……"
215
+ }
216
+ ```
217
+
218
+ ## 7. 存储影响
219
+
220
+ - 文档级媒体信息继续使用 `source_documents.metadata` JSONB。
221
+ - 第二批 MVP 为 `source_sections` 增加 `metadata` JSONB + GIN,用于保存视频片段的 `start_ms/end_ms/frame_timestamp_ms/extraction_kind`。
222
+ - 可选优化(不阻塞):如需高频 `media_type` 过滤可加表达式索引,但 JSONB GIN 对 `@>` 与 key 路径已覆盖,**建议先不加**。
223
+
224
+ ## 8. 边界 / 非目标(明确不做)
225
+
226
+ - 不新建表、不改现有文本链路、不新增 `source_type` 值(如 `"media"`)——`source_type` 语义保持。
227
+ - 不做视频语义理解(仅字幕/帧描述/OCR)。
228
+ - 不做对象存储/大文件托管(文件仍走本地路径/URL)。
229
+ - 初始 MVP 不做权限/配额控制;P3 已补充 Bearer principal、任务/文档隔离和数据库配额。
230
+ - 不把导入动作记入 EventStore(列为后续增强)。
231
+
232
+ ## 9. 决策点结论(已确认)
233
+
234
+ | 决策点 | 结论 |
235
+ |---|---|
236
+ | D1 media 对象形态 | 单一对象 + null 填充(通过) |
237
+ | D2 media_type 顶层冗余 | 冗余(通过) |
238
+ | D3 title 归属 | 只进 `document.title` 列,不进 semantic(通过) |
239
+ | D4 metadata.content | 存截断摘要,全文进 sections(通过) |
240
+ | D5 llm_caption / transcribe 默认 | 默认开,缺依赖降级 + warnings(通过) |
241
+ | D6 文档类枚举值 | `document`(非 application),`add_document` 即专用入口(通过) |
242
+ | D6a text 归类 | 并入 `document`(通过) |
243
+ | D7 smart_brain 门面 | 阶段 4 做薄封装(通过) |
244
+ | D8 枚举命名 | 产品语义为准,不与 IANA 对齐(通过) |
245
+ | D9 filters[:media_type] | 单值 + 数组(通过) |
246
+
247
+ ## 10. 后续阶段对照
248
+
249
+ - **阶段 1**:SmartRAG `MediaMetadataExtractor`(image/audio/video 技术元数据解析,Python bridge,可降级)。
250
+ - **阶段 2**:媒体内容可检索化(图片描述/OCR、音频转写、视频音轨转写和关键帧描述已支持通过 extractor callable 接入)。
251
+ - **阶段 3**:SmartRAG `add_image/add_audio/add_video/add_media` API(复用 `create_document` 管线)。
252
+ - **阶段 4**:smart_brain 适配层写 API(三客户端)+ HTTP JSON/multipart 协议 + `filters[:media_type]` 检索过滤 + 门面封装(已完成)。
253
+ - **阶段 5**:测试、文档、示例(`examples/media_memory.rb`)。
254
+
255
+ ## 11. P1 / P2 生产能力补充
256
+
257
+ - **P1**:内置 OCR/视觉/转写适配器、时间戳切片、场景检测、安全限制、本地内容寻址存储、PostgreSQL 异步队列和 worker。
258
+ - **P2**:任务分页与状态过滤、取消与人工重试、过期 `processing` 恢复、终态保留期清理、队列统计及健康检查。失败的异步上传在清理期内保留,以支持人工重试。
259
+ - `media_jobs` 由迁移 013 创建,迁移 014 增加恢复和清理所需的组合索引。
260
+ - **P3**:迁移 015 增加 heartbeat lease、按 principal 隔离的幂等键、`media_objects` / `media_object_references` 引用管理和数据库配额计数。内容存储支持本地 CAS 与可选 S3/MinIO;HTTP 可启用 Bearer 认证和调用方配额。
261
+ - **数据完整性修复**:迁移 016 为文档增加 `principal` owner,并用 `media_jobs.staging_media_object_id` 显式保护 queued/processing/failed 任务的源对象。同步导入在语义提取前登记零引用对象,失败后可由 GC 回收;检索、读取、列表、删除和统计按认证 principal 隔离。
262
+ - **幂等冲突检测**:迁移 017 为任务增加非空 `request_fingerprint`,并为历史任务回填 SHA-256 指纹。指纹由 operation、source 和递归规范化后的可序列化 options 组成;同 principal/幂等键/指纹返回原任务,同 principal/幂等键但指纹不同则返回 HTTP 409 `idempotency_conflict`。不同 principal 可复用同一键。
263
+ - **检索纵深隔离**:认证 principal 先转换为 PostgreSQL 中拥有的 document ID 白名单并下推搜索,再对后端返回候选逐条复核 owner。HTTP Bearer 认证失败返回 401,检索结果不公开内部 principal 过滤字段。
264
+ - **真实 MinIO E2E**:显式启用的集成规格验证两个独立 S3 client 实例间的字节一致性、异步 worker 对 `s3://` URI 的物化、引用计数、解除引用后的真实删除,以及 retained failed job 对 staging 对象的 GC 保护。
265
+
266
+ ### 11.1 升级和调用方约束
267
+
268
+ 1. 部署新队列代码前,先将 SmartRAG 数据库迁移到 017;新列为 `NOT NULL`,绕过队列直接写 `media_jobs` 的内部工具也必须写入有效指纹。
269
+ 2. 网络重试必须复用原幂等键和完全相同的业务载荷。若 source、operation 或 options 改变,应创建新幂等键,不能把 409 当作成功去重。
270
+ 3. SmartBrain `HttpClient` 将 SmartRAG HTTP 409 包装为 `status: "failed"` 和 warning;`DirectClient` 直接传播 `MediaJobQueue::IdempotencyConflict`。业务层应分别检查结果状态或捕获异常。
271
+ 4. MinIO/S3 多实例部署必须使用所有 worker 均可访问的 endpoint、bucket 和 prefix。任务保留期结束并被 prune 后,零引用 staging 对象才允许被 GC。
@@ -0,0 +1,278 @@
1
+ ## 1. 目的
2
+
3
+ MemoryTypes 用于把“对话与工具事件中可沉淀的长期信息”结构化,解决:
4
+ - 记忆污染(把闲聊当长期事实)
5
+ - 冲突不可控(同一事实多版本)
6
+ - 检索不可用(只存全文,无法聚合/过滤/关联)
7
+ - 无法解释(不知道这条记忆来自哪里)
8
+
9
+ 本规范定义:
10
+ - 记忆类型(type)
11
+ - key 规则(如何唯一标识一条记忆)
12
+ - value 形态(建议的 JSON)
13
+ - 写入门控与冲突合并策略(最低要求)
14
+
15
+ ---
16
+
17
+ ## 2. 总体存储模型(建议)
18
+
19
+ ### 2.1 memory_items(结构化)
20
+ 字段建议:
21
+ - `id`
22
+ - `type`
23
+ - `key`
24
+ - `value_json`
25
+ - `confidence`(0..1)
26
+ - `status`(active|superseded|retracted)
27
+ - `source_turn_id`
28
+ - `source_message_id`(可选)
29
+ - `evidence_refs`(可选:document_id/section_id/url)
30
+ - `updated_at`
31
+
32
+ ### 2.2 memory_chunks(可检索文本)
33
+ - `id`
34
+ - `memory_item_id`
35
+ - `text`(用于 FTS/embedding)
36
+ - `embedding`
37
+ - `tsv`
38
+ - `meta_json`(包含 type/key、版本、语言等)
39
+
40
+ > 规则:memory_items 是真相;memory_chunks 是派生索引内容,可重建。
41
+
42
+ ---
43
+
44
+ ## 3. 类型清单(v0.1)
45
+
46
+ v0.1 约定以下类型(type):
47
+
48
+ ### 3.1 profile(用户/主体画像)
49
+ - 含义:稳定身份信息(职业、背景、组织、长期角色)
50
+ - key 规则:`profile:<subject>`
51
+ - subject 常用:`user`(默认)、或 `agent`(多主体时)
52
+ - value_json 示例:
53
+ ```json
54
+ {
55
+ "subject": "user",
56
+ "facts": [
57
+ {"k": "role", "v": "Executive Secretary General of ...", "since": "2024-05-17"}
58
+ ]
59
+ }
60
+ ```
61
+
62
+ * 写入门控:只有明确陈述且稳定的信息才写入;不确定内容写入 events,不写 profile。
63
+
64
+ ### 3.2 preferences(偏好与约束)
65
+
66
+ * 含义:写作风格、工具偏好、语言偏好、预算偏好等
67
+ * key 规则:`pref:<scope>:<name>`
68
+
69
+ * scope:`writing|coding|tools|ui|other`
70
+ * value_json 示例:
71
+
72
+ ```json
73
+ {
74
+ "scope": "writing",
75
+ "name": "tone",
76
+ "value": "focused and exacting",
77
+ "priority": 0.8
78
+ }
79
+ ```
80
+
81
+ * 冲突策略:同 key 新值覆盖旧值(旧值 status=superseded),保留历史版本。
82
+
83
+ ### 3.3 goals(长期目标)
84
+
85
+ * 含义:项目目标、学习目标、长期规划
86
+ * key 规则:`goal:<project_or_topic>:<name>`
87
+ * value_json 示例:
88
+
89
+ ```json
90
+ {
91
+ "project": "SmartBrain",
92
+ "name": "local_first_memory_runtime",
93
+ "description": "Build ...",
94
+ "status": "active"
95
+ }
96
+ ```
97
+
98
+ ### 3.4 tasks(任务与待办)
99
+
100
+ * 含义:可追踪的任务项(含状态流转)
101
+ * key 规则:`task:<project>:<task_id>`(task_id 可为 uuid 或 slug)
102
+ * value_json 示例:
103
+
104
+ ```json
105
+ {
106
+ "project": "SmartBot",
107
+ "task_id": "brain_runtime_mvp",
108
+ "title": "Integrate SmartBrain into SmartBot loop",
109
+ "status": "todo|doing|done|blocked",
110
+ "due": "2026-03-01",
111
+ "notes": ["..."]
112
+ }
113
+ ```
114
+
115
+ * 重要:tasks 应当支持状态更新(commit_turn 时识别“已完成/阻塞”)。
116
+
117
+ ### 3.5 decisions(决策与承诺)
118
+
119
+ * 含义:已经决定的方案、选择、不可逆约束
120
+ * key 规则:`decision:<project>:<topic>`
121
+ * value_json 示例:
122
+
123
+ ```json
124
+ {
125
+ "project": "SmartRAG",
126
+ "topic": "retrieve_api_contract",
127
+ "decision": "Add retrieve(plan) returning EvidencePack",
128
+ "rationale": "Contract-based integration with SmartBrain",
129
+ "made_at": "2026-02-20"
130
+ }
131
+ ```
132
+
133
+ ### 3.6 entities(实体)
134
+
135
+ * 含义:对话中出现的重要实体(人/组织/项目/仓库/文件/URL 域名等)
136
+ * key 规则:`entity:<kind>:<canonical>`
137
+
138
+ * kind:`person|org|repo|file|url|topic|other`
139
+ * value_json 示例:
140
+
141
+ ```json
142
+ {
143
+ "kind": "repo",
144
+ "canonical": "zhuangbiaowei/smart_rag",
145
+ "aliases": ["smart_rag"],
146
+ "attrs": {"host": "github.com"}
147
+ }
148
+ ```
149
+
150
+ * 备注:entities 通常配合 entity_mentions 表用于关联检索。
151
+
152
+ ### 3.7 events(重要事件)
153
+
154
+ * 含义:可被未来引用的关键事件(发布、会议、里程碑、异常)
155
+ * key 规则:`event:<project_or_scope>:<date>:<slug>`
156
+ * value_json 示例:
157
+
158
+ ```json
159
+ {
160
+ "scope": "SmartBrain",
161
+ "date": "2026-02-20",
162
+ "title": "Decided to split memory runtime into SmartBrain",
163
+ "impact": "architecture"
164
+ }
165
+ ```
166
+
167
+ ### 3.8 cases(案例/经验片段)
168
+
169
+ * 含义:某次任务的输入—过程—输出—结果,可复用
170
+ * key 规则:`case:<domain>:<slug_or_id>`
171
+ * value_json 示例:
172
+
173
+ ```json
174
+ {
175
+ "domain": "rag_debug",
176
+ "problem": "...",
177
+ "solution": "...",
178
+ "outcome": "works",
179
+ "artifacts": [{"type":"doc","ref":"..."}]
180
+ }
181
+ ```
182
+
183
+ ### 3.9 patterns(模式/规则)
184
+
185
+ * 含义:从多个案例/对话中归纳出的可复用策略
186
+ * key 规则:`pattern:<domain>:<name>`
187
+ * value_json 示例:
188
+
189
+ ```json
190
+ {
191
+ "domain": "context_composing",
192
+ "name": "slot_based_composition",
193
+ "rule": "system core -> summary -> recent -> evidence -> user",
194
+ "confidence": 0.7
195
+ }
196
+ ```
197
+
198
+ ---
199
+
200
+ ## 4. key 设计规则(必须遵守)
201
+
202
+ 1. **稳定性**:同一事实应映射到同一 key(便于更新与去重)
203
+ 2. **可读性**:key 应可读可排查(不全是 uuid)
204
+ 3. **可扩展**:允许引入 scope/domain/project 前缀
205
+ 4. **可多主体**:必要时将 subject 纳入 key(profile/user vs profile/agent)
206
+
207
+ ---
208
+
209
+ ## 5. 写入门控(Retention Gate)最低要求
210
+
211
+ SmartBrain 在 commit_turn 时必须执行门控:
212
+
213
+ * 必写(高价值):
214
+
215
+ * tool_call 结果(尤其是产出 artifact、变更状态)
216
+ * refs(文件/URL)及其摘要/元信息
217
+ * decisions(明确决策)
218
+ * tasks(新增/更新/完成)
219
+ * 条件写(中价值):
220
+
221
+ * preferences(明确偏好、可稳定复用)
222
+ * goals(明确长期目标)
223
+ * entities/events(出现频繁或被强调的实体/事件)
224
+ * 不写入长期记忆(仅存 event):
225
+
226
+ * 闲聊、情绪性内容、一次性无复用信息
227
+ * 模糊推测、未确认事实
228
+
229
+ ---
230
+
231
+ ## 6. 冲突合并策略(最低要求)
232
+
233
+ ### 6.1 覆盖型(overwrite)
234
+
235
+ 适用:preferences/goals/tasks(同 key 新值应覆盖旧值)
236
+
237
+ * 旧值标记:`status = superseded`
238
+ * 保留历史版本(便于回滚/审计)
239
+
240
+ ### 6.2 多版本并存(versioned)
241
+
242
+ 适用:profile(谨慎)、decisions/events(应保留历史)
243
+
244
+ * 以时间或版本号区分(在 value_json 中存 `version` 或 `made_at`)
245
+ * compose 时默认选最新/最高置信
246
+
247
+ ### 6.3 撤回(retracted)
248
+
249
+ 适用:用户明确否认的事实
250
+
251
+ * 将旧条目标记 `status = retracted`
252
+ * 新条目可写入修正事实(同 key 或新 key)
253
+
254
+ ---
255
+
256
+ ## 7. memory_chunks 文本化规则(用于检索)
257
+
258
+ 为了让 FTS/embedding 有用,每个 memory_item 应生成一个或多个 chunk 文本:
259
+
260
+ * 第一行:`[type:key]`(用于定位)
261
+ * 主体:对 value_json 的可读摘要
262
+ * 可附:来源/时间/项目
263
+
264
+ 示例(preferences):
265
+
266
+ ```
267
+ [preferences:pref:writing:tone]
268
+ User prefers a focused and exacting tone for technical documents.
269
+ Updated at: 2026-02-20
270
+ ```
271
+
272
+ ---
273
+
274
+ ## 8. 版本与兼容
275
+
276
+ * v0.1:类型集合与 key 规则为最低一致性要求
277
+ * 可新增 type,但必须遵守 key 规则
278
+ * 破坏性变更(重命名 type/key 规则)需要 major 版本与迁移策略