用代码图搜索代码
本指南介绍如何把仓库纳入代码图,然后用它来回答重构之前你真正关心的问题:哪些东西依赖它?
代码图是一个符号与边的数据库,由 tree-sitter 解析你已注册的检出内容构建而成。它的工具面向智能体——你需要通过请求智能体来使用它们。
开始之前
标题为“开始之前”的部分代码图为 Dart、JavaScript、TypeScript、TSX、PHP、Python、Rust、Zig、C、C++、Go、Java、Ruby、C#、Swift、Kotlin、R、Assembly、MATLAB 和 Ada 建立索引。其他任何语言的文件都不会被解析,因此不会出现在 search_code、code_symbol、code_callers、code_callees 或 code_impact 中。
还有两件事会决定哪些内容会被索引:
- 在 git 工作树中,枚举工作交由
git ls-files --cached --others --exclude-standard处理,因此每个.gitignore、嵌套忽略文件、.git/info/exclude以及全局排除文件都会生效。正是这一点让node_modules和构建产物不会被纳入代码图。 - 生成的 Dart 一律会剔除。生成的文件通常会被提交,因此仅靠 git 无法排除它们,而且它们在每次代码生成运行时都会变动。
为仓库建立索引
标题为“为仓库建立索引”的部分注册检出会触发 RepoAdded,从而自动为它启动 index_code 流水线。参见向工作区添加仓库。
手动重新索引:
- 打开 设置 → 工作区 → 仓库。
- 点击仓库所在行上的 索引代码 按钮。
- 运行期间,按钮会显示已完成文件数与总数,并提供取消控件。完成后它会变成一个带有符号数量的对勾。
代码图按工作区、仓库和检出分区:关联的检出是一个分区,每个空间工作树也各自拥有一个分区(以其隔离仓库 id 为键)。
有两个限流机制值得了解,因为它们能解释那种看起来像卡死的等待:
- 文件监视器在主机上一次只允许一个索引任务运行——第二个检出需要等待。
index_code流水线另有单独限制,每个工作区只能有一个运行,因此同一工作区中的两个仓库会排队,而不同工作区可以并行建立索引。索引器本身会把同一个检出的两次运行串行化,这样流水线启动和监视器扫描就不会重复解析它。 - 属于休眠空间(过去一周内没有任何消息)的工作树既不会被监视,也不会被索引。关联的检出仍会被监视。跳过决定会在五分钟后重新检查,因此重新活跃起来的空间会被重新纳入。
查找符号
标题为“查找符号”的部分让智能体去搜索。所用的工具是 search_code,它同时需要一个工作区和一个仓库:
search_code(workspace_id: "...", repo_id: "...", query: "authentication middleware")仓库 id 来自 list_repos。可选的 mode 参数取值为 keyword、semantic 或 hybrid,默认是 hybrid——对名称、签名和文档注释做 BM25 检索,并与向量相似度融合。
每个结果都带有该符号的 id、名称、限定名、种类、文件路径、起始行和结束行,以及它的签名(如果有)。这个 id 就是你传给本页其他每个工具的句柄。
如果你知道确切的名称,也可以直接查找:
code_symbol(workspace_id: "...", repo_id: "...", name: "MyClass")追踪调用
标题为“追踪调用”的部分两者都接受来自搜索结果的 symbol_id,外加一个可选的 limit(默认 50):
code_callers(workspace_id: "...", symbol_id: "...")code_callees(workspace_id: "...", symbol_id: "...")code_callers 返回有边指向该符号的那些符号;code_callees 返回它所依赖的那些符号。
查看某项改动会破坏什么
标题为“查看某项改动会破坏什么”的部分整页内容就是为了介绍这个工具:
code_impact(workspace_id: "...", symbol_id: "...", depth: 3)它计算反向依赖半径:沿 calls、extends 和 implements 边直接或间接依赖该符号的所有内容(导入、混入和泛型引用虽然存储在代码图中,但这里不会遍历)。depth 是最大跳数,取值在 1 到 6 之间,默认是 2。
结果包含三个字段:
root—— 你所查询的符号impacted—— 可达集合,包括深度为 0 的根符号,每个符号都带有它到根的depthedgeCount—— 遍历经过了多少条边,给出的是计数而不是边本身
在重命名或修改签名之前运行它,并把受影响列表作为范围交给智能体。
结果会对照调用方自己的工作副本进行检查
标题为“结果会对照调用方自己的工作副本进行检查”的部分对于智能体调用方,空间 id 会自动注入,结果会与该空间的工作副本进行核对。如果某个符号的文件在调用方的目录树中已不存在,该符号会被略去,响应中会带有 staleOmitted 计数,并附一条说明:索引中这些符号已经过期。
这就是为什么你和智能体对同一个查询可能得到不同的答案,也是为什么一个空间中的智能体与另一个空间中的智能体会得到不同的答案。一个空间中的每次对话都共用同一个工作树。核对采用失效开放策略:宁可给出过期的答案,也不返回空结果。
当你想要某项改动的影响范围时,可以让智能体运行 code_impact(或 review_studio.blastRadius)。参见审查计算。
语义搜索需要嵌入模型
标题为“语义搜索需要嵌入模型”的部分符号和事实会在写入时生成嵌入,且仅当设备端嵌入模型已安装时才会如此。在此之前,mode: "semantic" 以及 hybrid 的语义部分没有可匹配的内容,搜索实际上只按关键词进行。
请在建立索引之前,先在 设置 → 服务器 → 诊断与隐私 → 语义搜索 中安装该模型。符号会在其文件被摄取时获得向量。
另请注意,任何一次服务器二进制文件的重建都会重新暂存语法 dylib 并改变它们的 mtime,从而使所有索引检查点失效,并迫使下次运行时对每个检出做一次完整重新遍历。它会重新计算哈希,但不会重新提取未发生变化的文件。
代码图里有什么
标题为“代码图里有什么”的部分符号种类: function、method、class、field、enum、constructor、getter、setter、typedef、extension、mixin、variable。
边种类: calls、imports、extends、implements、mixes in、references。
这些工具的规范签名见 MCP 工具。