はじめに
前回の記事で、AIトレーナー「かな」を自作して20kg痩せた話を書いた。
きれいにまとめたが、裏側は失敗だらけだった。
「これで速くなるはず」「これで品質が上がるはず」— 自信満々で実装した技術が、計測したら逆効果だったことが何度もある。
この記事では、実装して、計測して、捨てた技術を5つ紹介する。捨てたのは技術そのものだけではない。自分の検証結果を捨てた話も、参照画像を量産する作戦を捨てた話もある。
成功談より失敗談の方が他人の役に立つと信じているので、数字ごと全部さらす。
前提: どんなシステムか
- Discord Bot(EC2上のPython常駐プロセス)
- LLMはAmazon Bedrock経由のClaude(Converse API + Tool Use)
- AIが自律的にツール(計算機・Web検索・スプレッドシート書き込み等)を呼ぶエージェント構成
- 詳細は前回記事参照
なお、レイテンシ計測は個人環境での実測(サンプル数少なめ)。厳密なベンチマークではなく「個人開発者が計測して意思決定した記録」として読んでほしい。
1. 3フェーズアーキテクチャ:入力トークンを減らしたら3倍遅くなった
前提: ツールを使うAIは、同じコンテキストを何度も再送している
まず前提の説明から。
このBotでは、LLMが必要に応じてWeb検索(WebSearch)や計算機(Calculate)などのツールを呼び出す。例えばカレーのカロリーを調べたり、摂取カロリーと消費カロリーの差分を計算したりする。
LLMはカロリー収支の暗算をよく間違えるので、四則演算だけは専用ツールに逃がしている。
AIがこれらのツールを使う時、裏側では次のようなループが回っている。
ポイントは、LLMのAPIは状態を持たないこと。ツールの実行結果を渡すには、会話の全コンテキストに結果を付け足して、もう一度丸ごと送り直すしかない。このAPI呼び出し1回分を、この記事では「ラウンド」と呼ぶ。
やりたかったこと
このBotのコンテキストは、システムプロンプト+会話履歴+長期記憶+記録データで約40,000文字。ツールを1回使うたびにこれを再送する。calculateを4回呼べば、合計5ラウンド×40,000文字。明らかに無駄に見える。
そこで処理を3フェーズに分離した。
旧方式: 同じ処理を1+N回
3フェーズ方式: フェーズごとに役割を分ける
理論上、フル送信が5回→2回になる。コスト60%減、レイテンシも大幅改善のはず。
実測結果
旧方式(単一ループ): 17-27秒
3フェーズ方式: 42-157秒 ← ???
悪化した。それも大幅に。
なぜ悪化したか
フェーズ1の「もうツール不要だよね?」という判断だけで15-18秒かかった。軽量コンテキスト(フルの1/20)に削ったのに、である。
後日、この現象を切り出して追試した。同じ質問を、システムプロンプト約1,800字と約40,000字の2水準で3回ずつ実行(Opus 4.8)。
| 入力トークン | TTFT平均 | 合計時間平均 |
|---|---|---|
| 1,781 | 2.0秒 | 12.3秒 |
| 39,017 | 2.7秒 | 14.1秒 |
入力を22倍にしても、応答時間は15%しか変わらなかった。LLMの1呼び出しには、入力量にほぼ依存しない固定のコストがある。
つまり、コンテキストを削っても1呼び出しは速くならない。一方で呼び出し回数を増やせば、1回あたり10秒超の固定コストが丸ごと純増する。「軽量コンテキスト×N回」は構造的に負ける設計だった。
旧方式は「判断」と「応答生成」を1回のAPI呼び出しで同時にやっていた。「判断だけのラウンド」が存在しない分、構造的に速かったのだ。
なお実測の42-157秒という大きなブレには、フェーズ2(応答生成)が19-127秒とバラついた影響もある。ツール結果を変則的なテキスト要約形式で渡していたのが原因の可能性があるが、断定はできていない。ただ、上記の構造的敗因だけで撤退判断には十分だった。
学び
入力トークン削減 ≠ レイテンシ削減。ラウンドを増やす最適化は、固定オーバーヘッドで簡単に相殺される。
ちなみに実際に効いたのは「calculate配列化」だった。これだけでこれまでは消費カロリーと朝昼晩の摂取カロリーを出す4回の足し引きで4回呼んでいたcalculateツールを1回でまとめてできるようにしたのだ。ただ足し算をするだけのラウンドは取るに足らないと思っていたが、ラウンドを減らす方向が正解で、必要なのは「4回のツール呼び出しを1回にまとめてください」とツール定義に書くだけ。実装は5分だった。3フェーズに費やした数時間を返してほしい。
2. thinking制御:「効果なし」と結論した検証自体が、間違っていた
この章で捨てたのは技術ではなく、自分の検証結果だ。少し毛色が違うが、5つの中で一番高くついた失敗かもしれない。
やりたかったこと
使用モデル(Claude Fable 5)はextended thinking(応答前の内部推論)がデフォルトON。応答まで毎回20-40秒かかる。
「雑談にthinkingは要らないのでは? 思考量を下げれば速くなるのでは?」という仮説を立てた。
Bedrockではeffortパラメータ(low/medium/high)でthinking量を制御できる。ちなみにこのモデルはadaptive thinkingのみ対応で、thinking完全OFFは400エラーになる(これも試して分かった)。
1回目の検証:「effortは効かない」と結論
雑談プロンプトを各effort 2回ずつ実測した。
low: 平均21.7秒
medium: 平均32.3秒
high: 平均18.9秒 ← 最速
effortを下げても速くならない。outputTokensも全effortでほぼ同じ(530〜580)。
「雑談レベルではそもそもthinkingが発生していない。effortは意味がない」と結論し、effort設定を削除してデフォルトに戻した。
この結論が、半分間違っていた。
2回目の検証:プロンプト複雑度を変えたら、真逆の結果が出た
後日、検証をやり直した。今度は「雑談」と「複雑な論理パズル」の2水準×各effort 3回、条件をインターリーブして実行。
※1回目とは計測時期・プロンプトが違うため絶対値は比較できない(雑談の秒数が1回目より速いのはそのため)。見てほしいのはeffort間の傾向。
プロンプト effort 合計時間(平均) TTFT outputTokens
──────────────────────────────────────────────────────
雑談 low 8.9秒 2.5秒 257
雑談 medium 10.3秒 2.5秒 302
雑談 high 10.7秒 2.5秒 307
複雑 low 22.8秒 2.5秒 1,122
複雑 medium 48.8秒 33.5秒 2,481
複雑 high 52.9秒 38.7秒 2,765
- 雑談: effort無関係。全条件でTTFT約2.5秒、thinkingほぼゼロ。1回目の結論はここだけ見れば正しかった
- 複雑タスク: effortが劇的に効く。lowはthinkingをスキップして22.8秒、medium/highは30秒以上thinkingしてから応答を生成し約50秒。lowが2倍以上速い
1回目の検証は「雑談プロンプト1種類」しか試していなかった。adaptive thinkingは入力の複雑さに応じて発動を決めるので、thinkingが発動しない入力でeffortを変えても差が出ないのは当たり前だった。検証設計のミスで「effortは効かない」という間違った一般化をしていた。
では、lowで品質は落ちるのか
ここで偶然が仕事をした。検証に使った論理パズルが、私の作問ミスで解なし(どのケースでも条件が成立しない矛盾パズル)だったのだ。
これは図らずも最高の品質テストになった。「矛盾に気づけるか」をlow vs highで比較できる。
結果:両方とも矛盾を正しく検出した。 全ケースを場合分けし、「条件を満たす解が存在しない」と結論し、構造的な理由まで説明した。
実際の回答の結論部分を抜粋する。
effort=lowの回答(18.4秒):
すべてのケースで真実を言う人が2人になり、「真実は1人だけ」という条件を満たす犯人は存在しません。
(中略)
※もし条件が「1人だけが嘘を言い、残り3人が真実」であれば、ケース4(Dが犯人、嘘つきはDのみ)が唯一の解として成立します。おそらく本来はそちらの設定と思われます。
effort=highの回答(72.2秒):
発言をよく見ると、**2組の「否定ペア」**になっています。
- AとB:A「Bが犯人」⇔ B「私(B)は犯人でない」→ 互いに正反対の主張なので、必ずどちらか一方だけが真実
- CとD:D「Cの発言は嘘だ」→ Cの否定なので、必ずどちらか一方だけが真実
したがって、犯人が誰であっても真実を言う人は必ずちょうど2人になり、「真実を言うのは1人だけ」という条件は絶対に成立しません。
どちらも矛盾を見抜き、出題ミスの可能性まで指摘している。highの方が説明の構造化はわずかに丁寧だが、結論の正しさは同じ。
差が出たのはコストと時間だけ。
low: 18.4秒 / 922トークン
high: 72.2秒 / 3,421トークン
同等の品質の答えを、highは約4倍の時間と課金対象outputTokensを使って出した。 回答文の長さはほぼ同じだが、thinkingトークンもoutputTokensとして計上されるため、見えない思考にトークンを使っていることになる。(もちろんこれは1タスクでの結果。より高難度の問題ではhighが勝る可能性は残る)
学び
「効果がなかった」という検証結果は、「試した条件では」という限定付き。条件を1水準しか振っていない検証は、検証になっていない。
この章で捨てたのは、effort設定そのものではなく「1回目の検証結果」だ。
では、Botにeffort=lowを入れたのか
入れなかった。理由は2つある。
理由1: そもそも恩恵を受ける場面が稀。
このBotの会話の大半は、食事の報告・体重の記録・雑談だ。今回の検証で分かった通り、この種の入力ではthinkingが元々発動しない。つまり、この種の入力ではlowにしてもほぼ速くならないし、highのままでも余計なthinkingコストはほぼ発生しない。コストがかさむのは、thinkingが実際に発動する複雑タスクの時だけだ。
理由2: 数少ない複雑タスクが、よりによって品質リスクの核心。
では複雑タスクは何かというと、「今夜の食事提案」「減量計画の立て直し」「今後の見通し」。この種のタスクには嫌な性質がある。
劣化しても気づけない。
カロリー計算なら間違いは数字でバレる(そもそも計算はcalculateツールに委譲済みでthinking非依存)。だが提案が浅くなっても、出てくるのはもっともらしい提案文で、表面上は分からない。じわじわ質が下がり、気づいた頃には原因を特定できない。正直、得意分野ならまだしも、栄養や運動や人体の仕組みに関して、私には高度なAIの推論の正しさを評価することはできない。——これがシンギュラリティなのか?いや、ただの無知である。
整理するとこうなる。
| Botのワークロード | 頻度 | lowの効果 |
|---|---|---|
| 記録・雑談 | 大半 | 速くならない(thinking元々ゼロ) |
| 提案・計画・見通し | 稀 | 速くなるが、品質劣化を検出できない |
利得はほぼ発生せず、リスクは価値の中核にだけ乗る。 この非対称性なら見送り一択だった。せっかく過去のユーザーの傾向や体重の推移など貴重な情報持たせているのに、それをもとにした提案力を妥協することはできない。それっぽい会話ができればいいのであれば、そもそもFable 5ではなくHaikuで十分なのだ(Haikuは会話の品質も低かったので見送ったのだが)。
逆に言えば、複雑タスクが高頻度で、かつ出力の正しさを機械的に検証できる用途——分類、抽出、コード生成など——ならlowは有力な選択肢だと思う。Fable 5はlowでも悪くない結果を出しそうだし。要はワークロードの実態や品質を見極めて決めることだ。
3. プロンプトキャッシュ:3回失敗して、4回目で82%ヒット
やりたかったこと
Bedrockのプロンプトキャッシュ。cachePointまでのプレフィックスが前回と一致すれば、入力処理をスキップできるので、レイテンシもコストも大幅に下がるはず。固定プロンプトや過去の会話履歴など入力に繰り返しの多い会話Botには相性が良く、かなり期待していた機能だった。公式ドキュメントを読む限り、設定するだけで効きそうに見える。
現実は4回見直しが必要だった。
前提1: このBotが毎回LLMに送っているもの
キャッシュの話をする前に、このBotがLLMに何を送っているかを説明しておく。細かい構成は省くが、大きく3種類ある。
| 種類 | 中身 | 変わる頻度 |
|---|---|---|
| 固定プロンプト | キャラ設定・応答ルール・ツール定義 | ほぼ変わらない |
| 動的プロンプト | 現在時刻・天気・関連する長期記憶の検索結果 | 毎回変わる |
| 会話履歴 | 直近30件のやり取り | 毎回少し変わる(毎ターン末尾の会話が追加され、冒頭の会話が削除される) |
合計で約40,000文字。これを毎ターン送っていた。このうち大部分(固定プロンプト+会話履歴)は前回とほぼ同じ内容の再送なので、キャッシュが効けば大幅なコスト削減になる——はずだった。
前提2: キャッシュの条件はモデルごとに違う
もう1つ、ハマりの土台になった前提。プロンプトキャッシュは「対応モデルかどうか」だけでなく、キャッシュのTTL(保持時間)がモデルごとに異なる。 そしてチャットボットにとって、このTTLが死活問題になる。
私が使ってきたモデルの条件はこうだった(2026年7月11日時点)。
| モデル | キャッシュ対応 | TTL | チャットボットでの実用性 |
|---|---|---|---|
| Claude Opus 4.8 | ✗ 非対応 | — | 論外(これで1回目の失敗) |
| Claude Sonnet 5 / Opus 4.6 | ○ | 5分 | ほぼ効かない(下記) |
| Claude Fable 5 | ○ | 1時間 | 実用になる |
なぜ5分では効かないのか。キャッシュは「前回のリクエストからTTL以内に、同じプレフィックスで叩く」ことで初めてヒットする。APIを連打するバッチ処理なら5分で十分だ。だが人間相手のチャットボットは、会話のターン間隔が平気で5分を超える。 メッセージを送って、返事を読んで、食事をして、30分後に次を送る——その間にキャッシュは消えている。次のターンは毎回コールドスタートだ。
つまり私のユースケースでは、TTL 1時間のモデル(Fable 5)に移行したことが、キャッシュがそもそも成立する前提条件だった。 5分TTLのモデルで同じ構成を組んでも、連続した会話以外ではほぼヒットしない。
この後の試行錯誤は「1時間TTLが使える」前提での話として読んでほしい。
失敗の歴史
1回目:cache_readが常に0
当時のモデル(Claude Opus 4.8)にcachePointを付けて実行 → 何度やってもcache_read=0。
→ そもそもこのモデルがキャッシュ非対応だった。 対応モデル一覧の確認を怠った完全な凡ミス。
2回目:cache_writeは出るのにcache_readが0
対応モデルに切り替え → cache_write=12,984と書き込みは発生。しかし読み込みは0のまま。
→ 原因:この時点ではプロンプトが固定/動的に分かれておらず、1つのシステムプロンプトに天気・長期記憶・当日データが全部混在していた。1文字でも違えばプレフィックス不一致でキャッシュミス。毎回変わる内容を含むプロンプトは、永遠にキャッシュに当たらない。キャッシュのうち、部分一致すればそこだけキャッシュヒットすると勘違いしていた。
3回目:51%ヒットで頭打ち
プロンプトを固定部分(キャラ設定・ルール)と動的部分(時刻・天気・記憶)に分割し、固定部分の直後にcachePointを配置 → cache_read=15,184、全入力の51%がヒット。
→ 前進。しかし会話履歴が一向にキャッシュされない。
4回目:82%ヒット達成
原因は2つあった。
改善前: 会話履歴が永久にキャッシュミス
改善後: 変動要素を境界の後ろへ
-
原因1: 動的プロンプト(記憶検索結果等)が、会話履歴のcachePointより手前に注入されていた。変動要素がキャッシュ境界の手前にあると、そこから後ろは全部ミスする。
→ 対策: 動的プロンプトを最後のuserメッセージの先頭(キャッシュ境界の後ろ)に移動 -
原因2: 会話履歴を「直近30件」で取得していたため、会話が進むたびに先頭の2件(ユーザー発言+AI応答)がスライドして消える。プレフィックスの先頭が毎回変わるので一致しない。
→ 対策: 会話が1往復進むと履歴は2件増える。そこで連続会話中に限り会話履歴上限も+2ずつ増やす。次のターンでは、前回のユーザー発言とAI応答も会話履歴に含まれる一方で、履歴の先頭は動かない。プレフィックスが安定してキャッシュが当たる。
ターン1: cache_read=0, cache_write=27,672 ← 初回書き込み
ターン2: cache_read=27,672, cache_write=600 ← 全部ヒット!
ターン3: cache_read=28,272, cache_write=961 ← 増分だけ書き込み
全入力の82%がキャッシュヒット。リクエストあたりの実効コストは約57%削減。
※ 図では簡略化しているが、実際はcachePointを3箇所に置いている。稀に固定部分が変わっても境界ごとに置いておくと部分ヒットでそこだけは回収できるためだ。
意外な落とし穴
レイテンシはほぼ変わらなかった。 キャッシュ導入前後で、通常会話の応答時間は40秒前後のまま。
入力処理のスキップで縮むのは2-4秒程度。§2で書いた通りこのモデルは出力生成が支配的なので、誤差に埋もれた。プロンプトキャッシュはコスト削減の手段であって、体感速度はほぼ改善しない(少なくともこの構成では)。
学び
キャッシュの鉄則:「変動要素は必ずキャッシュ境界より後ろに置く」。1文字の違いも許されない完全一致の世界。
4. Discordストリーミング応答:edit型は読めたものじゃなかった
やりたかったこと
応答速度を上げたいと試行錯誤してきたが、逐次応答をくれれば体感的には改善される。そしてBedrockにはストリーミング応答機能がある。そこで、ChatGPTのような、応答がリアルタイムに流れてくる体験をDiscordで再現したい。
Discord APIにはメッセージ編集(edit)があるので、「まず空メッセージをsend → ストリーミングで受信したテキストを逐次editで追記」すれば実現できる。素直に考えればこの設計になる。
実装して分かった問題
①画面がガタガタ動いて読めない。 editでメッセージが伸びるたびに表示がジャンプする。読んでいる途中の行が画面外に飛んでいく。特にスマホでひどい。
②そもそも逐次表示の恩恵が薄い。 §2で書いた通り、使用モデルは複雑な入力だとthinkingが先に走り、その後テキストを生成する。つまり待ち時間の前半は何も表示されず、その後ドバッと流れる。ChatGPT的な「ぽつぽつ表示」にならない。
試した方式と結果
| 方式 | 結果 | 理由 |
|---|---|---|
| edit型(1メッセージを逐次edit) | ✗ | 画面ジャンプで読めない |
| 生成完了後にまとめて分割送信 | ✗ | 何も変わらない |
| send型・空行で単純分割 | ✗ | 箇条書きで回答する際にタイトル行が単独送信される等、細切れで不自然 |
| send型・空行区切り+短い塊は結合 | ✅ | 意味のまとまりごとに届く |
採用した方式は「空行(\n\n)で区切りつつ、100字未満の塊は次の塊と結合してから送信」。
実例:517字の応答が4チャンク(103字/155字/142字/111字)に分割された。箇条書きの途中で切れない。
結論:チャンクごとの逐次出力は可能になったが、前述の通り書きだすまでが長いので、正直使用感としてはあまり改善しなかった。
send型にも残った問題
DiscordのUIは読んでいる途中で新規メッセージが来るとその分だけ上にスクロールされ読んでいる途中で流れていくという致命的な問題がある。最終的には、応答の結合目安を逐次変更する実装にした。具体的には1チャンク目は100文字→2チャンク目は200文字→3チャンク目は300文字とした。これにより、レイテンシは短く見えるがログが流れる頻度は落とすことができた。
学び
ストリーミングUIは「配信プラットフォームの表示挙動」とセットで設計する。APIでできること(edit)と、体験として成立すること(send+意味単位分割)は別物。
そもそもDiscord botではなくLine botにすればしなくてよい苦労だった。
レイテンシは重要な課題なので今後も試行錯誤していくことになるだろう。
5. Nova Canvasでキャラの顔を固定してポーズは自由に:ありものでは無理だった
やりたかったこと
AIトレーナー「かな」の画像を送ってくる機能がある(本人が自律的にツールを呼ぶ)。この画像を、同じ顔のまま文脈に合った場面・ポーズで生成したい。ジムで話している時は運動着、料理の話ならキッチン、おやすみの挨拶なら寝る前の姿——キャラクターの一貫性が「伴走してくれる相手」の実在感を支えるからだ。
Amazon Nova CanvasのIMAGE_VARIATION(参照画像+類似度パラメータで画像生成)で試行錯誤した。
試行錯誤の記録
第1ラウンド: similarityStrengthの調整
| 設定 | 結果 |
|---|---|
| similarityStrength=0.5 | 顔が明らかに別人になる |
| similarityStrength=0.6 | 顔はギリギリ保てる。ただし服やポーズが参照画像に固定される |
| さらに下げてポーズ自由化 | 顔が崩れる |
「顔」と「ポーズ」が1つのパラメータに同時にぶら下がっていて、独立に制御できない。上げれば両方固まり、下げれば両方崩れる。
ベースとして登録した参考画像
「スーツを着てカロリー計算しガッツポーズをして」
similarityStrength=0.6。顔はギリギリ保てる。ただし服が参照画像に固定される。
「スーツを着てカロリー計算しガッツポーズをして」
similarityStrength=0.5。顔が明らかに別人になる。
第2ラウンド: 参照画像を増やして場面バリエーションを確保
パラメータで無理なら、場面別の参照画像を複数用意すればいい。ジム・キッチン・部屋着・スーツ……と参照画像を作り始めた。
ここで新たな問題が2つ。
1つ目。場面別の参照画像自体をどう作るか。「同じ顔で服だけ違う」画像を生成で作ろうとすると、その生成でまた顔が変わる。ニワトリと卵だ。最終的に、元画像から服を差し替える手作業の雑コラで参照画像を量産した。個人開発の闇である。
2つ目。苦労して雑コラ参照を用意しても、そこから生成すると、なぜか顔が大きく変わるケースがある。雑コラの品質が影響しているのか、参照画像との相性なのか、原因は特定できなかった。そもそも同じ参照画像・同じ設定でも生成のたびに顔は微妙に揺れる。「同じ顔」の再現は、期待していたレベルでは元々成立していなかった。
スーツ用参考画像として作った雑コラ。
雑コラ参考画像をもとに生成されたかな。なぜ。
第3ラウンド: コンテンツフィルターの壁
おやすみの挨拶用にベッドのシーンも用意した。もちろん変な意味は無いのだが、これは画像生成モデルのコンテンツフィルターに弾かれた。「ベッド+女性キャラクター」の組み合わせは、プロンプトを工夫してもブロックされることが多く、安定運用は無理と判断して廃止した。
ちなみに、上記以外でも、画像生成の際によくコンテンツフィルターに弾かれているようだ。繰り返しになるが変な意味のない健全な指示しかしていないにも関わらず、である。厳しいコンテンツフィルターと女性トレーナーは相性が悪いのだろう。だが、フィルターに弾かれるとそのエラーメッセージを受けてAIが自律的に画像生成プロンプトを書き換えてツールループの中で改善し、結果的に適切な画像を出してくれるので、少なくとも運用上は、最終的に画像が出ないケースはほとんどなかった。この問題に気付いたのも、上記のツールループの繰り返し数を調べている際にログをみてたまたま気づいたほどだ。
結論: ありものでは、キャラクターの自由なポーズ変更は無理
3ラウンドの試行錯誤の末の結論はシンプルだった。マネージドな画像生成サービスをそのまま使う範囲では、「同じキャラクターを自由な場面・ポーズで出し続ける」ことはできない。
- パラメータ(similarityStrength)は顔とポーズを独立制御できない
- 参照画像を増やす作戦は、参照自体の製造とフィルターの壁がある
- そもそも同一設定でも顔は揺れる
本当にやるなら、Face Swap(外部ライブラリ)やLoRA(キャラクターの顔を学習)といった専用の仕組みが要る。今回は「AWSマネージドサービスの範囲でやる」方針だったので見送った。
落とし所
similarityStrength=0.6で顔を守りつつ、生き残った4場面(ジム・キッチン・部屋着・スーツ)の参照画像をS3に置き、AIが会話の文脈で選ぶ形にした。ポーズはほぼ固定だが、「文脈に合った姿で登場する」体験としては成立している。顔は違うけど、たまに似るのでよしとする。人間だって写真写りでだいぶ変わるし。
正直に言うと、この結論に至るまでに同じ検証を2回やりかけた。「もしかしたらいいパラメータがあるのでは」と。「構造的に無理」という結論はドキュメントに残さないと、忘れた頃にまた同じ袋小路に入る。
学び
「パラメータのどこかに最適解がある」とは限らない。要素技術の検証(顔は保てるか)だけでなく、運用全体(参照画像の製造、フィルター、生成の揺れ)まで通して初めて「できる/できない」が言える。そして「できない」という結論こそ記録に残す。
まとめ
5つの失敗に共通するのは、直感で「良さそう」と思った設計が、計測で否定されたこと。
| 直感 | 現実 |
|---|---|
| 入力トークンを減らせば速くなる | ラウンド純増で3倍遅くなった |
| 「効果なし」の検証結果は信じていい | 条件を1水準しか振っておらず、結論が覆った |
| キャッシュは設定すれば当たる | 配置を間違えると永久にミス |
| edit型がストリーミングの自然な形 | 画面が飛んで読めない |
| キャラ画像はパラメータ調整でどうにかなる | ありものでは「同じ顔で自由なポーズ」は無理 |
LLMアプリはまだ「定石」が固まっていない分野で、Webで調べても答えがないことが多い。だからこそ実装して数字を見るしかない。
幸い、個人開発は「試して捨てる」コストが極端に低い。承認プロセスもリリーススケジュールもない。1時間で実装→計測→不採用、ができるなら失敗は財産だ。
この記事の5つの失敗が、誰かの1時間を節約できれば嬉しい。
いいね・ストックいただけると続編の執筆モチベーションになります。
シリーズ: AIボディメイクトレーナー開発記
- #1 30代95kgのエンジニアがAIトレーナーを自作して20kg痩せた話
- #2 本記事
- #3 pgvector + 深夜バッチで「記憶するAI」を実装した話(近日公開)




