見出し画像

見積 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. (1 話) ネットの評判と実機動作は別物

  2. (2 話) 診断ツール自身も診断され続ける必要がある

  3. (3 話) バグは同じツールの別の場所にも繰り返し現れる

  4. (4 話) 結論には賞味期限がある

  5. (5 話) プロダクトの存在意義は環境変化で書き換わる

  6. (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 個。

いいなと思ったら応援しよう!

zephel01 サーバー代とコーヒー代になります☕ 役に立ったら応援よろしくお願いします!