智能体循环 · 工具调用 · 上下文窗口 · CLAUDE.md · checkpoint · 权限模式 · Plan 模式 · 审查 diff

用 AI 编程工具干活:你出需求和验收标准,它跑循环,你审结果

Claude Code 这类工具本身就是一个 agent:模型提议“读这个文件、改那一行、跑一下测试”,外面那层程序(harness)真正去执行,结果送回模型,再决定下一步,直到做完。精华:它能干多好,取决于两件你负责的事。一是它看得见什么:项目文件、CLAUDE.md、你给的上下文。二是它能不能自己验证:有没有一条命令(通常是测试)能告诉它做对了没有。不懂这一点的典型用法,是在网页聊天框里贴代码、再把回答复制回来,这时你自己成了工具执行者;或者一句话甩过去、不审就全盘接受。

全景:一个 FastAPI 请求的一生 · 站末总结(不是链路上的一站,是写这条链路的方式)地图:站 01 · 用 AI 编程工具干活以 Claude Code 官方文档(2026-11)为准

①什么时候用得上:这两天的每一页,都是这样做出来的

站 01 这 7 页,从 uv 到 pytest,每一页的实验代码、实测数字、页面本身,都是 Claude Code 在这个仓库里一轮轮循环做出来的:读 skill 里的要求、建项目、跑实验、写页面、校验 HTML、发布、推送、等上线、清理。你看到的是结果,没看到的是中间那些工具调用。这一页把它摊开,然后轮到你自己来。

20 次提交

2026-11-08 起学习笔记仓库的全部提交,每一次都带着 Co-Authored-By: Claude,新增 15,890 行 实测(git log --shortstat)。

0 个 CLAUDE.md

这个仓库没有 CLAUDE.md。规矩放在两个 skill 里(learn 182 行、reverse-learn 122 行),偏好放在 10 条自动记忆里,每次会话开头加载。

1 个真 bug

pytest 那一页,测试第一次跑就抓到 httpx.ReadTimeout 没接住;修复、重跑、全绿,是一次完整的“收集上下文、动手、验证”。⑤ 就拿它来复盘。

需求工作要用:招聘要求里有 4 份点名要会用 AI 编程工具;更要紧的是,站 04 要你亲手写一个 agent,而 Claude Code 就是一个现成的、每天在用的 agent。会用它,就是先从外面把“模型提议、程序执行、结果送回”这个循环看熟。

②常见笨办法:要么你当它的手,要么你当它的橡皮图章

笨办法一 网页聊天,复制粘贴
你:(贴 main.py 的 60 行)
    这里为什么会 500?
它:可能是 fetch 没处理……
你:(复制它的代码,粘回去,
     跑测试,再贴报错回去)
它看不到你的项目,看不到测试结果。读文件、跑命令、贴结果全是你在做,你就是那个“工具执行者”。
笨办法二 一句话甩过去,全盘接受
你:加个缓存
它:(改了 6 个文件,引入一个新依赖,
     顺手重命名了两个函数)
你:看着挺多的,应该没问题吧
    git commit -am "add cache"
没说缓存什么、多久过期、怎么算做完;也没看 diff。错了往往要过很久才发现。
该有的样子 你定目标和验收,它跑循环
你:tests/test_api.py 里
    test_summary_marks_hung_host 失败了,
    httpx.ReadTimeout 没被 fetch 接住。
    改 main.py 让它通过,别动测试,
    跑 uv run pytest 确认全绿。
它:(跑测试 → 读报错 → 读 main.py
     → 加 2 行 → 再跑 → 10 passed)
你:(看 diff,确认只加了一个 except)
需求里有:在哪、为什么错、不许动什么、怎么算做完。它自己能验证,你只审最后那几行改动。

③工具和路线

工具形态它能看到 / 能做适合
Claude Code终端里的 agent(也有桌面、网页、IDE 插件)整个项目、终端命令、git 状态、CLAUDE.md 和记忆;能读写文件、跑测试、提交跨多个文件的改动、排查、跑实验,像这两天这样
Cursor基于 VS Code 的编辑器Tab 补全(按键级);Agent 聊天能改多个文件、跑命令;规则放在 .cursor/rules/*.mdc,也读 AGENTS.md(按文档)边写边补全,喜欢在编辑器里看改动
编辑器补全插件写代码时给下一行建议主要是当前文件和附近上下文写样板代码
网页聊天对话框只有你贴进去的东西问概念、讨论设计,不适合改项目
① 让它先读懂

“这个项目做什么、怎么跑测试?”先看它的理解对不对,不对就纠正,或者写进 CLAUDE.md。

② 先有验收标准

有测试就指定测试;没有就先让它(或你)写一个会失败的测试。大改动先用 Plan 模式出方案。

③ 让它跑循环

改代码、跑测试、看结果、再改。中途方向不对就按 Esc 打断,直接说哪里不对。

④ 你审 diff 再提交

git diff 逐行看:只改了该改的?有没有顺手多做?测试有没有被改松?

本页以 Claude Code 为主:这两天的页面都是用它做的,你手边就有。Cursor 的思路一样,区别在界面;凡是 Cursor 特有的说法都按官方文档写,本机没有实际操作过。

④背后的机制:一个 agent 循环、一扇上下文窗口、两张安全网

先知道这些
  • 模型一次只写一个 token,而且不记得上一次对话:每轮都要把需要的东西重新放进上下文窗口。见站 02 全景 一句话怎么变成模型的回答。
  • 工具调用:模型不能自己读文件,它只能输出“我要调用某个工具,参数是什么”,由外面的程序执行,再把结果送回。站 04 会亲手写这一层。

1智能体循环:收集上下文、动手、验证,转到做完为止 站 04 你要亲手写的就是这个

你:需求 + 验收 “让这个测试通过,别动测试” 你:审 diff、拍板 随时可以 Esc 打断 模型:想下一步 “调用 Bash: pytest” harness:真的去做 按权限模式决定要不要问你 工具调用 结果回到上下文 pytest 那页修 bug 时,真实的几轮 1 Bash pytest -q → 1 failed, 9 passed 2 读输出 E httpx.ReadTimeout: agent hung 3 定位 fetch 只接了 TimeoutError(main.py 是上一页它自己写的) 4 编辑 main.py:加 except httpx.HTTPError 5 Bash pytest -v → 10 passed 6 Bash pytest --cov → 96%,3 行没覆盖 每一步的结果都决定了下一步做什么:第 2 步看到异常类型,才知道去第 3 步看 fetch。 官方文档把这三个阶段叫 gather context、take action、verify results。
Claude Code 就是“模型 + 一圈工具 + 管理上下文的程序”。站 04 你会写一个 200 行的值班助手 v1,结构和这张图一样:模型提议调用 查日志、解析 GC 日志,你的代码执行,结果送回,直到它答得出来。

2上下文窗口:它“知道”的一切都得放在这里 ≈ 一张大小有限的工作台

每次会话开头就在

系统说明、CLAUDE.md、自动记忆 MEMORY.md 的前 200 行或 25 KB、各 skill 的简介。

干活时不断加进来

你的每句话、它读过的每个文件、每条命令的输出。读得越多,桌面越满。

快满了就压缩

自动把对话压成摘要。摘要保留请求和关键代码,早先的细节指令可能丢。可以 /compact 并说明重点保留什么。

所以规矩写进文件

长期要遵守的写进 CLAUDE.md(Cursor 是 .cursor/rules 或 AGENTS.md),每次会话都会重新加载,不怕被压缩掉。

每个新会话都从一张空桌子开始,不记得上次聊过什么。这就是这两天每做一页都要先“读 skill、读地图、读全景页”的原因,也是练习 2 要你写 CLAUDE.md 的原因:把每次都要重复说的话,变成它每次都会自己读到的文件。看当前桌面上放了什么:/context。

3两张安全网:checkpoint 管文件,权限模式管动作

checkpoint:改文件之前先拍快照

它每次改文件前都保存一份原样。改坏了,按两次 Esc 回到之前的状态,或者直接说“撤销刚才的改动”。

只管本地文件。推送代码、改数据库、调外部 API、发布页面、删除线上的东西,这些都撤不回来。所以这两天每次 git push 和发布前,都要先确认要推什么。

它和 git 是两回事:checkpoint 是会话里的后悔药,git 提交才是长期记录。练习里每完成一步就提交一次。

权限模式:Shift+Tab 切换

模式它可以不问你就做什么
Manual什么都要问:改文件、跑命令都先征求同意
Accept edits改文件、mkdir、mv 这类不问,其他命令还问
Plan只读、只出方案,不改源文件
Auto后台有个分类器审查,拦下有风险的动作,其余直接做

常用又安全的命令(uv run pytest、git status)可以写进 .claude/settings.json 的允许列表。刚上手建议 Manual 或 Accept edits,大改动先切 Plan。

4交给它还是自己来:两条标准

标准一:能不能自动验证

有测试、有类型检查、有一条命令能说“对”或“不对”,它就能在循环里自己纠错。验证不了的(“这个设计好不好”“这个阈值该设多少”),它只能猜,你得自己判断。

标准二:错了能不能撤回

改本地文件,错了有 checkpoint 和 git;推送、发布、删数据、动生产配置,错了就收不回来。撤不回来的事,要么你亲手做,要么它做之前你逐字看过。

实验台:这件事交给 AI 吗?8 件值班助手里的真事

按上面两条标准判断。这是经验规则,不是实测;不同团队尺度可以不一样,重要的是说得出理由。

先选一件事,再猜:

5为什么这样设计:给模型整个项目和一个终端,而不只是补全下一行

agent:看得见全局,能自己验证Claude Code、Cursor 的 Agent

  • 能跨文件找关联、能跑测试看结果,改错了自己发现、自己再改。
  • 一个需求可以连着几十次工具调用做完,你只在两头出力。
  • 代价:权限大,必须有 checkpoint、权限模式这些安全网;做得多,审查的担子也重。

补全:只看光标附近,猜下一行Tab 补全一类

  • 快、打扰少,你始终在掌控每一个字。
  • 不知道项目里别处有什么,不会跑测试,对不对全靠你当场判断。
  • Cursor 文档写明:项目规则对 Tab 补全不起作用。

决定胜负的约束:写代码最难的不是敲字,而是“找到该改哪儿”和“确认改对了”。补全帮不上这两件事,agent 可以,前提是它能读整个项目、能执行验证命令。所以这类工具都在往“给模型一个终端”的方向走,同时用 checkpoint 和权限把风险关在笼子里。

最少的操作:Claude Code 常用命令 都来自官方文档

做什么Claude Code说明
在项目里开始cd 项目 && claude它能看到这个目录和子目录
生成项目说明/init生成一份 CLAUDE.md 草稿,你再改
看上下文里有什么/context桌面占了多少、被什么占了
主动压缩/compact 重点保留 API 的改动告诉它摘要里留什么
切换模型/model
停下来Esc取消正在跑的工具调用,等你说话
撤回文件改动连按两次 Esc只管本地文件
切权限模式Shift+TabManual / Accept edits / Plan / Auto
接着上次的会话claude --continue / /resume新会话不记得旧对话
检查安装和配置/doctor

⑤跟着做一遍:复盘那次修 bug,每一步看什么

值班助手的代码已经整理成一个独立的 git 仓库:~/claude/oncall-helper(就在这台机器上,一次提交,10 个测试从零跑通 实测)。下面把 pytest 那一页修 bug 的过程拆成 6 步,每步写清“它做了什么”和“你该看什么”。⑥ 的练习就在这个仓库里做。

0准备:装 uv、拿到依赖、确认测试能跑
curl -LsSf https://astral.sh/uv/install.sh | sh     # 这台机器上还没装 uv
cd ~/claude/oncall-helper
uv sync                                              # 按 uv.lock 装依赖,含开发依赖 pytest
uv run make_logs.py                                  # 生成 logs/(已被 .gitignore 忽略)
uv run pytest -q                                     # 应该看到 10 passed
claude                                               # 在这个目录里启动 Claude Code
步它做了什么你该看什么
1 需求收到:“让 test_summary_marks_hung_host 通过,别动测试,跑 uv run pytest 确认”。需求里有没有“在哪、怎么算做完、什么不许动”。缺哪样,它就会猜哪样。
2 先看失败跑 pytest -q:1 failed, 9 passed,报错 httpx.ReadTimeout: agent hung。它是不是先复现了问题,而不是一上来就改代码。没复现的修复,等于没验证。
3 定位看出 fetch 只接住了 asyncio.timeout 抛的 TimeoutError。它说的原因你认不认可。这里要你懂 asyncio 的超时,否则判断不了它对不对。
4 改在 fetch 里加一个 except httpx.HTTPError,记成这一台出错。改动范围:只动了 main.py 的两行?测试文件一个字没动?
5 验证再跑 pytest -v:10 passed;覆盖率 96%。看到的是真实输出,不是它嘴上说“应该能过了”。
6 审查、提交(你来做)git diff,确认后提交。异常类选得太宽了吗?httpx.HTTPError 会不会把不该吞的错误也吞了?这是你的判断,不是它的。
$ git diff main.py
     except TimeoutError:
         return HostGc(host=host, error="timeout 1s")
+    except httpx.HTTPError as e:                  # httpx 自己的超时、连不上:也记成这一台出错
+        return HostGc(host=host, error=type(e).__name__)
     return parse(host, r.text)
  • 审两行,一处,测试没动:范围对。
  • 审httpx.HTTPError 是 httpx 所有请求异常的父类,超时、连不上、协议错误都会被记成“这一台出错”。对值班助手合理:一台机器出问题,不能拖垮整个汇总。
  • 审但它没处理“日志代理返回 500”这种情况(不抛异常),pytest 页预测题 5 推出过。这就是下一条需求,可以留给练习 4。
到这里已经能交差了:知道一次“需求、复现、定位、修改、验证、审查”是什么样,知道每一步该盯什么。
还没做的,就是 ⑥ 要你亲手做的
  • 你自己写需求、自己审 diff → 练习 3
  • 把每次都要说的话写进 CLAUDE.md → 练习 2
  • 先出方案再动手 → 练习 4

⑥刻意练习:6 个练习,由易到难,做对了你自己看得出来

都在 ~/claude/oncall-helper 里做,每做完一个提交一次。练习 1 到 4 是这一站的过关要求,5、6 选做。做完后把仓库推到你的 GitHub,或者直接告诉我做到了哪一步,我来看提交记录。

1让它先讲懂这个项目
你说
“这个项目做什么?怎么跑测试?fetch 遇到哪几种情况会把这一台标成出错?”
做对了
它读了 main.py、tests/、pyproject.toml,说出 uv run pytest,并且列出:asyncio 1 秒超时、httpx.HTTPError、日志里没有停顿。你拿 ⑤ 对一下,它说漏或说错的地方,就是你要纠正的地方。
2写一份 CLAUDE.md
你做
运行 /init 生成草稿,然后自己改:测试命令;不要改 uv.lock,加依赖要用 uv add;测试不许碰网络;提交信息用中文。提交它。
做对了
退出,重开一个新会话,直接问“怎么跑测试、能不能 pip install”,它不用再读代码就答对,因为 CLAUDE.md 每次都会加载(见 ④-2)。
3先定验收,再让它写
你说
“在 tests/test_api.py 里用 parametrize 给 minutes 加 0、1、60、61 四个边界,预期 422、200、200、422,再给 /healthz 补一个测试。只改 tests/,跑 pytest 和覆盖率确认。”
做对了
git diff --stat 只有 tests/test_api.py;pytest 显示 15 passed;覆盖率报告里第 85 行(healthz)不再列在 Missing 里。
4大一点的改动:先 Plan,再动手
你做
Shift+Tab 切到 Plan 模式,说:“日志代理返回非 200 时,这一台要标成出错,而不是 no pauses;超时秒数要能在测试里改小。先给方案。”审方案,满意了再切回去让它做。
做对了
Plan 模式下它只读、只出方案,没有改任何文件;动手后新增的测试里,“日志代理返回 500”那一台的 error 不是 no pauses;超时测试不到 0.2 秒;全部测试通过。
5(选做)故意给一个模糊需求
你说
“加个缓存。”看它做了什么,然后连按两次 Esc 撤回。再改写成:“同一个 service 和 minutes,30 秒内重复请求直接返回上次结果;只缓存成功的;加测试。”
做对了
你能说出第一次它自己“猜”了哪些东西(缓存什么、多久、放哪、出错时缓不缓存),第二次这些都被你的需求定死了。撤回后 git status 是干净的。
6(选做)同一件事,换 Cursor 做一遍
你做
用 Cursor 打开仓库,在 .cursor/rules/ 下写一条 .mdc 规则(或者直接放一个 AGENTS.md),用它的 Agent 做练习 3 的同类改动。
做对了
写一段对比:哪个更顺手、哪个审查改动更方便、规则文件的写法差在哪。这部分本页是按 Cursor 文档写的,你的体验比我的描述更可靠。
规范

和 AI 结对时,团队里的几条约定

先有能跑的验证,再让它改

没有测试的代码,先让它补测试并看着测试失败一次。

它说“改好了”,其实没人验证过。

需求写清四样

在哪、要什么结果、什么不许动、怎么算做完。

它替你猜,猜的方向未必是你要的。

每次提交前自己看 diff

提交信息里写的是你认可的改动;看不懂的改动不提交,先问它为什么。

不理解的代码进了仓库,出事时没人说得清。

撤不回的动作你来确认

推送、发布、删数据、改生产配置,执行前逐字看一遍。

checkpoint 管不到的地方出事。

反复说的话写进 CLAUDE.md

CLAUDE.md 提交进仓库,团队共享;个人偏好放用户级配置。

每次会话重新解释一遍,压缩后又忘。

它不懂的领域,你得懂

⑤ 第 3、6 步全靠你懂 asyncio 和异常层级才审得了。

“看起来对”的错误代码。

下一圈

  • Hooks:每次改完文件自动跑格式化和测试,把“验证”从约定变成机制。
  • Skills:把这两天的 learn、reverse-learn 当范例,给值班助手写一个“排查 Full GC”的 skill(站 07)。
  • Subagents:把“查日志、查指标、查笔记”分给三个子 agent 并行(站 08 的预演)。
  • MCP:把值班助手的接口接进 Claude Code,让它直接调用(站 07)。
  • 用 git worktree 同时开两个会话,各改一个分支。

↺回到⑤:拿你自己的那几次,和 ⑤ 对一对

做完练习 3、4 后,翻回 ⑤ 的表格逐行对照:你的需求里四样都有吗?它先复现了吗?你看 diff 时发现过什么?把发现写进 CLAUDE.md,下一次就不用再说。

1. 用一句话说出这一页的精华。

AI 编程工具是一个 agent:模型提议工具调用、外面的程序执行、结果送回,循环到做完;它能干多好,取决于它看得见什么(项目、CLAUDE.md)和能不能自己验证(测试、命令),你守住需求和审查两头。

2. 在网页聊天里贴代码、复制回答,痛在哪?

模型看不到项目、跑不了测试,读文件、执行命令、贴结果全由你手工完成,你成了工具执行者;而且它没法自己验证,对不对全靠你当场判断。

3. 为什么长期规矩要写进 CLAUDE.md,而不是在对话开头说一遍?是 ④ 哪条?

④-2:每个新会话都从空的上下文开始,长对话还会被压缩成摘要,早先的细节指令可能丢;CLAUDE.md 每次会话开头都会加载。

4. 预测:你让它“修好这个 bug”,但项目里没有任何测试。它最可能怎么“验证”?会出什么问题?

它可能只是读一遍改过的代码就说“应该好了”,或者自己临时写个脚本跑一下。没有可重复的测试,修复的正确性只能靠你判断,下次有人改动时也不会有人发现它又坏了。所以先补一个会失败的测试。

从 ④-4 的标准一(能不能自动验证)推出。

5. 预测:在 Accept edits 模式下,它改坏了 main.py 又执行了 git push。按两次 Esc 能撤回什么,撤不回什么?

能撤回本地 main.py 的改动;撤不回已经推到远端的提交(还得另做一次提交或回滚)。而且 Accept edits 模式下 git push 这种命令本来就会先问你,按了同意就是你的决定。

从 ④-3:checkpoint 只管本地文件,权限模式管动作。

6. 放回全景:站 01 的 10 站里,哪些是这次“和 AI 结对”时你最需要自己懂的?为什么?

第 5~7 站(asyncio)和第 8 站(解析和异常)。⑤ 里那个 bug 的根源是“超时有两种、异常类不同”,看懂它要懂事件循环怎么超时、httpx 的异常层级;审查 except httpx.HTTPError 吞得太宽还是正好,也要懂第 8 站解析失败时会怎样。工具能替你写代码,但审查需要你懂原理,这也是前面 7 页要一页页讲透的原因。

见 全景第 7 站。

下一步:站 01 的 8 个知识点到这里都有页了。做完练习 1~4 以后,说“回到全景”,合上页面把站 01 的 10 站讲给我听。