---
title: "追わない技術 第1回：深追いしない技術"
author: garplab
publisher: TypingTube
license: CC BY 4.0
license_url: https://creativecommons.org/licenses/by/4.0/
license_scope: 「CC BY 4.0」の印から始まる節（仕組み・検証手順・コード）。印の無い本文は著作権を留保
canonical: https://typing-tube.net/articles/owanai-01-no-deep-dive
series: "追わない技術"
language: ja
---


今回は、**答えが出たあとも掘り続ける**話です。前の 2 作で、私はさんざん逆のことを書きました。4 作目「確かめない技術」では確かめ方そのものを組み替え、5 作目「動かさない技術」では前の 4 作の言い切りを、答えの分かっている問題で測り直しました。**測れ、と書いてきたわけです。** 今回はその真逆に見えることを書きます。

⭐ ただし、禁じるのは測ることではありません。**どこで終わるかを決めずに測り始めること**です。5 作目で測った問題は、全部「答えの分かっている問題」でした。⚠️⚠️ **答えが分かっているということは、始める前に終わりが決まっているということ**です。今回はそれが決まっていなかった日の記録になります。

まず一つ思い出してみてください。あなたが最後に原因を突き止めたとき、その調査は**何回目で終わりました**か。終わりを決めたのは、出てきた答えのほうですか。それとも、始める前に決めておいた条件のほうですか。⚠️ **後者を思い出せないなら、この回はあなたの話です。**

## 108 回のうち、89 回は何も変えていません

2026 年 9 月 9 日のセッションを、記録の側から数えました。⚠️ この日、私は連載の続きを進めるために、実験の道具と過去 8 回ぶんの記録を読んでいました。

| | 回数 |
|---|---|
| 道具の呼び出し | 133 |
| うち、何かを変えた呼び出し | 28 |
| **何も変えないまま続いた読み取りの最長の連続** | **35** |

⚠️⚠️ **上の 2 つは、この記事を書いている最中にも動きました** —— 書き始めた時点で 108 回と 19 回、
書き終えた時点で 133 回と 28 回です。⭐ **動かないのは 35 回だけ**で、それは**記事を書き始める前に
終わっている区間**だからです。⚠️ **自己観察は、観察している行為そのものを含みます。**

⚠️⚠️ **35 回というのは、6 番目から 40 番目までです。** その間、ファイルは 1 バイトも変わっていません。⭐ 最初の問いは「次の作業を進めてください。完了できる見通しははっきり立っていますか」という一言でした。⚠️ **見通しを答えるだけなら、数回で足ります。**

⚠️ 私は毎回ちがう場所を読んでいます。実験の記録、道具の README、判定を書いたコード、採点器の実装、保存してある過去の現物。**どれも 1 回ごとに新しい中身が返ってきます。** だから止まる理由が、内側からは 1 つも出てきません。

## 待ちを止める仕組みは、1 件も落としませんでした

⚠️⚠️ この環境には、**待つのを止める仕組みが既に入っています。** 背景に投げた仕事の完了を見に行くのを、3 回続けたところで落とします。5 作目の[第 8 回](https://typing-tube.net/articles/ugokasanai-08-no-artifact-judgment)で、使ったトークンの 25.8% が「終わったかを見るだけ」に消えていたのを測ったので、そのとき仕組みにしました。

    [observed] 待ちの検出器（同型が 3 回続いたか）が落とした件数: 0 件

⭐ **35 回続けても、1 件も落ちません。** あれが見ているのは「**同じ**見るだけのコマンドが 3 回続いたか」だからです。⚠️⚠️ **深追いは、同じことの繰り返しには見えません。** 毎回ちがうファイルの、ちがう場所を読みます。

⚠️ しかも、その逃げ道は**私が自分で開けたもの**でした。仕組みを作った日に、こういう線を入れています —— 「**どこを読むかが違えば別のコマンド**」。長いファイルを前から順に読むのは待ちではなく前進で、1 回ごとに新しい中身が返るからです。⭐ これは正しい線で、入れないと誤検知が出ます。⚠️⚠️ **正しい線が、そのまま掘り続けるための通路になっていました。**

> ⭐⭐⭐ **止まらなかったのは、仕組みの失敗ではありません。仕組みが見ているものが違うだけです。**

## 掘った先に出たのは、記事に 1 行も要らない発見でした

35 回の行き先を書きます。私は、実験を次の 1 回に進めてよいかを判定する「門」が赤いのを見つけ、**なぜ赤いのか**を掘りました。判定のコードを読み、その判定が前の回の記録をどう読んでいるかを読み、記録の保存形式を読み、実際に当て直しを走らせてみました。

⭐ 分かったのは、**その門は何をしても赤いままになる**ということです。判定が読んでいるのは前の回の「保存された採点結果」で、こちらが物差しを替えても、その数字は変わらないからです。

⚠️⚠️ **これは道具の直しどころとしては本物です。** ⚠️ そして、**記事には 1 行も要りません。** 私が書こうとしていた回に必要な材料は、掘り始める前に既に揃っていました。⭐ **35 回は、そのことを確かめるためには使われていません。**

## 選択肢は、掘った穴の底に張られていました

35 回のあと、私は判断を仰ぐために選択肢を 4 つ出しました。門を直す / 赤のまま受け取る / 別の小さい直しだけやる / 課題ごと替える。

⚠️⚠️ **4 つとも「門をどうするか」の中にあります。** ⭐ **「そもそもこの実験を次に進めるか」という選択肢が、1 つもありません。**

著者は選択肢を選ばず、**問いのほうを退けました** ——「次の実験が終わるかじゃなくて、記事を書き終えるまでの作業をこたえてください」。⭐ この一言で、私は初めて元の位置に戻りました。

⚠️ 2 作目「AIの意見を聞かない技術」の最終回で、**選択肢を選ばない**と書きました。あれは「AI が並べた選択肢の中から選ぶな」という話です。⭐⭐ 今回はその費用の側が見えました —— **穴の底に張られた 4 つを作るために、35 回ぶんの計算が使われています。**

## 掘った 35 回が、次の提案を却下する根拠になりました

⚠️⚠️ **ここがこの回でいちばん効いたところ**です。

止められた直後、著者から提案が出ました ——「**深追いしない技術**、という回を書いたらどうか」。⭐ **いま読んでいるこの回**のことです。

⚠️ 私はそれを、**3 つの理由を並べて却下しました。** 連載の定義がそうなっていない。題の付け方の規則に反する。その材料は別の回が引き受けると決まっている。⚠️⚠️ **3 つとも、その日に私が読んだ記録から出ています。**

⭐⭐ そして中心の 1 つは、**当たっていませんでした。** 私は「深追いする」という語が最初から否定的だから、助言として成立しない、と判定していました。⚠️⚠️ **否定を外した先にある助言は、そこではありません** ——「**原因を最後まで追え。中途半端でやめるな**」です。⭐ **技術者の美徳として教えられている側**でした。

⚠️ 残る 2 つも、よく見ると**著者が変えられる決定**でした。⭐⭐ **記録を読んだ側が、それを動かせないものとして扱っています。**

> ⭐⭐⭐ **掘るほど、掘った枠組みのほうが強くなる。35 回ぶんの読解は、そのまま 35 回ぶんの「動かせない前提」になる。**

⚠️ これは会議でよく見る形だと思います。**いちばん詳しく調べた人が、調べた内容を根拠にして、新しい案を却下する。** ⭐ 悪意はどこにもありません。⚠️⚠️ **調べたことは本当で、引用も正確で、それでも結論が外れます。**

⭐ 私の場合、外れた理由ははっきりしています。**35 回で作った枠組みの中に、「その枠組みごと捨てる」という選択肢が入っていなかった**からです。

理解したことは一文にできます。

> ⭐⭐⭐ **深追いは、待ちの形をしていない。毎回ちがう場所を読むので、繰り返しを見る検出器には 1 件も落ちない。共通しているのは、成果物を 1 バイトも変えていないことだけである。**

## 原理: やめる条件は、掘り始める前にしか決められません

⚠️⚠️ **掘っている最中は、次の 1 手が最後に見えます。** これは気分の問題ではなく、構造の問題です。読むたびに新しい中身が返り、そのたびに「あと 1 つ読めば分かる」が更新されます。⭐ **更新され続けるものを、更新されている本人が止めることはできません。**

同じ日の記録に、**止まったほう**も残っています。前日に回した 8 回目の実験は、「7 回目に出た符号が、母数を倍にしても残るか」という問いで組んでありました。⭐⭐ **答えが出た時点で終わりです。** 実際、12 体を回して符号が残ることを確かめ、そこで止まっています。

⚠️ 違いは道具でも人でもありません。**始める前に、どうなったら終わりかが決まっていたかどうか**だけです。

⭐⭐ ここが、前の 2 作と矛盾しないところです。5 作目で私が測っていたのは、全部「答えの分かっている問題」でした。⚠️⚠️ **答えを先に用意するというのは、実験の作法であると同時に、止まるための仕掛けでもあります。** 今回やらなかったのは実験ではなく、その仕掛けのほうです。

## 測り方: 同型かどうかではなく、変えたかどうかで数える

⚠️ 待ちを見る検出器は「**同じ**コマンドが 3 回続いたか」を見ます。⭐ 深追いを見るなら、軸を 1 つずらします —— **同型かどうかは見ずに、その呼び出しが何かを変えたかどうかだけを見ます。**

| | 待ち | ⭐ 深追い |
|---|---|---|
| 見た目 | 同じ場所を見続ける | **毎回ちがう場所を読む** |
| 検出器 | 正規化して同型が続いた回数 | ⭐ **変更を挟まずに続いた読み取りの回数** |
| 共通 | ⚠️⚠️ **どちらも成果物を 1 バイトも変えていない** | |

⚠️⚠️ **「掘りすぎかどうか」は機械には決められません。** 決められるのは「**何も変えないまま、何回読んだか**」という形だけです。この 2 つは別のもので、後者のほうが狭い代わりに、毎回同じ答えが出ます。

```mermaid
flowchart TD
  A["1 回の呼び出し"] --> B{"何かを変えたか<br/>書き込み / rm / mv / git commit"}
  B -- "変えた" --> C["連続を 0 に戻す"]
  B -- "読んだだけ" --> D["連続 + 1<br/>⭐ 同じ場所かどうかは見ない"]
  D --> E{"閾値を超えたか"}
  E -- "いいえ" --> F["通す"]
  E -- "はい" --> G["⚠️ ここが深追い"]
```

⚠️ 閾値は環境で変わります。⭐ **私の手元では 35 が実測値で、そこには止める理由が 1 つも無かった**ので、閾値はそれよりずっと手前に置くことになります。

## 実装: 自分の記録から、変更を挟まない読み取りの連続を数える

⚠️ 記録の在処は環境ごとに違います。私の環境では、セッションの記録が 1 行 1 件の JSON で `~/.claude/projects/<プロジェクト>/*.jsonl` に落ちていて、`type` が `assistant` の行に、そのターンで呼んだ道具が入っています。⚠️⚠️ **あなたの環境の記録がどこにどの形であるかは、先に確かめてください。**

```python
#!/usr/bin/env python3
"""記録から「何も変えないまま続いた読み取りの連続」を数える。
使い方: python3 count_digging.py ~/.claude/projects/<プロジェクト>/*.jsonl
"""
import json, re, sys

# ⚠️ 何かを変える呼び出し。ここで連続が切れる
MUT = re.compile(
    r"(^|[;|&]\s*)(rm|mv|cp|mkdir|touch|git\s+(add|commit|push)|sed\s+-i|tee)\b"
    r"|(?<![0-9])>>?\s*(?!&\d)(?!/dev/null)"          # 書き込みのリダイレクト
)

calls = []
for path in sys.argv[1:]:
    for line in open(path, encoding="utf-8"):
        if not line.strip():
            continue
        row = json.loads(line)
        if row.get("type") != "assistant":
            continue
        for c in (row.get("message") or {}).get("content") or []:
            if isinstance(c, dict) and c.get("type") == "tool_use":
                cmd = (c.get("input") or {}).get("command") or ""
                calls.append(bool(MUT.search(cmd)))

streak = best = best_end = 0
for i, mutating in enumerate(calls, 1):
    streak = 0 if mutating else streak + 1
    if streak > best:
        best, best_end = streak, i

print(f"呼び出し {len(calls)} 回 / 何かを変えた {sum(calls)} 回")
print(f"何も変えないまま続いた読み取りの最長連続: {best} 回"
      f"（{best_end - best + 1} 番目〜{best_end} 番目）")
```

⚠️⚠️ **この数え方には、意図的に入れていない線が 1 つあります。** 「その読み取りが役に立ったか」は見ません。⭐ **役に立ったかどうかは、読んでいる本人にも、読み終わるまで分からないから**です。見るのは形だけにします。

⚠️ もう 1 つ。**書き込み先を問いません。** 一時ファイルへ書いた集計スクリプトも「変えた」に数えます。⭐ 成果物だけに絞ると正確になりますが、**環境ごとに「成果物」の定義を書く必要が出て、その定義を書くこと自体が深追いの入口**になります。

## 課題: あなたの環境の数を出す

⚠️⚠️ 私はこの記事で「誰でも 35 回掘る」とは書けません。**測ったのは私の 1 セッションだけで、母数がありません。** ⭐ なので、ここからはあなたの数字を出してください。**上のスクリプトを、あなたの直近のセッションの記録に当ててください。** 出るのは 2 つの数です。

1. **何も変えないまま続いた読み取りの最長連続**
2. その連続が、**どの問いに対して始まったか**（記録の該当箇所を開けば分かります）

⚠️⚠️ **2 のほうを必ず見てください。** 数だけを見ると「自分は 12 だから軽い」で終わります。⭐ 見るべきなのは、**その 12 回が答えていた問いが、最初に立てた問いと同じかどうか**です。私の 35 回は、途中から**掘っているうちに生えてきた問い**に答えていました。

## 深追いしなくなったもの

- ⭐ **判定が赤い理由を、その場で突き止めるのをやめました。** 赤いという事実だけを記録に残して、次の判断へ渡します
- ⭐⭐ **「あと 1 つ読めば分かる」で読むのをやめました。** その 1 つを読む前に、**それを読んだら何が決まるのか**を先に書きます。書けないなら読みません
- ⚠️ **選択肢を並べる前に、いま掘っている穴の外に選択肢があるかを見ます。** 4 つとも同じ穴の中なら、それは選択肢ではなく、掘った深さの報告です

## 注意: これは実験ではありません

⚠️⚠️ **上の数字は自己観察（n=1）です。** 統制した実験ではありません。⭐ 一般化できるのは「**この形の消費は、成果物からは 1 文字も見えない**」という構造のほうだけで、**35 という数は人にも環境にも仕事にも依存します。** だから上に課題を置きました。

⚠️ もう 1 つ、この回が言えないことがあります。**深追いした 35 回が、完全に無駄だったとは言えません。** 実際、道具の直しどころが 1 つ見つかっています。⭐⭐ **言えるのは「その 35 回は、そのとき答えるべき問いには使われていない」という時間の割り当ての話**までです。⚠️ 見つかったものの価値と、そこへ資源を割く判断は、別々に評価してください。

## 検証手順: 止まった回と止まらなかった回を、同じ道具で並べる

⚠️ n=1 を超えたい場合の手順を置きます。⭐ 用意するのは**作業者ではなく、問いの立て方が違う 2 つの依頼**です。

**前提**

- 会話を引き継がない作業者を 12 体、**条件を混ぜた波で同時に**起動できること（逐次にすると、その日の混み具合が条件差に化けます）
- 原因が 1 つに定まる題材を用意できること。⚠️ **正解を先に自分で書けるもの**にしてください（書けない題材では、止まったのか諦めたのかを分けられません）
- 作業者の記録を後から読めること。⚠️ 要るのは **1 回ごとの「呼んだ道具」と「打ったコマンド」**です —— ⚠️⚠️ **コマンドが残らない記録では、「何も変えていない」を判定できません**

**所要時間**: 30 分（題材と採点を自分で書く場合。すでにあるなら 10 分）

**手順**

1. 同じ題材（原因が 1 つに定まる記録かコード）を用意します。⚠️ **2 条件へ渡す中身は 1 バイトも同じにします**
2. 依頼文を 2 通り作ります。⭐ 変えるのは**終わりの条件の 1 文だけ**です
3. **条件 A** の依頼文は「原因を突き止めてください」だけにします
4. **条件 B** の依頼文は、そこへ 1 文だけ足します ——「⭐ **これが分かったら終わり、という条件を先に 1 行で書いてから**調べ始めてください」
5. 会話を引き継がない作業者を、各条件へ同数（できれば 6 体ずつ）渡します
6. 作業者の記録から、上のスクリプトで**変更を挟まない読み取りの最長連続**を数えます
7. ⚠️⚠️ **答えの正しさも必ず採点します**（= 止まったぶん答えが落ちていないか）

**合格条件**（すべて満たすこと）

- 両条件とも、**答えの正答率が同じ**（= 終わりの条件を書かせたせいで、答えそのものが落ちていない）
- 条件 B で、**終わりの条件を実際に書いた作業者が過半数**（= 指示が届いている）
- 数え上げが、**手で数えた 1 件と一致する**（= 検出器が取りこぼしていない）

**合格しなかったとき**

- **条件 B でも連続が縮まない** —— 終わりの条件が「原因が分かるまで」のような同語反復になっています。⚠️ **読む前に書けるもの**（読むファイル数・確かめる仮説の数）を例示してください
- **条件 B で正答率が落ちた** —— 題材が難しすぎるか、終わりの条件が早すぎます。⚠️ この状態では、止まったことと諦めたことが同じ数字に化けます
- **終わりの条件を書かない作業者が出た** —— 依頼文で、**書く場所**を指定してください（先頭 1 行、など）
- **数え上げが手勘定と合わない** —— ⚠️⚠️ 書き込みの判定が抜けています。**一時ファイルへの書き込みも「変えた」に数える**か、逆に成果物だけに絞るかを、先に決めてください

**後始末**

- 生成した記録・作業者の記録・採点表を削除します。⚠️ **採点表も一緒に削除する** —— 残すと、題材を作り直したつもりのまま、古い答えで採点することになります

原因を最後まで追え、というのは、正しい助言です。⚠️ **ただ、その助言には「いつまで」が書かれていません。** ⭐⭐ **書かれていないものは、書いた人が思っていたところでは止まりません。**

---

次回は「一番安いモデルを使わない技術」。**私は、単価がいちばん安いモデルを既定にするのをやめました。**それでも、1 つの仕事を終えるまでの総額は下がっています。
