Gemini CLIとペアプロし、PDF発注書の自動転記システムを開発した全記録
はじめに
LLMがコーディングを支援する時代、私たちはAIとどう向き合うべきでしょうか?
今回は、GoogleのGemini CLIを「壁打ち相手」兼「デバッグパートナー」として、面倒な事務作業を自動化するWebアプリケーション開発に挑戦してみました。
開発したのは、「PDFで届く発注書を、Googleスプレッドシートに自動転記するシステム」 です。
この記事では、AIとの対話を通じてエラーを解決し、アプリケーションを完成させるまでの、生々しいペアプログラミングの全記録を共有します。
Step 1: 要件定義と技術選定
まず、実現したいことをGeminiに伝えます。
私:
PDFがアップロードされたらOCRで文字起こしし、AI(Gemini)が内容を解析して、Googleスプレッドシートに追記するPythonプログラムを開発したい。
これに対し、Geminiは必要なライブラリ(Google Cloud Vision, Google Sheets, Gemini)と、CLIツールとしての基本的な開発計画を提案してくれました。ここまでは順調です。
Step 2: Web UIの実装とsystemdでの永続化
開発途中で「CLIツールよりWeb UIの方が使いやすい」と考え、Geminiに相談。すぐにFlaskを使ったWebアプリケーションへの方針転換が決まりました。ファイルアップロード画面の実装もスムーズに進み、WebサーバーGunicornとsystemdを使って永続化する段階まで進みました。しかし、ここからが本番でした。
最初の壁:503 Service Unavailable
systemdでサービスを起動した途端、ブラウザに「503 Service Unavailable」が表示されました。
私:
systemdで起動すると503エラーになります。sudo systemctl status myapp.serviceのログを見ると、Flaskアプリ自体は正常に起動しています。
Gemini:
ログの提供ありがとうございます。アプリが起動しているのにApacheから接続できない場合、最も一般的な原因はファイルパーミッションです。Apacheユーザー(www-dataなど)が、あなたのアプリケーションディレクトリやPythonの実行ファイルにアクセスできていない可能性があります。ディレクトリの権限を確認・修正してください。
Geminiの指摘は的確でした。Flaskアプリのディレクトリに実行権限を付与すると、503エラーは解消されました。
次の壁:500 Internal Server Error (メモリ不足)
接続できたと思ったら、今度はPDFの処理中に「500 Internal Server Error」が発生。Gunicornのログには不穏なメッセージが。
Worker was sent SIGKILL! Perhaps out of memory?
私:
500エラーが出ました。ログにPerhaps out of memory?とあります。Gunicornのワーカー数を3から1に減らしましたが、改善しません。
Gemini:
メモリ不足が根本原因のようですね。ワーカー数を減らしても解決しない場合、処理方法の見直しが有効です。PDFをメモリに読み込む代わりに、Google Cloud Storageに一旦アップロードし、Vision APIにGCS上のファイルを直接処理させる非同期アーキテクチャを推奨します。
この提案は正攻法ですが、私はある点が気になっていました。
私:
重要な情報です。python main.pyで手動実行した場合は、メモリ不足エラーは起きません。systemd経由でGunicornで動かした場合のみ発生します。この違いを踏まえて、他の解決策はありますか?
Gemini:
なるほど!それは非常に重要な切り分けです。手動実行時と挙動を近づけるアプローチを試しましょう。Gunicornのワーカータイプを、デフォルトのsyncから、メモリ効率が良いとされる**geventに変更してみてください。また、PDFのOCR処理には時間がかかる可能性があるため、Gunicornのタイムアウト時間**をデフォルトの30秒から120秒などに延長するのも有効です。
この提案が大当たりでした。ワーカータイプをgeventに変更し、タイムアウトを延長することで、メモリ不足エラーは完全に解決しました。AIが後からの追加情報で、より深いコンテキストを理解し、提案の精度を上げていく過程は、まさに人間とのペアプロそのものでした。
最後の壁:AIの応答がJSONとして不正
最後に、データ抽出に使うGeminiモデルを、高速なgemini-flashから高精度なgemini-proに変更したところ、json.loads()でエラーが発生。
私:
gemini-proの応答がJSONとしてパースできません。ログを見ると、応答テキストの末尾に```のような余計な記号が付いています。
Gemini:
gemini-proは、より丁寧に応答を生成するため、説明文やマークダウンのコードブロック記号を含めてしまうことがあります。堅牢性を高めるため、応答テキスト全体をJSONとしてパースしようとせず、正規表現などを使って{で始まり}で終わる最初の部分文字列だけを抽出してから、JSONとしてパースする方法に切り替えましょう。
この修正により、AIの応答形式の揺らぎに強い、安定したデータ抽出処理が完成しました。
まとめ:AIは粘り強いデバッグパートナーである
今回の開発を通じて、AI、特にGemini CLIは、単なるコード生成器ではないことを実感しました。
- 仮説提案: エラーログから、可能性の高い原因を即座にリストアップしてくれる。
- 軌道修正: 「手動実行ならOK」といった追加情報(コンテキスト)を与えることで、より精度の高い解決策を再提案してくれる。
- 堅牢性の向上: エラーの根本原因(応答形式の揺らぎなど)を指摘し、より安定した実装方法を提案してくれる。
もちろん、最終的な判断を下すのは人間です。しかし、思考の壁打ちとデバッグの選択肢を高速で提供してくれるAIは、間違いなく開発者の生産性を劇的に向上させる、最高のパートナーになり得ると感じました。
この記事で紹介した内容以外にも、技術情報をブログで発信しています。
MEANTECH
Discussion