RAG退潮后,用「文件系统+grep」给智能体搭一套可验证的检索骨架
1. 为什么我又把向量库删了换回文件系统 grepRAG 退潮这件事我在两个项目里体会得特别明显。一个是公司内部的技术文档库大概三千多份 Markdown 和 PDF另一个是十几万行的 Java 单体仓库。前者用向量检索后者用代码语义搜索两个都踩过坑文档改一版要重跑 embedding代码合并一次要等索引同步最要命的是检索结果没法解释——用户问「为什么给我这段」我只能说「相似度高」。后来我把这两套东西都拆了换成最朴素的「文件系统 grep」骨架目录即分区文件名即标签grep 即检索原语让智能体自己决定搜什么、搜几轮。这套东西就是现在常说的 Agentic Search核心不是索引多聪明而是搜索过程可审计、可复现、可验证。它适合谁适合手里有本地知识库或代码仓库、想用最小依赖跑通智能体检索、又不想被 embedding pipeline 绑架的开发者。下面我把目录约定、grep 脚本、TaoToken 统一 Key 通道配置和验证动作完整拆一遍你照着改路径就能跑。2. 前置TaoToken 统一 Key 与 API 通道这套骨架里grep 负责「找」模型负责「读和判断」。找的部分零依赖读的部分需要一个稳定的模型通道。我用 TaoToken 做统一入口原因是它把对话、编码、Agent 调用收敛到一套 Key 和一套 API 上settings.json 和 config.toml 里只维护一份配置换模型不用改代码。你需要先拿到 Key进控制台创建 API Key地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。创建后复制那串 sk- 开头的字符串后面所有配置都复用它。API 基址统一用 https://taotoken.net/api 注意这个地址不带任何查询参数别自己拼。模型选择上分两条线临时验证检索效果、跑单轮问答用模型对话就行入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 如果是长期编码、Agent 循环调用、需要稳定额度和更低单次成本走 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 。我实测下来Agentic Search 这种「多轮小请求」的模式用 Coding Plan 比按量计费更可控因为一轮检索可能触发五到十次模型调用。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 配置字段以文档为准。如果你用 Claude Code 这类终端 Agent它的 Anthropic 兼容接入说明在 https://taotoken.net/claude-code-anthropic?utm_sourcetaotoken_aicg_blog_endutm_contentclaude_code_anthropicutm_campaignrewrite 把 base_url 和 api_key 填进去即可不用改它的检索逻辑。3. 可复制配置目录约定 grep 脚本 settings.json3.1 目录约定让文件系统自己成为索引我不再切 chunk而是用目录层级表达语义分区。约定如下你按自己业务改名即可knowledge-base/ ├── 00-index/ # 放全局说明、术语表grep 时优先扫这里 │ └── glossary.md ├── 10-docs/ # 产品文档按模块分子目录 │ ├── auth/ │ │ ├── login.md │ │ └── token.md │ └── billing/ │ └── invoice.md ├── 20-code/ # 代码仓库直接软链或 clone 进来 │ └── user-service/ ├── 30-logs/ # 日志样本按日期分文件 │ └── 2026-02-01.log └── 90-archive/ # 过期内容默认排除关键点有三个。第一目录名带数字前缀grep 时可以用--include精确限定范围比如只搜10-docs。第二每个目录放一个_meta.md写清楚这个分区里有什么、更新频率、负责人智能体第一轮先读它相当于「目录的目录」。第三归档区单独放检索脚本默认排除避免过期内容污染结果。3.2 grep 检索脚本可审计的搜索原语我写了一个agent_search.sh它不调用任何模型只做三件事按分区搜、按文件类型过滤、输出带行号和文件路径的结果。智能体拿到这些结果后再决定读哪个文件。#!/usr/bin/env bash # agent_search.sh - 可审计的 grep 检索骨架 # 用法: ./agent_search.sh 关键词 [分区目录] [文件类型] set -euo pipefail QUERY${1:?请传入搜索关键词} SCOPE${2:-knowledge-base} INCLUDE${3:-*.md} # --exclude-dir 排除归档和版本控制目录 # -n 输出行号, -H 输出文件名, -I 跳过二进制 rg --no-heading -n -H -I \ --exclude-dir{90-archive,.git,node_modules,target} \ --glob $INCLUDE \ --max-count 5 \ $QUERY $SCOPE \ | head -n 80这里用rgripgrep它比系统 grep 快一个数量级而且默认递归、默认跳过二进制。--max-count 5限制每个文件最多返回 5 行命中避免一个文件刷屏。head -n 80控制总输出量防止把模型上下文塞爆。如果你机器上没装 ripgrep用系统 grep 也能跑把命令换成grep -rn -I --include$INCLUDE --exclude-dir90-archive $QUERY $SCOPE | head -n 80实测下来ripgrep 搜十几万行代码库是几十毫秒级系统 grep 大概慢三到五倍但都能接受。重点是这套东西没有索引同步延迟文件一改下次搜索立刻是新内容。3.3 settings.jsonClaude Code 类 Agent 的接入配置如果你用终端 Agent把下面这段放进它的 settings.json路径以你实际安装为准通常在~/.claude/settings.json或项目根目录{ env: { ANTHROPIC_BASE_URL: https://taotoken.net/api, ANTHROPIC_API_KEY: sk-你的Key, ANTHROPIC_MODEL: claude-sonnet-4-5 }, permissions: { allow: [ Bash(rg:*), Bash(grep:*), Bash(find:*), Bash(cat:*), Read(*) ] } }permissions.allow这段是重点只放行只读的检索命令不让 Agent 随便写文件或执行构建。这样即使模型判断失误最坏结果也只是多搜几次不会破坏仓库。模型名按你实际可用的填不确定就先在模型对话里试。3.4 config.toml自研 Agent 的配置骨架如果你自己写 Agent 循环用 config.toml 更清晰[llm] base_url https://taotoken.net/api api_key sk-你的Key model claude-sonnet-4-5 max_tokens 4096 temperature 0.2 [search] root ./knowledge-base exclude_dirs [90-archive, .git, node_modules, target] default_glob *.md max_hits_per_file 5 max_total_lines 80 [agent] max_rounds 6max_rounds 6是防止 Agent 无限搜索的保险丝。Agentic Search 的本质是「多轮搜索 逐步收敛」但轮数不设上限会烧 token六轮对大多数问题够用。4. 验证请求命中率与延迟怎么测配置好之后别急着上生产先做两个验证动作。4.1 延迟验证grep 本身有多快time ./agent_search.sh UserService knowledge-base/20-code *.java我在一台普通开发机上跑十几万行 Java 仓库返回 80 行结果耗时在 40 到 90 毫秒之间。对比之前向量检索的 300 到 800 毫秒差距是数量级的。你可以把time换成hyperfine跑多次取平均更准。4.2 命中率验证用固定问题集打分准备一个eval.jsonl每行一个问题加期望命中的文件路径{q: 登录 token 怎么刷新, expect: 10-docs/auth/token.md} {q: 发票金额字段叫什么, expect: 10-docs/billing/invoice.md} {q: UserService 在哪定义, expect: 20-code/user-service/UserService.java}然后写个脚本对每个问题跑 grep看期望文件是否出现在结果里#!/usr/bin/env bash # eval_hit.sh - 计算 grep 命中率 HIT0; TOTAL0 while IFS read -r line; do Q$(echo $line | python3 -c import sys,json;print(json.load(sys.stdin)[q])) EXP$(echo $line | python3 -c import sys,json;print(json.load(sys.stdin)[expect])) TOTAL$((TOTAL1)) if ./agent_search.sh $Q knowledge-base * | grep -q $EXP; then HIT$((HIT1)) fi done eval.jsonl echo 命中率: $HIT / $TOTAL我自己的文档库跑下来纯 grep 的 Top-80 命中率在 70% 左右。剩下的 30% 怎么办交给 Agent 第二轮把第一轮命中的文件路径喂给模型让它生成更精确的正则再搜一次。两轮之后命中率能到 90% 以上。这就是 Agentic Search 和「一条 grep 定生死」的区别——搜索策略由模型动态调整而不是靠一个固定的相似度阈值。4.3 端到端验证一次完整请求curl https://taotoken.net/api/v1/messages \ -H x-api-key: sk-你的Key \ -H anthropic-version: 2023-06-01 \ -H content-type: application/json \ -d { model: claude-sonnet-4-5, max_tokens: 1024, messages: [ {role: user, content: 根据以下 grep 结果回答登录 token 怎么刷新\n10-docs/auth/token.md:23: refresh_token 有效期 7 天\n10-docs/auth/token.md:45: 调用 /auth/refresh 接口} ] }返回正常就说明通道通了。注意这里我把 grep 结果直接拼进 prompt模型只负责「读」不负责「找」职责分离出了问题好定位。5. 本篇常见错排查报错一rg: command not found。没装 ripgrep。macOS 用brew install ripgrepUbuntu 用apt install ripgrep或者退回系统 grep脚本里换命令即可。报错二搜索结果为空但文件里明明有。九成是--glob写错了。比如你搜.java文件却写了--glob *.md自然搜不到。先用rg --files knowledge-base | head看看实际有哪些文件再定 glob。报错三Agent 反复搜同一个词不收敛。检查max_rounds是否设了以及 prompt 里有没有明确「如果连续两轮结果相同就停止」。我踩过的坑是没限制轮数模型在一个模糊问题上搜了十几轮token 烧得心疼。报错四401 或鉴权失败。先确认 Key 没写错、没多空格再确认 base_url 是https://taotoken.net/api而不是带路径的完整地址。如果用的是 Claude Code 类工具检查 settings.json 里字段名是不是ANTHROPIC_API_KEY不同工具字段名可能不同以接入文档为准。报错五结果里混进归档内容。检查--exclude-dir有没有覆盖你的归档目录名。我一开始把归档叫old/脚本里排除的是90-archive结果搜出一堆过期文档后来统一命名才解决。报错六中文搜索命中率低。grep 对中文分词不友好长句搜不到。解决办法是把查询拆成关键词或者让模型先把问题转成几个短词再搜。这也是 Agentic Search 的一环——查询改写交给模型匹配交给 grep。6. 把 Key 通道和检索骨架接起来到这里检索骨架和模型通道都通了。最后一步是把两者接成一个循环Agent 拿到问题 → 生成 grep 关键词 → 执行agent_search.sh→ 读命中文件 → 判断是否够用 → 不够就改写关键词再搜 → 够了就回答。这个循环里grep 保证「找得到、可复现」TaoToken 保证「读得动、调得稳」。长期跑编码类 Agent 的话建议把额度走 Coding Plan入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding_planutm_campaignrewrite 比按量计费更适合这种多轮小请求的模式。临时验证检索效果、试不同模型对同一批 grep 结果的阅读能力用模型对话就够了入口在 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 。Key 管理和新建都在控制台地址是 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi_keysutm_campaignrewrite 。我现在维护这套骨架的方式很简单每周跑一次eval_hit.sh看命中率有没有掉掉了就补_meta.md或者调整目录分区而不是去重跑 embedding。文件系统 grep 最大的好处不是快是它坏了你能看懂哪里坏了。向量检索坏了你只能盯着相似度分数发呆。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →