先日の記事で作ったという記事を書いたpipeですが、GeminiAPI対応をして色々と楽しくもありましたが、困ったこともあったので共有しておきたいと思います。
1. MacのシステムPythonが3.9
一つ目はMacのシステムPythonが古く、deprecated-generative-ai-pythonしか使えませんでした。リポジトリ名からも分かるように既に非推奨になってしまったライブラリでもあり、最大の問題がオプショナルな引数を受け取ることが出来ないことでした。
Pythone3.9系自体が2025.10にはサポートが切れることもあり、早目にアップグレードした方がいいです。また、現在はgoogle/genaiに移行していることもあり、google-generativeaiを使わないで済むように新規開発をする場合はPythonのバージョンを上げるか、pyenvで開発をする方がいいでしょう。
個人的にはgoogleapis/js-genaiで開発した方が効率が良かったなと思っています。
2. Function CallingとGrounding with Google Searchを併用できない
GeminiAPI自体はデフォルトでは履歴も管理しておらず、与えられたプロンプトに対して推論結果を返すことしか出来ません。そんなAPIに対してファイル操作やWeb検索というツールを与えるのがFunction Callingです。一方でGrounding with Google SearchはGoogleの検索機能をGeminiに追加してくれるものですが、両者のどちらかを選択する必要があります。つまり、ファイル編集をしたい場合はFunction CallingをGoogle検索をした場合はGroundingを選ぶか、GoogleSearchAPIを使って検索を行う、もしくはBot対策をした上で情報を取得する必要があります。
今回はマルチエージェントパイプラインという特性からも相性が良かったsearch_agentというサブエージェントを使う方針で解決しましたが、エージェントの二重化は避けられない点が非常に面倒でした。google_web_search(ツール名)を使う場合はtools/google_web_searchを登録しておいて、サブエージェントを裏で起動するというやり方をとっています。ツールはメンテナンス性を考えて各機能毎にファイルを分ける方法をとっており、以下はsearch_agentのコードです。
def google_web_search(query: str) -> Dict[str, Any]:
"""
Performs a web search using Google Search and returns the results by executing a search agent.
"""
if not query:
return {"error": "google_web_search called without a query."}
try:
# pyenv exec python src/search_agent.py "$query" を実行
# tools/google_web_search.pyから見たプロジェクトルートはPath(__file__).parent.parent
command = f"pyenv exec python {Path(__file__).parent.parent / 'src' / 'search_agent.py'} \"{query}\""
print(f"Executing search agent: {command}")
# サブプロセスを実行し、出力をキャプチャ
process = subprocess.run(command, shell=True, capture_output=True, text=True, check=True)
if process.stderr:
print(f"Search agent stderr: {process.stderr}", file=sys.stderr)
return {"content": process.stdout.strip()}
except subprocess.CalledProcessError as e:
return {"error": f"Failed to execute search agent: {e.stderr.strip()}"}
except Exception as e:
return {"error": f"Failed to execute search agent: {e}"}
3. gemini-cliのナレッジカットオフが古い
今回は基本的にGeminiにコードを書いてもらっていたのですが、gemini-cliの場合は新しくてもナレッジカットオフ(ファインチューニング完了)が2024.06のものしかないため、google-genaiが何者か教えることから始める必要がありました。隙あらば古いgenerativeaiを使おうとするのでそこが面倒でしたね。APIモードで開発しているので、構造化したJSON Schemaを渡して対応してもらって都度直すのが嫌って素のgemini-cliを使っていたこともあり、セッション単位/ターン単位で動的に変更出来るようにすることも今後は考えたいと思います。
結論
GeminiAPIの対応はするつもりがなかったんですが、やりたかったJSON Schema対応が内部でマークダウンに変更されてそう(Gemini談)やツールのトークン計算が出来ないという問題があり、折角だからGeminiAPI対応してしまおうということでやってみました。
正直、簡易チャットエージェントを作ることが目的だったので、そこまでやる必要はあるのだろうかと自問自答しましたが、内部動作を知るいい機会でもあったのでやってみました。結果的にツールがどの様に動くのか?特にGeminiの場合は正規表現でエラーを連発するケースが多々あり、Function Callingで与える関数で軽減することが出来るだろうか?といったことやURLを与えても読まずに無視するのはなぜか?といった背景がよく分かったという意味で非常に良い経験を積むことが出来ました。
ツールを使うだけでなく、作ってみるというのはAI(LLM)を理解するという意味で非常に良いトライアルになると思います。