個人開発でAIバックエンドを回していると、レスポンスの速さと同じくらい「一台のサーバーでどれだけリクエストを捌けるか」が効いてきます。私自身、複数のアプリからGemini APIを叩く小さな中継サーバーを Go で書き直したところ、常駐メモリと起動時間の両方が目に見えて軽くなりました。goroutine による並行処理と、単一バイナリで完結する配布のしやすさ。この2点が、Go を選ぶ静かな決め手になっています。
扱うのは、Google 公式の Go SDK(google.golang.org/genai)を使った実装です。テキスト生成からマルチモーダル画像解析、ストリーミング、マルチターン会話まで手を動かし、そのうえで入門記事では省かれがちな並行リクエストのレート制御・タイムアウト設計・モデル選定という、本番で必ずぶつかる論点まで踏み込みます。
Go の基本文法を理解していれば、AI API の利用経験は問いません。全体像を先に押さえたい方は、Gemini API クイックスタートもあわせてご覧ください。
# プロジェクトディレクトリの作成mkdir gemini-go-app && cd gemini-go-app# Go モジュールの初期化go mod init gemini-go-app# Google Gen AI Go SDK のインストールgo get google.golang.org/genai
API キーの設定
API キーは環境変数 GEMINI_API_KEY として設定します。SDK がこの環境変数を自動的に読み取るため、コード内にキーを直接記述する必要はありません。
GenerateContentStream は Go 1.23 の range-over-func(イテレータ)パターンに対応しており、for ... range で簡潔に書くことができます。ストリーミングの詳しい実装パターンについては、ストリーミング応答とマルチターン会話の実装ガイドも参考になります。
Gemini API のエラーハンドリングについてさらに詳しく知りたい方は、Gemini API のエラーハンドリングとリトライ設計で網羅的に解説しています。
goroutine で並行リクエストを捌く — セマフォによるレート制御
Go の魅力は並行処理にありますが、Gemini API には毎分あたりのリクエスト数(RPM)の上限があります。何も考えずに goroutine を大量に起動すると、すぐに 429 RESOURCE_EXHAUSTED に阻まれます。ここで効くのが、バッファ付きチャネルを使った軽量なセマフォです。同時実行数を明示的に絞りながら、複数プロンプトをまとめて処理します。
package mainimport ( "context" "fmt" "log" "sync" "google.golang.org/genai")// generateBatch は最大 concurrency 本の goroutine で並行生成するfunc generateBatch( ctx context.Context, client *genai.Client, prompts []string, concurrency int,) []string { results := make([]string, len(prompts)) sem := make(chan struct{}, concurrency) // 同時実行数を絞るセマフォ var wg sync.WaitGroup for i, prompt := range prompts { wg.Add(1) go func(idx int, p string) { defer wg.Done() sem <- struct{}{} // 空きが出るまでブロック defer func() { <-sem }() // 完了したら枠を返す resp, err := client.Models.GenerateContent(ctx, "gemini-2.5-flash", genai.Text(p), nil) if err != nil { results[idx] = fmt.Sprintf("[error] %v", err) return } results[idx] = resp.Text() }(i, prompt) } wg.Wait() return results}func main() { ctx := context.Background() client, err := genai.NewClient(ctx, nil) if err != nil { log.Fatal(err) } defer client.Close() prompts := []string{ "Go のスライスと配列の違いを一文で", "defer の実行順序を一文で", "チャネルの向き指定の意味を一文で", } for i, out := range generateBatch(ctx, client, prompts, 2) { fmt.Printf("[%d] %s\n", i, out) }}
実装上の指針はシンプルです。まず Flash で組み、品質が要件に届かない箇所だけ Pro に差し替える。最初から Pro を選ぶと、レイテンシもコストも過剰になりがちです。モデル名は設定ファイルや環境変数に逃がしておくと、gemini-2.5-flash と gemini-flash-latest の切り替えがコード変更なしで済み、運用中の比較検証がぐっと楽になります。
まとめ
公式 Go SDK を使えば、テキスト生成からマルチモーダル、ストリーミング、マルチターン会話までは驚くほど短いコードで書けます。そのうえで本番を見据えるなら、並行リクエストのセマフォ制御・呼び出し単位のタイムアウト・実測にもとづくモデル選定という3点が、体験とコストを守る土台になります。