当预期命令输出可能超过20行时,应使用 ctx_execute 将数据捕获并索引到本地知识库,而非直接输出到上下文窗口;需要从已索引数据中提取特定信息时,则应使用 ctx_search 进行查询。正确的分层使用(捕获层与过滤层分离)是避免上下文窗口浪费、实现高达98%节省的关键。
Context Mode 使用最佳实践:ctx_execute/ctx_search 的正确用法与常见反模式
对于使用 Context Mode(上下文模式)的 AI 编码助手开发者而言,正确运用 ctx_execute 和 ctx_search 是实现上下文高效管理的核心。这两个工具并非简单的命令执行或文本搜索,它们构成了一个分层的数据处理管道:ctx_execute 负责捕获,ctx_search 负责过滤。理解并遵循其设计原则,是避免反模式、最大化会话连续性和节省效果的前提。
一、决策树:何时用 ctx_execute,何时用 Bash/Read
在开始任何操作前,应依据以下决策流程选择工具:
- 输出量确定性与大小:如果命令输出确定少于20行(如
git status、ls、echo),直接使用 Bash。这是最快的路径。 - 输出量不确定或可能很大:对于任何读取、查询、列出、记录、测试、构建、比较的操作(如
npm test、gh pr list、kubectl get pods、分析大型日志),一律使用ctx_execute。它会将输出捕获到本地索引,而非填满上下文窗口。 - 需要读取文件内容进行分析:不要使用
Read工具将整个文件加载到上下文。应使用ctx_execute_file,它会在沙箱中处理文件,将分析结果(而非原始内容)返回。 - 需要从已捕获数据中多次查询:先用
ctx_execute将命令输出或文件内容捕获并索引,然后使用ctx_search针对索引数据进行一次或多次查询。
核心原则:ctx_execute 是数据的写入器,其目标是生成一份完整的、可供后续查询的索引记录。ctx_search 是数据的读取器,用于从这份记录中提取答案。绝不可将过滤逻辑前置到 ctx_execute 中。
二、ctx_execute 的正确用法:作为“捕获层”
ctx_execute 的使命是完整捕获一次操作的原始输出(stdout),并将其自动索引到基于 FTS5 的知识库中。你编写的脚本逻辑应聚焦于分析并打印出清晰的结论,而不是为了“节省空间”而提前过滤数据。
正确模式:执行完整分析并打印结论
// 使用 ctx_execute 分析 API 响应
const resp = await fetch('https://api.example.com/data');
const data = await resp.json();
// 进行完整分析
const summary = {
total: data.length,
errorCount: data.filter(item => item.status === 'error').length,
categories: [...new Set(data.map(item => item.category))]
};
// 打印结构化结论,而非原始数据
console.log(`数据总量: ${summary.total}`);
console.log(`错误数量: ${summary.errorCount}`);
console.log(`分类列表: ${summary.categories.join(', ')}`);
这个脚本通过 fetch 获取了完整的原始数据(可能非常大),但 console.log 输出的只是数十行的分析摘要。完整的原始 JSON 响应被 ctx_execute 捕获并索引,而你支付的上下文成本仅为摘要的几十个 token。
分页数据收集示例:
// 使用 ctx_execute 收集并分析分页数据
let allItems = [];
let page = 1;
while (true) {
const resp = await fetch(`/api/items?page=${page}&limit=100`);
const { items, totalPages } = await resp.json();
allItems.push(...items);
if (page >= totalPages) break;
page++;
}
// 执行聚合分析
const grouped = {};
allItems.forEach(item => {
grouped[item.type] = (grouped[item.type] || 0) + 1;
});
console.log(`已收集全部 ${allItems.length} 个项目`);
console.log('按类型分布:');
for (const [type, count] of Object.entries(grouped)) {
console.log(` ${type}: ${count}`);
}
三、ctx_search 的正确用法:作为“过滤层”
当数据被 ctx_execute 或 ctx_fetch_and_index 索引后,ctx_search 用于进行精准查询。其关键实践是:
- 批量查询:将多个相关问题放入一个
queries数组,通过单次调用完成,避免多次独立调用。 - 指定来源:当知识库中索引了多个文档时,始终使用
source参数来限定搜索范围,避免结果污染。 - 利用语义:BM25 算法采用 OR 语义,使用 2-4 个具体的技术术语通常能获得最佳结果。
// 在索引了 React 文档和 Zod 文档后,进行批量查询
ctx_search({
queries: [
"React memo 缓存",
"Zod schema union",
"useEffect 清理函数"
],
source: "React" // 仅搜索 React 文档
});
四、8 个常见反模式及其修正方案
以下反模式直接导致上下文窗口浪费或操作失败,应严格避免。
-
小输出用 execute:
- 反模式:用
ctx_execute执行node --version。 - 后果:引入不必要的 LLM 摘要调用开销。
- 修正:对少于20行的确定小输出,直接使用 Bash。
- 反模式:用
-
忘记打印输出:
- 反模式:在
ctx_execute脚本中计算了结果,但忘记console.log。 - 后果:stdout 为空,摘要无意义,本次调用完全浪费。
- 修正:每个
ctx_execute脚本都必须以打印关键发现结束。
- 反模式:在
-
用 Bash 处理复杂数据:
- 反模式:用复杂的
curl | jq | sed管道处理 JSON API。 - 后果:脚本难以编写和维护,且原始响应仍可能因管道未完全过滤而进入上下文。
- 修正:改用
language: javascript或language: python在ctx_execute中处理。
- 反模式:用复杂的
-
加载整个文件到上下文:
- 反模式:先用
Read工具读取package-lock.json(万行级),再提问。 - 后果:文件内容占满上下文窗口,后续对话质量急剧下降。
- 修正:使用
ctx_execute_file,在沙箱中编写代码提取所需信息(如特定包的版本)。
- 反模式:先用
-
用管道截断输出 (
| head):- 反模式:
npm test 2>&1 | head -30。 - 后果:仅看到测试输出开头,丢失了关键的失败详情和总结。
- 修正:使用
ctx_execute执行npm test,让其捕获全部输出并生成摘要。
- 反模式:
-
合并捕获层与过滤层(关键反模式):
- 反模式:在
ctx_execute脚本内部使用grep或条件判断来“精简”输出,然后再进行总结。 - 后果:被过滤掉的数据从未进入索引,后续无法用
ctx_search检索。这等于花钱建了个不完整的图书馆。 - 修正:理解
ctx_execute是一次性写入的索引。所有数据筛选应推迟到ctx_search这一下游查询层进行。下图展示了正确的分层架构:
┌──────────────────────┐ ┌──────────────────────┐ │ ctx_execute │ ───▶ │ ctx_search │ │ (捕获层) │ │ (过滤层) │ │ │ │ │ │ 将命令的完整输出 │ │ 在已捕获的索引中 │ │ 写入本地索引 │ │ 进行查询 │ └──────────────────────┘ └──────────────────────┘ ▲ ▲ │ │ 职责:完整捕获数据 职责:精准检索数据 在此不要做任何过滤。 所有过滤操作在此完成。 - 反模式:在
-
错误使用
ctx_index的content参数:- 反模式:将
browser_snapshot()返回的巨大文本或MCP工具的原始响应,通过ctx_index(content: ...)传递。 - 后果:数据首先作为工具参数进入了上下文窗口,然后被写入索引,上下文使用量翻倍。
- 修正:对于文件,始终使用
ctx_index(path: ...)或ctx_execute_file(path: ...),让服务器直接读取文件。content参数仅用于你亲自编写的一小段文本。
- 反模式:将
-
忽略 Playwright 的
filename参数:- 反模式:直接调用
browser_snapshot(),让其将 10万+ token 的无障碍树返回到上下文。 - 后果:上下文窗口被单次快照瞬间耗尽。
- 修正:始终使用
filename参数(如browser_snapshot(filename: "/tmp/snapshot.md")),然后通过ctx_index或ctx_execute_file处理该文件。
- 反模式:直接调用
遵循这些最佳实践,你将能有效驾驭 Context Mode 的强大能力,让 AI 编码助手在长对话中保持高性能,专注于解决你的业务问题,而非与上下文限制作斗争。
FAQ
Q: 应该使用 ctx_execute 还是 ctx_execute_file?
A: ctx_execute 用于运行一段代码(JavaScript, Python, Shell) 来分析数据或调用API,其代码本身是你提供的。ctx_execute_file 用于读取一个已存在的文件并对其进行分析,文件路径由你提供,代码也是你提供的,但代码中可通过 FILE_CONTENT 变量直接访问文件内容。
Q: ctx_search 的查询结果不理想怎么办?
A: 首先确保使用了 source 参数来缩小范围。其次,BM25 算法更适合具体的技术术语而非宽泛的问题描述。尝试使用更具体的关键词组合,例如将 “如何使用React状态” 改为 “useState hook 更新状态”。如果原始数据捕获不完整(例如因错误使用了管道截断),则搜索也无能为力,需确保捕获层的完整性。
Q: 如何知道一个命令的输出会有多大?
A: 对于不熟悉的 CLI 工具,最安全的方式是默认使用 ctx_execute。它的设计就是为了处理不确定的大输出。如果你确定输出极少(例如一个简单的 which node),才考虑使用 Bash。