🛜

【Rust】Azure OpenAI Apiに接続する方法

2025/02/16に公開

【Rust】Azure OpenAI APIと通信する方法

この記事では、Rustのをasync-openaiクレートを用いてAzure OpenAI APIに接続し、チャット形式のリクエストを送信する方法を解説します。async-openaiクレートはopenAIのApiだけでなく、Azure OpenAI API対応しています。


1. 処理の全体の流れ

今回のコード例では、以下の手順でAzure OpenAI APIと通信を行っています。

  1. 環境変数の設定: APIキーやエンドポイント、APIバージョンなどの設定値を.envファイルを読み込み。
  2. Azure API接続の設定: AzureConfigを利用し、Azure OpenAI APIへの接続情報を構築。
  3. リクエストの作成: ユーザーの入力に基づいたチャットリクエストを組み立て。
  4. ストリーミングレスポンスの取得: APIからの応答をストリーム形式で受け取り、最終的なレスポンステキストを生成します。
  5. 結果の出力: 取得した応答をコンソールに表示します。

2. 環境変数と.envファイルの利用

まず、Azure OpenAI APIへの接続情報は環境変数で管理します。これにより、APIキーやエンドポイントなどの機密情報をソースコードから分離し、セキュリティを高めています。

開発時には、.envファイルを作成し、workspaceの環境変数を設定します。Rustでは、dotenvクレートを利用して読み込むことができます。

use dotenv::dotenv;
use std::env;
dotenv().ok();
    let api_key = env::var("AZURE_OPENAI_API_KEY").expect("AZURE_OPENAI_API_KEY must be set");
    let end_point = env::var("AZURE_OPENAI_ENDPOINT").expect("AZURE_OPENAI_ENDPOINT must be set");
    let api_version = env::var("AZURE_OPENAI_API_VERSION").expect("AZURE_OPENAI_API_VERSION must be set");

引用: dotenv crate - Rust Docs


3. Azure OpenAI APIとの接続設定

Azure OpenAI APIに接続するためには、AzureConfigを用いて設定を行います。以下のコードでは、APIキー、エンドポイント、デプロイメントID(ここではgpt-4o-mini)、およびAPIバージョンを指定しています。

let config = AzureConfig::new()
    .with_api_key(api_key)
    .with_api_base(end_point)
    .with_deployment_id("gpt-4o-mini")
    .with_api_version(api_version);

この設定により、Rust側のクライアントはAzure環境にあるOpenAI APIへ正しく接続できるようになります。

参考: async_openai GitHub Repository


4. APIリクエストの作成と送信

次に、ユーザーからの入力に基づいたチャットリクエストを構築します。リクエストは、CreateChatCompletionRequestArgsを利用して組み立て、モデル名やメッセージ内容を指定します。

let request = CreateChatCompletionRequestArgs::default()
    .model("gpt-4o-mini")
    .messages(vec![
        ChatCompletionRequestMessage::User(user_input.to_string().into())
    ])
    .build()?;

このリクエストを送信することで、Azure OpenAI API側でチャット形式の応答が生成されます。


5. ストリーミングによるレスポンスの取得

Azure OpenAI APIからのレスポンスはストリーミング形式で受信されます。ここでは、futures_util::stream::StreamExtを利用して、ストリームから逐次応答内容を取得し、最終的な文字列としてまとめています。

// ストリームでレスポンスを取得
let mut response = client.chat().create_stream(request).await?;
let mut full_response = String::new();

while let Some(item) = response.next().await {
    let stream_response = item?;
    if let Some(choice) = stream_response.choices.first() {
        if let Some(content) = choice.delta.content.as_ref() {
            full_response.push_str(content);
        }
    }
}

この方式により、応答が少しずつ生成される様子をリアルタイムで受け取ることができます。

引用: Futures in Rust - Async Book


メイン関数では、環境変数のロードや非同期関数の呼び出し、結果の表示を行っています。

#[tokio::main]
async fn main() {
    dotenv().ok();
    let user_input = "こんにちは";
    match chat_with_gpt4omini(user_input).await {
        Ok(reply) => println!("GPT-4ominiの応答: {}", reply),
        Err(e) => eprintln!("エラー: {}", e),
    }
}

参考: Error Handling in Rust - The Rust Programming Language


処理の結果 

下記はコードの完成版です。

完成版

use futures_util::stream::StreamExt;
use async_openai::types::{CreateChatCompletionRequestArgs, ChatCompletionRequestMessage};
use std::error::Error;
use async_openai::{Client, config::AzureConfig};
use dotenv::dotenv;
use std::env;
async fn chat_with_gpt4omini(user_input: &str) -> Result<String, Box<dyn Error>> {
    
    let api_key = env::var("AZURE_OPENAI_API_KEY").expect("AZURE_OPENAI_API_KEY must be set");
    let end_point = env::var("AZURE_OPENAI_ENDPOINT").expect("AZURE_OPENAI_ENDPOINT must be set");
    let api_version = env::var("AZURE_OPENAI_API_VERSION").expect("AZURE_OPENAI_API_VERSION must be set");


    let config = AzureConfig::new()
        .with_api_key(api_key)
        .with_api_base(end_point)
        .with_deployment_id("gpt-4o-mini")
        .with_api_version(api_version);
        
    
    let openai_client = Client::with_config(config);
        // reqwestのクライアントを構築(SSL証明書の検証の有無)
    let reqwest_client = reqwest::Client::builder()
        .danger_accept_invalid_certs(false)
        .build()?;

    // reqwestのクライアントを利用してOpenAIクライアントを初期化
    let client = openai_client.with_http_client(reqwest_client);

    let request = CreateChatCompletionRequestArgs::default()
        .model("gpt-4o-mini")
        .messages(vec![
            ChatCompletionRequestMessage::User(user_input.to_string().into())
        ])
        .build()?;

    // ストリームでレスポンスを取得
    let mut response = client.chat().create_stream(request).await?;
    let mut full_response = String::new();
    
    while let Some(item) = response.next().await {
        let stream_response = item?;
        if let Some(choice) = stream_response.choices.first() {
            if let Some(content) = choice.delta.content.as_ref() {
                full_response.push_str(content);
            }
        }
    }
    
    if full_response.is_empty() {
        Err("No content found in the response".into())
    } else {
        Ok(full_response)
    }
}


#[tokio::main]
async fn main() {
    dotenv().ok();
    let user_input = "こんにちは";
    match chat_with_gpt4omini(user_input).await {
        Ok(reply) => println!("GPT-4ominiの応答: {}", reply),
        Err(e) => eprintln!("エラー: {}", e),
    }
}

6. 最後に

async-openaiのdocumentを読んでいたところ、chatだけでなく、Assistantや音声の処理もできそうだったので、意外といろんな実装が出来そう。

Discussion