.NET 10 と Angular Signals による「ローカルファースト」エンタープライズ RAG(ベクターメモリー)アーキテクチャ

Dev.to / 2026/5/20

💬 オピニオンDeveloper Stack & InfrastructureTools & Practical UsageModels & Research

要点

  • 著者は、クラウドベースのベクターデータベース依存を取り除き、.NET 10 とローカルSQLite層に基づいて「ローカルファースト」のエンタープライズRAGアーキテクチャを再構築しました。
  • 不安定な実験用プレビュー・パッケージ(SemanticKernelコネクタやVectorData抽象化など)を、バージョン不一致や脆弱性警告を避けるために、安定して長期サポートされるネイティブな.NETエンタープライズ用パッケージへ置き換えました。
  • provider-agnostic なC#埋め込みラッパー(GoogleEmbeddingGenerator)を導入し、DI/IoC登録の変更だけで、Google Gemini/OpenAI/完全ローカルLLMなどの埋め込みプロバイダーをコアのエンドポイント実装を触らずに切り替えられるようにしました。
  • 外部の数学ライブラリやPythonサービスに依存せず、意味的な近さ(ベクトルのコサイン類似度)を純粋な.NETで計算する、依存関係ゼロの高性能コサイン類似度実装を用意しています。
  • データ肥大化を抑えるため、Angularフロントエンド側でファイルパス(必要に応じて内容)を決定論的にハッシュ化し、SQLiteの ON CONFLICT(Id) によるアップサート挙動で重複行の増加を防ぐ仕組みを追加しました。

私の .NET AI Architect Laboratory プロジェクト開発のフェーズ3の間、外部かつコストのかかるクラウドベースのベクターデータベース依存(ベンダーロックイン)を完全に無効化しました。代わりに、.NET 10 core、ローカルSQLiteレイヤー、Angular Signals を用いたローカル・ファーストのエンタープライズ RAG 基盤を構築しました。

実施した操作は以下の通りです:

  1. 実験用プレビュー・パッケージの依存関係を整理
    プロジェクトから実験的な SemanticKernel.Connectors および VectorData.Abstractions のプレビューパッケージを完全に排除しました。これらは常にバージョン不一致、構造の不安定さを引き起こし、NU1904 のような脆弱性に関する警告も含まれていました。私はアーキテクチャを、フレームワーク自身のネイティブで安定しており、長期サポートされているエンタープライズパッケージに固定しました。

  2. プロバイダー非依存の埋め込み基盤
    GoogleEmbeddingGenerator という純粋な C# ラッパーを書き、Microsoft の新しいエンタープライズAI標準(Microsoft.Extensions.AI)と、Google の公式 GenAI SDK を抽象化しました。

私は Gemini の text-embedding-004 モデルが生成する高次元の double[] 配列を、.NET インターフェイスが期待する float[] ベクトルへ動的にキャストしました。
アーキテクチャ上の獲得点:今後のフェーズで、IoC(DI)レジストリを Program.cs の中で切り替えるだけで、コアとなるエンドポイントのアーキテクチャに一切手を加えずに、OpenAI あるいは完全にローカルな LLM(Ollama/Llama など)へ移行するための完全な柔軟性を提供しました。

  1. ゼロ依存の純粋 C# コサイン類似度エンジン ベクトル間の意味的な近さを計算するために、重い外部数学ライブラリやサードパーティの Python サービスへのゼロ依存を実現しました。私は、.NET core 上で直接動作する、メモリに優しく高性能なコサイン類似度行列を実装しました:

public static float CosineSimilarity(float[] vectorA, float[] vectorB)
{
if (vectorA.Length != vectorB.Length)
throw new ArgumentException("Vectors must have the same identical dimensions.");

float dotProduct = 0.0f, normA = 0.0f, normB = 0.0f;
for (int i = 0; i < vectorA.Length; i++)
{
dotProduct += vectorA[i] * vectorB[i];
normA += vectorA[i] * vectorA[i];
normB += vectorB[i] * vectorB[i];
}
return (normA == 0.0f || normB == 0.0f) ? 0.0f : dotProduct / ((float)Math.Sqrt(normA) * (float)Math.Sqrt(normB));
}

  1. データ膨張に対する決定論的な重複排除
    同一のコードブロックやファイルがシステムに連続して追加し直される場合に、SQLite テーブルが肥大化するのを防ぐため、Angular フロントエンド層(memory-dashboard.component.ts)内に、ファイルパスに基づく決定論的な Base64 パス・ハッシュ機構を設けました。各ファイル内容に対して厳密に一意で確定的な Id が生成されるようにすることで、SQLite ネイティブの ON CONFLICT(Id) DO UPDATE 制約を発火させ、データベース内での重複行の膨張を完全にゼロにしました。

  2. 知識拡張されたエージェンシー・フロー
    この作成したローカルベクトルメモリを、当社の自律型マルチツール・エージェント(/api/architect/inspect-autonomous)に統合しました。エージェントがアーキテクチャ分析のタスクを受け取ると、ディスク上の実ファイルを直接スキャンする前に、バックグラウンドでこのローカル SQLite ベクトルレイヤーへクエリを発行します。たとえば、ユーザーが「フロントエンドのアクセス用ポートをレビューして」といった一般的な目的を提示したとき、意味検索エンジンはローカルメモリから言及されていない CORS 設定コードのスニペットを取得し、それをエージェントのリアルタイムなシステムコンテキスト(プロンプト)に注入します。エージェントは、ローカライズされたエンタープライズ領域の経験を完全に武装した状態で意思決定を生成します。

️ ダッシュボード RAG パネルのプレビュー
統合された RAG パネルのライブ画面上の成果物は、以下のように機能します:

Makale içeriği

  1. リアクティブ管理ボード:Angular Signals & Tailwind UI
    このローカル・ベクトルストリーム全体を、Angular のリアクティブ Signals アーキテクチャと、ダークテーマの Tailwind CSS v3 インターフェースを用いて可視化しました。単一のリアクティブな状態フラグにより、システムは遅延ゼロで Code Analyzer の部屋と Knowledge RAG の部屋の間をシームレスに切り替え、制御フロー全体を 1 つのコックピットへ変換します。

コードを探索する
フェーズ3の完了後の次のステップは、自動コード取り込みパイプライン(フェーズ4)の開発です。これは、バックグラウンドで変更されたコードを自動的に追跡し、実行中にローカルメモリをオンザフライで更新します。

GitHub リポジトリ:github.com/muratsuzen/dotnet-ai-lab

モデルそのものは単に私たちが借りるエンジンにすぎません。本当の価値は、その周りに構築するアーキテクチャ基盤、コンテキスト、そしてドキュメントにあります。このラボは、その旅のための私の恒久的なデジタル・ログブックです。