やってみたら思った以上にエンジニアだった公務員の奮闘記― 区職員×都庁ICT職が挑む、生成AIプロジェクト(後編)
API接続で見えた改善ポイントと最適化の工夫
私は東京都のICT職員として、今はGovTech東京に派遣されています。区市町村DXグループに所属し、主に区市町村におけるツールやシステム開発など、先進的な取り組みの推進を支援するとともに、都内全域での共同化を促進する業務を担当しています。
「前編」では、生成AIプラットフォームを活用して法令検索チャットボットのプロトタイプを構築しました。後編では、イケダさんと同じく区市町村DXグループに所属する私が、都のICT職としてAPI接続後の改善プロセスに焦点を当て、どのようにボトルネックを見つけ、改善につなげたのかをお話します。
「APIを叩くとしばらく反応なし、???と思いながら待つこと1分。ようやく返ってきたのでレスポンスを確認したら、あれっ、コストが想定外に多いんですけど…?」
そんな発見から始まった、Difyアプリの改善ストーリーです。
まずはAPI接続してみたら…
前半で作ったアプリは、現場の業務にしっかりフィットしていて「これは使える!」という手応えを感じました。
次のステップとして、このアプリをバックエンドにしたフロントを作成する準備を始めました。アプリとはプロキシを介してAPI接続します。
Difyは使ったことがなく、正直よくわかりませんでした。
でも「API接続の確認ならできる」と思い、ワクワクしながらAPIを叩いてみました。すると、しばらく反応がなくて「大丈夫かな…?」と不安になりながら1分ほど待ち、ようやく返ってきたレスポンスを確認したところ、コストが想定以上にかかっていることに気づきました…。返ってきたけど全然大丈夫じゃ無い…
APIのレスポンスで分かること
APIは、アプリやサービス同士がやり取りするための仕組みです。リクエストを送ると、相手が処理してレスポンスを返してくれます。今回は、Difyに構築した法令AI検索チャットボットにリクエスト(質問)を送ると、レスポンス(回答)が返ってきます。
APIを叩くと返ってくるのはJSON形式のレスポンスです。
JSONは、キーと値のペアで構造化されたデータで、システム間のやり取りに広く使われています。見た目は { "key": "value" } のようなシンプルな書き方ですが、階層構造を持ち、複数の情報をまとめて返せるのが特徴です。
Difyのレスポンスには、質問に対する回答だけでなく、処理に関するメタ情報も含まれています。例えば、どれだけトークンを使ったか、推定コスト、処理時間(レイテンシ)などです。
こうした情報を読み解くことで、「どこでどれだけ時間がかかっているのか」「どこでコストが膨らんでいるのか」といった改善のヒントが見えてきます。
usage情報を見てビックリ
APIのレスポンスに含まれる usage 情報を確認した瞬間、思わず「えっ?」となりました。
prompt_tokens(入力プロンプトで消費したトークン数)が想定以上に大きかったのです。
ここには、入力側の prompt_tokens、出力側の completion_tokens、合計消費トークン数、推定コスト、レイテンシなどがまとまっています。
usageの例
{
"usage": {
"prompt_tokens": 25330, // 入力(プロンプト)で消費したトークン数
"prompt_unit_price": "0.03", // 入力(プロンプト)の単価(係数適用前の基本価格)
"prompt_price_unit": "0.001", // 単価の係数(例: 0.001 = 1/1,000。この係数で単価を調整し、最終価格を算出)
"prompt_price": "0.7599", // 入力側で発生した合計金額(USD)
"completion_tokens": 2656, // 出力(応答)で消費したトークン数
"completion_unit_price": "0.6", // 出力(応答)の単価(係数適用前の基本価格)
"completion_price_unit": "0.000001", // 単価の係数(例: 0.000001 = 1/1,000,000。この係数で単価を調整し、最終価格を算出)
"completion_price": "0.0015936", // 出力側で発生した合計金額(USD)
"total_tokens": 27986, // 全体で消費した合計トークン数(prompt_tokens + completion_tokens)
"total_price": "0.7614936", // 全体で発生した合計金額(prompt_price + completion_price)(USD)
"currency": "USD", // 金額の通貨単位
"latency": 87.826297177001834 // リクエスト開始から完了までの処理時間(秒)
}
}
コスト計算式
prompt_price
= prompt_tokens * prompt_unit_price * prompt_price_unit
completion_price
= completion_tokens * completion_unit_price * completion_price_unit
出力(completion)は単価が高めですが、極端には増えにくいです。
一方で入力(prompt)は参照情報・履歴などの情報を加えていくと簡単に膨らむため、全体コストへの影響が大きくなりがちです。
今回のケースでは、入力プロンプトが圧倒的に多いことが判明しました。
入力の消費トークン数の多さは、そのままコストや応答速度に直結します。
そのため、どの工程でどれだけトークンを消費しているのかを把握することが、改善の第一歩です。
原因を探ってみる
1. 各LLMのトークン消費を可視化
APIのレスポンスの usage 情報を収集し、node_type: "llm" のノードごとに入力・出力トークン数、合計トークン数、レスポンスタイム、推定コストを一覧化しました。
これにより、どのノードがボトルネックになっているかを特定できました。
LLMノード別ダッシュボード例
| LLMノード | prompt_tokens | completion_tokens | total_tokens | latency(s) | total_cost(USD) | cost_share(%) |
|---|---|---|---|---|---|---|
| LLM1 | 8,000 | 120 | 8,120 | 5.2 | 0.001272 | 6.2 |
| LLM2 | 31,000 | 900 | 31,900 | 9.7 | 0.005190 | 23.5 |
| LLM3 | 42,000 | 700 | 42,700 | 10.8 | 0.006720 | 32.9 |
| LLM4 | 20,000 | 400 | 20,400 | 6.6 | 0.003240 | 15.9 |
| LLM8 | 4,300 | 150 | 4,450 | 4.2 | 0.000735 | 3.6 |
2. アプリのフローを構造化
フロー全体を図に起こし、各LLMノードのプロンプトを配置しました。
これで、どのプロンプト(図の赤枠)が入力を膨らませているかが一目で分かるようになりました。
さらに、フローを自分で書き起こすことで、どのように回答を生成しているかだけでなく、設計思想や処理の意図まで理解が深まりました。

(イメージ図)回答生成の流れを示したフローの下に各ブロックの処理内容を補足表示。LLMブロック周辺に実際のプロンプトを記載した図を作成して分析に活用
3. 分析結果
法令全文をそのままプロンプトに突っ込んでいたプロセスが最大の原因でした。
「現場で使えるレベルの回答品質」を最優先し、高精度モデルを採用しましたが、コストが想定以上に高く、レスポンスも遅いことが分かりました。
つまり、入力情報の整理に改善の余地がありました。
とりあえず、まずはシンプルに改善してみた
最初に試したのは、すべてのLLMを安価な言語モデルに切り替えること。
モデルを変えると約200倍差
入力プロンプトが多い場合、モデルを変えるだけで全然変わります
比較例:
| 言語モデル | prompt_unit_price | prompt_price_unit | price(USD)/token | トークン(例) | USD | 円($1=150) |
|---|---|---|---|---|---|---|
| gpt‑4.1 | 0.03 | 0.001000 | 0.00003000 | 50,000 | 1.5000 | ¥225.00 |
| gpt‑4o‑mini | 0.15 | 0.000001 | 0.00000015 | 50,000 | 0.0075 | ¥1.13 |
安い言語モデルに切り替えて、簡単な質問で試してみた結果、問題無さそうな回答を生成。「お、これでいけるかも?」という手応えがありました。
しかし、少し複雑な質問を投げると、あれ…?明らかに間違った回答を生成するケースがちらほら。
どうやら、言語モデルによって回答のニュアンスや精度が変わるようです。
つまり、「安くすればいい」だけでは済まないということ。
ここからが、本格的なチューニングの始まりです。
工夫した改善ポイント
品質を落とさず、コストを下げ、応答速度も確保するために、次の工夫をしました。
1. モデルの使い分けと処理の集約
補助的な処理は安価モデルで対応
→コストを減らし速度も改善された
法令の解釈や最終回答生成は高精度モデルで実行
→コストが増えることを許容して品質確保
複数のLLMを直列で呼んでいた処理を、1回の呼び出しにまとめる設計に変更
→コストを減らして速度も改善された
2. 入力プロンプトの最適化(入力を節約)
知識取得で得られた情報をそのまま渡すのではなく、アプリのフロー内で、Pythonによる処理が可能な箇所(コードブロック)を活用し、後工程に必要な情報だけを抽出・整形するようにしました。
これにより、不要な情報を削除し、入力をコンパクトに保つことができました。
→コストを減らして速度も改善された
3. 実行順序の見直し
前処理結果に依存しないプロセスは、並列処理にして開始を前倒し。
→速度が改善された
検証と調整のプロセス
高精度モデルを使用した時の回答と、チューニング後の回答を、AIに比較分析させることで、品質の変化を定量的に検証しました。
あなたは、東京都内自治体の福祉事務所の品質管理担当です。以下の【入力】に含まれる「質問文」「回答A(高コストモデル)」「回答B(低コストモデル)」を用いて比較評価してください。外部推測・創作は一切せず、入力テキストのみで評価します。
【評価の前提】
- 回答Aを「正解(基準)」と仮定し、回答BをAに対する相対比較で評価します。
- 評価対象は次の3要素:
1) **結論の一致(質問文との整合性)**
- Aを正解と仮定し、BがAと同じ結論かを判定する。
- 判定には質問文の情報も参考にする。
2) **法令・通知の明示性**
- 法律名、条番号、通知名、番号、発出日、実施要領の章節が明記されているか。
3) **引用の構造化と実務要素**
- 原文+要約ペア、判断手順、必要証憑、重複給付不可、最も経済的な方法、決裁調書要素が含まれているか。
【出力要件】
1. **一致度評価(5段階)**
- 判定ラベルと基準:
- **5=完全一致**:結論・法令・引用・実務要素がAと同等、矛盾なし。
- **4=ほぼ一致**:軽微な不足(例:通知発出日欠落)以外は同等、結論は一致。
- **3=部分一致**:複数不足(条番号やペア提示不足、手順が薄い)、結論は一致。
- **2=かなり不足**:重要要素多数欠落(根拠・手順・証憑)、結論は曖昧。
- **1=大きく異なる**:結論不一致、または矛盾・誤りあり。
- **判定理由には、質問文と回答の整合性、A/B差分に加え、Bを参考にした場合にAと異なる判断をするリスクがあるかどうかも記載する。**
2. **差分の総括(Aを正としてBの不足を具体列挙)**
- 法令・通知の明示性:不足項目
- 引用の構造化:不足項目
- 実務要素:不足項目(質問文に照らして)
【禁止事項】
- 質問文や外部資料を仮定した推測はしない。入力テキストのみで評価。
- 存在しない条文や通知の創作は禁止。
【入力】
- 質問文:
{{question}}
- 回答A:
{{answer_A}}
- 回答B:
{{answer_B}}
分析結果をもとに、問題箇所の仮説を立て、プロンプトを調整しました。
このプロセスを繰り返すことで、改善の効果を確認しながら進めることができました。
実務者によるユーザーレビュー
アプリの改善は進みましたが、ユーザーが使えるものでなければ意味がありません。
そこである程度改善が進んだ段階で、業務知識のある方(前編記載のイケダさん)にユーザーレビューを依頼しました。
- 実際の業務で使えるか
- 回答の根拠が適切か
- 運用上のリスクがないか
こうした視点でレビューしてもらうことで、技術的な最適化だけでなく、実務に即した品質を確保できました。
最終的にどうなった?
- コスト:4割削減に成功(更なる削減に向けて調整中)
- 品質:ほぼ維持
- 速度:回答待ち時間が約半分に改善
まだ完成ではありませんが、現場のニーズに応えられる形に向けて、着実に前進しています。
GovTech東京で区職員×都庁ICT職が挑んだ生成AIプロジェクト
今回の取り組みは、現場を知る区市町村職員と、技術を担う都のICT職が協力して進めているコラボレーションプロジェクトです。
- 現場の課題感を理解しているからこそ、必要な機能や使いやすさを見極められる
- 技術の知見があるからこそ、最適化や改善をスピーディに進められる
GovTech東京では、こうした協働を通じて、行政サービスの質を高めるためのチャレンジを続けています。
現在も開発を進めている段階ですが、それぞれの強みを活かしながら、より良いプロダクトを目指して試行錯誤を重ねているところです。
今回は、API接続で見えた改善ポイントと、現場視点での最適化の工夫を紹介しました。
行政の現場と技術を「つなぐ」プロジェクト。
区役所で住民対応をしている人がプロトタイプを作り、東京都のICT職が最適化する。
やってみるとこれがものすごくしっくりくる組み合わせでした。
異なる立場の公務員がタッグを組むことで、行政DXに新しい可能性が見えてきた気がしています。
東京都が設立した外郭団体「GovTech東京」のテックブログです。GovTech(ガブテック)は、Government×Technologyの融合させた言葉。このブログでは、行政DXへの技術的挑戦、現場で得た知見、そして組織のカルチャーを発信していきます。govtechtokyo.or.jp
Discussion