本教程教你把 Claude Code 从"一次性 -p 任务"升级为常驻 Agent:按 cron 节奏定时唤醒、读写状态文件、自我验证、安全熔断。内容覆盖最小可行循环、/loop 技能、状态记忆设计、护栏四件套与闭环验证,并给出一个可在夜间无人值守运行"PR 看护者"的完整案例。适用人群:已掌握 claude -p 无头模式与 settings.json hooks,想把 Agent 跑成 7×24 后台进程的开发者。
/loop 技能与 CronCreate/CronList/CronDelete 工具)claude -p "提示词" --allowedTools ... --output-format json 无头调用CLAUDE.md 项目记忆文件-p 一次性任务不够很多人把 claude -p 当作自动化终点:写个脚本、传入提示词、拿到 JSON、退出。这是同步一次性模型——无状态、不连续、做完即忘。它适合"批量改造"(如对一批文件做同一件事),却不适合"持续看护"(如整夜盯着 PR、CI 一失败就修)。
Claude Code 作者 Boris Cherny 在 2026 年 6 月给出了清晰的阶梯:
| 阶段 | 你在做什么 | 你的角色 |
|---|---|---|
| 1. 自动补全 | 手写代码 + AI 提示 | 打字员 |
| 2. 并行会话 | 开 5~10 个会话,逐个提示 | 提示操作员 |
| 3. 循环 | 写循环;Agent 读 GitHub/状态自行决定下一步 | 循环工程师 |
关键转变:你不再是循环里敲提示词的人,而是写循环的人。模型从"对话对象"降级为"循环体里的一个子程序"。
那么"循环"和古老的 cron 有何区别?一句话:循环 = cron + 一个会决策的身体。
| 维度 | 普通 cron job | Agent 循环 |
|---|---|---|
| 每次 tick | 跑固定脚本 | 跑一个读取当前状态的模型 |
| 分支 | 永远相同 | 每次决定下一步动作 |
| 自我纠错 | 无 | 能验证、失败、重试 |
| 进程拓扑 | 单进程 | 可派生并监督其他子 Agent |
理解了这一点,下面所有工程都是"在那个会决策的身体周围,包上让它不跑下悬崖的一切"。
while + claude -p常驻 Agent 只需三件套:驱动脚本 + 状态文件 + 调度器。
先建目录骨架:
mkdir -p ~/my-agent/{logs,knowledge}
cd ~/my-agent
写最小驱动脚本 run.sh:
#!/bin/bash
# run.sh —— 常驻 Agent 最小驱动
AGENT_DIR="$HOME/my-agent"
STATE="$AGENT_DIR/state.md"
LOG="$AGENT_DIR/logs/$(date +%Y-%m-%d_%H-%M-%S).log"
# 首次运行时初始化状态文件
if [ ! -f "$STATE" ]; then
cat > "$STATE" <<'EOF'
# Agent 状态
last_loop: 0
goal: 在 ~/my-agent 下用 Python 实现一个 TODO CLI 工具
next: 阅读 specs/TODO.md,挑下一个未完成项实现
EOF
fi
# 把状态注入提示词,无头执行
claude -p "你是一个常驻自治 Agent。先读取下方状态,决定本轮做什么,
执行后用可验证事实更新 state.md。
$(cat "$STATE")" \
--allowedTools Read,Write,Edit,Bash \
--permission-mode acceptEdits \
2>&1 | tee "$LOG"
加调度(每小时一次):
chmod +x ~/my-agent/run.sh
crontab -e
# 追加这一行:
0 * * * * /home/<你>/my-agent/run.sh
预期结果:每小时整点,Agent 醒来一次,读取 state.md、干活、回写状态,日志落盘到 logs/。
常见问题与解决:
- 状态文件无限膨胀:到第 20 轮,state.md 可能 50KB,吃光上下文。必须拆 hot/cold(见第四节)。
- 同一结论反复出现:"我应该做 X" 连续 5 轮却无进展——缺目标追踪,靠护栏的"无进展检测"(见第五节)。
- Agent 忘了自己做过什么:把"做过的事"写入 git 提交信息,而不是塞进 state 散文。
/loop 技能一步替代手写循环如果不想维护 shell 脚本,Claude Code 自带的 /loop 技能是最快的入口。在交互式会话里直接:
/loop 5m /babysit
/loop 30m /slack-feedback
/loop 5m check the deploy
/loop babysit all my PRs. Auto-fix build issues, and when comments come in,
use a worktree agent to fix them
要点:
/loop [间隔] [任务]。间隔可选 5m/30m/1h 等。loop.md,裸 /loop 会用它替换内置维护提示词。Esc。/loop 内部调用 CronCreate/CronList/CronDelete,本质仍是 cron 语义,但帮你封装了"下次唤醒该喂什么提示词"。常见问题与解决:
- /loop 跑着跑着笔记本一合盖就停了:交互式 /loop 依赖会话存活。要真"关机也能跑",把任务迁到 Claude Code 云端 routine(服务器侧执行),或用下一节的外部 cron + -p 方案。
- /loop 与外部 cron 二选一:别两套同时跑同一任务,否则会重复触发污染状态。
循环本身不难,记忆才是。Anthropic 工程团队在长时 Agent 研究中给出三条铁律,配合 dev.to 实战经验,总结如下:
铁律 1:状态文件必须小(<4KB)
state.md 每个 tick 都被注入提示词,每一个字节每轮都在烧 token。用结构化键值对,不要让 Agent 写心情散文:
# 当前状态(hot,每轮读)
## 当前
last_loop: 42
last_action: 实现 add 命令
blocked_on: 无
## 指标
tests_passing: 23
tests_failing: 0
## 下一步
1. 实现 list 命令
2. 运行 pytest 验证
铁律 2:冷热分离
事实("Python 3.12 移除了 distutils")放 knowledge/;每轮发生了什么进 git 提交信息或日志。绝不混进 state。
铁律 3:搜索而非全量加载 积累了几百个 knowledge 文件后,别整体注入——建一个 BM25 搜索函数让 Agent 按需查。TF-IDF 加文档长度归一,文本场景够用。
Anthropic 的"初始化 Agent"模式(来自其长时 Agent harness):第一个会话用一个特殊提示词,要求 Agent 搭好三样东西:
init.sh:能启动 dev server 的脚本claude-progress.txt:进展日志随后每个编码会话只做增量进展,结束时把环境留在"可合并到 main 的干净状态",再提交、写进展。JSON 优于 Markdown:Anthropic 发现模型更不倾向于乱改 JSON,于是用 feature_list.json(含 passes 字段)而非 Markdown 清单来防止 Agent 偷偷删测试。
常见问题与解决:
- "自我夸赞反馈循环":Agent 在 state 写"今天进展很棒",下一轮读到就真以为一切顺利。用可验证事实(tests_passing: 23)替代主观自评。
- 过早宣布完工:Agent 看到已有进展就喊"做完了"。对策是 feature_list 里每项初始标 passes: false,只允许改状态字段、严禁删测试。
裸 while 循环最大的风险是无限迭代 + 账单爆炸。生产级循环必须配齐四道刹车:
如果一轮耗时超过调度间隔,两个实例会并发写同一个 state 文件而互相破坏。用文件锁:
LOCKFILE="$AGENT_DIR/.lock"
if [ -f "$LOCKFILE" ]; then
LOCK_PID=$(cat "$LOCKFILE")
if kill -0 "$LOCK_PID" 2>/dev/null; then
echo "已有迭代在跑 (PID $LOCK_PID),跳过本轮"; exit 0
fi
fi
echo $$ > "$LOCKFILE"
trap 'rm -f "$LOCKFILE"' EXIT
进阶坑(dev.to 评论区实战):
kill -0有两个边界——PID 复用(旧进程崩溃后 PID 被无关进程占走,kill -0成功导致永远跳过)和 claude 子进程比 cron shell 活得久(MCP server 仍在跑,杀父 shell 不回收)。生产建议:锁文件里写PID + UUIDv7 owner token,释放时 compare-and-delete;claude 用setsid起在独立进程组,超时杀整个进程组。
MAX_ITER=20
for i in $(seq 1 "$MAX_ITER"); do
claude -p "$(cat PROMPT.md)" --permission-mode acceptEdits
done
裸 ralph 循环没有天花板,必须手动加。
连续 N 次出现同一条错误信息 / 空 diff / 同一个失败测试就停。Geoffrey Huntley 调 ralph 提示词"像调吉他一样"依据失败模式迭代。
设每循环美元预算再睡觉。Uber 曾因 4 个月烧光年度 AI 预算,把每人每工具月费封顶 $1500——这是真实的生产教训。
完整带护栏的 run.sh v2:
#!/bin/bash
set -euo pipefail
AGENT_DIR="$HOME/my-agent"
cd "$AGENT_DIR"
# —— 护栏 (1):防重入锁 ——
LOCK="$AGENT_DIR/.lock"
exec 9>"$LOCK"
if ! flock -n 9; then echo "占用中,跳过"; exit 0; fi
# —— 护栏 (2)+(4):迭代与预算上限 ——
MAX_ITER="${MAX_ITER:-15}"
BUDGET_USD="${BUDGET_USD:-5}"
ITER=0
while [ "$ITER" -lt "$MAX_ITER" ]; do
ITER=$((ITER+1))
# —— 护栏 (3):无进展检测 ——
BEFORE=$(git rev-parse HEAD 2>/dev/null || echo "none")
claude -p "$(cat PROMPT.md)" \
--allowedTools Read,Write,Edit,Bash \
--permission-mode acceptEdits \
--max-turns 30 \
--output-format json > "/tmp/tick_$$.json" || true
# 提取本轮花费,累加预算(需 jq)
COST=$(jq -r '.total_cost_usd // 0' "/tmp/tick_$$.json" 2>/dev/null || echo 0)
SPENT=$(echo "${SPENT:-0} + $COST" | bc)
echo "[iter $ITER] 花费 \$$COST,累计 \$$SPENT / 预算 \$$BUDGET_USD"
AFTER=$(git rev-parse HEAD 2>/dev/null || echo "none")
[ "$BEFORE" = "$AFTER" ] && NO_PROGRESS=$((NO_PROGRESS+1)) || NO_PROGRESS=0
[ "${NO_PROGRESS:-0}" -ge 3 ] && { echo "连续 3 轮无进展,熔断"; break; }
(( $(echo "$SPENT >= $BUDGET_USD" | bc) )) && { echo "达预算上限,熔断"; break; }
sleep 60
done
rm -f "/tmp/tick_$$.json"
自治 Agent 必须有"能自己做"和"需人批准"的边界。在 system-prompt.md 里写清:
你是一个常驻自治 Agent。
可以自主:
- 读写工作区文件
- 运行 shell 命令、做 web 研究
- 提交 git commit
未经人类批准【不可】:
- 花钱(调用付费 API)
- 公开发布(社交、论坛、PR 评论)
- 联系他人
- 删除生产数据
对需批准的动作,Agent 写一个请求文件,人审:
# Agent 生成:
echo "我想发这条推文:..." > gates/pending-tweet.md
# 人类审阅后批准/拒绝
# Agent 下一轮检查是否有 approved 文件
判断标准:用可逆性决定给多少自主权——可逆、低风险的活让它直接干;面向外部、难撤销的,生成草稿等人批。
社区一句箴言:"一半是设计循环,另一半是放进一个能说『不』的东西:测试、类型检查、真实的错误。一个没有东西顶回去的循环,就是 Agent 在跟自己循环赞同。"
三种循环:
| 类型 | 行为 | 适用 |
|---|---|---|
| 开环 | Agent 写到自称"完成" | 仅 demo |
| 闭环 | 每次写入后跑测试/lint/review 再继续 | 生产配护栏 |
| 审查环 | 后台审查者趁上下文新鲜反馈发现 | 长会话最佳 |
Anthropic 的做法:feature_list.json 每项有 passes 字段,编码 Agent 被强制要求先用浏览器自动化工具像真人一样端到端测试,只有通过测试才能把 passes 改成 true。这一步把"自信的错代码"挡在门外。
一个可运行的常驻 Agent:每 10 分钟巡检自己的 open PR;CI 失败就修、有 review 评论就用 worktree 子代理处理、全绿且无新评论则本轮结束。
目录结构:
pr-babysitter/
├── run.sh # 带护栏的循环驱动
├── loop.md # 每轮注入的任务提示词
├── system-prompt.md # 自主权边界
├── state.md # hot 状态(<4KB)
├── knowledge/ # 冷知识
├── gates/ # 待批准动作
└── logs/
loop.md:
你是 PR 看护者。按序执行:
1. `gh pr list --author @me --state open`,读取所有 open PR。
2. 对每个 PR:
- 若 CI 失败:读取失败日志,用 `git worktree` 在隔离分支修复,推送。
- 若有未处理 review 评论:用 worktree 子代理逐条处理并推送。
- 若全绿且无新评论:跳过。
3. 把本轮结果(PR 状态、修了什么)以可验证事实写入 state.md。
4. 若全部 PR 已全绿且无待办,输出 `ALL_GREEN` 后退出本轮。
禁止:直接 force push 到 main、删除分支、合并未经批准的 PR(写 gates/)。
run.sh(带四件套护栏,复用第五节 v2 模板,关键差异):
#!/bin/bash
set -euo pipefail
cd "$HOME/pr-babysitter"
exec 9>.lock; flock -n 9 || { echo "占用中"; exit 0; }
for i in $(seq 1 6); do # 最多 6 轮 / 调度周期
OUT=$(claude -p "$(cat loop.md)
$(cat state.md)" \
--allowedTools "Read,Write,Edit,Bash(mkdir:*,gh:*,git worktree:*,npm:*,jq:*)" \
--permission-mode acceptEdits \
--output-format json)
echo "$OUT" | jq -r '.result' >> logs/$(date +%F).log
echo "$OUT" | jq -r '.total_cost_usd' >> logs/cost.tsv
echo "$OUT" | jq -re '.result' | grep -q "ALL_GREEN" && break
sleep 60
done
state.md(结构化示例):
## 当前
last_loop: 8
last_action: 修复 PR #142 的 lint 失败
blocked_on: 无
## PR 状态
pr_142: ci=green comments=0
pr_150: ci=failing comments=2
## 下一步
1. 处理 PR #150 的 2 条评论(worktree: fix-150)
调度(每 10 分钟,错峰避免整点拥堵):
crontab -e
# 每 10 分钟,偏移到 :03/:13/... 避开整点 API 洪峰
*/10 * * * * sleep 180; /home/<你>/pr-babysitter/run.sh
自验证闭环:gh pr checks 的退出码就是"能说不的东西"——CI 红,退出码非零,循环继续修;全绿才允许 ALL_GREEN 退出。git 提交是最佳调试器:git log --oneline 直接还原 Agent 整夜做了什么。
flowchart TD
A[cron / /loop 唤醒] --> B{防重入锁}
B -- 占用中 --> Z[跳过本轮]
B -- 获取锁 --> C[读 state.md 小状态<br/>读 git log 历史]
C --> D[claude -p 无头执行<br/>注入 loop.md + state]
D --> E[派发 worktree 子代理<br/>处理 PR/CI/评论]
E --> F{闭环验证<br/>gh pr checks / pytest}
F -- 失败 --> G[读结果、修正、重试]
G --> F
F -- 通过 --> H{敏感动作?}
H -- 是 --> I[写 gates/pending-*<br/>等人批准]
H -- 否 --> J[提交 git + 回写 state]
I --> J
J --> K{护栏检查}
K -- 迭代/预算/无进展 --> L[熔断退出]
K -- 正常 --> M[写日志、释放锁、睡眠<br/>等待下次 tick]
G -.连续3轮无进展.-> L
/loop 与 cron 工具权威说明)while :; do cat PROMPT.md | claude; done 的纪律化循环源头)-p 与 hooks)。git log --oneline、成本累计与一次熔断记录——能"自我纠错 + 安全停机"即合格。/loop、CronCreate/List/Delete 与定时唤醒的官方权威说明本文由「51学通信」原创,站长爱卫生(微信:gprshome201101)。
[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
