英语 | 日本语
yomu
AI代理的前端代码搜索。当你不知道代码的名字时,按概念查找代码。
问题
你需要找到聊天流挂钩 vercel/ai (3535个文件),但你不知道函数被调用了 useChat.
典型的代理工作流程:
glob "**/chat*" → 12 files. None are it (it's called use-chat.ts).
grep "stream.*hook" → 0 files.
grep "chat" → too many results. Try reading a few...
read packages/react/src/use-chat.ts → Found it. What does it import?
read packages/ai/src/ui/process-ui-message-stream.ts → Now I have context.3-5次工具调用,反复试验,上下文窗口中有噪音。
与yomu:
yomu search "streaming chat hooks"
## packages/react/src/use-chat.ts
Imports: @ai-sdk/provider-utils, @ai-sdk/ui-utils
Siblings: UseChatOptions [type_def], UseChatHelpers [type_def]
1. useChat [hook] — 58:210 (similarity: 0.85)
export function useChat({ api, ...options }: UseChatOptions): UseChatHelpers {
...full function body...
}
## packages/rsc/src/streamable-value/use-streamable-value.ts
2. useStreamableValue [hook] — 12:45 (similarity: 0.72)
...
## examples/ai-e2e-next/.../chat-context.tsx
3. useSharedChatContext [hook] — 8:22 (similarity: 0.68)
...1个电话。实现是第一个结果——在130个包含“useChat”的文件中,索引中总共有9015个块。
每个结果都包括完整的代码体、文件导入和兄弟定义。不需要后续阅读。
为什么不只是grep?
Claude Code的开发人员发现 这种代理搜索——让模型迭代地使用glob和grep——在代码导航方面优于RAG。他们是对的。当代理可以使用不同的关键字重试、读取目录结构并优化其搜索时,grep的工作效果非常好。
yomu不会与这种工作流程竞争。它 减少迭代次数:
| 方法 | 调用 | 上下文窗口成本 |
|---|---|---|
| grep/glob(迭代) | 3–5 | 每次失误都会增加噪音 |
| yomu搜索 | 1 | 代码+导入+兄弟姐妹在一个响应中 |
经典的RAG问题——索引同步延迟、陈旧嵌入、冷启动——得到了解决:
| 解决方案 | 详细信息 |
|---|---|
| 无同步延迟 | 每 search 检查索引新鲜度,如果文件发生更改,则自动重新分块 |
| 不需要API密钥 | 本地嵌入模型,当模型不可用时,FTS5全文回退 |
| 增量嵌入 | 每次搜索调用50个块,大多数导入的文件优先。无需前期构建 |
当你知道grep的名字时,它是一个合适的工具。yomu是在那之前的一刻——当你知道概念但不知道标识符的时候。
何时使用yomu(何时不使用)
| yomu | grep/glob |
|---|---|
| 你不知道代码叫什么 | 你知道确切的名字(grep "useAuth" 更快) |
| grep返回的结果太多——你需要impl | 你需要正则表达式匹配或精确的字符串搜索 |
| 您希望在一次调用中包含代码+导入+相关类型 | 代码库很小,很熟悉 |
yomu不能取代grep。它涵盖了grep不能的情况:按概念搜索。
设置
安装
brew install thkt/tap/yomu或者从源代码构建(需要Rust 1.85+):
cargo build --release配置
语义搜索使用局部嵌入模型(鲁里V 3约1.2GB)。如果模型已经在本地缓存, search 自动使用它-不需要API密钥。
如果模型未安装或不可用, search 返回到纯文本模式(FTS5)。所有其他命令(index, rebuild, impact, status)没有模型的工作。
没有手动索引。 search 第一次调用时自动索引。
平台说明
| 平台 | 构建命令 |
|---|---|
| macOS(苹果硅) | cargo build --release (默认:mlx后端) |
| Linux/x86 | cargo build --release --no-default-features --features candle |
命令
全球旗帜
| 标志 | 描述 |
|---|---|
--json | 输出为JSON(所有命令) |
--json 可以出现在子命令之前或之后:
$ yomu --json status
{"files":42,"chunks":187,"embedded_chunks":187,"embeddable_chunks":187,"embed_percentage":100,"references":156,"last_indexed":"2025-03-29 01:23:45"}yomu search [query] --按概念搜索
返回带有完整上下文的排名结果。每个结果包括:
| 包括 | 为什么 |
|---|---|
| 完整代码体 | 无后续 read 需要 |
| 文件导入 | 不打开另一个文件的依赖关系上下文 |
| Sibling defs | 同一文件中的其他函数/类型 |
| 块类型 | 组件/钩子/类型_def/css_rule/rust_fn |
选项:
| 标志 | 默认值 | 描述 |
|---|---|---|
--limit | 10 | 最大结果(最大值:100) |
--offset | 0 | 分页偏移(最大值:500) |
--from | -- | 搜索与文件或符号类似的代码(src/foo.rs 或 src/foo.rs:my_fn).查询变为可选 |
--no-embed | false | 跳过嵌入查找;仅使用FTS5。效果与 YOMU_EMBED=0 |
--from 使用目标的存储嵌入——不需要重新嵌入:
yomu search --from src/query/mod.rs # files similar to this file
yomu search --from src/query/mod.rs:rerank # files similar to this function
yomu search --from src/query/mod.rs "filter" # hybrid: similar to file + FTS on "filter"yomu impact --爆炸半径变化
显示哪些文件依赖于目标文件或符号。
$ yomu impact "packages/ai/src/ui/ui-messages.ts" --symbol UIMessage --depth 2
## Impact analysis: `packages/ai/src/ui/ui-messages.ts`
### Direct symbol references
- packages/ai/src/ui/process-ui-message-stream.ts
- packages/react/src/use-chat.ts
...34 files
### All transitive dependents
#### Depth 1
- packages/ai/src/ui/process-ui-message-stream.ts
...37 files
#### Depth 2
- packages/react/src/use-chat.ts
...18 files
Total: 55 dependent file(s)vercel/ai的实际输出。一个调用替换了手动跟踪导入。
选项: --symbol (可选,过滤到特定导出), --depth (默认值:3,最大值:10)
--json 返回结构化响应。 dependents[].references 为直接(深度=1)边填充,并列出每个边 (ref_kind, via_symbol) 从源文件中配对。传递性(深度>=2)依赖项通过中间文件到达目标,因此它们的 references 是 []:
{
"target": "src/storage.rs",
"in_index": true,
"dependents": [
{
"file_path": "src/indexer.rs",
"depth": 1,
"references": [
{"ref_kind": "named", "via_symbol": "Db"},
{"ref_kind": "named", "via_symbol": "open_db"}
]
},
{
"file_path": "src/main.rs",
"depth": 2,
"references": []
}
],
"symbol_refs": [],
"total": 2
}ref_kind 是其中之一 named / default / namespace / type_only / side_effect. via_symbol 是 null 用于名称空间/副作用导入,其中在导入站点上没有命名单个符号。
yomu index / yomu rebuild / yomu status
| 命令 | 详细信息 |
|---|---|
index | 更新块索引。没有API调用,对3535个文件约2.5秒。通常不需要-- search 自动索引 |
rebuild | 从头开始完全重新解析 |
status | 文件、块、嵌入覆盖率、引用 |
运作原理
Source files → tree-sitter AST → Semantic chunks → Local embeddings (Ruri v3) → Hybrid search| 阶段 | 详细信息 |
|---|---|
| 索引 | 树形图在函数/组件/类型边界处拆分代码。每个块都是一个可搜索的单元。导入图是在同一通道中构建的。在vercel/ai:3535个文件上→ 9,015个区块+5026个导入引用,2.5秒,零API调用 |
| 嵌入 | 块通过本地模型(Ruri v3,310M参数)增量嵌入。每个50块 search 调用,按导入计数进行优先级排序——最常用的代码首先被搜索。无需预先构建 |
| 搜索 | 三层混合:向量相似性→ 名称/路径匹配→ FTS5全文。使用IDF加权关键字评分重新排名。经常导入的文件排名更高,测试文件排名更低 |
支持的文件类型
| 类型 | 解析器 | 块类型 |
|---|---|---|
| TypeScript/TSX | 树保姆 | 组件、钩子、type_def、test_case、其他 |
| JavaScript/JSX | 树保姆 | 组件、钩子、type_def、test_case、其他 |
| Rust | 树保姆 | Rust_fn、Rust_struct、Rust_enum、Rust_trait、Rust_impl |
| CSS | 树形图 | CSS_rule(选择器、@media、@关键帧) |
| HTML | 树保姆 | HTML_element |
其他文件则退回到基于字符的重叠分块。
局限性
| 限制 | 详细信息 |
|---|---|
| 模型未自动下载 | 必须预缓存约1.2 GB的嵌入模型; search 不自动下载 |
| 不支持SCSS/Sass | 仅支持纯CSS |
| 冷启动 | 首先 search 调用分块+初始嵌入需要几秒钟的时间 |
| 跳过大文件 | 超过1 MB的文件将被排除在索引之外 |
| 嵌入选择退出 | 通过 --no-embed 到 yomu search,或设置 YOMU_EMBED=0; search 回退到纯文本模式 |
发展
设置
克隆后运行一次:
git config --local core.hooksPath .githooks这将安装一个运行的预提交钩子 cargo fmt --check 和 cargo clippy --all-targets --all-features -- -D warnings 每次提交之前。违规行为会中止提交。跳过一次提交: git commit --no-verify.
常用命令
cargo test # all tests
cargo clippy --all-targets --all-features -- -D warnings # lint (matches CI)
cargo fmt -- --check # format check建筑
src/
├── main.rs CLI entry point (clap)
├── lib.rs Crate root, public API
├── config.rs Runtime configuration
├── modernbert.rs ModernBERT model (mlx backend)
├── tools/ Application facade — orchestrates indexer, query, storage per command
├── indexer/
│ ├── mod.rs Orchestration: incremental index, embed budget
│ ├── chunker/ tree-sitter AST → semantic chunks
│ ├── embedder.rs Local embedding (ModernBERT/Ruri v3 via mlx-rs or candle)
│ └── walker.rs File discovery, .gitignore filtering
├── resolver.rs Import path resolution (tsconfig aliases, index.ts probing)
├── query/ Hybrid search + IDF reranking
└── storage/
├── mod.rs Schema, CRUD, types
├── search.rs Vector similarity, name matching, FTS5
├── embed.rs Embedding storage, vec_chunks
└── graph.rs Import graph traversal, dependents, siblings单一二进制,零运行时依赖关系。SQLite和SQLite-vec是静态链接的。
许可证
麻省理工学院
