主题
06.1 终端接管逻辑与工具循环
Claude Code 凭什么敢跑你的命令?这一章拆开 Agent Loop 的每一步。
读完你能做什么:准确预测它下一步会做什么,从而在正确的时机介入。
一、一个根本澄清:它不"控制"终端
很多人以为 Claude Code 像远程桌面一样"接管"了你的终端。不是的。
真相是:
text
Claude 生成一个"我想运行 X"的结构化请求
↓
Claude Code 客户端(本地程序)拦截这个请求
↓
客户端检查权限(见 05.5)
↓
客户端在一个受控子进程里执行 X
↓
客户端把 stdout/stderr/exit code 截取下来
↓
作为"工具结果"追加到 Claude 的上下文
↓
Claude 看到结果,继续下一步Claude 本身从头到尾没有碰过你的 shell。 它只是不断生成"请求",由客户端代为执行。这个区分是理解一切的基础:
- 权限提示为什么能拦住它 → 因为拦截发生在客户端,执行之前
- hook 为什么能干预 → hook 也在客户端侧
- 它为什么"看不到"没读过的东西 → 它只知道工具回填给它的内容
二、Agent Loop:完整的一圈
text
┌─────────────────────────────────────────────────┐
│ 1. 组装上下文 │
│ 系统提示词 + 工具定义 + CLAUDE.md + │
│ 历史 + 你的输入 │
└───────────────────┬─────────────────────────────┘
↓
┌─────────────────────────────────────────────────┐
│ 2. 前向传播,生成 │
│ 可能生成:普通文本 / 一个或多个 tool_use │
└───────────────────┬─────────────────────────────┘
↓
生成了 tool_use?
┌────┴────┐
否 是
↓ ↓
┌─────────┐ ┌──────────────────────────┐
│ 3a.回复 │ │ 3b. 客户端拦截 │
│ 结束本轮 │ │ ↓ 检查权限(05.5) │
└─────────┘ │ ↓ 运行 hook(PreToolUse) │
│ ↓ 执行工具 │
│ ↓ 运行 hook(PostToolUse)│
│ ↓ 截取结果 │
└──────────┬───────────────┘
↓
┌──────────────────────────┐
│ 4. 结果追加到上下文 │
│ 回到第 1 步 │
└──────────────────────────┘这个循环会一直转,直到 Claude 生成一个不含 tool_use 的回复(表示它认为任务完成或需要你输入)。
三、内置工具清单
Claude Code 的核心工具(MCP 工具是额外叠加的):
| 工具 | 作用 | 权限敏感度 |
|---|---|---|
Read | 读文件 | 低(但能读到敏感文件) |
Edit | 精确替换文件内容 | 中 |
Write | 写/覆盖文件 | 中 |
Bash | 执行 shell 命令 | 高 |
Glob | 文件名模式匹配 | 低 |
Grep | 内容搜索 | 低 |
Task / 子代理 | 派生子代理 | 中 |
WebFetch / WebSearch | 联网 | 中 |
用 --tools 限制可用工具:
bash
claude --tools "Bash,Edit,Read" # 只给这三个
claude --tools "" # 禁用所有内置工具四、它怎么决定用哪个工具
这不是硬编码的规则,而是概率生成。但有可预测的模式:
| 你的意图 | 它倾向的工具序列 |
|---|---|
| "这个函数在哪定义的" | Grep → Read |
| "改一下这个 bug" | Read → Edit → Bash(测试) |
| "这个项目怎么跑起来" | Read(README/package.json) → Bash |
| "重构整个模块" | Glob → Grep → Read × N → Edit × N → Bash |
| "为什么测试挂了" | Bash(测试) → Read(失败文件) → Edit → Bash(重跑) |
4.1 引导它的工具选择
你可以在提示词里明确指定策略,避免它用低效的路径:
text
❌ 它可能一上来 Read 一堆文件
✅ 先用 grep 定位 reconcile 相关的函数,只输出匹配行。
看清楚后再决定读哪几个文件,不要一次读整个目录。这直接对抗了"把大量文件读进中段衰减区"的问题(见 03.2)。
五、并行 vs 串行工具调用
5.1 它可以在一轮里发多个工具调用
当多个操作互不依赖时,Claude 可以在同一轮并行发起:
text
同时读三个不相关的文件
同时跑 lint 和 typecheck这比串行快得多。
5.2 引导并行
text
如果多个操作之间没有依赖关系,在同一批次并行执行,不要一个一个来。
比如:同时读 config.ts、routes.ts、和跑一次 git status。5.3 什么时候必须串行
当后一步依赖前一步的结果时,必须串行,且不要预先规划超过两步:
text
每次只执行一步,看到结果再决定下一步。
前一步的结果可能改变你的判断,不要一次性规划 10 步然后盲目执行。原理见 02.5 第七节。
六、长工具调用的后台化
某些工具调用很慢(跑完整测试套件、构建)。Claude Code 会自动把长时间运行的工具调用挪到后台,避免阻塞。
你也可以显式用后台执行:
bash
# 把一个 shell 命令作为后台任务跑
claude --bg --exec 'pytest -x'查看和管理:
text
> /tasks # 查看后台工作(含已完成的子代理)七、它"看到"的工具结果长什么样
理解这一点能帮你优化。工具结果是文本,追加到上下文。这意味着:
7.1 大输出会撑爆上下文
text
跑一次测试 → 3000 行输出 → 全部进上下文 → 挤占后续空间对策:让它过滤。
text
运行测试时用管道只保留失败信息:
npm test 2>&1 | grep -A5 -E "(FAIL|✕|Error)" | head -50
不要把完整输出读进上下文。7.2 它可能误读结果
工具结果是文本,Claude 对它的理解仍是概率性的。长输出、相似的多个结果,都可能被误读。对关键判断,让它引用具体行:
text
基于测试输出回答时,引用具体的失败行,不要笼统概括。八、MCP 工具的叠加
MCP server 提供的工具会叠加到内置工具之上,进入同一个循环。区别:
Claude Code 自己也能作为 MCP server 暴露给其他程序:
bash
claude mcp serve # 把 Claude 作为 stdio MCP server 启动九、把机制转化为控制力
| 机制 | 你的操作杠杆 |
|---|---|
| 它只生成请求,客户端执行 | 用权限/hook 在执行前拦截(05.5、06.5) |
| 循环转到无 tool_use 才停 | 给可验证的完成标准,避免它过早停 |
| 工具结果是文本,会累积 | 过滤大输出,控制上下文 |
| 工具选择是概率的 | 在提示词里指定搜索/读取策略 |
| 可并行可串行 | 明确告诉它哪些能并行 |
| 不预先规划太多步 | 要求"一步一看" |
十、一个观察练习
想真正理解 Agent Loop,跑这个并全程观察:
text
> 用 --verbose 的心态给我讲解你的每一步:
我要你找出这个项目里所有直接拼接 SQL 字符串的地方(潜在注入风险)。
每次调用工具前,先说明:你要调什么工具、为什么、期望看到什么。
调用后,说明结果是否符合预期、下一步怎么走。你会清楚看到"思考 → 工具 → 观察 → 再思考"的循环,以及它如何根据每一步的真实结果调整策略。