跳转到内容

探索陌生代码

agent 读陌生代码烧 token 的速度飞快:为了“建立全局感”倾倒整个文件,为找一个类型的定义 反复重读,为搞清一个 40 行函数的所作所为塞进日志体量的上下文。CtxCtl 把流程倒过来—— 先拿地图,只读你需要的地盘。以下命令全部只读且无状态;不索引、不缓存。

outline 每个符号打一行——种类、名称、行区间、签名——外加 token 节省统计。这是对任何受支持 文件最便宜的定向扫描:

Terminal window
ctxctl outline src/server.rs
# src/server.rs [12 symbols, ~2.1 KB -> ~410 tokens, saved ~80%]
fn handle_request L:42-58 pub async fn handle_request(&self, id: u64)
struct RequestHandler L:12-40 pub struct RequestHandler {
const MAX_RETRIES L:60 const MAX_RETRIES: u32 = 3;

仅凭这一步,agent 不读文件就已经掌握它的形状。超大文件的符号列表超过阈值(默认 50)后会折叠成 一行 ... [N symbols omitted] 标记;表头始终保留总数。想要极简输出可加 --no-doc 去掉文档注释。

大纲点出了感兴趣的符号之后,往往还不需要立刻读完整函数体:

Terminal window
# 只要声明行
ctxctl symbol src/server.rs --name handle_request --signature
# 签名 + 函数体的折叠标记
ctxctl symbol src/server.rs --name handle_request --compact

--compact 返回 AST 剪枝视图:签名(python 还带装饰器)、一条 // ... [N lines omitted] 折叠标记(python 为 # …),以及存在时的裸收尾行。它字节稳定且重新解析不会报错, 下游工具照常消费。

这两个开关回答 agent 最常见的问题——“这个函数收什么、返回什么?”——代价只是完整读取的零头。

要真正的实现时,不带附加参数的 symbol 会从原始源码返回该符号的逐字切片:

Terminal window
ctxctl symbol src/server.rs --name handle_request
# handle_request src/server.rs:42-58 (58 tokens, saved ~85%)
pub async fn handle_request(&self, id: u64) -> Result<String, Error> {
let row = self.db.get(id).await?;
Ok(row.to_string())
}

切片原样保留注释、格式和缩进——它是源码,不是摘要。几个有用的精调:

  • --kind <k> 收窄同名匹配(方法对局部变量)。出现重名时,除非收窄,否则源码顺序第一个胜出。
  • --lines 3-10 在符号内部再取子区间,定位到精确行后使用。
  • 退出码 4 表示未找到符号——多半是拼写错误或文件不对,而不是功能缺失。

对于落在任何单个符号之外的区间——模块级文档块、配置表——用 read,它完全不需要 AST:

Terminal window
ctxctl read src/server.rs --lines 100-150
ctxctl read src/server.rs --lines 100-150,200-210 # 多个区间,逗号分隔

开区间会钳制到文件末尾(--lines 10-)。退出码 2 表示区间无效或越界。

跨文件跳转之前,先看看这个文件依赖什么。deps 列出每个导入的目标、种类与行号:

Terminal window
ctxctl deps src/main.rs
# src/main.rs [3 imports, ~512 B -> ~64 tokens, saved ~88%]
external serde L:1
local crate::lib L:2

local / external 的区分直接告诉 agent 哪些跳转留在仓库内(值得跟一个 outline), 哪些跨进第三方依赖(通常根本不值得读)。

同一套工作流覆盖的不止源码——符号引擎为标记与样式语言也提供了后端:

  • Markdown: 每个 ATX/setext 标题都是符号,且标题的切片覆盖整个小节——因此 symbol README.md --name Install 返回的正是那一节。
  • CSS/SCSS: 规则集是符号(选择器列表即名称),嵌套的 @media 块也包含在内。
  • HTML:id 属性的元素可以用该 id 寻址。

agent 探索文档密集型仓库时,享受同样的“先大纲后切片”纪律,无需任何特殊处理。

一次完整的便宜探索长这样:

Terminal window
ctxctl outline src/server.rs # map
ctxctl deps src/server.rs # what it hangs off
ctxctl symbol src/server.rs --name handle_request --compact # shape of the target
ctxctl symbol src/server.rs --name handle_request # body, verbatim
ctxctl read src/server.rs --lines 100-110 # anything outside symbols

每一步的输出都指向下一步的决策点,而每一步都远小于整个文件。想让命令输出同样变小,见 压缩命令输出;“切片而非摘要”背后的理由在设计原则