見積 3〜4 週間の機能追加を 2 日で終わらせた話 — 「罠を踏んだ経験」が勝手に効き始める瞬間
TL;DR: CodeRouter v1.10.0 で 5 つの新機能を追加した。事前見積は 3〜4 週間。実際は 2 日で全部出荷できた。魔法は使っていなくて、連作 1〜6 話で踏んだ罠が、コードの「型」になっていただけ。新機能を足すたびに「あ、これ前に作ったあのパターンと同じだ」が連続して起き、毎回ゼロから考える部分がほぼなかった。今回はその「型が効く感覚」の話。
あらすじ — 7 話目です
第 1 話 (v1.8.1)ガチで動かしてみたら 3 連敗した話 — note 推奨モデルを Ollama で動かして 3 連敗
第 2 話 (v1.8.2)自分が作った診断ツールに自分が騙された話 — Gemma 4 は実は完全動作していた
第 3 話 (v1.8.3)Ollama で詰んだ Qwen3.6 を llama.cpp で動かしたら、もう 1 つ偽陽性を出してた話
第 4 話 (v1.8.4)「フレームワーク待ち」の前提が翌日崩れた話 — LM Studio 0.4.12 で翌日解決
第 5 話 (v1.8.5)Claude Code とローカル LLM を繋ぐ 5 通りの経路 — CodeRouter の存在意義を整理
第 6 話 (v1.9.0)自分の検証フローに自分が騙された話 — v1.9 系で踏んだ 3 つの罠
第 7 話 (本記事)見積 3〜4 週間 → 実 2 日の話
1〜6 話の通低音は「動くはず → 実機で裏切られる → コードを直す」のループでした。第 7 話はその逆で、ループで研いだ道具が「勝手に効く」瞬間の話です。
何を作ったのか(5 つの新機能)
v1.10.0 で追加した機能を、ざっくり一覧にします。

どれもユーザーから見れば「あると嬉しい」機能。開発者から見ると、それぞれ 3 日〜2 週間はかかりそうな規模でした。
事前の見積
v1.9.0 を出した直後に、次に何をやるかのメモを書いていました。

合計 3〜4 週間。特に #4 は「長時間動かしても止まらない」を実現する核心で、一番時間がかかると思っていました。
実際に起きたこと
1 日目(4/29): v1.9.0 GA → v1.9.1 patch
朝から始めて、#1(streaming 集計)と #2(モデル名振り分け)を昼過ぎに完了。
#1 が一瞬で終わった理由: v1.9.0 で非ストリーミング側のトークン集計はすでに作ってあった。ストリーミング側はその「写し」を作るだけで、新しく考えることがなかった。
#2 が一瞬で終わった理由: v1.6.0 で「画像の有無でプロファイルを切り替える」ルーターをすでに作っていた。「画像の有無」を「モデル名」に置き換えるだけで、追加する場所も書き方もまったく同じだった。
ここで v1.9.1 として一旦切り出し。
2 日目前半(5/1 午前): #3 月次予算
予算管理って Redis とか DB がいるのでは? と思うかもしれませんが、CodeRouter は「依存ライブラリ 5 個」というルールを守っています(fastapi / uvicorn / httpx / pydantic / pyyaml だけ)。Redis を入れた瞬間にこの強みが消えるので、メモリ上で管理、プロセス再起動でリセットという割り切りにしました。
個人利用なら 1 ヶ月プロセスを動かしっぱなしにすることが多いので、実用上は問題ありません。
実装自体は、v0.6 で作った「有料プロバイダーをスキップする仕組み」のほぼコピペ。「有料だからスキップ」を「予算超過だからスキップ」に変えるだけ。半日。
2 日目後半(5/1 午後): #4 メモリ + backend 健康、#5 長文ルーティング
ここが事前見積で 1〜2 週間 + 3〜5 日 = 最大 2.5 週間と踏んでいた部分です。
実際にやってみると:
#4 メモリ圧迫ガード: Ollama が VRAM 不足で落ちた時、エラーメッセージに「out of memory」等が含まれるかを見るだけ。見つけたら、そのプロバイダーを一定時間スキップする。仕組みは v1.9.0 で作った「tool ループ検知 → 一時停止」のパターンと同じ。検知する対象が「tool ループ」から「OOM エラー」に変わっただけ。
#4 backend 健康監視: プロバイダーの状態を「健康 → やや不調 → 不調」の 3 段階で追跡する。連続失敗で降格、1 回成功で即復帰。これも構造は同じで、「何を数えるか」が違うだけ。
#5 長文ルーティング: #2(モデル名振り分け)でやった手順をそのまま繰り返し。「モデル名」を「推定トークン数」に置き換えるだけ。
午後いっぱいで 3 つとも完了。夜に v1.10.0 タグを切りました。
なぜ 2 日で終わったのか
振り返ると、5 機能すべてに共通することがあります。
「ゼロから考える部分」がほぼなかった。

第 1 話で Ollama に 3 連敗して doctor probe を直し、第 2 話で偽陽性を踏んで検知ロジックを直し、第 3 話で別のプローブにも同じバグがあることに気づき、第 4 話で「結論が翌日変わる」経験をし、第 5 話で CodeRouter の存在意義を再定義し、第 6 話で検証フロー自体の罠を踏んだ。
その都度、罠を「二度と踏めない仕組み」に変えてコードに埋め込んでいた。guard パターン、ログの型、メトリクスの追加手順、設定スキーマの拡張方法 — 全部が「型」として残っていた。
v1.10.0 の 5 機能は、その型に当てはめるだけだった。
数字で見る

後方互換性は完全維持。新しい設定項目は全部 optional で、何も書かなければ v1.9.x と同じ挙動です。
メタ教訓
連作 1〜6 話のメタ教訓を再掲します:
(1 話) ネットの評判と実機動作は別物
(2 話) 診断ツール自身も診断され続ける必要がある
(3 話) バグは同じツールの別の場所にも繰り返し現れる
(4 話) 結論には賞味期限がある
(5 話) プロダクトの存在意義は環境変化で書き換わる
(6 話) ドキュメントより実装の挙動が真実
第 7 話の教訓:
罠を踏むたびに「踏めない仕組み」に変えていくと、ある時点で新機能の追加コストが急激に下がる。
「フレームワークが成熟する」とはこういうことなのか、という実感がありました。1〜6 話の罠はその時は辛かったけど、全部が v1.10 の 2 日出荷に効いていた。
逆に言えば、罠を踏まずに「正解」だけ積み上げていたら、この速度は出なかったと思います。罠を踏んで、原因を突き止めて、コードの構造で再発を防ぐ、というサイクルを 6 回繰り返したからこそ、7 回目で「型にはめるだけ」になった。
v2.0 に向けて
v1.10.0 で CodeRouter の v1.x 系は一段落です。「6 種類の障害パターン」のうち、v1.x で対処できる 4 つは全部実装しました。
残る 2 つは:
Context overflow: 長時間セッションで会話が膨らみすぎて、モデルの入力上限を超えてしまう問題
Quality drift: 何時間も動かしていると、応答品質が静かに劣化していく問題
これらは「短時間のテスト」では見つからない。長時間稼働して初めて浮き彫りになる障害で、v2.0 系で取り組みます。
第 7 話で「コードが揃った」状態にはなりましたが、「コードが揃った」と「壊れない」は別の話。次はそこに踏み込みます。
CodeRouter のリポジトリ: https://github.com/zephel01/CodeRouter
uvx --from coderouter-cli coderouter serve --port 8088 で v1.10.0 が動きます。Python 3.12 以上、依存 5 個。
いいなと思ったら応援しよう!
サーバー代とコーヒー代になります☕ 役に立ったら応援よろしくお願いします!