はじめに
前回の記事では、Codexの実行履歴を分析するためにRollout JSONLを利用できることを紹介しました。
これでようやく分析ができると思ったのですが、早速問題が発生しました。
Rollout JSONL、デカすぎる。
実際に、ある開発セッションのJSONL全文を計測すると、約400万トークンもありました。だいぶ多いですね。
これをそのままLLMに渡すのは、コンテキスト長の制限だけでなく、トークン消費の面でも非効率です。無駄を見つけるために大量のトークンを消費する。何をしてるんやろう、という話です。
そこで今回は、Rollout JSONLから必要な情報だけを取得し、できるだけ少ないトークンで実行時間やトークン消費の無駄を分析するSkillを作成しました。
想定読者
- Codex CLIを使っている方
- Codexのトークン消費や実行時間を改善したい方
結論
Pythonによる集計とCodexによる段階的な調査を組み合わせることで、LLMに渡す情報量を大幅に削減できました。
仕組みはシンプルです。
- PythonでJSONLを解析し、必要な情報だけを出力する
- Codex Skillで調査手順を制御し、不要な情報取得を防ぐ
実際に3つの開発セッションを分析したところ、JSONL全文と比較してツール出力の情報量を99.46%削減できました。なかなかいい数字です。
作成したSkillはOSSとして公開しています。
1. Rollout JSONLの構造と分析方針
前回の記事でも説明しましたが、Rollout JSONLには、セッション情報、モデルの応答、ツールの呼び出し・実行結果、トークン使用量などが記録されています。
ただ、セッション分析のために、すべてのソースコードやツール出力をLLMに読み込ませる必要はありません。例えば、トークン使用量の合計を知りたいだけなら、Pythonで計算すれば済む話です。
わざわざLLMに大量のデータを渡して足し算してもらう必要はありません。電卓の仕事は電卓に任せましょう。
というわけで、JSONLの解析と集計はPythonに任せ、LLMには必要な情報だけを渡す方針にしました。
2. Pythonスクリプトの作成
まず、セッション分析を次の3段階に分けました。
- 分析対象のセッションを特定する
- ボトルネックの候補を発見する
- 必要な箇所だけ詳しく調査する
いきなりログを全部読むのではなく、少しずつ調査対象を絞っていく作戦です。この流れを実現するために、5つのコマンドを作成しました。
2.1 overview:分析対象を特定する
まずは、どのセッションを分析するのかを特定します。
例えば、直近5つのセッションを確認してみましょう。
python -B $script overview --last 5 --project .
セッションID、実行日時、使用モデル、トークン使用量などの概要が出力されます。
出力例(一部抜粋):
{"session_id":"...","model":"gpt-6.1-sol","tool_calls":50}
{"session_id":"...","model":"gpt-6.1-terra","tool_calls":72}
この情報から候補を絞り、必要ならPR作成操作などの記録と照合して対象を特定します。
2.2 report:ボトルネックの候補を発見する
対象を特定できたら、いよいよ無駄探しです。
python -B $script report --file $file --top 5 --max-total-chars 6000
※ $fileには対象JSONLのパスを指定します。
reportでは、前回の記事で紹介した5種類の無駄の候補を集計します。
| 調査候補 | 内容 |
|---|---|
| 大量出力 | ツール結果の出力が大きい |
| 長時間処理 | 処理や待機に時間がかかっている |
| 失敗 | コマンドの失敗や例外が発生している |
| 出力の切り詰め | ツール結果が途中で切り詰められている |
| 重複操作 | 同じ引数のツールを繰り返し実行している |
例えば、実際に分析したセッションでは、こんな結果が得られました。
| 指標 | 結果 |
|---|---|
| ツール呼び出し | 50回 |
| ツール出力合計 | 約33万文字 |
| 最初の8回の出力 | 約18万文字(55.2%) |
最初の8回だけで、出力全体の半分以上を占めていました。
なかなか豪快な出力ですね。何をそんなに読み込んだのか気になるので、(codexが)この8回を詳しく調べてみます。
なお、Pythonが見つけるのはあくまで調査候補です。大量出力や長時間処理が、必ずしも無駄とは限りません。それを判断するのはCodexの仕事です。
2.3 calls:ツールの操作内容を確認する
では、最初の8回で何をしていたのでしょうか。callsで操作内容を確認します。
python -B $script calls --file $file --from-id 1 --to-id 8
callsでは、各ツールの操作概要、出力文字数、実行時間などを取得できます。
| ID | 操作内容 | 出力文字数 |
|---|---|---|
| 5 | 複数のソースファイルを取得 | 約3.2万文字 |
| 6 | ソースファイルやテストを取得 | 約4.2万文字 |
なるほど。ID 5・6で大量のソースコードを取得していたようです。
ここで重要なのは、ツールの実行結果そのものは取得せず、概要だけを確認できること。大量のソースコードを読まずに、調査対象を絞れます。
どうやらID 5が気になるので、もう少し詳しく調べてみましょう。
2.4 detail:特定の操作を詳しく調べる
detailでは、指定したツール呼び出しの詳細を取得できます。
python -B $script detail --file $file --id 5 --around 1 --max-chars 1200 --max-total-chars 3500
取得できる主な情報はこちら。
| 項目 | 内容 |
|---|---|
tool |
ツールの種類、実行時間、出力文字数など |
arguments |
ツール呼び出し時の引数 |
output |
ツールの実行結果 |
context_before / context_after
|
実行前後のメッセージ |
これらを確認すれば、どんなコマンドが実行され、なぜ大量出力が発生したのかを詳しく調べられます。
もちろん、ここでも出力量は制限します。せっかく調査対象を絞ったのに、詳細調査で大量のログを読み込んでしまっては意味がありません。
2.5 message:会話内容を確認する
ツールの実行結果だけでは、Codexがなぜその操作をしたのか分からないこともあります。
例えば、レビュー後に修正が発生していた場合。「そもそも、なんで修正することになったんやっけ?」と、当時のやり取りを確認したくなるかもしれません。
そんなときに使うのがmessageです。
python -B $script message --file $file --line $messageLine --max-chars 1500
※ $messageLineには、取得したいメッセージのJSONL上の行番号を指定します。
ユーザーやCodexのテキストメッセージを取得できるため、当時の判断や手戻りの経緯を確認できます。なお、レビュー結果がツールの実行結果として記録されている場合は、detailを使用します。
2.6 Skillによる調査手順の制御
Pythonスクリプトは完成しましたが、これだけでは安心できません。Codexが毎回適切なコマンドを使い、効率よく調査してくれるとは限らないからです。
せっかく情報を絞る仕組みを作ったのに、Codexが「とりあえず全部見てみよう」と言い出したら困ります。
そこで、SKILL.mdに次のルールを追加しました。
- 対象特定 → 集計 → 必要な詳細調査の順に進める
- 同じ情報を繰り返し取得しない
- 不要な大量出力を避ける
- 十分な根拠が揃ったら調査を終了する
また、大量出力や長時間処理を見つけても、すぐに「無駄だ!」と決めつけないようにしています。必要なテストやレビューまで削減してしまっては本末転倒です。
何でも削ればいいというものでもありません。難しいところです。
3. 検証結果
さて、実際にどれくらい効率化できたのでしょうか。
3つの開発セッションのJSONLを、作成したSkillで分析してみました。JSONL全文と、分析中にツールからCodexへ返されたテキストのトークン数を比較した結果がこちらです。
| 指標 | 結果 |
|---|---|
| JSONL全文(3件合計) | 約540万トークン |
| 分析時のツール出力 | 約2.9万トークン |
| 情報量削減率 | 99.46% |
| 分析全体の消費トークン | 約43.5万トークン |
| 分析実行時間 | 約119秒 |
トークン数の比較にはo200k_baseを使用しました。
JSONL全文の約540万トークンに対し、実際のツール出力は約2.9万トークン。情報量を99.46%削減できました。
思った以上に減りました。これなら約400万トークンのログを見ても、ちょっとだけ優しい気持ちになれます。
しかも、3つのセッションに共通するボトルネックや、個別の手戻りの原因まで調査し、改善案も提示できました。
今回は全文読み込みとの情報量比較であり、Skillを使わない方法との厳密な比較実験ではありません。それでも、必要な情報を絞って取得できることを確認できました。
4. OSS公開
今回作成したSkillは、GitHubで公開しました。
興味のある方は、ぜひ使ってみてください。私もまだまだ改善していく予定です。
まとめ
Codexの動きをすべて追いかけるのは大変ですが、実行ログを分析すれば、普段は気づきにくい無駄も見えてきます。
そして今回は、その無駄を探す作業自体も効率化できました。無駄をなくすための作業に無駄があったら、なんか嫌ですからね。
これからも実行ログを観察しながら、少しずつCodexの開発効率を改善していきたいと思います。
