Skip to content

Prompt API

Prompt API は、本番アプリケーションで大規模言語モデル (LLM) と対話するための包括的なツールキットを提供します。これは以下の機能を提供します。

  • Kotlin DSL: 型安全な構造化プロンプトを作成
  • マルチプロバイダー対応: OpenAI、Anthropic、Google、その他のLLMプロバイダーをサポート
  • 本番環境向け機能: リトライロジック、エラーハンドリング、タイムアウト設定など
  • マルチモーダル機能: テキスト、画像、音声、ドキュメントの処理

アーキテクチャの概要

Prompt API は、主に3つのレイヤーで構成されます。

  1. LLMクライアント: 特定のプロバイダー (OpenAI、Anthropicなど) への低レベルインターフェース
  2. デコレーター (Decorator): リトライロジックなどの機能を追加するオプションのラッパー
  3. プロンプトエグゼキューター (Prompt Executor): クライアントのライフサイクルを管理し、使用を簡素化する高レベルの抽象化

プロンプトの作成

Prompt API は、Kotlin DSL を使用してプロンプトを作成します。以下の種類のメッセージをサポートしています。

  • system: LLMのコンテキストと指示を設定します。
  • user: ユーザー入力を表します。
  • assistant: LLMのレスポンスを表します。

シンプルなプロンプトの例を以下に示します。

kotlin
val prompt = prompt("prompt_name", LLMParams()) {
    // Add a system message to set the context
    system("You are a helpful assistant.")

    // Add a user message
    user("Tell me about Kotlin")

    // You can also add assistant messages for few-shot examples
    assistant("Kotlin is a modern programming language...")

    // Add another user message
    user("What are its key features?")
}

プロンプトの実行

特定のLLMでプロンプトを実行するには、次の手順を実行します。

  1. アプリケーションとLLMプロバイダー間の接続を処理する、対応するLLMクライアントを作成します。例:
kotlin
// Create an OpenAI client
val client = OpenAILLMClient(apiKey)
  1. プロンプトとLLMを引数としてexecute メソッドを呼び出します。
kotlin
// Execute the prompt
val response = client.execute(
    prompt = prompt,
    model = OpenAIModels.Chat.GPT4o  // You can choose different models
)

以下のLLMクライアントが利用可能です。

Prompt API を使用するシンプルな例を以下に示します。

kotlin

fun main() {
    runBlocking {
        // Set up the OpenAI client with your API key
        val token = System.getenv("OPENAI_API_KEY")
        val client = OpenAILLMClient(token)

        // Create a prompt
        val prompt = prompt("prompt_name", LLMParams()) {
            // Add a system message to set the context
            system("You are a helpful assistant.")

            // Add a user message
            user("Tell me about Kotlin")

            // You can also add assistant messages for few-shot examples
            assistant("Kotlin is a modern programming language...")

            // Add another user message
            user("What are its key features?")
        }

        // Execute the prompt and get the response
        val response = client.execute(prompt = prompt, model = OpenAIModels.Chat.GPT4o)
        println(response)
    }
}

リトライ機能

LLMプロバイダーと連携する際、レート制限や一時的なサービス停止といった一時的なエラーに遭遇することがあります。RetryingLLMClientデコレーターは、あらゆるLLMクライアントに自動リトライロジックを追加します。

基本的な使用方法

既存のクライアントをリトライ機能でラップします:

kotlin
// Wrap any client with retry capability
val client = OpenAILLMClient(apiKey)
val resilientClient = RetryingLLMClient(client)

// Now all operations will automatically retry on transient errors
val response = resilientClient.execute(prompt, OpenAIModels.Chat.GPT4o)

リトライ動作の設定

Koog は、いくつかの事前定義されたリトライ設定を提供します:

設定最大試行回数初期遅延最大遅延ユースケース
DISABLED1回 (リトライなし)--開発/テスト
CONSERVATIVE3回2秒30秒通常の本番運用
AGGRESSIVE5回500ミリ秒20秒クリティカルな操作
PRODUCTION3回1秒20秒推奨されるデフォルト

これらを直接使用するか、カスタム設定を作成できます:

kotlin
// Use predefined configuration
val conservativeClient = RetryingLLMClient(
    delegate = client,
    config = RetryConfig.CONSERVATIVE
)

// Or create custom configuration
val customClient = RetryingLLMClient(
    delegate = client,
    config = RetryConfig(
        maxAttempts = 5,
        initialDelay = 1.seconds,
        maxDelay = 30.seconds,
        backoffMultiplier = 2.0,
        jitterFactor = 0.2
    )
)

リトライ可能なエラーパターン

デフォルトでは、リトライメカニズムは一般的な一時的エラーを認識します:

  • HTTPステータスコード: 429 (レート制限)、500、502、503、504
  • エラーキーワード: "rate limit", "timeout", "connection reset", "overloaded"

特定のニーズに合わせてカスタムパターンを定義できます:

kotlin
val config = RetryConfig(
    retryablePatterns = listOf(
        RetryablePattern.Status(429),           // 特定のステータスコード
        RetryablePattern.Keyword("quota"),      // エラーメッセージ内のキーワード
        RetryablePattern.Regex(Regex("ERR_\\d+")), // カスタム正規表現パターン
        RetryablePattern.Custom { error ->      // カスタムロジック
            error.contains("temporary") && error.length > 20
        }
    )
)

プロンプトエグゼキューターでのリトライ

プロンプトエグゼキューターを使用する際は、エグゼキューターを作成する前に基盤となるクライアントをラップします:

kotlin
// Single provider executor with retry
val resilientClient = RetryingLLMClient(
    OpenAILLMClient(System.getenv("OPENAI_API_KEY")),
    RetryConfig.PRODUCTION
)
val executor = SingleLLMPromptExecutor(resilientClient)

// Multi-provider executor with flexible client configuration
val multiExecutor = MultiLLMPromptExecutor(
    LLMProvider.OpenAI to RetryingLLMClient(
        OpenAILLMClient(System.getenv("OPENAI_API_KEY")),
        RetryConfig.CONSERVATIVE
    ),
    LLMProvider.Anthropic to RetryingLLMClient(
        AnthropicLLMClient(System.getenv("ANTHROPIC_API_KEY")),
        RetryConfig.AGGRESSIVE  
    ),
    // Bedrock クライアントには、すでにAWS SDKのリトライ機能が組み込まれています
    LLMProvider.Bedrock to BedrockLLMClient(
        awsAccessKeyId = System.getenv("AWS_ACCESS_KEY_ID"),
        awsSecretAccessKey = System.getenv("AWS_SECRET_ACCESS_KEY"),
        awsSessionToken = System.getenv("AWS_SESSION_TOKEN"),
    ))

ストリーミングでのリトライ

ストリーミング操作はオプションでリトライできます (デフォルトでは無効です):

kotlin
val config = RetryConfig(
    maxAttempts = 3
)

val client = RetryingLLMClient(baseClient, config)
val stream = client.executeStreaming(prompt, OpenAIModels.Chat.GPT4o)

: ストリーミングのリトライは、最初のトークンを受信する前の接続障害にのみ適用されます。ストリーミングが開始されると、コンテンツの整合性を維持するためにエラーはそのまま渡されます。

タイムアウト設定

すべてのLLMクライアントは、リクエストのハングを防ぐためのタイムアウト設定をサポートしています:

kotlin
val client = OpenAILLMClient(
    apiKey = apiKey,
    settings = OpenAIClientSettings(
        timeoutConfig = ConnectionTimeoutConfig(
            connectTimeoutMillis = 5000,    // 接続確立まで5秒
            requestTimeoutMillis = 60000    // リクエスト全体で60秒
        )
    )
)

エラーハンドリングのベストプラクティス

本番環境でLLMを操作する際は:

  1. 予期せぬエラーを処理するために、常にtry-catchブロックで操作をラップしてください
  2. デバッグのために、コンテキスト情報とともにエラーをログに出力してください
  3. クリティカルな操作には、フォールバック戦略を実装してください
  4. システムの問題を特定するために、リトライパターンを監視してください

包括的なエラーハンドリングの例:

kotlin
try {
    val response = resilientClient.execute(prompt, model)
    processResponse(response)
} catch (e: Exception) {
    logger.error("LLM operation failed", e)
    
    when {
        e.message?.contains("rate limit") == true -> {
            // レート制限を特別に処理
            scheduleRetryLater()
        }
        e.message?.contains("invalid api key") == true -> {
            // 認証エラーを処理
            notifyAdministrator()
        }
        else -> {
            // 代替ソリューションにフォールバック
            useDefaultResponse()
        }
    }
}

マルチモーダル入力

プロンプト内でテキストメッセージを提供するだけでなく、Koogではuserメッセージとともに画像、音声、動画、ファイルをLLMに送信することもできます。標準的なテキストのみのプロンプトと同様に、プロンプト構築のためのDSL構造を使用してメディアをプロンプトに追加します。

kotlin
val prompt = prompt("multimodal_input") {
    system("You are a helpful assistant.")

    user {
        +"Describe these images"

        attachments {
            image("https://example.com/test.png")
            image(Path("/User/koog/image.png"))
        }
    }
}

テキストプロンプトコンテンツ

さまざまなアタッチメントタイプをサポートし、プロンプト内のテキスト入力とファイル入力を明確に区別するために、テキストメッセージはユーザープロンプト内の専用のcontentパラメータに配置します。ファイル入力を追加するには、attachmentsパラメータ内のリストとして提供します。

テキストメッセージとアタッチメントのリストを含むユーザーメッセージの一般的な形式は以下のとおりです。

kotlin
user(
    content = "This is the user message",
    attachments = listOf(
        // Add attachments
    )
)

ファイルアタッチメント

アタッチメントを含めるには、以下の形式に従ってattachmentsパラメータにファイルを提供します。

kotlin
user(
    content = "Describe this image",
    attachments = listOf(
        Attachment.Image(
            content = AttachmentContent.URL("https://example.com/capture.png"),
            format = "png",
            mimeType = "image/png",
            fileName = "capture.png"
        )
    )
)

attachmentsパラメータはファイル入力のリストを受け取り、各項目は以下のクラスのいずれかのインスタンスです。

  • Attachment.Image: jpgpngファイルなどの画像アタッチメント。
  • Attachment.Audio: mp3wavファイルなどの音声アタッチメント。
  • Attachment.Video: mpgaviファイルなどの動画アタッチメント。
  • Attachment.File: pdftxtファイルなどのファイルアタッチメント。

上記の各クラスは以下のパラメータを受け取ります。

名前データ型必須説明
contentAttachmentContentYes提供されるファイルコンテンツのソースです。詳細については、AttachmentContentを参照してください。
formatStringYes提供されるファイルの形式です。例: png
mimeTypeStringOnly for Attachment.File提供されるファイルのMIMEタイプです。例: image/png
fileNameStringNo拡張子を含む提供されるファイルの名前です。例: screenshot.png

AttachmentContent

AttachmentContentは、LLMへの入力として提供されるコンテンツのタイプとソースを定義します。以下のクラスがサポートされています。

AttachmentContent.URL(val url: String)

指定されたURLからファイルコンテンツを提供します。以下のパラメータを取ります。

名前データ型必須説明
urlStringYes提供されるコンテンツのURLです。

AttachmentContent.Binary.Bytes(val data: ByteArray)

バイト配列としてファイルコンテンツを提供します。以下のパラメータを取ります。

名前データ型必須説明
dataByteArrayYesバイト配列として提供されるファイルコンテンツです。

AttachmentContent.Binary.Base64(val base64: String)

Base64文字列としてエンコードされたファイルコンテンツを提供します。以下のパラメータを取ります。

名前データ型必須説明
base64StringYesファイルデータを含むBase64文字列です。

AttachmentContent.PlainText(val text: String)

アタッチメントタイプがAttachment.Fileの場合にのみ適用されます。プレーンテキストファイル(text/plainMIMEタイプなど)からコンテンツを提供します。以下のパラメータを取ります。

名前データ型必須説明
textStringYesファイルのコンテンツです。

混在するアタッチメントコンテンツ

異なるタイプのアタッチメントを個別のプロンプトやメッセージで提供するだけでなく、以下に示すように、単一のuserメッセージで複数かつ混在するタイプのアタッチメントを提供することもできます。

kotlin
val prompt = prompt("mixed_content") {
    system("You are a helpful assistant.")

    user {
        +"Compare the image with the document content."

        attachments {
            image(Path("/User/koog/page.png"))
            binaryFile(Path("/User/koog/page.pdf"), "application/pdf")
        }
    }
}

プロンプトエグゼキューター

LLMクライアントがプロバイダーへの直接アクセスを提供するのに対し、プロンプトエグゼキューターは、一般的なユースケースを簡素化し、クライアントのライフサイクル管理を処理する、より高レベルの抽象化を提供します。これらは、次のような場合に理想的です:

  • クライアント設定を管理せずに迅速なプロトタイプ作成を行いたい場合
  • 統一されたインターフェースを通じて複数のプロバイダーと連携したい場合
  • 大規模なアプリケーションでの依存性注入 (Dependency Injection) を簡素化したい場合
  • プロバイダー固有の詳細を抽象化したい場合

エグゼキューターの種類

Koog フレームワークはいくつかのプロンプトエグゼキューターを提供します。

  • 単一プロバイダーエグゼキューター:

    • simpleOpenAIExecutor: OpenAIモデルでプロンプトを実行するため。
    • simpleAnthropicExecutor: Anthropicモデルでプロンプトを実行するため。
    • simpleGoogleExecutor: Googleモデルでプロンプトを実行するため。
    • simpleOpenRouterExecutor: OpenRouterでプロンプトを実行するため。
    • simpleOllamaExecutor: Ollamaでプロンプトを実行するため。
  • マルチプロバイダーエグゼキューター:

    • DefaultMultiLLMPromptExecutor: 複数のLLMプロバイダーを操作するため

単一プロバイダーエグゼキューターの作成

特定のLLMプロバイダー向けのプロンプトエグゼキューターを作成するには、対応する関数を使用します。 例えば、OpenAIプロンプトエグゼキューターを作成するには、simpleOpenAIExecutor 関数を呼び出し、OpenAIサービスでの認証に必要なAPIキーを提供する必要があります。

  1. プロンプトエグゼキューターの作成:
kotlin
// Create an OpenAI executor
val promptExecutor = simpleOpenAIExecutor(apiToken)
  1. 特定のLLMでプロンプトを実行:
kotlin
// Execute a prompt
val response = promptExecutor.execute(
    prompt = prompt,
    model = OpenAIModels.Chat.GPT4o
).single()

マルチプロバイダーエグゼキューターの作成

複数のLLMプロバイダーを操作するプロンプトエグゼキューターを作成するには、次の手順を実行します。

  1. 必要なLLMプロバイダーのクライアントを、対応するAPIキーを使用して構成します。例:
kotlin
val openAIClient = OpenAILLMClient(System.getenv("OPENAI_KEY"))
val anthropicClient = AnthropicLLMClient(System.getenv("ANTHROPIC_KEY"))
val googleClient = GoogleLLMClient(System.getenv("GOOGLE_KEY"))
  1. 構成されたクライアントをDefaultMultiLLMPromptExecutor クラスのコンストラクタに渡し、複数のLLMプロバイダーを持つプロンプトエグゼキューターを作成します。
kotlin
val multiExecutor = DefaultMultiLLMPromptExecutor(openAIClient, anthropicClient, googleClient)
  1. 特定のLLMでプロンプトを実行:
kotlin
val response = multiExecutor.execute(
    prompt = prompt,
    model = OpenAIModels.Chat.GPT4o
).single()