AIとのセッションは「5分で捨てる」か「何日も使い回す」かの二択だった
セッションをどう区切るかは、AIコーディングでいちばん地味に悩むところだと思う。長く続ければ文脈は残るが重くなる。短く切れば軽いが説明をやり直すことになる。
自分がどう使っているのかを一度も測ったことがなかったので、117本ぶんのログから、各セッションの最初のイベントと最後のイベントの時刻を拾って分布を出した。
結果は、予想していたどの形とも違った。
真ん中がごっそり抜けている
5分未満が46本、6時間以上が44本。その間が合計24本しかない。
きれいな二峰分布になった。平均を取ると意味のない数字が出るタイプの形で、実際に中央値は66分だが、66分前後のセッションはほとんど存在しない。
内訳を見ると納得できる。短いほうの46本は、起動して1つ2つ質問して閉じたもの。117本のうち19本は人間の発言が0件で、開いて何も言わずに終わっている。コマンドを確認したかっただけ、みたいな使い方だ。
長いほうの44本は、その日のうちに終わっていない。いちばん長いものは最初と最後の間隔が約12日あった。
12日間ぶっ通しで作業したわけではない
ここは正直に書いておかないといけない。この「長さ」は作業時間ではない。
セッションを --resume で再開すると、同じファイルに続きが書かれる。だから最初と最後の時刻の差は、そのセッションが生きていた期間であって、その間ずっと画面に向かっていたわけではない。
実際、同一セッション内で30分以上の間隔が空いた箇所を数えると、全体で237回あった。1日の作業が終わって翌日また同じセッションを開く、というのを繰り返せば、こうなる。
つまりセッションログの時刻からは、作業時間を測れない。私は最初これで「のべ2,158時間」という数字を出してしまい、1か月で2,000時間は物理的に無理だと気づいて計算をやめた。33日間は792時間しかない。
測れるのは「セッションがどれだけ長く生き続けたか」までで、そこから先を知りたいなら、30分以上空いた箇所で区切って作業ブロックを数えるような処理が要る。今回はそこまでやっていない。
二極になる理由
なぜ真ん中が無いのか、心当たりはある。
短いセッションは質問だ。「このコマンドどう書くんだっけ」「この設定どこにある」。答えが出たら閉じる。文脈を積む必要がないので、次に同じことを聞くときも新しいセッションでいい。
長いセッションはプロジェクトだ。1つの機能を作り始めると、そのために読んだファイル、決めた方針、踏んだ失敗が全部コンテキストに載っている。これを捨てて説明し直すのが面倒なので、翌日も同じセッションを開く。そうやって延びていく。
中間、つまり「1時間くらいで区切りをつけて終わる作業」が無いのは、たぶん個人開発だからだ。区切りをつける外的な理由(会議、終業、レビュー依頼)が無いので、終わるまで続けるか、最初から短いかのどちらかになる。
長く使い回すことのコスト
長いセッションが悪いとは思っていないが、代償はある。
ひとつは重さで、コンテキストが伸びるほど1回の応答が重くなる。33日間のキャッシュ読み込みは36億トークンあり、応答1回あたり平均19万トークンを読み直している。長いセッションほどこの数字が大きくなる。
もうひとつは、これがより厄介なのだが、別のセッションから見えないことだ。
実際に事故った。あるサイトの改修を1つのセッションで完成させ、コミットまで済ませた。その2日後、別のセッションで同じ問題に取り組み始めて、まったく同じ作業をもう一度やった。最初のセッションの成果はブランチに残っていたのに、2つ目のセッションはそれを知らなかった。
セッションを長く使い回す運用は、その中では文脈が完璧に保たれる。でも外からは何も見えない。セッションが長いほど、その中に閉じ込められる情報も増える。
対策は、セッションの外に書くこと
この分布を見てから、運用を1つ変えた。長いセッションでやったことを、セッションの外のファイルに落とすようにした。
具体的には3つ置いている。
タスク一覧のファイル。 何が終わっていて何が残っているかを、セッションをまたいで参照できる形にしておく。「どのブランチに何が入っているか」もここに書く。上の事故のあと、未マージのブランチを残す場合は必ず書くというルールを足した。
運用ルールのファイル。 事故の記録と、その再発防止をここに書く。日付と実例つきで書くと、別のセッションでも同じ判断ができる。
引き継ぎ書。 調査だけ終わって修正が未着手、のような中途半端な状態のときに、単発のファイルを置く。実際いま、このリポジトリには別の作業の引き継ぎ書が1つ転がっている。
どれも特別な仕組みではなく、ただのMarkdownファイルだ。ただ、セッションログは自分では読み返せない(500MBある)ので、人間が読める形に落としておく場所は要る。
自分の分布を見てみると早い
同じことをやるなら、必要なのは各ファイルの最初と最後のタイムスタンプだけだ。
if (typeof d.timestamp === 'string') {
const t = Date.parse(d.timestamp);
if (firstTs === null || t < firstTs) firstTs = t;
if (lastTs === null || t > lastTs) lastTs = t;
}
出てきた分布が二峰なら、私と似た使い方をしている。その場合、長いほうのセッションで得た情報をどこに逃がすかを決めておくと、後で同じ作業を二度やらずに済む。
一峰にまとまっているなら、たぶんそれは区切りをつける習慣がある人で、率直にうらやましい。