01 — 问题

记忆不是知识

AI 智能体有记忆——但记忆不是知识。GoClaw 已有三层记忆:工作记忆 → 情景记忆 → 语义记忆。但当智能体需要查找具体文档、交叉引用文件、或跟踪文档关系时——记忆系统不够用。

1

搜索分散——需要分别查询每个存储

2

没有文档关系——反向链接不存在

3

内容过期——外部编辑未同步到数据库

Knowledge Vault 解决全部三个问题:文档注册表 + 维基链接 + 混合搜索 + 文件系统同步

02 — 架构

记忆系统之上的查询层

Component角色
VaultStore文档 CRUD、链接管理、混合搜索(FTS + 向量)
VaultSearchService搜索协调器:跨 vault、情景、知识图谱的并行扇出
EnrichWorker5 阶段异步管线:准备 → 摘要 → 嵌入 → 分类 → 维基链接
VaultSyncWorker文件系统监控:检测变更,同步内容哈希
VaultInterceptor挂钩文件操作:智能体写入时自动注册
VaultRetriever将 vault 搜索桥接到智能体 L0 记忆

写入路径

写入路径 — 智能体写入文件
智能体写入文件 → 工作区文件系统
VaultInterceptor (AfterWrite)
EventBus: VaultDocUpserted
P0: Prepare
P1: Summarize
P2: Embed
P3: Classify
P4: Wikilinks

读取路径

读取路径 — 智能体搜索
VaultStore
0.4
FTS + Vector
EpisodicStore
0.3
会话摘要
KGStore
0.3
实体相似度
Normalize
Dedup
Sort
Top N

租户与作用域隔离

每个文档属于一个作用域:personal(仅智能体)、team(团队工作区)、shared(跨智能体,尚未实现)。租户 A 的文档与租户 B 完全隔离——即使是链接也不能跨租户。个人文档可以链接到团队文档。

03 — 数据模型

vault_documents + vault_links

文档注册表:元数据指针。内容存储在文件系统;数据库保存路径、哈希、嵌入。

vault_documents — schema
CREATE TABLE vault_documents ( id UUID PRIMARY KEY, tenant_id UUID NOT NULL, agent_id UUID, -- nullable: team/shared docs team_id UUID, -- team scoping scope TEXT DEFAULT 'personal', -- personal | team | shared path TEXT NOT NULL, -- workspace-relative title TEXT DEFAULT '', doc_type TEXT DEFAULT 'note', content_hash TEXT DEFAULT '', -- SHA-256 summary TEXT DEFAULT '', -- LLM-generated embedding vector(1536), -- pgvector cosine tsv tsvector GENERATED ALWAYS AS ( to_tsvector('simple', coalesce(title,'') || ' ' || coalesce(path,'') || ' ' || coalesce(summary,'')) ) STORED, metadata JSONB DEFAULT '{}', UNIQUE(tenant_id, COALESCE(agent_id, nil-uuid), COALESCE(team_id, nil-uuid), scope, path) );
COALESCE 技巧:nil-UUID 占位符允许 agent_id 为 NULL 时同一路径有多个文档——解决没有智能体所有权的团队文档边缘情况。

索引

HNSW(分层可导航小世界,m=16,ef=64)——专用于向量搜索的索引,查找语义相似的文档。GIN(广义倒排索引)——全文搜索索引,用于关键字匹配。

HNSW
Vector Index
GIN
FTS Index
m=16
HNSW M
ef=64
HNSW ef

vault_links

vault_links — bidirectional links
CREATE TABLE vault_links ( id UUID PRIMARY KEY, from_doc_id UUID REFERENCES vault_documents(id) ON DELETE CASCADE, to_doc_id UUID REFERENCES vault_documents(id) ON DELETE CASCADE, link_type TEXT DEFAULT 'wikilink', context TEXT DEFAULT '', UNIQUE(from_doc_id, to_doc_id, link_type) );

7 种链接类型:wikilink(自动从 [[...]])、referencedepends_onextendsrelatedsupersedescontradicts。语义链接由 LLM 分类。

04 — 维基链接

双向 [[链接]]

使用 [[target]] 格式的双向 Markdown 链接——类似 Obsidian 或 Notion。

internal/vault/links.go
var wikilinkRe = regexp.MustCompile(`\[\[([^\]|]+)(?:\|[^\]]+)?\]\]`) // [[path/to/file.md]] → path-based // [[name|display text]] → display text ignored // Context: ~25 chars before + after

解析策略

Exact pathGetDocument(tenantID, agentID, target)
Path + .md — Retry with .md suffix
Basename search — Indexed column path_basename
Basename + .md — Last resort. Unresolved = nil

同步策略

SyncDocLinks()——替换策略:提取 [[...]] → 删除旧的传出维基链接 → 解析目标 → 批量创建新链接。语义链接(LLM 分类)不受影响。

05 — 混合搜索

FTS + 向量 + 跨存储扇出

为什么需要"混合"?

假设智能体搜索"用户认证":FTS 找到精确关键字但遗漏使用不同术语的文档("登录流程")。向量搜索 理解语义等价但有时返回松散相关的结果。结合使用:FTS 提供精确度,向量提供召回率。

步骤 1:Vault 中的 FTS + 向量

FTS — keyword match (ts_rank)
SELECT ..., ts_rank(tsv, plainto_tsquery('simple', $1)) AS score FROM vault_documents WHERE tenant_id = $2 AND tsv @@ plainto_tsquery('simple', $1) ORDER BY score DESC LIMIT $N
Vector — semantic match (pgvector cosine)
SELECT ..., 1 - (embedding <=> $1) AS score FROM vault_documents WHERE tenant_id = $2 AND embedding IS NOT NULL ORDER BY embedding <=> $1 LIMIT $N -- Score = 1 - cosine_distance (1.0 = identical)
合并:FTS 0.4,向量 0.6。按最高分归一化 → 加权求和。同时出现在两者中的文档 → 分数相加。

步骤 2:跨 3 个源扇出

VaultSearchService.Search() — Parallel Fan-Out
VaultStore
0.4
FTS + Vector
EpisodicStore
0.3
对话历史
KGStore
0.3
Knowledge graph
Normalize (max=1.0)
按 ID 去重
加权降序排序
Top N

优雅降级:存储为 nil → 跳过。

超额返回:每个存储返回 maxResults*2。

团队上下文:来自 RunContext——防止伪造。

06 — 丰富处理管线

5 阶段异步工作器

文档写入后,还不能用于搜索。EnrichWorker 通过 5 个阶段处理使其可搜索。

P0Prepare
P1Summarize
P2Embed
P3Classify
P4Wikilinks
Phase 0: Prepare

去重检查(docID + 哈希)→ 批量获取元数据 → 读取文件(最大 4MB)→ 过滤已有摘要的文档。

Phase 1: Batch Summarize

将 5 个文档打包到 1 个 LLM 调用中。温度 0.2,最大 1536 token。JSON 输出:[{"idx":1,"summary":"..."}]减少 5 倍 LLM 调用。

Phase 2: Embed

拼接标题 + 路径 + 摘要 → 1536 维嵌入向量。将文本转换为语义空间中的坐标。

Phase 3: Classify Links

FindSimilarDocs(余弦 ≥ 0.7)→ LLM 分类为 6 种链接类型。温度 0.1。如果没有有意义的关系,输出 SKIP

Phase 4: Wikilink Sync

提取 [[...]] → 解析目标 → 删除旧的维基链接 → 批量创建新链接。去重映射上限 10K 条目,驱逐 25%。

调优常量

5
Batch Size
3
Max Concurrent
3k
Runes/File
0.7
Cosine Min

重试:递增超时 5→7→10 分钟,退避 0→2→4 秒BatchQueue:每个租户:智能体的无锁生产者-消费者——防止重新扫描时的惊群效应。

07 — 文件系统同步与安全

同步和保护工作区

智能体写入文件,但它们可能被外部修改(用户编辑、git pull)。Vault 有 3 种同步机制:

VaultSyncWorker

fsnotify 监控工作区。防抖 500ms → SHA-256 → 对比数据库 → 变更时触发 EnrichWorker。仅同步已注册的文档。

SafeWalkWorkspace

遍历整个工作区,有限制:5K 文件,总共 500MB,每个文件 50MB。跳过符号链接、node_modules.git。路径遍历被阻止。

Lazy Hash Sync

VaultInterceptor.BeforeRead()——智能体读取文件时,检查文件系统哈希与数据库。即使监控器未运行也能捕获外部编辑。

所有权推断

workspace/ → scope inference
workspace/ ├── agents/{agent_key}/... → scope="personal" ├── teams/{team_uuid}/... → scope="team" └── anything/else → scope="shared"
08 — 检索器集成

自动注入到智能体上下文

VaultRetriever 在智能体思考前自动将相关文档注入上下文——不需要手动调用 vault_search

RetrieverConfig
type RetrieverConfig struct { RelevanceThreshold float64 // 0.3 — 剔除过低结果 MaxL0Items int // 5 — 限制上下文大小 TenantID string }

用户问"如何设置认证" → vault 自动注入 docs/auth.md(得分 0.92)+ SOUL.md(得分 0.45)→ 更准确的回答。

09 — 用例

实际应用场景

智能体工作区组织

智能体写笔记,使用 [[wikilinks]] 交叉引用。Vault 自动检测链接、创建反向链接、索引内容。

团队知识共享

个人文档仅智能体可见。团队文档所有成员可搜索。个人可以 [[link]] 到团队文档。

上下文感知响应

VaultRetriever 在智能体回答前自动注入相关文档。

10 — 快速入门

打开仪表板,立即使用

Knowledge Vault 无需设置——打开仪表板即可开始。

localhost:3000/vault
Knowledge Vault Dashboard

打开 Knowledge Vault

左侧边栏 → Vault(DATA 部分)。双面板 UI:文档列表(左)+ 知识图谱可视化(右)。类型筛选芯片 + 智能体/团队下拉菜单。

上传文档

点击 +(右上)→ "上传到 Vault" 对话框 → 选择目标(共享/智能体/团队)→ 拖放或浏览文件(.md、.txt、.json、.yaml、.csv 等)→ 上传。丰富处理自动运行。

重新扫描工作区(可选)

点击 重新扫描工作区(+ 按钮旁边)→ 扫描工作区,检测新/变更文件,自动推断作用域(个人/团队/共享)。

探索、图谱和搜索

边栏按类型浏览文档。右侧面板显示知识图谱——平移/缩放探索关系。搜索栏用于统一搜索。在详情面板创建手动链接。智能体自动使用 vault。

11 — 智能体工具

vault_search — 唯一的工具

智能体只有 1 个工具与 vault 交互。跨所有知识源的统一搜索。

ParamTypeRequired描述
querystring自然语言搜索查询
scopestring筛选:personal、team、shared(默认:all)
typesstring逗号分隔:context、memory、note、skill、episodic(默认:all)
maxResultsnumber最大结果数(默认:10)
vault_search — 示例
{ "query": "authentication flow", "scope": "team", "types": "context,note", "maxResults": 10 } // 用户:"查找关于认证的文档" // Agent → vault_search(query="authentication") // → Top 10 from vault + episodic + KG
12 — REST API

HTTP 端点

Documents

MethodEndpoint功能
GET/v1/vault/documents文档列表(筛选:scope、doc_type、team_id)
POST/v1/vault/documents创建新文档
GET/v1/vault/documents/{docID}获取文档详情
PUT/v1/vault/documents/{docID}更新元数据
DELETE/v1/vault/documents/{docID}删除文档

Links

MethodEndpoint功能
GET.../{docID}/linksOutbound + backlinks
POST/v1/vault/links创建链接(from、to、type、context)
DELETE/v1/vault/links/{linkID}删除链接
POST/v1/vault/links/batch批量获取多个文档 ID 的链接

搜索和运维

MethodEndpoint功能
POST/v1/vault/searchUnified cross-store search
POST/v1/vault/upload上传文件(最多 50 个文件,每个 50MB)
POST/v1/vault/rescan重新扫描工作区
GET...enrichment-status丰富处理进度(JSON/SSE)

每个智能体端点:所有端点也有 /v1/agents/{agentID}/vault/... 作用域版本(向后兼容)。

并发保护:重新扫描阻止每个租户的并行扫描。非所有者:只能看到个人文档和自己的团队。

13 — 架构演进

4 migrations

Migration内容
000038Initial: vault_documents, vault_links, vault_versions
000042添加 summary,重新生成 tsvector
000043添加 team_idcustom_scope
000046可空 agent_id、COALESCE 约束、自动作用域触发器
迁移 046:智能体被删除且文档没有团队时,触发器自动设置 scope='shared'——防止孤立文档。
14 — 总结

文件参考

ComponentFile角色
Vault serviceinternal/vault/*.go搜索协调器、丰富处理、维基链接、文件系统遍历
PG storeinternal/store/pg/vault_*.go混合搜索(FTS + 向量)、链接管理
SQLite storeinternal/store/sqlitestore/vault_*.go精简版:仅 FTS
Toolsinternal/tools/vault_*.govault_search 工具、VaultInterceptor 挂钩
HTTP handlersinternal/http/vault_*.goREST API、上传、重新扫描、丰富处理状态
Migrationsmigrations/000038-000046架构演进(4 次迭代)

设计权衡

Search Weights

FTS 0.4,向量 0.6——向量优先语义;FTS 补充关键字精确度。跨存储 0.4/0.3/0.3——Vault 精选内容优先。

Batch Processing

每个 LLM 调用 5 个文档——平衡吞吐量与质量。余弦 0.7——仅分类真正相似的文档,减少噪声。

Schema Flexibility

可空 agent_id——团队文档不需要智能体所有权。替换策略用于维基链接——简单、幂等。