LLMプロバイダー実装とGemini/OpenRouter対応(開発日記 No.090)

に公開

関連リンク

はじめに

昨日はコマンドライン実行の動作検証を終え、今日はかねてから課題だったLLMプロバイダーの実装に取り組みます。複数のLLMを簡単に切り替えられるようにするのが目標です。

背景と目的

現在、LLMを活用したコンテンツ変換処理を開発していますが、特定のLLMプロバイダーに依存した設計になっています。将来的に様々なLLMを利用したいと考え、プロバイダーを抽象化し、柔軟な構成に変更することが急務となりました。今回の実装では、GeminiとOpenRouterをサポートすることを目指します。

検討内容

まずは、必要なインターフェースを定義することから始めました。LLMプロバイダーのベースクラスを設け、各プロバイダーがそれを継承する形にします。設定方法については、APIキーなどの機密情報を安全に管理するため、環境変数からの読み込みを必須とすることに決定。また、レートリミットの問題も考慮し、エクスポネンシャルバックオフの実装も視野に入れることにしました。

実装内容

まず、content_converter/llm/ ディレクトリに、LLMプロバイダーの基本クラス LLMProvider を実装しました。次に、GeminiとOpenRouterのプロバイダーをそれぞれ gemini.pyopenrouter.py に実装。プロンプトの管理を容易にするため、prompts.py にプロンプトテンプレートを定義しました。

# 例: content_converter/llm/gemini.py
class GeminiProvider(LLMProvider):
    def __init__(self, api_key: str):
        self.api_key = api_key

    def generate_text(self, prompt: str) -> str:
        # Gemini API を使用してテキストを生成するロジック
        pass

テストも重要なので、各プロバイダーに対応したテストケースを tests/ ディレクトリに作成しました。

# 例: tests/test_gemini_provider.py
def test_gemini_provider_generate_text():
    provider = GeminiProvider(api_key="test_api_key")
    result = provider.generate_text("テストプロンプト")
    assert isinstance(result, str)

最後に、content_converter/llm/__init__.py を更新し、新しいモジュールをインポート。requirements.txt に必要なライブラリを追加しました。

技術的なポイント

今回の実装で特に意識したのは、抽象化とエラーハンドリングです。LLMProvider をベースクラスとすることで、新しいプロバイダーの追加が容易になりました。また、APIキーの管理には環境変数を使用し、セキュリティを確保。レートリミット対策として、エクスポネンシャルバックオフの実装を検討中です。

所感

LLMプロバイダーの実装は、予想以上にスムーズに進みました。抽象化の設計がうまくいったおかげで、GeminiとOpenRouterのプロバイダーを比較的簡単に実装できました。テストも全てパスし、カバレッジも100%を達成できたのは大きな成果です。ただ、エクスポネンシャルバックオフの実装は今後の課題として残りました。色々なLLMを試せる基盤ができたので、今後の開発が楽しみです!

今後の課題

  • エクスポネンシャルバックオフの実装
  • より多くのLLMプロバイダーのサポート
  • ドキュメントの充実
  • エラーハンドリングの改善

まとめ

今日は、LLMプロバイダーの実装を行い、GeminiとOpenRouterに対応しました。抽象化された設計により、今後の拡張性が高まりました。テストも全てパスし、安定した基盤を構築できました。今後は、エクスポネンシャルバックオフの実装や、より多くのプロバイダーのサポートに取り組んでいきます。

GitHubで編集を提案

Discussion