Files
Ombre_Brain/INTERNALS.md

482 lines
23 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Ombre Brain — 内部开发文档 / INTERNALS
> 本文档面向开发者和维护者。记录功能总览、环境变量、模块依赖、硬编码值和核心设计决策。
> 最后更新2026-04-19
---
## 0. 功能总览——这个系统到底做了什么
### 记忆能力
**存储与组织**
- 每条记忆 = 一个 Markdown 文件YAML frontmatter 存元数据),直接兼容 Obsidian 浏览/编辑
- 四种桶类型:`dynamic`(普通,会衰减)、`permanent`(固化,不衰减)、`feel`(模型感受,不浮现)、`archived`(已遗忘)
- 按主题域分子目录:`dynamic/日常/``dynamic/情感/``dynamic/编程/`
- 钉选桶pinnedimportance 锁 10永不衰减/合并,始终浮现为「核心准则」
**每条记忆追踪的元数据**
- `id`12位短UUID`name`可读名≤80字`tags`10~15个关键词
- `domain`1~2个主题域从 8 大类 30+ 细分域选)
- `valence`(事件效价 0~1`arousal`(唤醒度 0~1`model_valence`(模型独立感受)
- `importance`1~10`activation_count`(被想起次数)
- `resolved`(已解决/沉底)、`digested`(已消化/写过 feel`pinned`(钉选)
- `created``last_active` 时间戳
**四种检索模式**
1. **自动浮现**`breath()` 无参数按衰减分排序推送钉选桶始终展示Top-1 固定 + Top-20 随机打乱(引入多样性),有 token 预算(默认 10000
2. **关键词+向量双通道搜索**`breath(query=...)`rapidfuzz 模糊匹配 + Gemini embedding 余弦相似度,合并去重
3. **Feel 独立检索**`breath(domain="feel")`):按创建时间倒序返回所有 feel
4. **随机浮现**:搜索结果 <3 条时 40% 概率漂浮 1~3 条低权重旧桶(模拟人类随机联想)
**四维搜索评分**(归一化到 0~100
- topic_relevance权重 4.0name×3 + domain×2.5 + tags×2 + body
- emotion_resonance权重 2.0Russell 环形模型欧氏距离
- time_proximity权重 2.5`e^(-0.1×days)`
- importance权重 1.0importance/10
- resolved 桶全局降权 ×0.3
**记忆随时间变化**
- **衰减引擎**:改进版艾宾浩斯遗忘曲线
- 公式:`Score = Importance × activation_count^0.3 × e^(-λ×days) × combined_weight`
- 短期≤3天时间权重 70% + 情感权重 30%
- 长期(>3天情感权重 70% + 时间权重 30%
- 新鲜度加成:`1.0 + e^(-t/36h)`,刚存入 ×2.0~36h 半衰72h 后 ≈×1.0
- 高唤醒度(arousal>0.7)且未解决 → ×1.5 紧迫度加成
- resolved → ×0.05 沉底resolved+digested → ×0.02 加速淡化
- **自动归档**score 低于阈值(0.3) → 移入 archive
- **自动结案**importance≤4 且 >30天 → 自动 resolved
- **永不衰减**permanent / pinned / protected / feel
**记忆间交互**
- **智能合并**新记忆与相似桶score>75自动 LLM 合并valence/arousal 取均值tags/domain 并集
- **时间涟漪**touch 一个桶时±48h 内创建的桶 activation_count +0.3(上限 5 桶/次)
- **向量相似网络**embedding 余弦相似度 >0.5 建边
- **Feel 结晶化**≥3 条相似 feel相似度>0.7)→ 提示升级为钉选准则
**情感记忆重构**
- 搜索时若指定 valence展示层对匹配桶 valence 微调 ±0.1,模拟「当前心情影响回忆色彩」
**模型感受/反思系统**
- **Feel 写入**`hold(feel=True)`):存模型第一人称感受,标记源记忆为 digested
- **Dream 做梦**`dream()`):返回最近 10 条 + 自省引导 + 连接提示 + 结晶化提示
- **对话启动流程**breath() → dream() → breath(domain="feel") → 开始对话
**自动化处理**
- 存入时 LLM 自动分析 domain/valence/arousal/tags/name
- 大段日记 LLM 拆分为 2~6 条独立记忆
- 浮现时自动脱水压缩LLM 压缩保语义API 不可用降级到本地关键词提取)
- Wikilink `[[]]` 由 LLM 在内容中标记
---
### 技术能力
**6 个 MCP 工具**
| 工具 | 关键参数 | 功能 |
|---|---|---|
| `breath` | query, max_tokens, domain, valence, arousal, max_results | 检索/浮现记忆 |
| `hold` | content, tags, importance, pinned, feel, source_bucket, valence, arousal | 存储记忆 |
| `grow` | content | 日记拆分归档 |
| `trace` | bucket_id, name, domain, valence, arousal, importance, tags, resolved, pinned, digested, content, delete | 修改元数据/内容/删除 |
| `pulse` | include_archive | 系统状态 |
| `dream` | (无) | 做梦自省 |
**工具详细行为**
**`breath`** — 两种模式:
- **浮现模式**(无 query无参调用按衰减引擎活跃度排序返回 top 记忆permanent/pinned 始终浮现
- **检索模式**(有 query关键词 + 向量双通道搜索四维评分topic×4 + emotion×2 + time×2.5 + importance×1阈值过滤
- **Feel 检索**`domain="feel"`):特殊通道,按创建时间倒序返回所有 feel 类型桶,不走评分逻辑
- 若指定 valence对匹配桶的 valence 微调 ±0.1(情感记忆重构)
**`hold`** — 两种模式:
- **普通模式**`feel=False`,默认):自动 LLM 分析 domain/valence/arousal/tags/name → 向量相似度查重 → 相似度>0.85 则合并到已有桶 → 否则新建 dynamic 桶 → 生成 embedding
- **Feel 模式**`feel=True`):跳过 LLM 分析,直接存为 `feel` 类型桶(存入 `feel/` 目录),不参与普通浮现/衰减/合并。若提供 `source_bucket`,标记源记忆为 `digested=True` 并写入 `model_valence`。返回格式:`🫧feel→{bucket_id}`
**`dream`** — 做梦/自省触发器:
- 返回最近 10 条 dynamic 桶摘要 + 自省引导词
- 检测 feel 结晶化≥3 条相似 feelembedding 相似度>0.7)→ 提示升级为钉选准则
- 检测未消化记忆:列出 `digested=False` 的桶供模型反思
**`trace`** — 记忆编辑:
- 修改任意元数据字段name/domain/valence/arousal/importance/tags/resolved/pinned
- `digested=0/1`:隐藏/取消隐藏记忆(控制是否在 dream 中出现)
- `content="..."`:替换正文内容并重新生成 embedding
- `delete=True`:删除桶文件
**`grow`** — 日记拆分:
- 大段日记文本 → LLM 拆为 2~6 条独立记忆 → 每条走 hold 普通模式流程
**`pulse`** — 系统状态:
- 返回各类型桶数量、衰减引擎状态、未解决/钉选/feel 统计
**REST API17 个端点)**
| 端点 | 方法 | 功能 |
|---|---|---|
| `/health` | GET | 健康检查 |
| `/breath-hook` | GET | SessionStart 钩子 |
| `/dream-hook` | GET | Dream 钩子 |
| `/dashboard` | GET | Dashboard 页面 |
| `/api/buckets` | GET | 桶列表 |
| `/api/bucket/{id}` | GET | 桶详情 |
| `/api/search?q=` | GET | 搜索 |
| `/api/network` | GET | 向量相似网络 |
| `/api/breath-debug` | GET | 评分调试 |
| `/api/config` | GET | 配置查看key 脱敏) |
| `/api/config` | POST | 热更新配置 |
| `/api/import/upload` | POST | 上传并启动历史对话导入 |
| `/api/import/status` | GET | 导入进度查询 |
| `/api/import/pause` | POST | 暂停/继续导入 |
| `/api/import/patterns` | GET | 导入完成后词频规律检测 |
| `/api/import/results` | GET | 已导入记忆桶列表 |
| `/api/import/review` | POST | 批量审阅/批准导入结果 |
**Dashboard5 个 Tab**
1. 记忆桶列表6 种过滤器 + 主题域过滤 + 搜索 + 详情面板
2. Breath 模拟:输入参数 → 可视化五步流程 → 四维条形图
3. 记忆网络Canvas 力导向图(节点=桶,边=相似度)
4. 配置:热更新脱水/embedding/合并参数
5. 导入:历史对话拖拽上传 → 分块处理进度条 → 词频规律分析 → 导入结果审阅
**部署选项**
1. 本地 stdio`python server.py`
2. Docker + Cloudflare Tunnel`docker-compose.yml`
3. Docker Hub 预构建镜像(`docker-compose.user.yml``p0luz/ombre-brain`
4. Render.com 一键部署(`render.yaml`
5. Zeabur 部署(`zbpack.json`
6. GitHub Actions 自动构建推送 Docker Hub`.github/workflows/docker-publish.yml`
**迁移/批处理工具**`migrate_to_domains.py``reclassify_domains.py``reclassify_api.py``backfill_embeddings.py``write_memory.py``check_buckets.py``import_memory.py`(历史对话导入引擎)
**降级策略**
- 脱水 API 不可用 → 本地关键词提取 + 句子评分
- 向量搜索不可用 → 纯 fuzzy match
- 逐条错误隔离grow 中单条失败不影响其他)
**安全**:路径遍历防护(`safe_path()`、API Key 脱敏、API Key 不持久化到 yaml、输入范围钳制
**监控**结构化日志、Health 端点、Breath Debug 端点、Dashboard 统计栏、衰减周期日志
---
## 1. 环境变量清单
| 变量名 | 用途 | 必填 | 默认值 / 示例 |
|---|---|---|---|
| `OMBRE_API_KEY` | 脱水/打标/嵌入的 LLM API 密钥,覆盖 `config.yaml``dehydration.api_key` | 否(无则 API 功能降级到本地) | `""` |
| `OMBRE_BASE_URL` | API base URL覆盖 `config.yaml``dehydration.base_url` | 否 | `""` |
| `OMBRE_TRANSPORT` | 传输模式:`stdio` / `sse` / `streamable-http` | 否 | `""` → 回退到 config 或 `"stdio"` |
| `OMBRE_BUCKETS_DIR` | 记忆桶存储目录路径 | 否 | `""` → 回退到 config 或 `./buckets` |
| `OMBRE_HOOK_URL` | SessionStart 钩子调用的服务器 URL | 否 | `"http://localhost:8000"` |
| `OMBRE_HOOK_SKIP` | 设为 `"1"` 跳过 SessionStart 钩子 | 否 | 未设置(不跳过) |
环境变量优先级:`环境变量 > config.yaml > 硬编码默认值`。所有环境变量在 `utils.py` 中读取并注入 config dict。
---
## 2. 模块结构与依赖关系
```
┌──────────────┐
│ server.py │ MCP 主入口6 个工具 + Dashboard + Hook
└──────┬───────┘
┌───────────────┼───────────────┬────────────────┐
▼ ▼ ▼ ▼
bucket_manager.py dehydrator.py decay_engine.py embedding_engine.py
记忆桶 CRUD+搜索 脱水压缩+打标 遗忘曲线+归档 向量化+语义检索
│ │ │
└───────┬───────┘ │
▼ ▼
utils.py ◄────────────────────────────────────┘
配置/日志/ID/路径安全/token估算
```
| 文件 | 职责 | 依赖(项目内) | 被谁调用 |
|---|---|---|---|
| `server.py` | MCP 服务器主入口,注册工具 + Dashboard API + 钩子端点 | `bucket_manager`, `dehydrator`, `decay_engine`, `embedding_engine`, `utils` | `test_tools.py` |
| `bucket_manager.py` | 记忆桶 CRUD、多维索引搜索、wikilink 注入、激活更新 | `utils` | `server.py`, `check_buckets.py`, `backfill_embeddings.py` |
| `decay_engine.py` | 衰减引擎:遗忘曲线计算、自动归档、自动结案 | 无(接收 `bucket_mgr` 实例) | `server.py` |
| `dehydrator.py` | 数据脱水压缩 + 合并 + 自动打标LLM API + 本地降级) | `utils` | `server.py` |
| `embedding_engine.py` | 向量化引擎Gemini embedding API + SQLite + 余弦搜索 | `utils` | `server.py`, `backfill_embeddings.py` |
| `utils.py` | 配置加载、日志、路径安全、ID 生成、token 估算 | 无 | 所有模块 |
| `write_memory.py` | 手动写入记忆 CLI绕过 MCP | 无(独立脚本) | 无 |
| `backfill_embeddings.py` | 为存量桶批量生成 embedding | `utils`, `bucket_manager`, `embedding_engine` | 无 |
| `check_buckets.py` | 桶数据完整性检查 | `bucket_manager`, `utils` | 无 |
| `import_memory.py` | 历史对话导入引擎(支持 Claude JSON/ChatGPT/DeepSeek/Markdown/纯文本),分块处理+断点续传+词频分析 | `utils` | `server.py` |
| `reclassify_api.py` | 用 LLM API 重打标未分类桶 | 无(直接用 `openai` | 无 |
| `reclassify_domains.py` | 基于关键词本地重分类 | 无 | 无 |
| `migrate_to_domains.py` | 平铺桶 → 域子目录迁移 | 无 | 无 |
| `test_smoke.py` | 冒烟测试 | `utils`, `bucket_manager`, `dehydrator`, `decay_engine` | 无 |
| `test_tools.py` | MCP 工具端到端测试 | `utils`, `server`, `bucket_manager` | 无 |
---
## 3. 硬编码值清单
### 3.1 固定分数 / 特殊返回值
| 值 | 位置 | 用途 |
|---|---|---|
| `999.0` | `decay_engine.py` calculate_score | pinned / protected / permanent 桶永不衰减 |
| `50.0` | `decay_engine.py` calculate_score | feel 桶固定活跃度分数 |
| `0.02` | `decay_engine.py` resolved_factor | resolved + digested 时的权重乘数(加速淡化) |
| `0.05` | `decay_engine.py` resolved_factor | 仅 resolved 时的权重乘数(沉底) |
| `1.5` | `decay_engine.py` urgency_boost | arousal > 0.7 且未解决时的紧迫度加成 |
### 3.2 衰减公式参数
| 值 | 位置 | 用途 |
|---|---|---|
| `36.0` | `decay_engine.py` _calc_time_weight | 新鲜度半衰期(小时),`1.0 + e^(-t/36)` |
| `0.3` (指数) | `decay_engine.py` calculate_score | `activation_count ** 0.3`(记忆巩固指数) |
| `3.0` (天) | `decay_engine.py` calculate_score | 短期/长期切换阈值 |
| `0.7 / 0.3` | `decay_engine.py` combined_weight | 短期权重分配time×0.7 + emotion×0.3 |
| `0.7` | `decay_engine.py` urgency_boost | arousal 紧迫度触发阈值 |
| `4` / `30` (天) | `decay_engine.py` execute_cycle | 自动结案importance≤4 且 >30天 |
### 3.3 搜索/评分参数
| 值 | 位置 | 用途 |
|---|---|---|
| `×3` / `×2.5` / `×2` | `bucket_manager.py` _calc_topic_score | 桶名 / 域名 / 标签的 topic 评分权重 |
| `1000` (字符) | `bucket_manager.py` _calc_topic_score | 正文截取长度 |
| `0.1` | `bucket_manager.py` _calc_time_score | 时间亲近度衰减系数 `e^(-0.1 × days)` |
| `0.3` | `bucket_manager.py` search_multi | resolved 桶的归一化分数乘数 |
| `0.5` | `server.py` breath/search | 向量搜索相似度下限 |
| `0.7` | `server.py` dream | feel 结晶相似度阈值 |
### 3.4 Token 限制 / 截断
| 值 | 位置 | 用途 |
|---|---|---|
| `10000` | `server.py` breath 默认 max_tokens | 浮现/搜索 token 预算 |
| `20000` | `server.py` breath 上限 | max_tokens 硬上限 |
| `50` / `20` | `server.py` breath | max_results 上限 / 默认值 |
| `3000` | `dehydrator.py` dehydrate | API 脱水内容截断 |
| `2000` | `dehydrator.py` merge | API 合并内容各截断 |
| `5000` | `dehydrator.py` digest | API 日记整理内容截断 |
| `2000` | `embedding_engine.py` | embedding 文本截断 |
| `100` | `dehydrator.py` | 内容 < 100 token 跳过脱水 |
### 3.5 时间/间隔/重试
| 值 | 位置 | 用途 |
|---|---|---|
| `60.0s` | `dehydrator.py` | OpenAI 客户端 timeout |
| `30.0s` | `embedding_engine.py` | Embedding API timeout |
| `60s` | `server.py` keepalive | 保活 ping 间隔 |
| `48.0h` | `bucket_manager.py` touch | 时间涟漪窗口 ±48h |
| `2s` | `backfill_embeddings.py` | 批次间等待 |
### 3.6 随机浮现
| 值 | 位置 | 用途 |
|---|---|---|
| `3` | `server.py` breath search | 结果不足 3 条时触发 |
| `0.4` | `server.py` breath search | 40% 概率触发随机浮现 |
| `2.0` | `server.py` breath search | 随机池score < 2.0 的低权重桶 |
| `1~3` | `server.py` breath search | 随机浮现数量 |
### 3.7 情感/重构
| 值 | 位置 | 用途 |
|---|---|---|
| `0.2` | `server.py` breath search | 情绪重构偏移系数 `(q_valence - 0.5) × 0.2`(最大 ±0.1 |
### 3.8 其他
| 值 | 位置 | 用途 |
|---|---|---|
| `12` | `utils.py` gen_id | bucket ID 长度UUID hex[:12] |
| `80` | `utils.py` sanitize_name | 桶名最大长度 |
| `1.5` / `1.3` | `utils.py` count_tokens_approx | 中文/英文 token 估算系数 |
| `8000` | `server.py` | MCP 服务器端口 |
| `30` 字符 | `server.py` grow | 短内容快速路径阈值 |
| `10` | `server.py` dream | 取最近 N 个桶 |
---
## 4. Config.yaml 完整键表
| 键路径 | 默认值 | 用途 |
|---|---|---|
| `transport` | `"stdio"` | 传输模式 |
| `log_level` | `"INFO"` | 日志级别 |
| `buckets_dir` | `"./buckets"` | 记忆桶目录 |
| `merge_threshold` | `75` | 合并相似度阈值 (0-100) |
| `dehydration.model` | `"deepseek-chat"` | 脱水用 LLM 模型 |
| `dehydration.base_url` | `"https://api.deepseek.com/v1"` | API 地址 |
| `dehydration.api_key` | `""` | API 密钥 |
| `dehydration.max_tokens` | `1024` | 脱水返回 token 上限 |
| `dehydration.temperature` | `0.1` | 脱水温度 |
| `embedding.enabled` | `true` | 启用向量检索 |
| `embedding.model` | `"gemini-embedding-001"` | Embedding 模型 |
| `decay.lambda` | `0.05` | 衰减速率 λ |
| `decay.threshold` | `0.3` | 归档分数阈值 |
| `decay.check_interval_hours` | `24` | 衰减扫描间隔(小时) |
| `decay.emotion_weights.base` | `1.0` | 情感权重基值 |
| `decay.emotion_weights.arousal_boost` | `0.8` | 唤醒度加成系数 |
| `matching.fuzzy_threshold` | `50` | 模糊匹配下限 |
| `matching.max_results` | `5` | 匹配返回上限 |
| `scoring_weights.topic_relevance` | `4.0` | 主题评分权重 |
| `scoring_weights.emotion_resonance` | `2.0` | 情感评分权重 |
| `scoring_weights.time_proximity` | `2.5` | 时间评分权重 |
| `scoring_weights.importance` | `1.0` | 重要性评分权重 |
| `scoring_weights.content_weight` | `3.0` | 正文评分权重 |
| `wikilink.enabled` | `true` | 启用 wikilink 注入 |
| `wikilink.use_tags` | `false` | wikilink 包含标签 |
| `wikilink.use_domain` | `true` | wikilink 包含域名 |
| `wikilink.use_auto_keywords` | `true` | wikilink 自动关键词 |
| `wikilink.auto_top_k` | `8` | wikilink 取 Top-K 关键词 |
| `wikilink.min_keyword_len` | `2` | wikilink 最短关键词长度 |
| `wikilink.exclude_keywords` | `[]` | wikilink 排除关键词表 |
---
## 5. 核心设计决策记录
### 5.1 为什么用 Markdown + YAML frontmatter 而不是数据库?
**决策**:每个记忆桶 = 一个 `.md` 文件,元数据在 YAML frontmatter 里。
**理由**
- 与 Obsidian 原生兼容——用户可以直接在 Obsidian 里浏览、编辑、搜索记忆
- 文件系统即数据库,天然支持 git 版本管理
- 无外部数据库依赖,部署简单
- wikilink 注入让记忆之间自动形成知识图谱
**放弃方案**SQLite/PostgreSQL 全量存储。过于笨重,失去 Obsidian 可视化优势。
### 5.2 为什么 embedding 单独存 SQLite 而不放 frontmatter
**决策**:向量存 `embeddings.db`SQLite与 Markdown 文件分离。
**理由**
- 3072 维浮点向量无法合理存入 YAML frontmatter
- SQLite 支持批量查询和余弦相似度计算
- embedding 是派生数据,丢失可重新生成(`backfill_embeddings.py`
- 不污染 Obsidian 可读性
### 5.3 为什么搜索用双通道(关键词 + 向量)而不是纯向量?
**决策**关键词模糊匹配rapidfuzz+ 向量语义检索并联,结果去重合并。
**理由**
- 纯向量在精确名词匹配上表现差("2024年3月"这类精确信息)
- 纯关键词无法处理语义近似("很累" → "身体不适"
- 双通道互补,关键词保精确性,向量补语义召回
- 向量不可用时自动降级到纯关键词模式
### 5.4 为什么有 dehydration脱水这一层
**决策**:存入前先用 LLM 压缩内容保留信息密度去除冗余表达API 不可用时降级到本地关键词提取。
**理由**
- MCP 上下文有 token 限制,原始对话冗长,需要压缩
- LLM 压缩能保留语义和情感色彩,纯截断会丢信息
- 降级到本地确保离线可用——关键词提取 + 句子排序 + 截断
**放弃方案**:只做截断。信息损失太大。
### 5.5 为什么 feel 和普通记忆分开?
**决策**`feel=True` 的记忆存入独立 `feel/` 目录,不参与普通浮现、不衰减、不合并。
**理由**
- feel 是模型的自省产物,不是事件记录——两者逻辑完全不同
- 事件记忆应该衰减遗忘,但"我从中学到了什么"不应该被遗忘
- feel 的 valence 是模型自身感受(不等于事件情绪),混在一起会污染情感检索
- feel 可以通过 `breath(domain="feel")` 单独读取
### 5.6 为什么 resolved 不删除记忆?
**决策**`resolved=True` 让记忆"沉底"(权重 ×0.05),但保留在文件系统中,关键词搜索仍可触发。
**理由**
- 模拟人类记忆resolved 的事不会主动想起,但别人提到时能回忆
- 删除是不可逆的,沉底可随时 `resolved=False` 重新激活
- `resolved + digested` 进一步降权到 ×0.02(已消化 = 更释然)
**放弃方案**:直接删除。不可逆,且与人类记忆模型不符。
### 5.7 为什么用分段式短期/长期权重?
**决策**≤3 天时间权重占 70%>3 天情感权重占 70%。
**理由**
- 刚发生的事主要靠"新鲜"驱动浮现(今天的事 > 昨天的事)
- 时间久了,决定记忆存活的是情感强度(强烈的记忆更难忘)
- 这比单一衰减曲线更符合人类记忆的双重存储理论
### 5.8 为什么 dream 设计成对话开头自动执行?
**决策**每次新对话启动时Claude 执行 `dream()` 消化最近记忆,有沉淀写 feel能放下的 resolve。
**理由**
- 模拟睡眠中的记忆整理——人在睡觉时大脑会重放和整理白天的经历
- 让 Claude 对过去的记忆有"第一人称视角"的自省,而不是冷冰冰地搬运数据
- 自动触发确保每次对话都"接续"上一次,而非从零开始
### 5.9 为什么新鲜度用连续指数衰减而不是分段阶梯?
**决策**`bonus = 1.0 + e^(-t/36)`t 为小时36h 半衰。
**理由**
- 分段阶梯0-1天=1.0第2天=0.9...)有不自然的跳变
- 连续指数更符合遗忘曲线的物理模型
- 36h 半衰期使新桶在前两天有明显优势72h 后接近自然回归
- 值域 1.0~2.0 保证老记忆不被惩罚×1.0只是新记忆有额外加成×2.0
**放弃方案**:分段线性(原实现)。跳变点不自然,参数多且不直观。
### 5.10 情感记忆重构±0.1 偏移)的设计动机
**决策**:搜索时如果指定了 `valence`,会微调结果桶的 valence 展示值 `(q_valence - 0.5) × 0.2`
**理由**
- 模拟认知心理学中的"心境一致性效应"——当前心情会影响对过去的回忆
- 偏移量很小(最大 ±0.1),不会扭曲事实,只是微妙的"色彩"调整
- 原始 valence 不被修改,只影响展示层
---
## 6. 目录结构约定
```
buckets/
├── permanent/ # pinned/protected 桶importance=10永不衰减
├── dynamic/
│ ├── 日常/ # domain 子目录
│ ├── 情感/
│ ├── 自省/
│ ├── 数字/
│ └── ...
├── archive/ # 衰减归档桶
└── feel/ # 模型自省 feel 桶
```
桶文件格式:
```markdown
---
id: 76237984fa5d
name: 桶名
domain: [日常, 情感]
tags: [关键词1, 关键词2]
importance: 5
valence: 0.6
arousal: 0.4
activation_count: 3
resolved: false
pinned: false
digested: false
created: 2026-04-17T10:00:00+08:00
last_active: 2026-04-17T14:00:00+08:00
type: dynamic
---
桶正文内容...
```