Doramagic 项目包 · 项目说明书

Localbrain 项目

为本地文件建立索引以进行语义搜索与重排序,可通过 MCP 服务器、CLI 或本地 Web 控制台使用。

概述与系统架构

Localbrain 是一款本地优先(local-first)的个人知识库检索工具,通过在用户机器上完成文件读取、文本分块、向量化与语义检索,让自然语言查询能够直接命中本地的 Markdown、纯文本等文档。README 中明确指出:用户数据始终留在本机,索引与查询均不依赖外部云服务,断网后已索引的内容仍可继续使用 资料来源:[README.md]()。

章节 相关页面

继续阅读本节完整说明和来源证据。

项目定位与核心能力

Localbrain 是一款本地优先(local-first)的个人知识库检索工具,通过在用户机器上完成文件读取、文本分块、向量化与语义检索,让自然语言查询能够直接命中本地的 Markdown、纯文本等文档。README 中明确指出:用户数据始终留在本机,索引与查询均不依赖外部云服务,断网后已索引的内容仍可继续使用 资料来源:README.md

围绕这一目标,系统提供三组核心能力:

  1. 本地语义索引 —— 通过本地嵌入模型将文档切片写入本地向量库;
  2. 多入口适配 —— 同时面向 MCP(Model Context Protocol)、Web 控制台和 CLI 提供薄入口,让 Claude Code 等外部 AI 工具也能消费本地知识;
  3. 自反馈回路 —— 通过查询聚类与知识空白报告,为索引的持续优化提供数据支撑。

分层架构

代码以 src/localbrain/ 为根,按 core / services / adapters 三层组织,并由一个组合根(composition root)统一装配:

flowchart TD
    A["适配层 Adapters<br/>MCP Server · Web UI · CLI"] --> B["服务层 Services<br/>IndexingService · SearchService · InsightsService"]
    B --> C["核心层 Core<br/>Indexer · Searcher · Scanner · Insights"]
    C --> D["基础设施<br/>SQLite(file_index/sources/queries) · Chroma(vector store) · Embedding Providers"]
    A -.启动.-> E["AppContext (context.py)<br/>composition root"]
    E --> B
    E --> C
    E --> D

各层职责:

  • 核心层(core/) 承担单一职责的领域逻辑,例如 core/indexer.py 只负责"load→chunk→embed→store + file_index 更新"流程,并以 yield {"phase":...} 形式对外暴露进度事件 资料来源:src/localbrain/core/indexer.py;core/chunking.py 只负责段落优先的贪心分块与相邻 overlap 合并 资料来源:src/localbrain/core/chunking.py
  • 服务层(services/) 是面向用例的薄编排,例如 IndexingService.run() 负责"扫源 → 生成 ChangeSet → 调用 Indexer → 流式返回进度",并以 rebuild=True 控制是否全量重建 资料来源:src/localbrain/services/indexing_service.py;InsightsService 仅作为 Insights.cluster(...) 的薄包装,用于查询聚类与知识空白 资料来源:src/localbrain/services/insights_service.py
  • 适配层(adapters/) 是面向协议的入口:adapters/__init__.py 中描述其为"core·services 之上的薄入口" 资料来源:src/localbrain/adapters/__init__.pymcp_server.py 基于 FastMCP 暴露 search / add_path / remove_path 等工具,让 Claude Code 通过 stdio 直接调用本地知识 资料来源:src/localbrain/adapters/mcp_server.pyadapters/web/__init__.py 则声明 Web 端为 FastAPI 后端 + 静态单页架构 资料来源:src/localbrain/adapters/web/__init__.py

关键数据流:索引与检索

系统通过 AppContext 把所有依赖拼装到一处:构造嵌入 provider、连接 SQLite、初始化 Chroma 向量库、构建 Scanner/Indexer/Searcher/FileIndex/SourceStore,并由各适配器按需取用 资料来源:src/localbrain/context.py。两侧数据流如下:

流向触发关键步骤落点
写入(索引)add_path / run(rebuild)Loader 按扩展名匹配 → chunk_text 分块 → EmbeddingProvider 编码 → Chroma 写入 → file_index 记录 hash/mtime/chunk_ids向量库 + SQLite
读取(检索)MCP search / Web 查询Searcher 在 Chroma 上做向量召回 → 可选 Reranker 重排 → 返回带分数的命中片段调用方

可插拔扩展点体现在两处 registry:嵌入侧支持 fastembed / ollama / sentence-transformers 三种 provider,按配置名懒加载 资料来源:src/localbrain/core/embed/registry.py;加载器侧通过 _LOADERS: list[Loader] 列表按 supports(path) 选择,当前内置 TextLoader 资料来源:src/localbrain/core/loaders/registry.py

持久化、配置与可扩展性

SQLite 作为元数据库,core/db.py 中声明了三张表:sources(注册路径与 glob)、file_index(path / hash / mtime / size / chunk_ids / source_id)和 queries(id / text / ts / hit / top_score),并启用 WAL 与 check_same_thread=False 以适配多适配器并发 资料来源:src/localbrain/core/db.py。向量库落盘到 chroma_dir,文件名以 provider.model_id 作为 collection 命名空间,避免不同模型切换时混用 资料来源:src/localbrain/context.py

扩展建议:

See Also

  • MCP 服务器适配器
  • 核心索引器
  • 嵌入与检索

来源:https://github.com/Tamariskwhisper962/Localbrain / 项目说明书

核心引擎:索引与数据管道

Localbrain 的核心引擎围绕"扫描 → 加载 → 分块 → 嵌入 → 持久化"五个阶段构建了一条可增量更新的数据管道。该管道的职责是把本地文件系统中的纯文本/结构化文档,转换为 Chroma 向量库中可语义检索的向量记录,并维护一份 SQLite 文件索引以追踪每个路径的哈希与对应分块。引擎本身不直接面向用户,所有调用都通过 AppContext 这一组合根注入到上...

章节 相关页面

继续阅读本节完整说明和来源证据。

章节 1. 扫描阶段

继续阅读本节完整说明和来源证据。

章节 2. 加载与分块

继续阅读本节完整说明和来源证据。

章节 3. 嵌入与持久化

继续阅读本节完整说明和来源证据。

概述

Localbrain 的核心引擎围绕"扫描 → 加载 → 分块 → 嵌入 → 持久化"五个阶段构建了一条可增量更新的数据管道。该管道的职责是把本地文件系统中的纯文本/结构化文档,转换为 Chroma 向量库中可语义检索的向量记录,并维护一份 SQLite 文件索引以追踪每个路径的哈希与对应分块。引擎本身不直接面向用户,所有调用都通过 AppContext 这一组合根注入到上层服务(IndexingService / SearchService / InsightsService)中,再由 MCP、CLI、Web 三种适配器暴露。

资料来源:src/localbrain/context.py:1-40CHANGELOG.md:0.1.0

架构总览:组合根

AppContextsrc/localbrain/context.py 中扮演组合根(composition root)的角色——它一次性装配配置、嵌入 provider、向量库、文件索引、扫描器、索引器等所有依赖。适配层只需要 AppContext() 一行即可获得完整的服务栈,避免在 MCP、CLI、Web 三个入口分别重复拼装。

graph LR
    A[适配器 MCP/CLI/Web] --> B[AppContext 组合根]
    B --> C[Scanner 扫描]
    B --> D[Indexer 索引]
    B --> E[VectorStore 向量库]
    B --> F[FileIndex SQLite]
    B --> G[Insights 洞察]
    C -->|ChangeSet| D
    D -->|embed + store| E
    D -->|update| F

资料来源:src/localbrain/context.py:1-40

数据管道:扫描到写入

1. 扫描阶段

Scanner 负责遍历已注册源(文件夹/文件),通过 mtime + 内容哈希 双重比对,产出 ChangeSet(包含 new / modified / deleted 三类路径)。这种"变更即差异"的设计让索引过程天然支持增量更新:未发生变化的文件直接跳过,从而避免重复嵌入。扫描完成后,ChangeSet 被交给 Indexer.apply()

资料来源:src/localbrain/core/indexer.py:1-40

2. 加载与分块

Indexer 根据路径扩展名从 Loader 注册表中选择合适的加载器,目前内置 TextLoader 用于 .md / .txt 等纯文本。文本随后进入 chunk_text():它首先按双换行切分为段落,再以"段优先 + 字符窗口回退"的贪心策略在 chunk_size(默认 1000)内累积;若某段超出窗口,则按 chunk_size - overlap 步长切分。最后,相邻分块会拼接前一个分块的尾部 overlap(默认 150 字符),形成"重叠上下文",保证检索时不会在块边界丢失语义。

# 摘自 src/localbrain/core/chunking.py
step = max(1, size - overlap)
for i in range(0, len(p), step):
    chunks.append(p[i:i + size])

资料来源:src/localbrain/core/loaders/registry.py:1-15src/localbrain/core/chunking.py:1-40

3. 嵌入与持久化

每个分块经 EmbeddingProvider.embed_texts() 编码为向量。Indexer.apply() 会以流式方式(yield 进度事件)依次处理删除、新增和修改三类目标:先调用 VectorStore.delete_documents() 清理旧向量,再写入新向量与元数据,最后在 FileIndex 中登记新哈希与 chunk_idsVectorStore 内部按 model_id 命名规则拆分 docs__<tag>queries__<tag> 两个 Chroma 集合,并使用 cosine 距离空间——这样切换嵌入模型时不会出现"新旧向量混合"的数据污染问题。

资料来源:src/localbrain/core/indexer.py:30-50src/localbrain/core/store.py:1-40

嵌入 Provider 注册表

make_provider() 采用字符串查表 + 懒加载(lazy import)的策略,把 provider 实现与业务解耦。当前内置三种实现:

Provider 名称后端适用场景
fastembedQdrant 出品的本地 ONNX 推理默认选项,零额外服务
ollama调用本地 Ollama HTTP /api/embeddings已部署 Ollama 的环境
sentence-transformersHuggingFace transformers需要自定义/实验性模型

例如 OllamaProvider 直接通过 urllib.requesthttp://localhost:11434/api/embeddings 通信,并以 ollama:<model> 作为 model_id 写入向量库标签。注册表还接受 fp16 参数用于推理精度控制。

资料来源:src/localbrain/core/embed/registry.py:1-20src/localbrain/core/embed/ollama_provider.py:1-30

与上层服务的耦合

核心引擎并不直接处理用户请求——它通过 IndexingService / InsightsService 等服务类与适配器对接。例如,MCP 适配器在 mcp_server.py 中通过 AppContext 拿到 IndexingService 后,将其 add_path() / remove_source() 方法注册为 @mcp.tool() 工具;InsightsService.report() 则把质询日志聚类为 FAQ 与知识空缺报告。这种"core 决定能力边界,adapters 决定暴露方式"的分层让 CLI 与 Web 也能复用同一套索引语义。

资料来源:src/localbrain/adapters/mcp_server.py:1-30src/localbrain/services/insights_service.py:1-15

常见失败模式

  • 嵌入模型未下载fastembed 首次使用会从 HuggingFace 拉取模型权重,需保持网络可达;CHANGELOG.md 指出 0.1.1 已将模型加载改为 lazy,从而保证 MCP 握手不被阻塞。
  • 路径 glob 不匹配add_path 默认 *.md,*.txt,若文件夹内全是 .pdf 等无内置 loader 的类型,is_supported() 会返回 None,导致整条路径被静默跳过。
  • Windows 控制台编码:0.1.1 之前的版本在 cp949 终端输出韩文/em-dash 时会崩溃,升级至 0.1.1 后已强制 UTF-8。
  • 向量库分集合未隔离:若手动修改 model_id 字符串,建议先备份 chroma/ 目录,避免误把不同维度的向量写入同一集合。

资料来源:CHANGELOG.md:0.1.1src/localbrain/core/loaders/registry.py:1-15

See Also

  • 核心引擎:搜索与重排
  • 核心引擎:嵌入与运行时
  • 适配器:MCP / CLI / Web
  • 数据模型:Source / FileRecord / ChangeSet

资料来源:src/localbrain/context.py:1-40CHANGELOG.md:0.1.0

适配器、配置与部署

Localbrain 采用清晰的三层结构:core (领域核心) → services (业务编排) → adapters (对外接口)。adapters/init.py 中明确说明 "adapters — MCP / CLI / Web. core·services 위의 얇은 진입점",即适配器是位于核心之上的"薄入口"层,仅负责协议转换与参数解析,不承载业务逻辑 资料...

章节 相关页面

继续阅读本节完整说明和来源证据。

1. 适配器层在整体架构中的位置

Localbrain 采用清晰的三层结构:core (领域核心) → services (业务编排) → adapters (对外接口)。adapters/__init__.py 中明确说明 "adapters — MCP / CLI / Web. core·services 위의 얇은 진입점",即适配器是位于核心之上的"薄入口"层,仅负责协议转换与参数解析,不承载业务逻辑 资料来源:src/localbrain/adapters/__init__.py:1-1

目前仓库提供三种适配器入口,覆盖了本地知识库与外部 AI 工具的所有典型交互场景:

所有适配器共享同一个 AppContext(定义于 src/localbrain/context.py),构造时即初始化 services,因此各协议层看到的"业务能力"完全一致 资料来源:src/localbrain/context.py:1-15

flowchart LR
    A[MCP stdio 客户端] --> B[adapters/mcp_server.py]
    C[终端 / 脚本] --> D[adapters/cli.py]
    E[浏览器] --> F[adapters/web]
    B --> G[AppContext]
    D --> G
    F --> G
    G --> H[services/*]
    H --> I[core/*]

2. CLI 命令矩阵

adapters/cli.py 通过 parser.add_subparsers 注册了完整的命令行表面。下表汇总了各子命令的关键参数与用途 资料来源:src/localbrain/adapters/cli.py:1-50

子命令关键参数默认值作用
add-sourcepath, --globs, --no-recursive--globs=*.md,*.txt注册索引源
list-sources列出已注册源
index--source-id, --rebuild全量源增量 / 全量索引
searchquery, -k, --path-prefix, --no-rerankk 来自 config语义检索
stats索引状态
insights--min-similarity0.80知识图谱 / FAQ 报告

index --rebuild 会清空 file_index 中对应源的全部记录并触发全量重建,常用于"模型更换"后向新集合回填数据 资料来源:src/localbrain/services/indexing_service.py:1-30

3. 配置系统

AppContext.__init__ 是唯一的"组合根"(composition root),它从 Config.load() 读取配置,并据此物化所有依赖 资料来源:src/localbrain/context.py:1-30

  • 嵌入 Providermake_provider(config.embedding.provider, model, fp16),通过字符串名路由到具体实现。core/embed/registry.py 支持 fastembedollamasentence-transformers 三家 资料来源:src/localbrain/core/embed/registry.py:1-20
  • 持久层connect(config.db_path) 创建 SQLite 连接,启用 journal_mode=WAL 并预建 sourcesfile_indexqueries 三张表 资料来源:src/localbrain/core/db.py:1-30
  • 向量库VectorStore(config.chroma_dir, provider.model_id) 将 Chroma 集合与嵌入模型 ID 绑定,便于后续按模型隔离。
  • 索引流水线scannerindexer 在此装配,indexer.apply(source, cs)load → chunk → embed → store + file_index 刷新 的单职责入口 资料来源:src/localbrain/core/indexer.py:1-20

4. 部署与典型运行模式

由于三种适配器共享同一 AppContext,部署方式可以按使用场景灵活切换:

  1. 本地 MCP 模式python -m localbrain.adapters.mcp_server 启动 stdio 进程,Claude Code 等客户端通过 MCP 协议调用 search / add_path 工具,从而将本地文档接入大模型 资料来源:src/localbrain/adapters/mcp_server.py:1-30
  2. CLI 模式python -m localbrain.adapters.cli <subcmd> 适合定时任务、CI 中的批量索引与检索。
  3. Web 模式adapters/web 暴露 FastAPI + 浏览器控制台,便于人工浏览索引状态、添加源与查看洞察。

README.md 给出的标准流程是:选择文件夹 → 等待进度条 100% → 自然语言搜索 → 在连接面板中管理 MCP 客户端;其强调 "Your data remains on your machine" 与 "It uses local models" 资料来源:README.md:1-50。当 embedding.provider 选择 ollamafastembed 时,整条链路(嵌入、检索、问答)均可在离线环境内完成,符合本地优先的部署哲学。

See Also

来源:https://github.com/Tamariskwhisper962/Localbrain / 项目说明书

失败模式与踩坑日记

保留 Doramagic 在发现、验证和编译中沉淀的项目专属风险,不把社区讨论只当作装饰信息。

medium 可能修改宿主 AI 配置

安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。

medium 能力判断依赖假设

假设不成立时,用户拿不到承诺的能力。

medium 维护活跃度未知

新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。

medium 存在评分风险

风险会影响是否适合普通用户安装。

Pitfall Log / 踩坑日志

项目:Tamariskwhisper962/Localbrain

摘要:发现 7 个潜在踩坑项,其中 0 个为 high/blocking;最高优先级:配置坑 - 可能修改宿主 AI 配置。

1. 配置坑 · 可能修改宿主 AI 配置

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:项目面向 Claude/Cursor/Codex/Gemini/OpenCode 等宿主,或安装命令涉及用户配置目录。
  • 对用户的影响:安装可能改变本机 AI 工具行为,用户需要知道写入位置和回滚方法。
  • 证据:capability.host_targets | https://github.com/Tamariskwhisper962/Localbrain | host_targets=mcp_host, claude

2. 能力坑 · 能力判断依赖假设

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:README/documentation is current enough for a first validation pass.
  • 对用户的影响:假设不成立时,用户拿不到承诺的能力。
  • 证据:capability.assumptions | https://github.com/Tamariskwhisper962/Localbrain | README/documentation is current enough for a first validation pass.

3. 维护坑 · 维护活跃度未知

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:未记录 last_activity_observed。
  • 对用户的影响:新项目、停更项目和活跃项目会被混在一起,推荐信任度下降。
  • 证据:evidence.maintainer_signals | https://github.com/Tamariskwhisper962/Localbrain | last_activity_observed missing
  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 证据:downstream_validation.risk_items | https://github.com/Tamariskwhisper962/Localbrain | no_demo; severity=medium

5. 安全/权限坑 · 存在评分风险

  • 严重度:medium
  • 证据强度:source_linked
  • 发现:no_demo
  • 对用户的影响:风险会影响是否适合普通用户安装。
  • 证据:risks.scoring_risks | https://github.com/Tamariskwhisper962/Localbrain | no_demo; severity=medium

6. 维护坑 · issue/PR 响应质量未知

  • 严重度:low
  • 证据强度:source_linked
  • 发现:issue_or_pr_quality=unknown。
  • 对用户的影响:用户无法判断遇到问题后是否有人维护。
  • 证据:evidence.maintainer_signals | https://github.com/Tamariskwhisper962/Localbrain | issue_or_pr_quality=unknown

7. 维护坑 · 发布节奏不明确

  • 严重度:low
  • 证据强度:source_linked
  • 发现:release_recency=unknown。
  • 对用户的影响:安装命令和文档可能落后于代码,用户踩坑概率升高。
  • 证据:evidence.maintainer_signals | https://github.com/Tamariskwhisper962/Localbrain | release_recency=unknown

来源:Doramagic 发现、验证与编译记录