GPT4All LocalDocs 实战指南:用本地嵌入索引把设备上的文档带进 LLM 对话
【免费下载链接】gpt4allGPT4All: Run Local LLMs on Any Device. Open-source and available for commercial use.项目地址: https://gitcode.com/GitHub_Trending/gp/gpt4all
LocalDocs 是 GPT4All 桌面端的核心 RAG(检索增强生成)能力:它把设备上的文件文件夹按设置切片,用 Nomic 的嵌入模型为每个文本片段生成嵌入向量,再在对话中做语义检索,把与提问最相关的片段注入 LLM 提示词——全程在本地完成,数据不出设备。读完本文,你将掌握 LocalDocs 集合的创建与重建流程、全部可配置项(分片大小、检索条数、文件扩展名、嵌入设备等)的默认值与取舍,以及从 LocalDocs 单例、Database 向量库到 EmbeddingLLM 的完整源码调用链,从而能准确判断它为什么快、何时会慢、如何调整。
一、LocalDocs 解决什么问题
LocalDocs 把你设备上文件中的信息私有地带入 LLM 对话(原文定义:brings the information you have from files on-device into your LLM chats — privately)。它的工作方式是:
- 把一个文件夹登记为一个collection(集合);
- 集合内的文件按扩展名白名单筛选后,被切成固定大小的文本片段(snippets/chunks);
- 每个片段由嵌入模型计算得到一个嵌入向量;
- 你在聊天框输入的问题也会被嵌入,系统通过向量相似度找到语义最接近的片段;
- 这些片段被追加进发给 LLM 的提示词,模型据此基于你的私有文档作答,并在回答下方给出Sources(来源)列表。
二、创建 LocalDocs 集合(操作步骤)
以下流程与桌面端 LocalDocs 视图 和 AddCollectionView 的交互一一对应:
- 点击
+ Add Collection,进入新建集合页面; - 为集合命名并关联一个文件夹(即截图所示的 "New Collection" 表单,填写名称后选择本地目录);
- 点击
Create Collection。索引进度会显示在 LocalDocs 页面:每个集合条目展示"正在索引的文件数 / 总文件数"、"已嵌入条数 / 总条数"等统计。集合全部就绪后会看到绿色的Ready指示器。注意:在整集合就绪之前,你已经可以针对已就绪的文件进行对话(源码中集合项的状态角色IndexingRole、CurrentDocsToIndexRole、TotalDocsToIndexRole、TotalEmbeddingsToIndexRole等在 LocalDocsModel 中定义,供 UI 逐条刷新); - 在聊天界面中,点击右上角按钮打开
LocalDocs,勾选/选择要参与本次对话的集合,即可让 LLM 获得这些文件的上下文; - 点击 LLM 回答下方的
Sources,查看本次回答实际引用了哪些文件与片段(是否默认展示由设置项Show Sources控制)。
后续重建:修改 LocalDocs 设置(如换嵌入模型、调整分片大小)之后,可以用新设置**重建(rebuild)**集合,而不是删掉重来。重建入口对应 LocalDocs::forceIndexing(),它会携带当前EmbeddingLLM::model()发出requestForceIndexing信号;Database::forceIndexing() 会先更新集合的embedding_model字段,再触发对文件夹的重新扫描与重新嵌入。此外,LocalDocs::addFolder() / removeFolder() 分别支持向集合增删文件夹——addFolder在取得嵌入模型为空时会直接告警返回,这是"没有嵌入模型就无法建索引"的硬前提。
三、工作原理:从文件到嵌入向量
3.1 分片:chunkSize 决定检索粒度
文件夹被登记后,Database 会对白名单扩展名的文件做文本抽取与分片,每个片段存入 SQLite 的chunks表。分片大小由localdocs/chunkSize(字符数)控制,默认512 字符。分片是"检索单元":查询只会命中整段片段,片段再被拼接进提示词。因此:
- 分片越大,单片包含的上下文越完整,回答越可能贴合事实,但单次生成的 token 越多、速度越慢,且相似度匹配的精准度下降;
- 分片越小,检索越聚焦,但容易把一句话拆断,造成上下文缺失。
LocalDocs 设置页 对这两个高级参数有明确警告:"Values too large may cause localdocs failure, extremely slow responses or failure to respond at all"(数值过大会导致 LocalDocs 失败、响应极慢甚至无响应),并提示"约等于N 个字符 × N 个片段会被加进模型上下文窗口"——这就是为什么它被归入 "Advanced usage only" 区块。
3.2 嵌入模型:本地模型 与 Nomic Embed API 二选一
How It Works 原文指出:LocalDocs 集合使用Nomic AI 免费、快速的设备端嵌入模型把文件夹索引为带嵌入向量的文本片段;这些向量用于在你的问题和提示词与文件片段之间做语义相似度匹配。
从源码结构看,GPT4All 对嵌入计算提供两条路径,由 EmbeddingLLMWorker 统一封装:
- 本地模型路径:
m_model(LLModel *)指向一个嵌入专用的本地模型,EmbeddingLLM::generateDocEmbeddingsAsync() 把片段批次QVector<EmbeddingChunk>交给独立工作线程(QThread m_workerThread)计算,避免阻塞 UI; - Nomic 云端 API 路径:
m_nomicAPIKey非空时(isNomic()判断),通过QNetworkAccessManager走 HTTP 请求 Nomic Embed API,本地不做嵌入计算; - 查询侧嵌入:EmbeddingLLM::generateQueryEmbedding() 对"用户提问"做同步嵌入(查询文本很短,无需异步)。
每条结果EmbeddingResult携带model / folder_id / chunk_id / std::vector<float> embedding,写回数据库时按(model, folder_id, chunk_id)定位到对应片段(见 database.cpp 中的 sqlAddEmbeddings 逻辑),因此不同嵌入模型产生的向量互不混用——这也是更换嵌入模型后必须重建集合的原因。
3.3 向量检索:usearch 索引 + 语义取回
向量存储基于 usearch(namespace us = unum::usearch;见 database.cpp)。对话发起检索时,调用链是:
- ChatLLM 读取
localDocsRetrievalSize(),对已启用集合发出requestRetrieveFromDB(enabledCollections, queryStr, retrievalSize, &databaseResults)(阻塞等待); EmbeddingLLM生成查询向量;- 数据库在 usearch 索引中做最近邻检索,取回 top-N 片段的
chunk_text,拼接进系统提示词上下文。
检索条数由localdocs/retrievalSize("Max document snippets per prompt")控制,默认3。设置页的帮助文本同样提示:数值越大越可能提高事实性,但生成更慢——它直接决定了"片段字符数 × 片段条数"注入的上下文体量。
四、LocalDocs 全部设置项与默认值
以下默认值来自 MySettings 的 basicDefaults,界面配置逻辑在 LocalDocsSettings.qml:
| 设置项(存储键) | 界面名称 | 默认值 | 说明 |
|---|---|---|---|
localdocs/chunkSize | Document snippet size (characters) | 512 | 每个文本片段的字符数;越大越"保真"但越慢 |
localdocs/retrievalSize | Max document snippets per prompt | 3 | 每次提示词注入的最多片段条数 |
localdocs/showReferences | Show Sources | true | 回答下方是否展示引用来源 |
localdocs/fileExtensions | Allowed File Extensions | docx, pdf, txt, md, rst | 逗号分隔白名单;只索引这些扩展名的文件 |
localdocs/useRemoteEmbed | Use Nomic Embed API | false | 改用 Nomic 云端 API 而非本地嵌入模型;需重启 |
localdocs/nomicAPIKey | Nomic API Key | 空 | 形如nk-+ 43 位字母数字(QML 内以正则/^(nk-[a-zA-Z0-9_-]{43})?$/校验);需重启 |
localdocs/embedDevice | Embeddings Device | Auto | 本地嵌入使用的计算设备(Auto 表示应用默认);需重启 |
几个实现层面的细节值得注意:
- 扩展名白名单带硬编码黑名单:LocalDocsSettings.qml 在用户输入后,会剔除常见不支持的扩展名(Office 二进制格式、图片、音视频、可执行文件、压缩包等),并做了小写化与去重。注释说明其立场:"We only support plain text and PDFs"——本地路径只真正处理纯文本类与 PDF(
docx通过 QXlsx/OOXML 相关依赖解析为文本)。 - 修改 chunkSize / 扩展名会即时广播:MySettings 的变更信号 触发 LocalDocs::handleChunkSizeChanged() / handleFileExtensionsChanged(),进而调用
Database::changeChunkSize / changeFileExtensions,使已有集合按新参数重建索引; - 数据库以设置创建:
LocalDocs构造时即用当前chunkSize与fileExtensions初始化 Database,并通过Qt::QueuedConnection把requestStart、requestAddFolder、requestRemoveFolder、requestForceIndexing等信号全部桥接到 Database 线程侧槽函数,保证索引操作不占用 GUI 线程。
五、源码结构速览
| 组件 | 文件 | 职责 |
|---|---|---|
LocalDocs单例 | localdocs.h / localdocs.cpp | 对外暴露addFolder、removeFolder、forceIndexing等 Q_INVOKABLE;持有Database与LocalDocsModel,负责信号路由 |
LocalDocsModel | localdocsmodel.h | 集合列表的 Qt 模型(QAbstractListModel),提供进度/状态角色供 QML 绑定 |
Database | database.cpp | SQLite 元数据(chunks、embeddings、collections表)+ usearch 向量索引 + 文件扫描与分片流(ChunkStreamer) |
EmbeddingLLM | embllm.h | 嵌入门面:本地LLModel或 Nomic API;查询嵌入(同步)与文档嵌入(异步) |
| 设置持久化 | mysettings.cpp | localdocs/*键的读写与默认值、变更信号 |
| UI | LocalDocsSettings.qml、AddCollectionView.qml | 设置表单、新建集合对话框、进度展示 |
六、使用前提与限制
- 必须先有可用嵌入模型:
addFolder与forceIndexing都会先检查EmbeddingLLM::model(),为空则记录 "ERROR: We have no embedding model" 并中止。即对话模型与嵌入模型是两回事,后者缺失时 LocalDocs 完全不可用; - 换模型 / 改参数需要重建:向量按
embedding_model字段隔离存储,旧向量对新模型无效,需走 rebuild 流程; - 上下文窗口预算:注入片段约为
chunkSize × retrievalSize字符量级,对短上下文模型要谨慎调大这两个值; - 隐私边界:默认(
useRemoteEmbed=false)嵌入全部在本地完成;勾选 Nomic Embed API 后,文档片段会经网络发送到 Nomic 服务做嵌入计算,不再完全离线——按设置页说明该项需重启应用生效。
【免费下载链接】gpt4allGPT4All: Run Local LLMs on Any Device. Open-source and available for commercial use.项目地址: https://gitcode.com/GitHub_Trending/gp/gpt4all
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考