每次新的聊天都会从一个忘记了你的文档的代理开始。它可以重新读取这些文档,代价是时间和上下文,或者它可以查询记住这些文档的东西。GroupDocs.Search.Mcp 在本地磁盘上保持一个具名的全文索引,该索引在会话和容器重启之间仍然存在,因此 Claude Desktop、Cursor 或 Copilot 在每个会话开始时就已经可以搜索项目的文档,并在文件更改时通过一次调用进行刷新:

我编辑了一些合同。刷新合同索引,然后告诉我现在哪些合同提到了处罚。

带有配置和故障排除的逐步版本在文档中:How to keep a document index current as files change。

“记忆” 对于代理意味着什么?

实际上有两件事:会话之外持久化的状态,以及保持该状态真实的廉价方式。聊天历史在这两方面都失败:它随会话结束而结束,且在文档更改时没有任何更新。搜索索引更适合文档。它与文档一起存放在磁盘上,能够在不加载文档的情况下回答“哪些文件说 X”,并且可以增量刷新。

session 1    add_to_index --> index "contracts" --+
                                                 |  kept on disk in
session 2    search, get_text_fragments <--------+  /data/.groupdocs-search-
             (nothing is re-read)                    index/contracts
files edit   update_index --> re-reads changed, added, deleted files only
new project  create_index {"indexName":"legal-2026"} --> a separate index

刷新是如何工作的?

update_index 将索引与磁盘上的文件进行比较,仅重新读取发生变化的部分。以下是我们在一次调用之间向合同添加处罚条款后服务器返回的结果:

-> get_index_info {"indexName":"contracts"}
<- { "documentCount": 5, "indexedPaths": [ "contracts" ],
     "documentsWithErrors": [], "status": "Ready" }

-> update_index {"indexName":"contracts"}
<- Index 'contracts' updated: 0 added, 1 updated, 0 removed;
   5 document(s) in the index.

-> search {"query":"penalty","indexName":"contracts"}
<- documentsFound 3, including the edited initech-nda.docx

计数告诉你发生了什么:重新读取了一个文件,其他文件未受影响。删除的文件会在同一次调用中消失。

为什么每个项目只有一个索引?

因为不同的语料库需要不同的答案。关于今年合同的问题不应出现去年的草稿,客户的文档也不应与另一个客户的混在一起。索引名称成本低:

-> create_index {"indexName":"legal-2026"}
<- Index 'legal-2026' created. Add documents with add_to_index
   (indexName: 'legal-2026').

每个索引都是 /data/.groupdocs-search-index 下的一个文件夹,get_index_info 在未指定名称时会列出所有索引。你很少需要显式调用 create_index,因为 add_to_index 在首次使用时会创建索引,但有意命名它们就是把“一个索引”变成“该项目的记忆”。

唯一的删除规则

引擎只删除已添加的路径,而不是路径内部的单个文件。当你尝试时,服务器会明确说明:

-> remove_from_index {"documentPath":"contracts/hooli-supply-terms.txt",...}
<- Removal failed for 'contracts/hooli-supply-terms.txt':
   'contracts/hooli-supply-terms.txt' is inside the indexed folder
   'contracts'. GroupDocs.Search removes whole indexed paths only: ...

因此请相应设计:如果你预期以后会丢弃语料库的某一部分(例如某一年、某个客户或草稿),请将这些部分作为独立路径(contracts/2025、contracts/2026)进行索引,这样每个路径都可以单独删除。删除磁盘上的文件并运行 update_index 也会将其移除。

无需请求即可保持最新

create_index (optional)
      |
      v
add_to_index ---> search ---> get_text_fragments
      ^              ^
      |              |  get_index_info: counts, paths, status
update_index  (files changed on disk)
      |
remove_from_index  (only a path that was given to add_to_index)

让刷新自动化的三种实用方式:

  1. 在代理的指令中。 在 CLAUDE.md 或 AGENTS.md 中加入一行:“在回答之前调用 update_index 更新该项目的索引(如果文件可能已更改)”,即可让代理在会话开始时执行此操作。
  2. 按计划执行。 任何支持 MCP 的自动化都可以在夜间调用 update_index;当变化很少时,调用非常快速。
  3. 在批量复制后。 一次调用即可捕获所有新增文件。

索引同样能够在升级后继续使用:由 GroupDocs.Search 22.7 到 26.8 构建的索引会在首次使用时自动转换,并在旁边保留备份。

代理决定的内容与索引执行的操作

代理决定的内容 索引执行的操作
问题属于哪个索引 将每个具名索引保存在其独立文件夹中
文件何时可能已更改 仅重新读取已更改、已添加和已删除的文件
搜索哪些词以及尝试哪些变体 匹配词语、短语、范围;报告找到的词条
引用多少上下文 返回包含请求词数前后文本的片段
向你提供什么信息 什么也不提供:仅返回计数、路径和文本,永不给出结论

这种划分是有意为之。判断权留给模型,而模型推理所依据的事实则来自你可以检查的工具输出。

诚实的限制

  • 在评估模式下,索引最多容纳 100 份文档,搜索最多返回 10 条结果。使用索引作为事实来源前请先调用 get_license_status。
  • 索引仅在 /data(或索引卷)是挂载的主机文件夹时才会持久化;否则随容器消失。
  • 索引包含文档的文本:请像处理文档本身一样保护并销毁它。
  • 仅限 Docker;在 Linux 上添加 --user "$(id -u):$(id -g)" 以便容器能够写入索引。

常见问答

代理会在会话之间记住我的文档吗?
有持久化索引时会:索引保存在磁盘上,下一次会话可以直接搜索而无需重新读取任何内容。

文件更改后我需要重新构建索引吗?
不需要。update_index 只会重新读取已更改、已添加和已删除的文件。

我可以将索引与只读文档分开存放吗?
可以。将文档以只读方式挂载,将可写文件夹挂载到 /index,并设置 GROUPDOCS_MCP_INDEX_PATH=/index。

深入了解