Back to home@Ankali-Aylina

code-rag

No description

Stars
1
Language
JavaScript
Created
Aug 26, 2026
Updated
Aug 29, 2026
GitHub repo

Introduction

code-rag — 本地代码库语义索引与检索(DSH 模式)

对本地代码库(C++ / Java 为主,支持中英文注释混合)做声明感知分块 → Ollama 向量化 → Qdrant 存储, 为 DSH 会话提供五个 MCP 工具 + 一个可视化索引面板:

工具(模型视角)作用
mcp__code_rag__search_code自然语言检索代码,返回文件路径 / 函数名 / 行号 / 相似度 / 片段(按 root 隔离)
mcp__code_rag__index_codebase异步索引:立即返回 taskId,后台执行,不受调用超时限制full: true 只重建当前根
mcp__code_rag__index_status索引状态 + 运行中任务的实时进度(百分比/文件/分块/错误明细)
mcp__code_rag__index_cancel取消当前根的运行中任务
mcp__code_rag__set_root切换当前代码库根(换工作区/项目后的第一步)

工具名前缀 mcp__code_rag__ 由 DSH 的 MCP 桥接插件(@deepseek-ai/dsh-mcp-client)按 mcp__<serverName>__<rawName> 规则生成,search_code 等是 MCP 服务器侧的原始名。

索引面板(Roo Code 风格)

MCP 服务器内置本地 HTTP 端点(127.0.0.1:8756,占用自动上探),会话输入框上方的 Code RAG 索引状态条(动态 Cordis 插件)直接读取它:

  • 显示:当前根、索引状态、进行中任务的进度条(% / 文件 / 分块)、错误明细;
  • 按钮:开始索引(增量)/ 全量重建 / 取消
  • 数据与按钮操作与 MCP 工具完全同源(同一任务管理器);
  • 目标根 = 当前会话工作区(面板默认对工作区操作;服务器根不同会提示);
  • 端口发现:探测 8756-8786 全部端口并选择 startedAt 最新(避免连到残留旧服务器);
  • 所有请求带 8s 超时,服务器无响应显示离线而非永久挂起。

设置与诊断页(插件 v1.1.0+):DSH 设置 →「Web 插件」区新增 Code RAG 卡片, 一键检测索引服务器 / Qdrant / Ollama / 模式预设 / 配置文件并列出问题清单;可在线修改 <root>/.code-rag/config.json(Qdrant/Ollama 地址、嵌入模型、维度、集合、端口、 分块行数)、启动/取消索引、一键重新生成预设(npm run setup)。数据经插件 host 半部的 /api/code-rag/* 环回端点(仅本机来源可访问,详见插件 README)。

插件源码(动态版):plugins/index-panel.client.js,可交给 cordis_define 临时启用。 已固化plugins/dsh-code-rag-index-panel/ 是常驻版 npm 插件(ModuleLoader 格式), 由 npm run setupfile: 依赖装入 web profile 的 bundles 列表(~/.dsh/profiles/web/package.json), 重启 DSH 后所有会话生效;此后修改 lib/client.js 由 client-hmr 轮询自动热更新(无需刷新页面)。

没有写死的路径:仓库内所有机器相关路径都是占位符({{CODE_RAG_DIR}} 等), 由 npm run setup 在安装时替换为实际绝对路径。换机器/挪目录后重新运行一次即可。

目录结构

code-rag/
├── package.json              # npm 脚本:setup / build / serve / index / search / status / smoke
├── tsconfig.json
├── src/
│   ├── main.ts               # CLI 入口(serve | index | search | status)
│   ├── server.ts             # MCP 服务器:五工具(异步任务 + HTTP 面板端点)+ stdio
│   ├── config.ts             # 配置解析:默认值 < 配置文件 < 环境变量 < CLI
│   ├── taskfile.ts           # 任务状态共享文件(index-task.json / panel.json)
│   ├── walk.ts               # 文件扫描:ignore 规则、白名单、二进制/超大文件过滤
│   ├── chunker.ts            # 声明感知分块(花括号深度 + 签名识别,150/20 兜底)
│   ├── embedder.ts           # Ollama /api/embed 批量嵌入客户端(支持取消)
│   ├── qdrant.ts             # Qdrant REST 客户端(集合/upsert/检索/删除,UUIDv5 确定性 ID)
│   ├── indexer.ts            # 增量索引编排(进度回调 + 可取消 + 原子状态文件)
│   ├── searcher.ts           # 语义检索 + 结果格式化
│   └── state.ts              # 状态文件(<root>/.code-rag/state.json)读写
├── preset/                   # Code RAG 模式预设模板(占位符,由 setup 生成到 ~/.dsh)
│   ├── agent.cordis.yml
│   ├── preset.yml
│   └── skills/code-rag/SKILL.md
├── plugins/index-panel.client.js  # 索引面板动态版(cordis_define 用,Client 半部)
│   └── dsh-code-rag-index-panel/    # 索引面板常驻版(npm 插件:package.json + lib/;plugins/ 为市场 CI 认可的子包目录)
├── scripts/setup.mjs         # ★ 一键接入:生成预设 + 同步 web profile(幂等,零依赖)
├── scripts/smoke.mjs         # 端到端冒烟测试(真实 Qdrant/Ollama)
├── scripts/verify-async.mjs  # 异步索引/进度/取消/HTTP 端点验证
├── testdata/sample-repo/     # 演示代码库(Java + C++,中英注释)
├── testdata/big-repo/        # 压力测试代码库(1200 个生成文件)
├── code-rag.config.example.json
└── cordis.patch.example.yml  # 全局接入 DSH 的补丁片段(方案 B,占位符示例)

一、安装与构建

前置依赖(本地免费,需先就绪)

索引依赖两个本机免费组件,缺一不可(设置卡片「重新检测」会把未就绪项列入问题清单): Qdrant(向量库,端口 6333)与 Ollama(本地嵌入,端口 11434)。

Qdrant —— Docker 一条命令启动:

docker run -d \
  --name qdrant \
  --restart unless-stopped \
  -p 6333:6333 \
  -v qdrant_data:/qdrant/storage \
  qdrant/qdrant

或用 Docker Compose(docker-compose.yml):

services:
  qdrant:
    image: qdrant/qdrant
    ports:
      - "6333:6333"
    volumes:
      - qdrant_storage:/qdrant/storage
volumes:
  qdrant_storage:

Ollama —— 安装 Ollama 后拉取默认嵌入模型 (bge-m3:多语言 + 代码,1024 维,中文/英文查询均可靠):

ollama pull bge-m3

然后安装构建:

cd code-rag
npm install
npm run build          # tsc → dist/

若想用回 nomic-embed-text(英文/标识符查询可用,中文语义查询效果差), 改配置 embedModel: nomic-embed-text + dimensions: 768,然后全量重建索引。

二、接入 DSH(两种方案)

方案 A:code-rag 模式(推荐,一键完成)

cd code-rag
npm install && npm run build
npm run setup            # 生成预设 + 同步面板插件(幂等,可重复执行)

npm run setup(scripts/setup.mjs,零依赖)会根据自身实际位置自动完成:

  • 生成模式预设 ~/.dsh/.agent-presets/code-rag/(模板见 preset/,其中的 {{CODE_RAG_DIR}} / {{CODE_ROOT}} 占位符被替换为绝对路径);
  • 把索引面板插件 dsh-code-rag-index-panelfile: 依赖同步进 ~/.dsh/profiles/web/package.json(含 bundle 条目),并同步已安装副本;
  • 可选参数:--root <代码库根目录>(服务器默认根,仅兜底)、--no-panel

换机器 / 挪目录后只需重新运行 npm run setup,无需手工改任何路径。

然后:

  1. 重启 DSH,在模式选择器里选 Code RAG 模式,新建会话(保持其运行——索引服务器随之启动);
  2. 换工作区时先让模型调用 mcp__code_rag__set_root(root 传当前工作目录绝对路径), 再执行 mcp__code_rag__index_codebase 建立索引(persona/技能会引导模型自动完成);
  3. 之后提问“哪里实现了 X / 找一下处理超时的代码”,模型自动调用 mcp__code_rag__search_code

多根隔离:每个仓库的向量按 root 命名空间隔离(检索/删除/全量重建都只作用于 当前根),多个项目可共存于一个 Qdrant 集合;full: true 不会误删其他仓库。 集合未建立索引时工具返回友好提示(“请先调用 index_codebase”),不会 404 报错。

生成的 agent.cordis.yml 里的 mcp-code-rag 行(等价模板,占位符由 setup 替换):

- id: mcp-code-rag
  name: '@deepseek-ai/dsh-mcp-client'
  config:
    serverName: code_rag          # 工具名前缀
    transport: stdio
    command: node
    args: ['<CODE_RAG_DIR>/dist/main.js', 'serve', '--root', '<CODE_ROOT>']
    cwd: '<CODE_ROOT>'            # = 默认代码库根目录
    toolCallTimeoutMs: 300000     # 索引已异步化,此超时只影响 index_status/search_code 等轻量调用
    failOnStartupError: false

方案 B:全局接入(所有会话可见)

cordis.patch.example.yml 里的 insert 片段合并进 <DSH_HOME>/profiles/web/cordis.patch.yml(其中的 <CODE_RAG_DIR> / <CODE_ROOT> 占位符换成你的实际绝对路径),重启 DSH。

三、索引命令

# 增量索引(默认代码库根目录 = 进程 cwd,可 --root 指定;多个仓库互不干扰)
node dist/main.js index --root <代码库根目录>

# 全量重建(只清空该 root 的向量后重新索引,不影响其他仓库)
node dist/main.js index --full --root <代码库根目录>

# 只统计不写入(演练)
node dist/main.js index --dry-run

# 查看状态
node dist/main.js status --root <代码库根目录>

增量原理:<root>/.code-rag/state.json 记录每个文件的 (mtime, size) 指纹。 未变化跳过;变化/新增 → 删除旧点 → 重嵌(确定性的 UUIDv5(root:file:startLine) 保证幂等覆盖); 磁盘上消失 → 按 payload.file + payload.root 精确清理。进程中断不损坏状态(临时文件 + 原子 rename)。 CLI 索引进度实时打印到 stderr 并写入 <root>/.code-rag/index-task.json(索引面板同源读取)。

四、异步索引(会话内)

index_codebase 默认异步:立即返回 taskId,后台执行——大项目不再超时。 进度经 index_status 轮询(模型会每 30-60 秒汇报一次),index_cancel 可取消; 会话输入框上方的索引面板显示同样的进度并提供按钮。

五、检索(混合检索)

search_code 采用混合检索:查询文本同时生成稠密语义向量(bge-m3)+ BM25 稀疏向量(标识符拆分/CJK bigram tokenizer),Qdrant Query API 以 RRF 融合两条 通道——自然语言语义("蓝牙重连逻辑")与精确标识符/错误串/数字(reconnectDevice6333C3861)一次调用同时覆盖,精确命中分数通常为 1.000。

node dist/main.js search "命令行参数解析" --limit 5
node dist/main.js search "reconnectDevice" --dir src --limit 5

六、分块策略(chunker.ts)

“拟 AST”——不依赖 tree-sitter(无解析器的轻量启发式近似):

  1. 轻量词法扫描逐行统计花括号深度(忽略字符串/注释内的括号);
  2. 逐行维护作用域栈,识别声明签名(支持 public/private 修饰符、template<>、 类/接口/struct/namespace、多行签名回溯 ≤4 行——回溯不越过已打开作用域, 排除 if/for/while 等控制流与 lambda);
  3. 每个命名声明(函数/类)是一个独立块,其前导文档注释(Javadoc/Doxygen)自动 并入块内,保证“文件 + 函数名”级别的检索精度;
  4. 超大声明(> 150 行)与无结构区域(文件头、命名空间外代码)内部用滑动窗口 150 行 / 重叠 20 行——即需求里的兜底策略;
  5. 纯结构碎块(孤立的右括号等)自动丢弃,避免污染检索;
  6. 每个块携带 file / function / class / start_line / end_line,嵌入文本带定位头 (// src/foo.cpp :: bar (lines 12-34)),提升检索精度。

分块回归测试:npm test(node:test,12 个用例固化历史边界——行尾注释回溯、 } else { 撕裂、多行签名、窗口切分、稀疏 tokenizer 等)。

七、配置

优先级:内置默认 < <root>/.code-rag/config.json < 环境变量 CODE_RAG_* < CLI。 把 code-rag.config.example.json 复制到 <root>/.code-rag/config.json 后修改。 常用项:qdrantUrlollamaUrlembedModeldimensionschunkSize/chunkOverlapignore(目录忽略)、extensions(语言白名单)、 httpPort(索引面板 HTTP 端点端口,默认 8756,占用自动上探;也可用环境变量 CODE_RAG_HTTP_PORT 覆盖。注意索引面板探测 8756-8786,改到区间外时需同步修改 面板插件 lib/client.js 里的 PORT_BASE)、 embedConcurrency/embedRetries(嵌入并发与失败重试,默认 4/3)。 (root 不在此配置:由启动参数 --root / 当前工作目录决定,多仓库用 set_root 切换。)

安全:面板 HTTP 端点只接受本机来源(127.0.0.1/localhost 的 Origin), 其他网页来源一律 403。

换嵌入模型:改 embedModeldimensionsindex(增量即可)会自动 检测到状态指纹与模型不匹配并全量重建。默认 bge-m3 = 1024 维; nomic-embed-text = 768 维。bge-m3 对中英混合注释的检索质量显著更好。

八、冒烟测试

npm run build && npm run smoke

依次验证:CLI 全量索引 → 中文查询「命令行参数解析」命中 App.parseArgs → 中文查询「指数退避重试算法」命中 engine.retryWithBackoff → MCP 握手(initialize / tools/list 四工具 / search_code / set_root / 空根 index_status 友好输出)。

九、工作原理速览

会话提问 ──> DSH 模型 ──> mcp__code_rag__search_code(MCP stdio)
                              │
                    code-rag 服务器(node dist/main.js serve)
                    ├─ 查询嵌入:Ollama /api/embed(bge-m3, 1024 维)
                    └─ 相似检索:Qdrant REST /points/search(Cosine)
                              │
                         返回 file + function + 行号 + 片段

索引路径:walk 扫描 → chunker 分块 → embedder 批量嵌入 → qdrant upsert(UUIDv5 幂等)→ state.json 指纹回写。删除路径:状态里有、磁盘上没有 → deleteByFile(payload.file 过滤)

十、常见问题

现象处理
search_code 提示“尚未建立索引”调用 index_codebase(可加 root 指定仓库)后重试
点“开始索引”没反应/卡住旧版服务器残留会占端口:重启 DSH 让新服务器(stdin 关闭即退出)接管;面板已选最新实例 + 8s 超时兜底
索引显示“0 个文件”服务器已加 0 文件防护:root 配错或 ignore 把源码目录排除了会明确报错;点击面板根名可切换
大项目索引超时已解决:index_codebase 默认异步立即返回,后台执行;用 index_status 看进度
看不到索引进度index_status(模型会汇报);或启用索引面板(输入框上方状态条 + 按钮)
换工作区后检索的还是旧项目set_root 切到当前工作目录,再 index_codebase
检索结果混入别的项目多根已按 root 隔离;确认 index_status 的当前根是否正确
索引任务卡住想停index_cancel 或面板的“取消”按钮
Ollama 找不到模型ollama pull bge-m3(默认)或 ollama pull nomic-embed-text
向量维度不匹配报错模型换过 → 同步改 dimensions + index --full
中文检索不准确认默认模型为 bge-m3(1024 维);nomic-embed-text 中文语义弱
端口不通docker ps 看 Qdrant;curl localhost:11434/api/tags 看 Ollama
MCP 工具没出现检查 DSH 日志中 mcp-client(code_rag) 行;确认 dist/main.js 路径存在
大仓库索引慢先看是不是把生成/构建目录扫进去了:node dist/main.js index --dry-run --root <仓库> 看 scanned 数。VS C++ 项目默认已忽略 Temperat.*(MSBuild 中间目录)、x64installer;其他项目的生成目录加到配置 ignore。真慢时调大 embedBatchSize / embedConcurrency(默认 32/4)
生成文件进了索引<root>/.code-rag/config.jsonignore 里加目录模式(支持 *),然后 index --full