ailia LLM マルチモーダル ガイド

ailia LLM でマルチモーダルプロジェクタを読み込み、画像・音声を入力する方法を説明します。構造体で渡すailiaLLMSetMultimodalPromptと、JSON履歴で渡すailiaLLMSetPromptJsonの2つの方法があります。

プロジェクタの読み込み

モデルを読み込んだ後、対応するprojectorをailiaLLMOpenMultimodalProjectorFileAで読み込みます。 画像と音声の対応状況はailiaLLMGetMultimodalCapabilitiesのvision_support / audio_supportで確認できます。メディア非対応のモデル/projectorや未読込の状態で画像・音声を指定するとINVALID_STATEです。

入力方法

ailiaLLMSetMultimodalPromptailiaLLMSetPromptJson
メッセージAILIALLMMultimodalChatMessageの配列messages配列のJSON(UTF-8)
メディアの位置contentの<__media__>プレースホルダーcontent配列の順序
入力形式ファイルパス、エンコード済みバッファ、Raw RGBファイルパス、Base64(エンコード済みファイル)
生成結果ailiaLLMGetDeltaTextを連結ailiaLLMGetResponseJsonで取得
Tool Useツール設定中はINVALID_STATEtoolsの有無にかかわらず使用可

画像・音声を入力するだけであればどちらの方法でも使用できます。Raw RGBを渡す場合はailiaLLMSetMultimodalPromptを、Tool Useと組み合わせる場合はailiaLLMSetPromptJsonを使用してください。 Tool Useの詳細はTool Use ガイドを参照してください。

SetMultimodalPrompt(構造体)

メッセージのcontentに<__media__>プレースホルダーを含め、対応するメディアをmedia_dataに順番に設定し、media_countに個数を指定します。 メッセージの内容は内部でコピーされるため、呼び出し後に解放できます。

AILIALLMMediaDataのmedia_typeには"image"または"audio"を指定します。画像と音声のどちらも使用できます。メディアは次のいずれかで指定します。

SetPromptJson(JSON)

画像・音声はuserのcontent配列に、textと並べて順番に指定します。

[{"role":"user","content":[
  {"type":"text","text":"この画像と音声について説明してください。"},
  {"type":"image","file_path":"/path/to/image.jpg"},
  {"type":"audio","file_path":"/path/to/audio.wav"}
]}]

image/audioはfile_pathまたはdataをちょうど1つ指定します。dataは標準Base64(パディング付き)で エンコードしたファイル内容です。JPEG/PNG、WAV/MP3/FLAC等を使用できます。URL取得、動画、生RGB/PCMには対応しません。 画像・音声を含む履歴は毎回再評価します。

エラー

C++サンプル(SetMultimodalPrompt)

モデルとprojectorを読み込み、構造体で画像を渡して応答を生成します。生成結果はGetDeltaTextで連結します。

#include "ailia_llm.h"
#include <cstdio>
#include <string>
#include <vector>

static int open_projector(AILIALLM* llm) {
    int status = ailiaLLMOpenMultimodalProjectorFileA(llm, "/path/to/mmproj.gguf");
    if (status != AILIA_LLM_STATUS_SUCCESS) return status;
    unsigned int vision = 0, audio = 0;
    status = ailiaLLMGetMultimodalCapabilities(llm, &vision, &audio);
    if (status != AILIA_LLM_STATUS_SUCCESS) return status;
    // vision_support / audio_support で画像・音声の対応を確認します。
    return vision ? AILIA_LLM_STATUS_SUCCESS : AILIA_LLM_STATUS_INVALID_STATE;
}

static int describe_image(AILIALLM* llm) {
    AILIALLMMediaData media = {};
    media.media_type = "image";
    media.file_path = "/path/to/image.jpg"; // dataとdata_sizeでバッファも指定可
    AILIALLMMultimodalChatMessage message = {};
    message.role = "user";
    message.content = "この画像について説明してください。 <__media__>";
    message.media_data = &media;
    message.media_count = 1;
    int status = ailiaLLMSetMultimodalPrompt(llm, &message, 1);
    if (status != AILIA_LLM_STATUS_SUCCESS) return status;
    std::string text;
    unsigned int done = 0;
    while (!done) {
        status = ailiaLLMGenerate(llm, &done);
        if (status != AILIA_LLM_STATUS_SUCCESS) return status;
        if (done) break;
        unsigned int size = 0;
        status = ailiaLLMGetDeltaTextSize(llm, &size);
        if (status != AILIA_LLM_STATUS_SUCCESS) return status;
        std::vector<char> delta(size);
        status = ailiaLLMGetDeltaText(llm, delta.data(), size);
        if (status != AILIA_LLM_STATUS_SUCCESS) return status;
        text += delta.data();
    }
    printf("%s\n", text.c_str());
    return AILIA_LLM_STATUS_SUCCESS;
}

int main() {
    AILIALLM* llm = nullptr;
    if (ailiaLLMCreate(&llm) != AILIA_LLM_STATUS_SUCCESS) return 1;
    int status = ailiaLLMOpenModelFileA(llm, "gemma-4-E2B-it-Q4_K_M.gguf", 4096);
    if (status == AILIA_LLM_STATUS_SUCCESS) status = open_projector(llm);
    if (status == AILIA_LLM_STATUS_SUCCESS) status = describe_image(llm);
    if (status != AILIA_LLM_STATUS_SUCCESS) {
        fprintf(stderr, "error %d: %s\n", status, ailiaLLMGetErrorDetail(llm));
    }
    ailiaLLMDestroy(llm);
    return status == AILIA_LLM_STATUS_SUCCESS ? 0 : 1;
}

C++サンプル(SetPromptJson)

同じ処理をJSON履歴で行います。履歴の編集にはnlohmann/jsonを使用します。

#include "ailia_llm.h"
#include <nlohmann/json.hpp>
#include <cstdio>
#include <string>
#include <vector>
using json = nlohmann::json;

static int open_projector(AILIALLM* llm) {
    int status = ailiaLLMOpenMultimodalProjectorFileA(llm, "/path/to/mmproj.gguf");
    if (status != AILIA_LLM_STATUS_SUCCESS) return status;
    unsigned int vision = 0, audio = 0;
    status = ailiaLLMGetMultimodalCapabilities(llm, &vision, &audio);
    if (status != AILIA_LLM_STATUS_SUCCESS) return status;
    // vision_support / audio_support で画像・音声の対応を確認します。
    return vision ? AILIA_LLM_STATUS_SUCCESS : AILIA_LLM_STATUS_INVALID_STATE;
}

static int describe_image_json(AILIALLM* llm) {
    json messages = json::array({{{"role", "user"}, {"content", json::array({
        {{"type", "text"}, {"text", "この画像について説明してください。"}},
        {{"type", "image"}, {"file_path", "/path/to/image.jpg"}}
    })}}});
    std::string input = messages.dump();
    int status = ailiaLLMSetPromptJson(llm, input.c_str());
    if (status != AILIA_LLM_STATUS_SUCCESS) return status;
    unsigned int done = 0;
    while (!done) {
        status = ailiaLLMGenerate(llm, &done);
        if (status != AILIA_LLM_STATUS_SUCCESS) return status;
    }
    unsigned int size = 0;
    status = ailiaLLMGetResponseJsonSize(llm, &size);
    if (status != AILIA_LLM_STATUS_SUCCESS) return status;
    std::vector<char> output(size);
    status = ailiaLLMGetResponseJson(llm, output.data(), size);
    if (status != AILIA_LLM_STATUS_SUCCESS) return status;
    try {
        json response = json::parse(output.data());
        printf("%s\n", response.at("content").get<std::string>().c_str());
    } catch (const json::exception&) {
        return AILIA_LLM_STATUS_INVALID_ARGUMENT;
    }
    return AILIA_LLM_STATUS_SUCCESS;
}

int main() {
    AILIALLM* llm = nullptr;
    if (ailiaLLMCreate(&llm) != AILIA_LLM_STATUS_SUCCESS) return 1;
    int status = ailiaLLMOpenModelFileA(llm, "gemma-4-E2B-it-Q4_K_M.gguf", 4096);
    if (status == AILIA_LLM_STATUS_SUCCESS) status = open_projector(llm);
    if (status == AILIA_LLM_STATUS_SUCCESS) status = describe_image_json(llm);
    if (status != AILIA_LLM_STATUS_SUCCESS) {
        fprintf(stderr, "error %d: %s\n", status, ailiaLLMGetErrorDetail(llm));
    }
    ailiaLLMDestroy(llm);
    return status == AILIA_LLM_STATUS_SUCCESS ? 0 : 1;
}