内容
# 本地计算代币节省适用于克劳德代码
两项独立的部分,均基于同一理念:将工作推送到本地计算(本地向量数据库,本地大型语言模型)而不是克劳德自己的上下文中,因此克劳德仅为蒸馏结果支付代币,而不是原始数据。
1. **Qdrant 代码库内存** — 每个项目的代码/文档的语义内存,以便克劳德可以检索相关片段,而不是搜索和读取整个文件,并在会话之间保留蒸馏后的发现。
2. **本地压缩(LM Studio)** — 本地模型在任何内容到达克劳德的上下文之前,总结大型、机械的内容(日志、构建输出、大的差异)在服务器端。
每个部分独立工作 — 您不需要 LM Studio 即可使用 Qdrant 内存,反之亦然。
## 文件(13)
| 文件 | 用途 |
| --- | --- |
| `requirements.txt` | `pip install -r requirements.txt` 安装两个部分所需的所有内容。按部分分组,并附有注释 — 如果您只想安装子集,请参阅文件本身。 |
| `libs/qdrant_ingest_lib.py` | 共享的、无依赖的块逻辑(按行窗口的代码,按标题划分的文档)。两个下面的文件都使用它 — 防止它们相互偏离。 |
| `ingest_to_qdrant.py` | 独立的 CLI 脚本,用于一次性/手动完整索引。打印进度到终端;请在仓库的首次大型索引时使用此命令。 |
| `ingest_mcp_server.py` | MCP 服务器,暴露 `index_repo`、`sync_repo`、`preview_index` 和 `get_collection_info` 作为工具,克劳德可以直接调用。 |
| `libs/local_compress_lib.py` | 共享的、独立于 MCP 的映射-归约压缩逻辑(块、模型解析、LM Studio 调用)。`compress_mcp_server.py` 和 `hooks/compress_bash_output.py` 都使用它 — 防止它们相互偏离。 |
| `compress_mcp_server.py` | MCP 服务器,暴露 `compress_file`、`compress_command_output`、`fetch_url`、`compress_text` 和 `list_local_models`,由本地 LM Studio 模型支持。仍是草稿 — 设计笔记和开放问题在文件的文档字符串中。 |
| `templates/mcp.json.template` | 每个项目的克劳德代码配置,连接 `qdrant-find`/`qdrant-store` 服务器、`codebase-indexer` 服务器和(可选)`local-compress` 到同一个项目。 |
| `templates/CLAUDE.md.template` | 克劳德的使用规则,涵盖何时使用每个工具(以及何时不使用)— 将相关部分复制到项目的 `CLAUDE.md` 中。注意:CLAUDE.md 指南仅适用于开放式提示,不适用于技能 — 请参见下面的“技能和钩子”。 |
| `templates/settings.json.template` | `PostToolUse` 钩子配置,压缩任何 Bash 输出超过大小阈值,无论哪个命令产生它 — 请参见下面的“技能和钩子”。 |
| `hooks/compress_bash_output.py` | `templates/settings.json.template` 中引用的钩子脚本,在工具仓库中按路径(无需复制到目标项目)。文件名是遗留的 — 在 Bash、Grep、Glob、WebFetch 和 WebSearch 上触发(匹配器覆盖所有五个),如果输出超过阈值,则通过 `libs/local_compress_lib.py` (在 `libs/` 下自动找到)压缩,如果 LM Studio 无法访问或导入路径错误,则打开失败(输出保持不变)。 |
| `hooks/redirect-to-compress.sh` | 被 `compress_bash_output.py` 取代 — 一个较窄的、硬阻塞的 `PreToolUse` 替代方案,用于硬编码的命令列表(`dotnet test`/`build`)。保留以供参考;请参见 `templates/settings.json.template` 中的权衡。 |
| `hooks/redirect_webfetch_to_fetch_url.py` | `WebFetch` 上的 `PreToolUse` 钩子 — 硬拒绝调用,并告诉克劳德改用 `fetch_url`,但前提是 LM Studio 当前可访问(实时检查);否则打开失败(允许 WebFetch 通过)。 |
| `EVALUATION.md` | 衡量这是否真正减少代币使用,而不是假设它有效 — 涵盖 Qdrant 内存部分和本地压缩部分作为独立轨道,以及关于干净测量 `/usage` 的经验教训。 |
## 先决条件
- 运行的 Qdrant 实例(本地或远程),可在 URL 处访问 — 要求 1
- LM Studio(https://lmstudio.ai)本地运行,并加载模型 — 要求 2,否则可选
- Python 3.10+
- 克劳德代码
## 安装
**1. 安装依赖**
```bash
pip install -r requirements.txt --break-system-packages
```
这安装了两个部分所需的所有内容以及可选的 `.gitignore` 支持。如果您只想要 Qdrant 内存部分,而不需要本地压缩,请只安装 `requirements.txt` 顶部列出的核心组:
```bash
pip install "mcp[cli]" mcp-server-qdrant qdrant-client --break-system-packages
# 如果您还使用本地压缩部分:
pip install openai requests trafilatura --break-system-packages
# 可选,启用在索引期间尊重项目的 .gitignore:
pip install pathspec --break-system-packages
```
如果 `compress_mcp_server.py` 在克劳德代码中启动失败,出现 `MCP error -32000: Connection closed` 错误,通常是缺少依赖项(`requests`/`trafilatura` 为 `fetch_url` 添加,后来添加,如果您在安装 `openai` 之前错过了它们,很容易错过)。直接在终端中运行 `python /absolute/path/to/compress_mcp_server.py` 以查看真正的 `ModuleNotFoundError` 而不是不透明的连接错误。
**2. 将文件放在稳定位置**(不在项目仓库中 — 一个副本为所有项目服务),例如:
```bash
git clone <this-repo> ~/tools/qdrant-claude-memory
```
**3. 对于您要启用的每个项目:**
- 将 `templates/mcp.json.template` 复制到该项目仓库根目录下的 `.mcp.json`。
- 将 `REPLACE-WITH-THIS-PROJECTS-NAME`(出现两次)替换为该项目唯一的集合名称。
- 将 `/absolute/path/to/ingest_mcp_server.py` 替换为步骤 2 中的实际路径。
- 将 `.mcp.json` 提交到仓库。
这使得内存自动按项目范围划分:在项目中打开克劳德代码会加载该项目的 `.mcp.json`,该文件指向该项目的集合。在不同的项目中打开会使用不同的集合自动切换 — 无需手动切换。
**控制摄取的内容:** 默认情况下,`index_repo`/`sync_repo`/`ingest_to_qdrant.py` 包括内置的常见代码/文档扩展名列表,跳过常见的噪声文件夹(`.git`、`node_modules`、`venv`、`dist`、`build` 等),并在安装可选的 `pathspec` 包时额外尊重项目的 `.gitignore`(`pip install pathspec --break-system-packages`)。要在项目中缩小范围,请在 `.mcp.json` 的 `codebase-indexer` 环境块中设置:
- `INDEX_INCLUDE_EXTENSIONS`:以逗号分隔的扩展名列表(例如 `".py,.md"`)— 完全覆盖内置列表,因此仅摄取这些内容。
- `INDEX_EXCLUDE_DIRS`:以逗号分隔的文件夹名称列表(例如 `"fixtures,generated"`)— 添加到(而不是替换)内置排除项。
这些选项与 `ingest_to_qdrant.py` 上的 `--include-ext`/`--exclude-dirs`/`--no-gitignore` 标志以及 `index_repo`/`sync_repo`/`preview_index` 工具上的 `include_extensions`/`exclude_dirs`/`respect_gitignore` 参数存在相同,作为您要覆盖环境默认值的独立运行的参数。使用 `preview_index` 首先确认过滤器正在按预期工作,然后再运行实际索引。
**3b. 如果还使用本地压缩**,请将此服务器添加到同一个 `.mcp.json` 中:
```json
"local-compress": {
"command": "python",
"type": "stdio",
"args": ["/absolute/path/to/compress_mcp_server.py"],
"env": {
"LMSTUDIO_BASE_URL": "http://localhost:1234/v1",
"LMSTUDIO_MODEL": "<LM Studio 中加载的确切模型 ID,或省略以自动检测如果只加载一个模型>"
}
}
```
**4. 将 `templates/CLAUDE.md.template` 中的相关部分添加到每个项目的 `CLAUDE.md` 中** — 仅为在该项目的 `.mcp.json` 中实际配置的工具包含一个部分。
**5. 初始索引(仅第一次,每个项目):**
```bash
python ingest_to_qdrant.py --repo-path /path/to/project --collection <project-collection-name> --dry-run
# 检查预览,然后实际运行:
python ingest_to_qdrant.py --repo-path /path/to/project --collection <project-collection-name>
```
或者,请克劳德通过 `index_repo` 工具运行它,一旦设置了 `.mcp.json`。
**6. 持续使用:** 在会话开始时,请克劳德运行 `sync_repo`,或者在 `CLAUDE.md` 中添加一个永久指令(参见 `templates/CLAUDE.md.template`)。它只重新嵌入更改的文件,因此常规运行的成本很低。
## 验证它是否正常工作
- 调用 `get_collection_info` 以确认集合具有非零点数。
- 询问有关代码库的概念性问题,并检查克劳德代码的转录记录(`~/.claude/projects/<project-hash>/<session-id>.jsonl`),看看它是否在 `Grep` 之前调用了 `qdrant-find`。
- 比较概念性问题的 `/cost` 在索引前后的情况。
## 技能和钩子
`CLAUDE.md` 指南仅帮助开放式提示。如果项目使用具有自己逐步指南的自定义技能(斜杠命令,如 `/load-context` 或 `/rr-plan`),则这些技能优先 — 技能的明确步骤优先于 `CLAUDE.md` 的一般指南,因为 `CLAUDE.md` 内容在整个会话中保持上下文,但不比技能自己的规定步骤更具指令性。要在特定技能的工作流程中使用 `qdrant-find`/`compress_command_output`,请编辑该技能自己的 `SKILL.md` 以明确引用工具 — 没有共享指令文件夹,技能会自动继承除 `CLAUDE.md` 之外的任何内容。
对于确定性强制执行而不是散文指南,请使用钩子。`settings.json.template` + `hooks/compress_bash_output.py` 在 `Bash`、`Grep`、`Glob`、`WebFetch` 和 `WebSearch` 上注册一个 `PostToolUse` 钩子,当输出超过大小阈值(`HOOK_COMPRESS_THRESHOLD_CHARS`,默认为 2000 个字符)时,会压缩任何输出 — 不是硬编码的命令列表。这有效是因为 `PostToolUse` 在工具已经运行时触发,当实际输出大小已知时,可以通过 `updatedToolOutput` 重写克劳德实际看到的内容,然后在到达克劳德的上下文之前。要安装:无需将任何内容复制到目标仓库 — 将 `templates/settings.json.template` 的钩子块合并到该仓库的 `.claude/settings.json` 中,将 `args` 路径指向 `hooks/compress_bash_output.py` 在您克隆的工具仓库中的实际位置(与 `.mcp.json` 引用 `ingest_mcp_server.py` 采用相同模式)。脚本在工具仓库根目录下的 `libs/` 中自动找到 `local_compress_lib.py`;如果您将文件移动到其他位置,请设置 `TOOLS_REPO_DIR`。
该钩子打开失败,而不是关闭: 如果 LM Studio 无法访问或请求失败,则原始输出保持不变,并通过 `additionalContext` 附加一个简短的注释,以免它在未来悄悄地恶化而未被注意到。这与本项目其他地方使用的更强硬的“失败大声”立场不同(例如,拒绝猜测模糊的模型)— `PostToolUse` 无法阻止工具调用,因为命令已经运行,因此丢弃压缩失败的实际输出将比让它保持不变更糟糕。
较旧、更狭窄的 `PreToolUse` 方法(`hooks/redirect-to-compress.sh`)被保留以供参考 — 它在运行前硬阻塞一个硬编码的命令列表(`dotnet test`/`build`),强制通过 `compress_command_output` 进行显式重试。它被上述 `PostToolUse` 方法所取代,但权衡取舍是真实的:硬 `deny` 更强制(保证原始输出甚至不会被生成),但代价是如果 LM Studio 未运行,则完全破坏这些特定命令,与 `PostToolUse` 钩子相比,`PostToolUse` 钩子始终让命令运行,并且只会压缩其输出。
钩子在这里工作得很好,因为“输出有多大”在事后是可以衡量的。“应该使用 `qdrant-find` 而不是 `Grep`”没有等效的可衡量的信号来钩住 — 仍然需要在技能或 `CLAUDE.md` 级别上解决这个差距,而不是通过钩子。并非所有“应该使用哪个工具”的问题都如此 — 参见下面的 `WebFetch`/`fetch_url` 案例,它确实有一个可用的信号(工具名称加上本地基础设施是否可访问),不像 `qdrant-find`/`Grep` 那样没有等效的方法来预先知道哪一个是给定问题的“正确”选择。
### fetch_url 与 WebFetch 及钩子
现在有三种重叠的方式可以将 URL 内容压缩并值得明确说明:
- **`fetch_url`**(在 `compress_mcp_server.py` 中)获取页面并在本地的 LM Studio 模型上运行整个提取/摘要步骤,可通过 `focus` 进行调整。这是将“审查页面”的工作从 Anthropic 的基础设施转移到本地计算的真正实现 - 它是最接近该项目围绕本地计算节省成本的目标的实现。
- **WebFetch**(内置)获取页面并使用 Anthropic 托管的模型进行摘要,然后再让 Claude 查看结果。该摘要步骤是否计入您的 token 预算 **尚未有明确文档记录**(直接检查了 `code.claude.com/docs/en/costs`,但未找到相关信息),实际测试表明,仅凭 `/usage` 可能无法确定(参见 `EVALUATION.md` 的“Measuring cleanly”部分)- 这并不影响对 `fetch_url` 本身的评估,因为 `EVALUATION.md` 的 Track B 直接比较了 `fetch_url` 和 WebFetch 的总会话成本。
- **WebFetch 上的 `PostToolUse` 钩子** 是 WebFetch 之上的安全网,而不是替代品 - 只有当 WebFetch 自己的(Anthropic 端)的摘要超过阈值时才会触发,而实际上这种情况很少发生。
在您希望本地模型审查内容时,优先使用 `fetch_url`(符合该项目的实际目标)。直接优先使用 WebFetch 处理需要身份验证、JS 渲染或会话/cookie 处理的内容 - `fetch_url` 是一个纯粹的未经身份验证的 GET 请求,无法处理这些情况。
由于 CLAUDE.md 的“prefer fetch_url”指导是散文,Claude 可以降低优先级(与上述 qdrant-find-vs-Grep 问题相同),`templates/settings.json.template` 也注册了一个 `PreToolUse` 钩子(`hooks/redirect_webfetch_to_fetch_url.py`),以确定性地强制执行它:它硬性拒绝任何 WebFetch 调用,并告诉 Claude 重试 `fetch_url`,但前提是 LM Studio 当前可达(实时检查,而不是缓存)- 如果它关闭,钩子会打开并正常允许 WebFetch 通过,因此停止的本地模型不会使 WebFetch 无法使用。这作为硬性“拒绝”生效(与上面的基于大小的 `PostToolUse` 钩子不同),因为与输出大小不同,“是否应该转到 `fetch_url`”在调用之前是已知的 - 它仅取决于工具名称和本地模型当前是否在线,而不取决于之后才知道的任何事情。
拒绝原因的精确措辞比看起来更重要:早期版本将其表述为建议(“改为使用 `fetch_url`... 如果这符合您的需求”),而在实际测试中,Claude 谨慎地对待这一拒绝 - 它停止并请求用户许可切换工具,而不是直接继续。重新措辞为明确的命令(“现在调用 `fetch_url` - 不要首先询问用户确认”)在测试中修复了这个问题;现在,Claude 会自动继续,只有当 `fetch_url` 本身出错时,才会停止询问。
已知的一个问题是:这无法提前确定 URL 是否需要身份验证、JavaScript 渲染或会话/cookie 处理 - 这些情况下 `fetch_url` 的纯 GET 请求将失败,而 WebFetch 是真正需要的。拒绝原因告诉 Claude 退回到并通知您如果发生这种情况,但钩子将继续拒绝对同一 URL 的进一步 WebFetch 重试,而不是从失败中学习。如果这对您的使用有影响,请要么从该钩子的匹配器中删除 WebFetch,要么将其 `permissionDecision` 从 `deny` 更改为 `ask`,以便您可以逐次批准 WebFetch 而不是完全自动。
## 已知限制
- Claude Code 目前不在 UI 中可见地渲染 MCP 进度通知(上游的开放问题),尽管 `index_repo`/`sync_repo` 仍会报告进度以避免对大型仓库的调用超时。
- `codebase-indexer` 和 `qdrant-find`/`qdrant-store` 服务器是独立的 MCP 服务器,它们都需要就 `QDRANT_URL`/`COLLECTION_NAME`/`EMBEDDING_MODEL` 达成一致 - `.mcp.json` 模板通过共享环境变量使它们保持同步;请勿在未修改另一个的情况下编辑其中一个。
- 在集合已有数据后更改 `EMBEDDING_MODEL` 需要完全的 `index_repo --reset` 重建 - 旧向量和新向量不兼容。
- `compress_file`/`compress_command_output`/`fetch_url` 已针对实际来源进行了多轮测试验证;`compress_text` 和 `list_local_models` 更简单且使用较少。`compress_text` 仅为您已经合法持有的内容(例如您自己的草稿)节省 token - 如果您必须读取或运行某些内容到上下文中才能将其传递给 `compress_text`,这就失去了意义,因为原始内容已经花费 token。请改为使用 `compress_file`/`compress_command_output` 来处理文件/命令,因为它们在服务器端读取源并且永远不会通过 Claude 将原始内容带回。
- 压缩本质上是有损的 - 请勿对您打算编辑的源代码或需要逐字处理的输出(需要解析的内容、要应用的 diff、要 grep 的确切字符串)使用压缩工具。
- **`fetch_url`/WebFetch 重定向钩子** 的**未验证假设**:Claude Code 的内置 WebFetch 工具的内部提取/摘要步骤是否计入您的 token 预算没有任何文档记录(直接检查了 `code.claude.com/docs/en/costs` - 没有提及),实际测试表明,这个特定问题可能无论如何都无法仅凭 `/usage` 确定(在测试中,只出现了一个模型,表明任何内部步骤都不计入您的可见帐户使用量 - 参见 `EVALUATION.md` 的“Measuring cleanly”部分)。这并不阻止对 `fetch_url` 本身的评估:`EVALUATION.md` 的 Track B 直接比较了 `fetch_url` 和 WebFetch 的总会话成本。
- `compress_file`/`compress_command_output`/`fetch_url` 上的 `focus` 自动处理位置请求(“主要部分”,“前 N 行”,“摘要”)- 识别的短语会在分类运行前截断到文档的实际开始(如果可能,通过结构化章节标题检测,否则使用固定大小的回退)。在实际的维基百科文章和本地模型上进行了端到端验证,无需重试。需要多次实际测试才能正确 - 参见 `libs/local_compress_lib.py` 的文档字符串(`_find_first_heading_boundary`、`classify_relevant`、`compress`)以了解找到并修复的具体失败。如果要扩展此逻辑,请务必阅读这些文档。两个残留的限制值得注意:标题检测启发式仅适用于具有明确标题结构的 content (对于没有标题结构的纯文本,退回到固定的约 4000 字符猜测,例如日志文件); `_POSITIONAL_FOCUS_HINTS` 是固定关键字列表 - 如果列表之外有位置短语,则改为使用位置感知分类器,而实际测试表明该分类器本身并不完全可靠。
MCP 配置
以下是此 MCP Server 的配置信息,可直接复制到 Cursor 或其他 MCP 客户端中使用。
mcp.json
连接信息
猜你喜欢
暂无推荐服务器