--- title: 架构设计 created: 2026-02-25 --- # 架构设计 ## 设计目标 1. 不使用本地 embedding 模型(避免常驻 Ollama) 2. 向量与元数据留在本地 PostgreSQL(数据可控) 3. 基于 Git 变更做增量 upsert/delete(避免全量重建) 4. 强一致:删除/重命名后不允许幽灵向量残留 5. 安全:敏感内容不入检索库,检索结果具备 Prompt 注入防护 ## 双层记忆模型 ``` ┌─────────────────────────────────────────────┐ │ Claude Agent (agent-with-memory.sh) │ │ │ │ Layer B: MEMORY.md (偏好/事实/约束) │ │ Layer A: pgvector 语义检索结果 │ └─────────────────────────────────────────────┘ ↑ ↑ Claude Code query_pgvector.py MEMORY.md PostgreSQL + pgvector ↑ incremental_ingest.py ↑ git post-commit hook ↑ Obsidian Vault (.md files) ``` ### Layer A:文档语义记忆 - Embedding:OpenRouter API(`openai/text-embedding-3-small`,dim=1536) - 存储:本地 PostgreSQL + pgvector 扩展 - 数据源:`01_Projects/`、`02_Areas/` - 排除:`00_Inbox/`、`04_Archive/`、`Infrastructure/`、`Home-Automation/` - 触发:git `post-commit` hook → 异步 `incremental_ingest.py` ### Layer B:事实与偏好记忆 - 来源:Claude Code `MEMORY.md`(查询时动态读取) - 用途:用户偏好、约束、近期状态 ## 组件职责 | 文件 | 职责 | |---|---| | `index_common.py` | 共享工具:环境加载、DB 连接、Embedding API、排除逻辑、跨平台锁 | | `blacklist.py` | 排除规则:路径模式、文件名关键词、敏感内容特征 | | `ingest_vault.py` | 全量重建索引,清理过期条目 | | `incremental_ingest.py` | 解析 `git diff-tree` 输出,处理 A/M/D/R 事件 | | `query_pgvector.py` | 余弦相似度检索,返回 `` 块 | | `install-hook.sh` | 向 `.git/hooks/post-commit` 追加异步索引触发器 | | `agent-with-memory.sh` | 合并 A+B 层上下文,启动带记忆的 claude 会话 | | `schema.sql` | DB schema:`memory_primary`(向量)、`memory_secure_audit`(隔离审计)| ## 数据库 Schema ```sql -- 主检索表 memory_primary ( id TEXT PRIMARY KEY, -- vault 相对路径 source TEXT, -- 同 id,用于上下文注入显示 content TEXT, -- 完整 markdown 文本 content_hash TEXT, -- sha256,用于变更检测 embedding VECTOR(1536), -- ivfflat 余弦索引 updated_at TIMESTAMPTZ ) -- 敏感文件审计表 memory_secure_audit ( id TEXT PRIMARY KEY, source TEXT, risk TEXT, -- 'excluded_or_sensitive' updated_at TIMESTAMPTZ ) ``` 索引:`ivfflat (embedding vector_cosine_ops) WITH (lists = 100)` ## 增量同步流程 ``` git commit └── post-commit hook(nohup,不阻塞提交) └── incremental_ingest.py --changes-file ├── 解析 git diff-tree 输出(A/M/T/D/R) ├── 获取 index_lock(跨平台文件锁) └── 逐事件处理: A/M/T → upsert_file() D → DELETE from both tables R → DELETE old, upsert_file(new) ``` ## 安全策略 1. 路径精确匹配:按 `Path.parts` 做目录排除,非子串匹配 2. 单命中隔离:任一敏感特征命中即隔离到 `memory_secure_audit` 3. 强一致删除:D/R 事件先删旧 ID,再处理新路径 4. 单写者锁:跨平台文件锁串行化所有索引写操作 5. 只读上下文注入:检索结果包装为 `` 标签,明确标注为非指令 6. 长度截断:注入前全局 `max_chars=2500` ## 关键权衡 | 优点 | 代价 | |---|---| | 不跑本地模型,设备压力低 | Markdown 文本发送到 OpenRouter(非纯本地隐私)| | 向量在本地 DB,数据控制力强 | 依赖网络与 API 可用性 | | 与现有 Git 工作流兼容 | 需配置 API key 与限流/重试策略 |