第3章: think → act → observe ── ReAct の系譜と現代の三拍子
Claude Code でも、Cursor の Agent モードでも、Codex CLI でも、画面に流れていく行は不思議とよく似ている。
● Bash(pnpm test) ⎿ 3 failing
● Read(src/parser.ts)
● Read(tests/parser.test.ts)
● Edit(src/parser.ts)
● Bash(pnpm test) ⎿ 1 failing
● Edit(src/parser.ts)
● Bash(pnpm test) ⎿ all green
直しました。空配列のときに落ちる境界条件を 2 箇所修正しています。人間が打ったのは最初の一文だけ。 そのあとは 何かが何度も繰り返している。
ファイルを読み、編集し、テストを流し、結果を見て、また直す。 人間がデバッグしているときの動きと、ほぼ同じ だ。
なぜどのプロダクトも、判で押したように同じ動きをするのか。 答えは ── どれも同じ三拍子で回っているから だ。
3.1 そもそも、なぜ「繰り返し」が要るのか
第1章で見たとおり、LLM は続きを書く機械でしかない。 道具を渡し、結果を続きとして食べさせる ── ここまでは 1 往復の話だった。
だが、1 往復で終わらせると エージェントとしてはほとんど役に立たない。 ファイルを 1 つ読んで終わり、テストを 1 回流して終わり、では「結果を見て次を考える」ができない。
実務でやりたいことは、ほぼ全部 多段 だ。
- バグ修正 = 失敗を観る → 原因を疑う → 直す → 流す → 違ったら別の場所を疑う → …
- 新機能 = 既存を読む → 設計する → 雛形を書く → 周辺を直す → ビルドが通るまで戻る → …
- 調査 = 仮説を立てる → 検索する → 怪しい所を読む → 仮説を更新する → …
どれも、最初に全部の手順を決めることが、原理的にできない タスクだ。 途中で見たものを材料に、次の一手が決まる。
エージェントの本質は「1 ステップの賢さ」ではなく、「結果に応じて次の 1 ステップを選び続けられること」 にある。 1 往復のツール呼び出しを、観測を踏まえて何度も繰り返す ── これが、ハーネスがやっている仕事の心臓部だ。
ここから本章では、この心臓部を think → act → observe という 3 拍子で捉え直す。
3.2 三拍子の正体 ── think / act / observe
ハーネスが回しているループを、最小の言葉に削ぐとこうなる。
| 拍子 | やっていること | 担当 |
|---|---|---|
| think | 今の状況を読み、次に何をするか考える | LLM |
| act | 道具を呼ぶ命令を出す → 実行する | LLM + ハーネス |
| observe | 実行結果を観測し、次の入力に積む | ハーネス |
observe の結果は 次の think に渡される。これが続くかぎり、回り続ける。
think → act → observe → think → act → observe → think → …
3 つの拍子の “担当” を見ると、思想が透けて見える。 think は完全に LLM の仕事。observe は完全にハーネスの仕事。act だけが両者の合作 だ。
冒頭の例を、この三拍子で見直すとこうなる。
| # | think (LLM の頭の中) | act (呼ばれた道具) | observe (結果) |
|---|---|---|---|
| 1 | まずテストを流して状況把握 | Bash(pnpm test) | 3 件失敗 |
| 2 | 失敗箇所のファイルを読む | Read(src/parser.ts) | 中身 |
| 3 | テスト側も読んでおく | Read(tests/parser.test.ts) | 中身 |
| 4 | パーサーの境界条件を直す | Edit(src/parser.ts) | 編集成功 |
| 5 | 直ったか確認 | Bash(pnpm test) | 1 件失敗 |
| 6 | もう一箇所修正 | Edit(src/parser.ts) | 編集成功 |
| 7 | 再確認 | Bash(pnpm test) | all green |
| 8 | 「直しました」と返事 | (ツール呼び出しなし) | — |
8 ステップ目だけが特別だ。道具呼び出しを含まない、ただのテキスト応答。 ここでハーネスはループから抜ける(停止条件の詳細は第4章で扱う)。
3.3 ReAct という発明 ── 2022 年の論文から
この三拍子は、現代のエージェントに勝手に降ってきた発明ではない。 2022 年に Yao らが発表した ReAct という論文 ──“Synergizing Reasoning and Acting in Language Models” ── が、この型を明示的に世に出した。
ReActLLM に 思考 (Reasoning) と行動 (Acting) を交互に出力させる プロンプト技法。 それまで「LLM は思考だけ」「LLM はツール呼び出しだけ」の片方に寄っていたものを、思考 → 行動 → 観測 → 思考 → 行動 と織り交ぜることで、複雑な多段タスクの精度が大きく上がることを示した。
ReAct 以前にも、LLM に多段タスクをやらせる試みはあった。素朴な発想はこうだった。
「最初に一気に 計画 を立てさせて、そのあと計画どおり順に道具を呼ばせれば早い」
これを Plan-and-Execute 型 と呼ぶ。 ところが実装してみると、これが脆い。
| やり方 | 強み | 弱み |
|---|---|---|
| Plan-and-Execute (先に全部計画) | 速い、見通しがよい | 途中で予想外の結果が出ても、最初の計画に従って暴走する |
| ReAct (やりながら考える) | 観測に応じて即座に方針転換できる | 計画が浅い、ループの暴走に弱い |
なぜ前者が脆いのか。理由は単純で、実世界の道具呼び出しは、しばしば予想外の結果を返す からだ。
ファイルを読んだら想定と中身が違う、テストを流したら別のテストまで落ちた、grep の結果が空だった ── こうした「観測の裏切り」に、Plan-and-Execute は弱い。
人間がデバッグするときと、まったく同じ問題 だ。 「テスト失敗 → 仮説 → 直す → 流す → 違った → 別の仮説」── これを最初に全部紙に書き出してから動く人はいない。 やりながら考える という人間的な進め方を、LLM のループで模倣しているのが think-act-observe である。
ReAct という名前は今や日常語ではないが、サイクルとしての思想は Claude Code、Cursor、Devin、Aider、OpenHands を含む全エージェントの土台 として残っている。
なお現代のエージェントは、両者を完全に排他にはしていない。 Claude Code の Plan mode、Cursor の “Plan” 機能 ── これらは 「最初にざっくり計画を立て、その後 ReAct で実行する」 ハイブリッドだ。計画とサイクルの混ぜ方は、第9章で本格的に扱う。
3.4 サイクルを 1 枚にまとめる
ここまでを 1 枚の絵に落とす。
通常のループ(黒い矢印)と、停止の経路(赤い破線)の 二通り が think の出口にある。 これが、ループの最小の絵だ。
3.5 三拍子の “境目” がプロダクトの個性を作る
think / act / observe ── 三拍子は共通だが、境目をどこに引くか はプロダクトごとに違う。 ここがハーネス(第2章)の腕の見せどころでもある。
たとえば、こんな違いがある。
- think の長さ: Claude Code は内部で長めに考える(extended thinking)。Aider は短く回す傾向
- act の粒度: Aider はコミット単位で act を区切る。Claude Code はもっと細かい単位
- observe の見せ方: Cursor はエディタの差分プレビューを observe の入力にする。Devin はブラウザのスクショまで含めて observe にする
同じ三拍子でも、1 拍を何秒・何トークン分にするか はハーネス設計の自由度だ。
「Cursor のほうが小回りが利く」「Devin はじっくり考える」── こうした体感差の多くは、think-act-observe をどの粒度で刻んでいるか の違いから来ている。 LLM の世代差ではない。
3.6 三拍子が強いことの裏返し ── 自分で終わりを決める難しさ
サイクルの強さは、そのまま弱さの予告でもある。
think-act-observe を回し続けると、原理的には 無限に回せる。 LLM 自身が「もう道具を呼ばない」と判断しないかぎり、ループは止まらない。
ところが、その「終わり」の判断を LLM 自身に任せている のがこのモデルだ。 判断ミスは、即座にループの病として現れる。
- 早すぎる終了 ── テストを 1 回流して 1 件落ちているのに「だいたい直しました」と止まる
- 無限ループ ── 同じ Edit → Bash → 失敗 を抜け出せず、何十ターンも回り続ける
両者は 同じ三拍子設計の表裏 だ。詳細は次の第4章(停止条件)と、第10章(三大病と HITL)で正面から扱う。
think-act-observe というサイクルは、見た目の単純さに対して、内部の “終わり方” が驚くほど難しい。 人間でも、デバッグを切り上げる判断や、同じバグに延々と取り組み続ける罠は普通にある。 LLM はこれを より大胆に やってしまう ── 自信過剰にも、頑迷にも。
エージェントを賢く使う設計の大半は、この弱点をどう囲い込むか に集中している。 本書の残りは、囲い込みの道具を一つずつ揃えていく旅でもある。
3.7 ループはどこに住んでいるか ── 第2章への接続
最後にひとつ、視点を引いておく。
think → act → observe というサイクルは、どこに実装されているか? 答えは前章で見たとおり、ハーネスの中 だ。
LLM 側にループの概念はない。LLM はあくまで「1 回分の think(続きを書く)」しかしない。 「もう一度呼ぶか、止めるか」を決めているのはハーネスのコード であって、LLM ではない。
第2章で挙げたハーネスの 7 つの仕事のうち、⑤ ループ制御 がまさにこの三拍子のことだ。 そして次章では、その隣にある ⑥ 停止判断 ── ループを誰がどう止めるのか ── を正面から扱う。
この章の振り返り
- エージェントの心臓部は think → act → observe の三拍子サイクル
- think は LLM、observe はハーネス、act は両者の合作
- 2022 年の ReAct 論文(Yao ら)が、思考と行動の交互という型を明示的に世に出した
- Plan-and-Execute(先に全部計画)は 観測の裏切り に弱く、現代のエージェントは ReAct を土台に置く
- 三拍子の 粒度の引き方 がプロダクトごとの個性を作る(Claude Code / Cursor / Devin / Aider)
- サイクルを止める判断は LLM に任されている ── ここに 早すぎる終了 / 無限ループ という弱点が眠る
- ループ本体は ハーネスのコード に住む。LLM 自身はループしない、1 ターン分だけ続きを書く
この章で読めるようになるツイート / ブログ
- 「ReAct ってもう古いの? 最近 ReAct って単語見ない」 → 名前は廃れたが、思想は現代エージェント全般の土台として生きている、と読める
- 「Plan mode でじっくり計画させたほうが結局速かった」 → 純粋な ReAct と Plan-and-Execute のハイブリッド設計が効く局面の典型例、と読める
- 「Cursor は小回り、Devin はじっくり、Claude Code はその中間」 → think-act-observe をどの粒度で刻むかという、ハーネス設計の違いとして読める
次章は、本章で予告した 「ループの終わり方」 に踏み込む。 誰が、どうやって、いつ止めるのか ── 停止条件の三本柱を解剖する。