mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-24 02:48:04 +00:00
docs: update sequence diagram, memory flow, vectorization strategy for StaticEmbedder + CleanTemplateText + three-branch vector
This commit is contained in:
@ -75,42 +75,44 @@ Setting `ctx.Response` at any stage jumps to `after_output`.
|
||||
```
|
||||
① Context (Working Window)
|
||||
RelevanceContext — In-memory events[] + JSON persistence
|
||||
Append: Each input, Vectorize(char 1-2gram TF-IDF)
|
||||
Prune: TF-IDF CosineSimilarity, keep topK + last 10
|
||||
├── Keep → timeline → system prompt (sorted by time)
|
||||
└── Low score → Document layer archive (ContextToDoc)
|
||||
Append: Each input, CleanTemplateText → three-branch vector(textForVector)
|
||||
agent→Response, user→Input, cold_storage→Input+Response
|
||||
StaticEmbedder pretrained word embedding / TF-IDF fallback
|
||||
Prune: StaticEmbedder CosineSimilarity, keep topK + last 10
|
||||
├── Keep → timeline → chronologically sorted → system prompt
|
||||
└── Low score → Document layer archive (original timestamp)
|
||||
Save: 5s debounce write to disk
|
||||
|
||||
↓ Prune archive ↑ LLM active recall
|
||||
↓ Prune archive ↑ LLM active recall
|
||||
|
||||
② Document (File Memory)
|
||||
DocStore — JSON files + TF-IDF InvertedIndex
|
||||
Write: Prune archive / doc_commit / Graph snapshot (syncGraphToDocs)
|
||||
Read:
|
||||
├── Auto-inject: Query(input, top3) → [Related Memory Docs] → system prompt (read-only, update AccessCount)
|
||||
├── Auto-inject: Query(input, top3) → similarity summary → [Related Memory Docs] → system prompt (read-only)
|
||||
└── LLM active: doc_query → Consume(read and delete)
|
||||
→ context.Append{Timestamp: d.CreatedAt, Source: "cold_storage"} per doc
|
||||
→ Docs written to context timeline with original timestamps, deleted from docStore
|
||||
Cold: FindColdDocs(72h, ≤2 accesses) → docToTriples → Graph
|
||||
|
||||
↓ Cold doc distillation ↑ Auto recall
|
||||
↓ Cold doc distillation ↑ Auto recall
|
||||
|
||||
③ Graph (Graph Database)
|
||||
SQLite — entities + relations tables
|
||||
Write: memory_commit / cold doc distillation / Pipeline rule distillation
|
||||
Write: memory_commit / cold doc distillation / Pipeline rule distillation / memory_merge
|
||||
Read:
|
||||
├── Auto recall: Indexer.BuildContext(input)
|
||||
│ → TF-IDF entity name search → BFS depth=2
|
||||
│ → CleanTemplateText → vector entity search + jieba keywords → SQLite LIKE + BFS depth=2
|
||||
│ → [Memory Index] → system prompt
|
||||
└── LLM active: memory_recall / doc_query
|
||||
└── LLM active: memory_recall / memory_merge / memory_purge / memory_edit / memory_delete_entity
|
||||
Social: person_query / set_trait / relate (wraps GraphDB)
|
||||
|
||||
④ Distillation Pipeline (30min heartbeat)
|
||||
distillContext → window > 2×maxSize → force Prune
|
||||
syncGraphToDocs → Graph snapshot to Document (cross-layer searchable)
|
||||
reorgGraph:
|
||||
Step1: indexer.Sync — rebuild entity TF-IDF vector index
|
||||
Step2: docStore.Reindex — rebuild document TF-IDF vector index
|
||||
Step1: indexer.Sync — rebuild entity vector index
|
||||
Step2: docStore.Reindex — rebuild document vector index
|
||||
Step3: Cold docs → docToTriples → GraphDB.Commit
|
||||
Step4: Entity similarity (Bigram Jaccard > 0.75) → consolidation → LLM decides merge
|
||||
Step5: evaluateGraphQuality → LLM decides keep/delete
|
||||
@ -121,36 +123,35 @@ Setting `ctx.Response` at any stage jumps to `after_output`.
|
||||
→ triples → GraphDB.Commit
|
||||
```
|
||||
|
||||
### Vectorization: Two Strategies
|
||||
### Vectorization: Pretrained Word Embedding + TF-IDF Fallback
|
||||
|
||||
Vectorization is used in 4 independent locations with different strategies:
|
||||
All vectorization unified under `StaticEmbedder` (`internal/memory/static_embedder.go`):
|
||||
|
||||
**Strategy A — Local Word Embedding** (`LocalWordEmbedder`, `internal/memory/embedder.go`), used by Context layer:
|
||||
|
||||
- **jieba tokenization** → removes stop words and single characters
|
||||
- **TF-IDF** as base word weight
|
||||
- **Sliding window (size=5)** counts word co-occurrence → **PMI (Pointwise Mutual Information)** → keeps top 50
|
||||
- **Vectorization**: `vec[ctx] += TF-IDF × PMI` + self-tag `__w__` + TF-IDF
|
||||
|
||||
**Strategy B — char-bigram TF-IDF + jieba keyword extraction** (`TFIDFVectorizer` + `ExtractKeywords`), used by Document and Indexer layers:
|
||||
|
||||
- **char bigram tokenization** (1-2 gram) for entity name vector search
|
||||
- **jieba tokenization** for keyword extraction, paired with SQLite LIKE + BFS traversal
|
||||
- **TF-IDF weights** + **inverted index**
|
||||
**Primary Strategy — Pretrained Word Embedding (aligned 300d)**
|
||||
- Model sources: ConceptNet Numberbatch (77-language aligned) / fastText Chinese / fastText English
|
||||
- Configured via `core.agent.embedding_model_path` (comma-separated multi-model)
|
||||
- Path containing `numberbatch` → auto-download ConceptNet; `cc.zh.` → fastText Chinese; `cc.en.` → fastText English
|
||||
- Falls back to ConceptNet by default if no match
|
||||
- **Pre-processing**: `CleanTemplateText` strips QQ tool-call templates and timestamp noise
|
||||
- **Three-branch vector source**: agent→Response, user→Input, cold_storage→Input+Response
|
||||
- **TF-IDF fallback**: auto-fallback to bag-of-words TF-IDF if model download fails or not configured
|
||||
|
||||
| Location | File | Purpose | Algorithm |
|
||||
|----------|------|---------|-----------|
|
||||
| Context Prune | `context.go:161` | Trim low-relevance context events | LocalWordEmbedder → CosineSimilarity(queryVec, evt.Vector) |
|
||||
| DocStore Query | `document.go:198` | Recall related content from document memory | char-bigram TF-IDF + jieba keywords → InvertedIndex + CosineSimilarity |
|
||||
| Indexer Entity Search | `indexer.go:149` | Recall related entities from Graph | char-bigram TF-IDF vector search + jieba keywords → InvertedIndex + CosineSimilarity + SQLite BFS |
|
||||
| Entity Similarity Detection | `agent.go:2297` | Detect similar entities in Graph | Bigram Jaccard (>0.75 → consolidation) |
|
||||
| Context Prune | `context.go:155` | Trim low-relevance context events | VectorizeClean → CosineSimilarity(queryVec, evt.Vector) |
|
||||
| DocStore Query | `document.go:206` | Recall from document memory | TF-IDF Vectorize → vec.Search |
|
||||
| Indexer Entity Search | `indexer.go:96+111` | Recall from Graph | vector entity search + jieba keywords → SQLite LIKE + BFS |
|
||||
| Entity Similarity Detection | `agent.go` | Detect similar entities in Graph | Bigram Jaccard (>0.75 → consolidation) |
|
||||
|
||||
### Context Layer
|
||||
|
||||
`internal/agent/core/context.go` — `RelevanceContext`
|
||||
- Maintains recent event list, writes JSON on each Append/Prune to prevent data loss
|
||||
- Word embedding relevance scoring on user input (LocalWordEmbedder → CosineSimilarity), keeps topK
|
||||
- Pre-vectorization pipeline runs through `CleanTemplateText` to remove template noise
|
||||
- Three-branch `textForVector`: agent events → Response, user events → Input, cold_storage → Input+Response
|
||||
- Pretrained word embedding `StaticEmbedder` → CosineSimilarity, auto-fallback to TF-IDF if unavailable
|
||||
- Protects last 10 events from eviction; excess candidates are sorted by relevance and archived to document memory
|
||||
- Archived events retain original timestamps; on `doc_query` recall they re-insert into the context timeline at their original position
|
||||
|
||||
### Document Layer
|
||||
|
||||
@ -171,6 +172,10 @@ Vectorization is used in 4 independent locations with different strategies:
|
||||
|------|---------|
|
||||
| `memory_recall` | Recall from Graph |
|
||||
| `memory_commit` | Write triples to Graph |
|
||||
| `memory_merge` | Merge two entity nodes |
|
||||
| `memory_purge` | Delete entity node |
|
||||
| `memory_edit` | Edit existing entity/relation |
|
||||
| `memory_delete_entity` | Delete entity and all its relations |
|
||||
| `memory_introspect` | View memory statistics |
|
||||
| `doc_query` | Search from Document |
|
||||
| `doc_commit` | Write to Document |
|
||||
|
||||
@ -37,7 +37,7 @@ Code is in the project root, implemented in Go.
|
||||
- Maintains a message loop (`eventLoop`), queuing input from the IO layer
|
||||
- Each input goes through the full processing pipeline: memory recall → persona injection → LLM call → tool execution → output delivery
|
||||
- LLM calls abstracted through Provider interface, supports 8 LLM sources with automatic fallback
|
||||
- Context management (`context.go`) based on word embedding scoring (LocalWordEmbedder → CosineSimilarity), automatic pruning of low-relevance events
|
||||
- Context management (`context.go`) based on pretrained word embedding scoring (StaticEmbedder → CosineSimilarity, TF-IDF fallback), automatic pruning of low-relevance events
|
||||
|
||||
**Memory System** (`internal/memory/`):
|
||||
- **GraphDB** (`graph.go`) — SQLite, entities + relations tables, BFS traversal
|
||||
|
||||
@ -75,42 +75,44 @@ eventLoop() → processTextInput()
|
||||
```
|
||||
① Context (工作窗口)
|
||||
RelevanceContext — 内存 events[] + JSON持久化
|
||||
Append: 每次输入, Vectorize(char 1-2gram TF-IDF)
|
||||
Prune: TF-IDF CosineSimilarity, 保留 topK + 最近10条
|
||||
├── 保留 → timeline → system prompt (按时间排序)
|
||||
└── 低分 → Document 层归档 (ContextToDoc)
|
||||
Append: 每次输入, CleanTemplateText → 三分支向量(textForVector)
|
||||
agent事件→Response, 用户事件→Input, cold_storage→Input+Response
|
||||
StaticEmbedder 预训练词嵌入 / TF-IDF 回退
|
||||
Prune: StaticEmbedder CosineSimilarity, 保留 topK + 最近10条
|
||||
├── 保留 → timeline → 按时间排序 → system prompt
|
||||
└── 低分 → Document 层归档 (原始时间戳)
|
||||
Save: 5s debounce 写盘
|
||||
|
||||
↓ Prune 归档 ↑ LLM 主动召回
|
||||
↓ Prune 归档 ↑ LLM 主动召回
|
||||
|
||||
② Document (文件记忆)
|
||||
DocStore — JSON文件 + TF-IDF InvertedIndex
|
||||
写入: Prune归档 / doc_commit / Graph快照(syncGraphToDocs)
|
||||
读取:
|
||||
├── 自动注入: Query(input, top3) → 【相关记忆文档】→ system prompt (只读, 更新 AccessCount)
|
||||
├── 自动注入: Query(input, top3) → 相似度摘要 → 【相关记忆文档】→ system prompt (只读)
|
||||
└── LLM主动: doc_query → Consume(读取并删除)
|
||||
→ 逐条 context.Append{Timestamp: d.CreatedAt, Source: "cold_storage"}
|
||||
→ 文档以原始时间戳写入 context 时间线, 从 docStore 删除
|
||||
冷化: FindColdDocs(72h, ≤2次访问) → docToTriples → Graph
|
||||
|
||||
↓ 冷文档蒸馏 ↑ 自动召回
|
||||
↓ 冷文档蒸馏 ↑ 自动召回
|
||||
|
||||
③ Graph (图数据库)
|
||||
SQLite — entities + relations 表
|
||||
写入: memory_commit / 冷文档蒸馏 / Pipeline 规则蒸馏
|
||||
写入: memory_commit / 冷文档蒸馏 / Pipeline 规则蒸馏 / memory_merge
|
||||
读取:
|
||||
├── 自动召回: Indexer.BuildContext(input)
|
||||
│ → TF-IDF 实体名搜索 → BFS depth=2
|
||||
│ → CleanTemplateText → 向量实体搜索 + jieba关键词 → SQLite LIKE + BFS depth=2
|
||||
│ → 【记忆索引】→ system prompt
|
||||
└── LLM主动: memory_recall / doc_query
|
||||
└── LLM主动: memory_recall / memory_merge / memory_purge / memory_edit / memory_delete_entity
|
||||
Social: person_query / set_trait / relate (包装 GraphDB)
|
||||
|
||||
④ 蒸馏管道 (每30min心跳)
|
||||
distillContext → 窗口>2×maxSize → 强制Prune
|
||||
syncGraphToDocs → Graph 快照写入 Document(跨层可搜索)
|
||||
reorgGraph:
|
||||
Step1: indexer.Sync — 重建实体TF-IDF向量索引
|
||||
Step2: docStore.Reindex — 重建文档TF-IDF向量索引
|
||||
Step1: indexer.Sync — 重建实体向量索引
|
||||
Step2: docStore.Reindex — 重建文档向量索引
|
||||
Step3: 冷文档 → docToTriples → GraphDB.Commit
|
||||
Step4: 实体相似度(Bigram Jaccard>0.75) → consolidation → LLM判断合并
|
||||
Step5: evaluateGraphQuality → LLM判断保留/删除
|
||||
@ -121,36 +123,35 @@ eventLoop() → processTextInput()
|
||||
→ 三元组 → GraphDB.Commit
|
||||
```
|
||||
|
||||
### 向量化算法:两种策略
|
||||
### 向量化:预训练词嵌入 + TF-IDF 回退
|
||||
|
||||
向量化在 4 个独立位置以不同方式使用:
|
||||
所有向量化统一使用 `StaticEmbedder`(`internal/memory/static_embedder.go`):
|
||||
|
||||
**策略 A — 局部词嵌入**(`LocalWordEmbedder`, `internal/memory/embedder.go`),用于 Context 层:
|
||||
|
||||
- **jieba 分词** → 去除停用词和单字
|
||||
- **TF-IDF** 作为基础词权重
|
||||
- **滑动窗口(size=5)** 统计词对共现 → **PMI(点互信息)** → 保留 top 50
|
||||
- **向量化**:`vec[ctx] += TF-IDF × PMI` + 自身上标 `__w__` + TF-IDF
|
||||
|
||||
**策略 B — char-bigram TF-IDF + jieba 关键词提取**(`TFIDFVectorizer` + `ExtractKeywords`),用于 Document 和 Indexer 层:
|
||||
|
||||
- **char bigram 分词**(1-2 gram)用于实体名向量搜索
|
||||
- **jieba 分词**用于关键词提取,配合 SQLite LIKE + BFS 遍历
|
||||
- **TF-IDF 权重** + **倒排索引**
|
||||
**主策略 — 预训练词嵌入(词对齐 300 维)**
|
||||
- 模型来源:ConceptNet Numberbatch(77 语对齐)/ fastText 中文 / fastText 英文
|
||||
- 通过 `core.agent.embedding_model_path` 配置(逗号分隔多模型)
|
||||
- 路径名含 `numberbatch` → 自动下载 ConceptNet,含 `cc.zh.` → fastText 中文,含 `cc.en.` → fastText 英文
|
||||
- 不匹配则默认 ConceptNet
|
||||
- **前处理**:`CleanTemplateText` 剥离 QQ 工具调用模版、时间戳噪声,避免垃圾干扰相似度
|
||||
- **三分支向量来源**:agent→Response,用户→Input,cold_storage→Input+Response
|
||||
- **TF-IDF 回退**:模型下载失败或未配置时自动回退词袋 TF-IDF,服务不中断
|
||||
|
||||
| 位置 | 文件 | 用途 | 算法 |
|
||||
|------|------|------|------|
|
||||
| Context Prune | `context.go:161` | 裁剪低相关性上下文事件 | LocalWordEmbedder → CosineSimilarity(queryVec, evt.Vector) |
|
||||
| DocStore Query | `document.go:198` | 从文档记忆召回相关内容 | char-bigram TF-IDF + jieba 关键词 → InvertedIndex + CosineSimilarity |
|
||||
| Indexer 实体搜索 | `indexer.go:149` | 从Graph召回相关实体 | char-bigram TF-IDF 向量搜索 + jieba 关键词 → InvertedIndex + CosineSimilarity + SQLite BFS |
|
||||
| 实体相似度检测 | `agent.go:2297` | 检测Graph中相似实体 | Bigram Jaccard (>0.75 → consolidation) |
|
||||
| Context Prune | `context.go:155` | 裁剪低相关性上下文事件 | VectorizeClean → CosineSimilarity(queryVec, evt.Vector) |
|
||||
| DocStore Query | `document.go:206` | 文档记忆召回 | TF-IDF Vectorize → vec.Search |
|
||||
| Indexer 实体搜索 | `indexer.go:96+111` | Graph实体召回 | 向量实体搜索 + jieba关键词 → SQLite LIKE + BFS |
|
||||
| 实体相似度检测 | `agent.go` | Graph中相似实体 | Bigram Jaccard (>0.75 → consolidation) |
|
||||
|
||||
### Context 层
|
||||
|
||||
`internal/agent/core/context.go` — `RelevanceContext`
|
||||
- 维护最近事件列表,每次 Append/Prune 写入 JSON 防丢
|
||||
- 用户输入时做词嵌入相关性评分(LocalWordEmbedder → CosineSimilarity),保留 topK
|
||||
- 向量化前统一经 `CleanTemplateText` 去模版噪声
|
||||
- 三分支 `textForVector`:agent 事件用 Response、用户事件用 Input、cold_storage 用 Input+Response
|
||||
- 预训练词嵌入 `StaticEmbedder` → CosineSimilarity,模型不可用时自动回退 TF-IDF
|
||||
- 保护最近 10 条记录免于淘汰,超出部分按相关性排序归档到文档记忆
|
||||
- 归档事件以原始时间戳写入文档记忆,后续 `doc_query` 召回时按原始时间戳插回时序
|
||||
|
||||
### Document 层
|
||||
|
||||
@ -171,6 +172,10 @@ eventLoop() → processTextInput()
|
||||
|------|------|
|
||||
| `memory_recall` | 从 Graph 召回 |
|
||||
| `memory_commit` | 写入 Graph 三元组 |
|
||||
| `memory_merge` | 合并两个实体节点 |
|
||||
| `memory_purge` | 删除指定实体 |
|
||||
| `memory_edit` | 编辑已有实体/关系 |
|
||||
| `memory_delete_entity` | 删除实体及其所有关系 |
|
||||
| `memory_introspect` | 查看记忆统计 |
|
||||
| `doc_query` | 从 Document 搜索 |
|
||||
| `doc_commit` | 写入 Document |
|
||||
|
||||
@ -37,7 +37,7 @@ HomeAgent 是一个持续运行的个人智能 Agent 框架。
|
||||
- 维护一个消息循环(`eventLoop`),从 IO 层排队接收输入
|
||||
- 每次输入走完整的处理管道:记忆召回 → 人格注入 → LLM 调用 → 工具执行 → 输出发送
|
||||
- LLM 调用通过 Provider 接口抽象,支持 8 个 LLM 源自动降级
|
||||
- 上下文管理(`context.go`)基于词嵌入评分(LocalWordEmbedder → CosineSimilarity),自动剪枝低相关性事件
|
||||
- 上下文管理(`context.go`)基于预训练词嵌入评分(StaticEmbedder → CosineSimilarity,TF-IDF回退),自动剪枝低相关性事件
|
||||
|
||||
**记忆系统** (`internal/memory/`):
|
||||
- **GraphDB** (`graph.go`) — SQLite,entities + relations 表,BFS 遍历
|
||||
|
||||
Reference in New Issue
Block a user