# rag-query-cli **Repository Path**: witink_frontier/rag-query-cli ## Basic Information - **Project Name**: rag-query-cli - **Description**: 通用的 cli 界面 rag 知识库问答。基于 milvus db 向量数据库和 bge-m3 内嵌模型。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-08-31 - **Last Updated**: 2026-09-02 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # rag-query-cli 内容无关的 RAG 查询 CLI:用本地 ONNX **BGE-M3** 模型把查询转成稠密/稀疏两路向量 → 在已有的 Milvus 集合上做两路检索 → **RRF** 融合 → 调 **OpenAI 兼容**的 LLM 流式作答并附 `[n]` 引用。 > 本项目**只查询**:不建集合、不入库、不写任何 chunks/embeddings 文件。目标集合 > `legend_rag_bge_m3` 由外部入库流程维护,schema 视为不可变。 ## 技术栈 - Node.js 24 + TypeScript 5(`NodeNext` / `strict` / `noEmit`),运行时用 `tsx` 直接跑 TS - Milvus:`@zilliz/milvus2-sdk-node`(gRPC) - 嵌入:`onnxruntime-node`(本地推理)+ `@huggingface/tokenizers`(纯 JS 分词) - LLM:`fetch` + SSE 解析,兼容任意 OpenAI 格式接口 - 测试:`vitest` ## 目录结构 ``` src/ cli/ 参数解析、渲染、main/REPL config.ts 配置解析与校验 embedder/ tokenizer / session / sparse / 单例 milvus/ client 单例 / 不可变 schema / 检索 retrieval/ 两路路径 + RRF 融合 + ColBERT 占位 llm/ prompt / SSE 解析 / 流式调用 scripts/ smoke.ts 三段式验证 ``` ## 环境要求 - Node.js ≥ 24 - 本地已运行 Milvus(默认 `127.0.0.1:19530`),且集合 `legend_rag_bge_m3` 已存在并加载 - 本地已准备好 BGE-M3 INT8 ONNX 模型目录(默认 `/home/lighter/projects/bge-m3-onnx-int8`) - 首次 `npm install` 会下载 `onnxruntime-node` 的原生二进制(postinstall) ## 安装 ```bash git clone && cd rag-query-cli npm install ``` > 若 `onnxruntime-node` 的 postinstall 被 npm 的 allow-scripts 拦截,请放行或手动确认其原生 > 绑定(`.node` 文件)已落入 `node_modules/onnxruntime-node/bin/napi-v6/linux/x64/`。 ## 配置 复制占位配置并填入真实值: ```bash cp .env.example .env ``` `.env` 字段说明: ### Milvus | 变量 | 说明 | 默认 | | --- | --- | --- | | `MILVUS_ADDRESS` | Milvus gRPC 地址 | `127.0.0.1:19530` | | `MILVUS_TOKEN` | 鉴权 token(无则留空) | 空 | | `MILVUS_USERNAME` | 用户名(无则留空) | 空 | | `MILVUS_PASSWORD` | 密码(无则留空) | 空 | | `MILVUS_DB_NAME` | 数据库名 | `default` | | `MILVUS_COLLECTION` | 目标集合名 | `legend_rag_bge_m3` | | `EMBED_DIM` | 稠密向量维度(须与集合一致) | `1024` | ### 本地模型 | 变量 | 说明 | 默认 | | --- | --- | --- | | `BGE_MODEL_PATH` | BGE-M3 ONNX 模型目录 | `/home/lighter/projects/bge-m3-onnx-int8` | | `EMBED_MAX_LENGTH` | 嵌入文本最大 token 数 | `8192` | | `QUERY_MAX_LENGTH` | 查询最大 token 数 | `512` | ### 检索(稠密/稀疏两路 + RRF) | 变量 | 说明 | 默认 | | --- | --- | --- | | `TOP_K` | 每路召回条数 | `50` | | `FINAL_K` | RRF 融合后保留条数 | `5` | | `RRF_K` | RRF 倒数排名融合常数 | `60` | | `RAG_COLBERT_ENABLED` | ColBERT 第三路(当前无向量,保持 `false`) | `false` | ### LLM(OpenAI 兼容) | 变量 | 说明 | 默认 | | --- | --- | --- | | `LLM_API_URL` | chat completions 端点 | `https://api.openai.com/v1/chat/completions` | | `LLM_API_KEY` | API key(**请勿提交真实密钥**) | `sk-REPLACE_ME` | | `LLM_MODEL` | 模型名 | `gpt-4o-mini` | | `LLM_TEMPERATURE` | 温度 | `0.2` | | `LLM_TIMEOUT_MS` | 请求超时(毫秒) | `120000` | | `LLM_MAX_CONTEXT_CHARS` | 拼接给 LLM 的上下文最大字符数 | `1500` | > 配置校验:数字解析失败、集合名为空、或 `FINAL_K > TOP_K` 都会在启动时抛错。 ## 运行 > 不配置 LLM 也能只验证检索链路:加 `--no-llm` 即可跳过 LLM 调用。 ### 单次问答(流式输出) ```bash npm run rag -- --query "你的问题" ``` ### 结构化 JSON 输出(关闭颜色,强制单次模式) ```bash npm run rag -- --query "你的问题" --json ``` 输出形如 `{query, config, timings, errors, hits, answer?, error?}`。 ### 只做检索、不调 LLM ```bash npm run rag -- --query "你的问题" --no-llm ``` ### 交互式 REPL ```bash npm run rag # 输入问题回车提问;exit / quit 退出 ``` ### 其它常用参数 `--collection ` 覆盖集合名、`--top-k `、`--final-k `、`--no-color` 关闭配色、`--help` 查看全部。 ### 三段式 smoke 验证 跑通 分词(A) → 模型(B) → 检索(C) 三个闸门,任一失败即非零退出: ```bash npm run smoke ``` ### 类型检查与测试 ```bash npm run typecheck # tsc --noEmit npm test # vitest run(36 单测,无外部依赖) npm run test:single -- src/retrieval/fusion.test.ts # 跑单文件 ``` ## 输出契约 流式逐字输出,段落顺序: ``` 🔍 检索中... 📚 找到 N 条参考资料 # 每条 100 字预览 + 相似度/匹配分 🤖 助手: # 流式回答,内含 [n] 行内引用 📖 引用来源 # 列出 [n] 对应出处 ⏱️ 耗时 ``` - 配色:cyan=品牌/助手、yellow=用户、gray=状态与引用、red=错误 - dense 命中显示 `相似度 XX.X%`(COSINE×100);仅稀疏命中显示 `匹配分 X.XXX`;RRF 分不展示 - 中文 prompt 要求 `[n]` 行内引用与兜底句"根据现有资料,我无法回答这个问题" ## 硬约束(改动会静默破坏检索) - 嵌入模型必须与入库时**完全一致**(同一本地 ONNX `gpahal/bge-m3-onnx-int8`,INT8,`pooling:cls` 已在图内完成,dense 已 L2 归一化)。 - `EMBED_DIM=1024` 须与集合一致;检索 `metric_type` 须匹配索引(dense=COSINE,sparse=IP)。 - 字段名 `dense`/`sparse`/`chunk_id`/`text`… 须与 `src/milvus/schema.ts` 完全一致。 - 稀疏向量传入 Milvus 必须是**非空**字典(空字典会被以 dim=0 拒绝)——空查询时稀疏路自动弃用。 - int64 张量必须用 `BigInt64Array`(用 `Int32Array` 会在 `session.run` 抛错)。 - 退出时必须 `session.release()` + `client.closeConnection()`,否则 gRPC 连接池会让进程挂住不退出。 ## ColBERT 第三路(默认关闭) `src/retrieval/colbert.ts` 只提供 `RetrievalPath` 接口占位,`RAG_COLBERT_ENABLED` 默认 `false`。 启用需:① 入库侧把每个 chunk 的 `colbert_vecs`([token,1024])持久化并与 `chunk_id` 关联; ② 用 `embedding_text` 而非 `text` 计算晚交互 MaxSim;③ 将其作为第三路带 `weight` 送进 `rrfFusion`。 当前库里没有 colbert 向量,故保持关闭。