# 读与搜 · read_file 与 grep 的门道

> 看似最简单的两个工具——读文件、搜代码——在 grok 里藏着不少门道：行号投影、多模态（PDF/图片/PPTX）、字符对齐的流式、包 ripgrep 的预算早停。这一章顺带澄清一个易混点：search_tool 搜的是「工具」不是代码。

- 作者：David（道雾轩）
- 专栏：Grok Build 源码解读（https://daiw.org/manual/grok-build.md）
- 最后更新：2026-09-15
- 原文：https://daiw.org/manual/grok-build/read-and-search
- 转载与引用：请注明出处并附原文链接（https://daiw.org/about/copyright）

# 读与搜 · read_file 与 grep 的门道

进具体工具。先看最基础的两个——读文件、搜代码。别小看它们，生产实现里门道不少。

## `read_file`：不只是读文本

id `read_file`(kind `Read`，只读)。基本参数 `target_file`(schema 里从 `path` 改名)、`offset`(起始行)、`limit`(行数)，输出**带行号**(`行号→内容`)，默认上限 1000 行 / 25000 token。行号很关键：后面的[编辑工具](https://daiw.org/manual/grok-build/edit-formats)靠它定位。

真正有意思的是**多模态**：靠魔数嗅探(`bytes_to_metadata`),`read_file` 能读 PDF、PPTX、Jupyter notebook、图片。图片会被 `compress_image_for_conversation` 压到模型能吃的尺寸(≤768KB base64、≤1024² 像素，JPEG 质量阶梯降级)再嵌进对话；PDF 支持按页范围(`pages: "1-5"`；超过 10 页必须给，一次最多 20 页)，默认把页面渲染成图片，`format: "text"` 则改为抽取文本。**一个「读文件」工具，顺手把「看图看文档」也办了。**

还有个流式细节：`execute()` 把**格式化后的投影**按字符对齐地分块流出(4KB 一块)，保证前端拼接起来和最终卡片**逐字节一致**——只有文本行流式(且要客户端声明了 `stream_tool_progress`)，图片/PDF/PPTX 都是终止性的。

## `grep`：包着 ripgrep

id `grep`(kind `Search`，只读)。它不自己实现搜索，而是**包 `rg` 二进制**：正则 `pattern`、`glob`、上下文 `-A/-B/-C`、`head_limit`(省略时内容模式默认 200 行、文件/计数模式默认 500 条；显式传入也会被夹在 2000 行/10000 条以内)。两个工程细节值得看：

- **预算早停**：stdout 读到 `head_limit+1` 行(多读一行用来判断「是否被截断」)就**提前 kill 掉 `rg`**——而且是在排空 stderr 之前 kill，免得在大目录树遍历上阻塞。
- **尊重 `.gitignore`**(除非你给了很宽的 glob)。

## 澄清：`search_tool` 搜的是「工具」不是代码

这是个极易混淆的点：**`search_tool` 不是代码搜索**，而是[工具协议那章](https://daiw.org/manual/grok-build/tool-protocol)提过的 **MCP 工具发现**元工具(相当于「工具的搜索引擎」)。grok CLI 从不把 MCP 工具直接列给模型——不管挂了几个，这套机制都常开：模型先用 `search_tool` 按 BM25 搜出相关工具(默认返回 5 条)，再用 `use_tool` 调。输出里还带 `total_hidden_tools` 告诉模型「还有多少没显示」。搜代码是 `grep`，搜工具是 `search_tool`——别弄反。

<Callout type="info">
  这套「一个 `read_file` 吃下多模态 + 字节级一致的流式 + `grep` 包 ripgrep 还带预算早停」，是「读和搜」这两件最朴素的事在生产里的真实复杂度。教学实现里它们各是三五行；这里每一个都得考虑大文件、二进制、超时、截断、流式一致性。
</Callout>

## 和《从 LLM 到 Coding Agent》对照

对照 [tool-use](https://daiw.org/manual/llm-to-agent/tool-use)：最小实现的 read/grep 就是 `fs.readFile` 和 `child_process.exec('grep')`。grok 的增量在多模态、流式一致性、外部二进制的预算控制，以及把「工具发现」本身也做成一个工具。下一章看更硬的：同一件「改文件」，grok 为什么要三种模型协议。

---

上一篇：[工具协议](https://daiw.org/manual/grok-build/tool-protocol) · 下一篇：[三种编辑格式](https://daiw.org/manual/grok-build/edit-formats)
