メインコンテンツまでスキップ

GenAI API の直接利用

LLM、VLM、または ASR モデルがアプリケーションと同じプロセスで実行される場合は、Neat の GenAI API を直接使用します。デプロイされた LLiMa モデルのディレクトリをロードし、GenerationRequest を作成し、完全な結果を待つか、生成されたトークンをストリーミングします。

ブラウザ、サービス、またはリモートクライアントが HTTP 経由でモデルを呼び出す必要がある場合は、代わりに GenAIサーバー を使用してください。どちらのアプリケーション境界を選択するかについては、生成AIモデルの概要 を参照してください。

適切なハンドラーを選択する

ほとんどのアプリケーションでは、GenAIModel から開始します。モデルディレクトリからモデルのタスクを自動的に検出し、以下の機能チェックを公開します。

  • accepts_text()
  • accepts_image()
  • accepts_audio()
  • task()
  • model_id()

アプリケーションがロードするものを知っており、より限定された API を使用したい場合は、タスク固有のハンドラーを使用します。

ハンドラー使用例
genai::GenAIModel自動検出された LLM、VLM、または ASR モデルのディレクトリ。
genai::VisionLanguageModelテキストのみの LLM および画像処理が可能な VLM。
genai::ASRModel音声認識モデル。

テキストリクエストを実行

#include "neat/genai.h"

#include <iostream>

int main() {
simaai::neat::genai::GenAIModel model(
"/media/nvme/llima/models/Qwen3-4B-Instruct-2507-GPTQ-a16w4");

simaai::neat::genai::GenerationRequest request;
request.prompt = "Explain what an API gateway is in one sentence.";
request.max_new_tokens = 64;

auto result = model.run(request);
std::cout << result.text << "\n";
}

run() は同期処理です。生成が完了した後、処理が終了します。これは、テスト、スクリプト、およびリクエスト/レスポンス形式のアプリケーションコードにとって最も単純な形式です。

生成されたトークンをストリームで処理する

呼び出し元が生成された内容をリアルタイムで確認する必要がある場合は、stream() を使用します。各項目は、最新のテキストフラグメント、現在のメトリック、および生成が終了したときの最終ステータスを含む TokenSample です。

simaai::neat::genai::GenerationRequest request;
request.prompt = "Give me three practical tips for designing a small REST API.";
request.max_new_tokens = 96;

simaai::neat::genai::GenerationStream stream_handle = model.stream(request);
for (const auto& token : stream_handle) {
std::cout << token.text << std::flush;
}
std::cout << "\n";

ユーザーがリクエストを閉じたり、プロンプトを変更したり、アプリケーションが生成処理のタイムアウトに達した場合、ストリームに対してcancel()を呼び出します。

VLMに画像を追加する

VLMは、テキストに加えて1つ以上の画像を受け入れます。画像は、単純なプロンプトの場合はGenerationRequest.imagesを介して、チャット履歴を使用する場合はChatMessage.imagesを介して渡されます。

Tensorの値として渡される画像は、uint8形式のHWC RGBテンソルである必要があります。OpenCVのcv::Mat入力は、Neat/OpenCVの規則に従います。つまり、3チャンネルの行列はBGRとして扱われ、リクエストに保存される前にRGBに変換されます。

simaai::neat::genai::VisionLanguageModel model(
"/media/nvme/llima/models/Qwen3-VL-4B-Instruct-GPTQ-a16w4");

cv::Mat image = cv::imread("scene.jpg");

simaai::neat::genai::GenerationRequest request;
request.prompt = "What is visible in this image?";
request.images = {image};
request.max_new_tokens = 128;

auto result = model.run(request);
std::cout << result.text << "\n";

同じ画像に関する繰り返しのご質問の場合、VisionLanguageModel.encode(...) は、モデル内で画像の埋め込みをキャッシュできます。その後、request.use_cached_images = true を設定するか、use_cached_images = true を含むチャットメッセージを使用します。

LoRAアダプターの切り替え

LLiMa の LORA_BRANCH モードでコンパイルされたモデルは、npy_files/<adapter-name> に保存されている互換性のあるアダプターを切り替えることができます。

model.set_lora("customer-adapter");
auto adapted = model.run(request);
model.unset_lora();

アダプター名は、パスではなく、単一のディレクトリ名である必要があります。切り替え時には、現在実行中の生成処理が完了するまで待機し、次のリクエストの前に、言語モデルのキャッシュされたトークン状態をクリアします。動的な切り替えは、ASR、推測デコーディングパッケージ、または永続的にマージされたLORA_MERGEDの重みに対しては利用できません。

音声の文字起こし

ASRモデルは、同じリクエスト/結果の形式を使用しますが、リクエストには音声データを含める必要があります。ファイルパスの場合はaudio_fileを、音声テンソルの場合はaudioを使用してください。

simaai::neat::genai::ASRModel model("/media/nvme/llima/models/whisper-model");

simaai::neat::genai::GenerationRequest request;
request.audio_file = "meeting.wav";

auto result = model.run(request);
std::cout << result.text << "\n";
std::cout << "language=" << result.language << "\n";

デフォルトの言語はautoであるため、多言語対応のWhisperモデルは入力言語を検知します。入力言語がわかっている場合は、request.languageをサポートされている言語コードまたは名前に設定してください。また、読み込まれたWhisperアーティファクトがそれらのプローブを提供する場合、no_speech_probavg_logprobも結果として表示されます。no_speech_probの値が高いほど、入力に音声が含まれていない可能性が高くなります。avg_logprobの値が高い(より負の値が小さい)ほど、Whisperが生成されたトークンにより高い平均確率を割り当てたことを意味します。

音声を英語に翻訳するには、翻訳タスクを選択してください。

request.asr_task = simaai::neat::genai::ASRTask::Translate;
auto result = model.run(request);

GenAIをグラフに組み込む

ほとんどの GenAI アプリケーションでは、run() / stream() を直接呼び出すのが最短の方法です。GenAI をより大きな Neat グラフの一段階として使用する場合は、公開グラフフラグメントを使用します。

  • genai::graphs::VisionLanguage(...)
  • genai::graphs::SpeechTranscriber(...)

これらの断片は、名前付きのグラフエンドポイントを通じてGenAIステージを公開するため、Neatの他の部分で使用されているのと同じGraphRunモデルを使用して、それらを組み合わせることができます。

ASRグラフの場合、SpeechTranscriberOptionsは、デフォルトで自動的なソース言語の検出と文字起こしを使用します。明示的に翻訳を選択してください。

auto model = std::make_shared<simaai::neat::genai::ASRModel>(
"/media/nvme/llima/models/whisper-small-a16w8");

simaai::neat::genai::SpeechTranscriberOptions options;
options.task = simaai::neat::genai::ASRTask::Translate;
options.streaming = true;

auto fragment = simaai::neat::genai::graphs::SpeechTranscriber(model, options);

このフラグメントは、audioaudio_pathを受け入れます。最終的なdoneバンドルには、モデルがプローブの出力を提供した際に、textfinish_reasonlanguageno_speech_prob、およびavg_logprobが含まれます。

auto model = std::make_shared<simaai::neat::genai::VisionLanguageModel>(
"/media/nvme/llima/models/Qwen3-VL-4B-Instruct-GPTQ-a16w4");

simaai::neat::genai::VisionLanguageOptions options;
options.max_new_tokens = 128;
options.streaming = true;

simaai::neat::Graph fragment =
simaai::neat::genai::graphs::VisionLanguage(model, options, "vlm");

リクエストルール

GenerationRequest は、意図的に明確に定義されています。

  • prompt または messages のいずれか一方のみを使用し、両方を同時に使用しないでください。
  • system_prompt は、prompt と組み合わせてのみ使用してください。
  • 画像を直接添付する場合は、prompt のみを使用し、メッセージごとの画像を添付する場合は、ChatMessage.images を使用します。
  • 直接添付する画像とキャッシュされた画像のいずれか一方のみを使用し、両方を同時に使用しないでください。
  • ASRリクエストでは、テキストまたは画像フィールドではなく、オーディオフィールドを使用します。

Qwen3やGemma 4 E2B/E4Bなどの推論モデルに対して、GenerationRequest.enable_thinking を設定することで、推論を有効にします。完全な結果では、推論を GenerationResult.reasoning に、最終的な回答を GenerationResult.text に格納します。ストリーミングされる TokenSample オブジェクトも同様に、reasoningtext を使用します。

これらのルールにより、Neat は、あいまいなプロンプトをランタイムに送信する代わりに、明確なリクエストエラーで早期に処理を停止できます。

次のステップ

  • GenAIサーバー を使用して、HTTP経由でモデルを公開します。
  • LLiMa を搭載した生成AI を使用して、GenAIモデルを準備し、ベンチマークテストを実施します。
  • グラフ を使用して、より大規模なアプリケーションのグラフを構築します。