今日、AI 機能を追加するほとんどの .NET チームは、同じ配管作業を書き上げます:HTTP クライアント、リトライ ポリシー、API キーのシークレット管理、そして誰かのクレジットカードに対するトークンごとの課金行です。Aspose.LLM は別の道を取ります。これは 自分のプロセス内で 大規模言語モデルの推論を実行する NuGet パッケージです。呼び出すサービスも、ローテーションするキーも、マシンを離れるリクエストもありません。

この記事ではライブラリを紹介し、その API が構築されている 3 つの概念を説明し、動作するチャットアプリケーションの作成手順をご案内します。パッケージ参照を追加できれば、数十行でプロンプトを送信できるようになります。

ローカルモデルが重要な理由

モデルをインプロセスで実行すると、構築できるものが変わります。

  • データはそのままです。 プロンプトはホストから決して外部に出ません。これは、契約書、医療記録、ソースコード、またはデータ居住ポリシーの対象となるその他の情報を扱う際に重要です。
  • トークンごとのコストはありません。 モデルがディスク上にある限り、推論は既に所有している CPU または GPU のコストであり、従量課金の API 呼び出しではありません。
  • 実行時にネットワーク依存はありません。 デスクトップツール、オンプレミスサービス、エアギャップ環境すべてが同じ方法で動作します。
  • デプロイメントアーティファクトは1つです。 モデル構成は別のアカウントのダッシュボードに存在するのではなく、アプリケーションと共に配布されます。

トレードオフは正直で、事前に述べておく価値があります: ハードウェアはユーザーが提供します。ローカルで実行されるモデルはローカルメモリが必要で、最初の実行時には数ギガバイトをダウンロードする必要があります。

Aspose.LLM for .NET の 3 つの概念

表面積は意図的に小さく設定されています。Aspose.LLMで行うほぼすべての操作は、これら3つのタイプに関係しています。

概念タイプ役割
LicenseAspose.LLM.Licenseライブラリを有効化します。その他の API を使用する前に SetLicense を呼び出してください。
Presete.g. Qwen25Presetモデルファイルとサンプラー温度などの生成パラメータをバンドルします。
API instanceAsposeLLMApiエントリーポイントです。プリセットから作成され、会話を保持し、SendMessageAsync を公開します。

プリセットは興味深いものです。モデルパス、トークナイザー設定、サンプラー値を手動で設定させる代わりに、プリセットは既知の良好な組み合わせをパッケージ化します。Qwen25Preset はデフォルトの開始点であり、パラメータを調整したり、後で別のプリセットに置き換えたりしても、コードの他の部分に手を加える必要はありません。

前提条件

コードを書く前に:

  1. パッケージをインストール - Install-Package Aspose.LLM
  2. ライセンスを配置 - 実行時に読み取れる場所に Aspose.LLM.lic を置きます。
  3. メモリ予算を確認 - Qwen25 プリセットには少なくとも 8 GB の空き RAM が必要です。

製品の詳細については、Aspose.LLM for .NET product pageをご覧ください。

最初のチャット

実際の会話を維持する最短のプログラムはこちらです。2回目と3回目の呼び出しに注目してください。API インスタンスは自動的にコンテキストを追跡するため、モデルはまだ Alice が誰かを認識しています。

コードが何をするか

  1. License を作成し、ライセンス ファイルを指すようにします。
  2. デフォルト構成で Qwen25Preset をインスタンス化します。
  3. そのプリセットから AsposeLLMApi インスタンスを 1 つ作成します。
  4. 同じ会話を共有する複数のプロンプトを送信します。
using Aspose.LLM;
using Aspose.LLM.Abstractions.Parameters.Presets;

var license = new Aspose.LLM.License();
license.SetLicense("Aspose.LLM.lic");

var preset = new Qwen25Preset();
using var api = AsposeLLMApi.Create(preset);

string reply = await api.SendMessageAsync("What is 2 + 2?");
Console.WriteLine(reply);
// Output: 2 + 2 equals 4.

await api.SendMessageAsync("My name is Alice.");
string reply2 = await api.SendMessageAsync("What is my name?");
Console.WriteLine(reply2);
// Output: Your name is Alice.

AsposeLLMApi.Create(preset) はセッション対応のクライアントを返します。各 SendMessageAsync 呼び出しはプロンプトを現在の会話に追加するため、状態を自分で管理することなくマルチターンの動作が得られます。using 宣言は重要です — インスタンスはネイティブリソースを所有しており、破棄する必要があります。

注: これらのサンプルは公式の Aspose ドキュメントに従っており、サンドボックスで実行されていません。出荷前にご自身の環境で確認してください。

単一リクエストの動作調整

会話形式の回答はある程度のランダム性が有益です。算術にはそれが必要ありません。インスタンスを再構成する代わりに、2つ目のプリセットを作成し、必要な呼び出しに渡します。

コードが何をするか

  1. 通常どおり、デフォルトのプリセットと API インスタンスを作成します。
  2. 低いサンプラ温度で strictPreset を構築します。
  3. preset 引数を介してそれを SendMessageAsync に渡します。
  4. 後続の呼び出しは元のデフォルトのままにします。
using Aspose.LLM.Abstractions.Parameters.Presets;

// Default preset used by the API instance
var defaultPreset = new Qwen25Preset();
using var api = AsposeLLMApi.Create(defaultPreset);

// A more deterministic preset, for this question only
var strictPreset = new Qwen25Preset();
strictPreset.SamplerParameters.Temperature = 0.1f;

string reply = await api.SendMessageAsync(
    "What is the square root of 144?",
    preset: strictPreset);

Console.WriteLine(reply);
// Output: The square root of 144 is 12.

SamplerParameters.Temperature はサンプラーが導入するランダム性の程度を制御します。0.1 に近い値はほぼ決定的な出力を生成し、より高い値はより多様な表現を生み出します。プリセットは呼び出し単位でスコープされるため、オーバーライドは会話の残りの部分に漏れません。

キャンセルとタイムアウト

生成時間は完全に予測できず、長時間実行されるリクエストはそれを待っているものをブロックします。SendMessageAsync は CancellationToken を受け取るので、1つ渡してください。

コードが何をするか

  1. 30秒の予算で CancellationTokenSource を作成します。
  2. cts.Token を SendMessageAsync に渡します。
  3. OperationCanceledException をキャッチし、優雅にデグレードします。
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(30));

try
{
    string reply = await api.SendMessageAsync(
        "Write a 500-word essay about migration patterns of the Arctic tern.",
        cancellationToken: cts.Token);
    Console.WriteLine(reply);
}
catch (OperationCanceledException)
{
    Console.WriteLine("Generation timed out.");
}

キャンセルはセッション状態をそのままに保つため、次の呼び出しで会話は通常どおり続行されます。ASP.NET Core ハンドラでは、ここでもリクエスト自身の RequestAborted トークンを転送してください。すでに切断されたクライアントに対して生成を続ける理由はありません。

完全なコンソール アプリケーション

まとめると、プロセスの存続期間中に1つのセッションを維持し、メッセージごとの失敗から回復する REPL です。

コードが何をするか

  1. 起動時にライセンスとデフォルトプリセットを一度設定します。
  2. プログラム全体で単一の AsposeLLMApi インスタンスを作成します。
  3. ユーザーが quit と入力するまで入力をループします。
  4. 各行を送信し、返信を表示します。
  5. メッセージごとに例外をキャッチし、1つの失敗がセッション全体を終了させないようにします。
using Aspose.LLM;
using Aspose.LLM.Abstractions.Parameters.Presets;

internal class SimpleChatDemo
{
    public static async Task Main()
    {
        var license = new Aspose.LLM.License();
        license.SetLicense("Aspose.LLM.lic");

var preset = new Qwen25Preset();
        using var api = AsposeLLMApi.Create(preset);

Console.WriteLine("Ask me anything. Type 'quit' to exit.");
        while (true)
        {
            Console.Write("> ");
            string? line = Console.ReadLine();
            if (line == null || line.Equals("quit", StringComparison.OrdinalIgnoreCase))
                break;

try
            {
                string reply = await api.SendMessageAsync(line);
                Console.WriteLine(reply);
            }
            catch (Exception ex)
            {
                Console.WriteLine($"Error: {ex.Message}");
            }
        }
    }
}

実際のアプリケーションに取り入れる価値のある設計ポイントが2つあります。まず、インスタンスは 一度だけ 作成され、再利用されます。作成にはコストがかかり、次のセクションで説明するように、同時に複数のインスタンスを使用することは許可されていません。次に、try‑catch はループの外側ではなく内部に配置されるため、1つの不正なメッセージがセッション全体ではなく、1回のターンだけのコストとなります。

ライブラリを評価するには、Aspose の一時ライセンス ページから一時ライセンスを取得してください。

最初に遭遇しやすいエラー

ErrorTypical causeRemedy
Not licensed for this methodライセンスファイルが存在しない、またはパスが間違っている作業ディレクトリから Aspose.LLM.lic が読み取れること、そして SetLicense が他の API 呼び出しの前に実行されていることを確認してください。
Only one AsposeLLMApi instance can be created at a time同時に2つのインスタンスが存在する、しばしばリクエストごとのファクトリから生成されるインスタンスをシングルトンとして登録するか、別のインスタンスを作成する前に前のインスタンスを破棄してください。
First response takes minutesエンジンがネイティブバイナリとモデルの重みをダウンロードしているクリーンなマシンでは5〜15分かかることを想定してください。Create を起動時に実行して、ユーザーが待ち時間を負担しないようにしてください。

サービスシナリオでは、2 行目が特に重要です。Aspose.LLM を DI コンテナに組み込む場合は、AsposeLLMApi をシングルトンとして登録し、アクセスをシリアライズしてください。スコープドまたはトランジェントの登録は、2 つのリクエストが重なるとすぐに失敗します。

追加リソース

結論

Aspose.LLM は「この .NET アプリケーションに LLM を追加する」作業を 3 つの型と 1 つのメソッドに簡略化します。ライセンスはライブラリを有効化し、プリセットはモデルと生成方法を定義し、AsposeLLMApi インスタンスが会話を保持します。そこから、SendMessageAsync は単一の質問、マルチターン セッション、呼び出しごとのパラメータ上書き、そしてキャンセル可能な長時間生成を処理します。

まずコンソール サンプルから開始し、モデルが機能の要件どおりに動作することを確認してください。その後、基本が確立したらマルチセッションと永続性の作業に進みます。

よくある質問

1. Aspose.LLM for .NET とは何ですか?

.NET プロセス内で大規模言語モデルの推論を実行する NuGet ライブラリです。プリセットを作成し、API インスタンスを生成してプロンプトを送信します — 外部サービス不要、API キーも不要です。

2. 使用するためにインターネット接続は必要ですか?

最初の実行時のみです。最初の Create 呼び出しは、プリセットで定義されたネイティブエンジンとモデルファイルをダウンロードし、その後アセットはローカルにキャッシュされます。

3. コードサンプルの前提条件は何ですか?

Aspose.LLM NuGet パッケージ、有効な Aspose.LLM.lic ファイル、そして選択したプリセットに十分な空き RAM が必要です - Qwen25 では少なくとも 8 GB を確保してください。

4. 単一リクエストのモデルの動作を変更するにはどうすればよいですか?

2番目のプリセットを作成し、そのパラメータ(例: SamplerParameters.Temperature)を調整して、preset 引数を介して SendMessageAsync に渡します。後続の呼び出しはインスタンスのデフォルトプリセットに戻ります。

5. 長時間かかっている生成を停止するにはどうすればよいですか?

SendMessageAsync に CancellationToken を渡し、OperationCanceledException をキャッチします。セッション状態はキャンセル後も保持されるため、会話は通常どおり続行されます。

6. 最初の応答が遅いのはなぜですか?

最初の Create 呼び出しはネイティブバイナリとモデルの重みをダウンロードします。クリーンなマシンでは 5〜15 分かかることがあります。ユーザーの最初のリクエスト時ではなく、アプリケーションの起動時にインスタンスをウォームアップしてください。

Read More