Skip to content

サービス

Lase が提供するサービスクラスの一覧です。すべて CodebaseJp\Lase\Services 名前空間に属します。

SubscriptionService

サブスクリプションの作成・更新を担当します。

createSubscription(Tenant $tenant, Plan $plan, Collection $options)

テナントに対してサブスクリプションを作成します。

  • 悲観的ロックでテナントをロックし、競合状態を防止
  • 現在のプランよりダウングレードする場合、利用量が新しい上限を超えていないかチェック
  • SubscriptionQuotaSubscriptionFeatureGrantedQuotaGrantedFeature を自動同期
  • DB トランザクション内で実行

AuthService

認証周りのロジックを担当します。アカウントの有効化・パスワードリセット・トークン発行などを処理します。

AnalyticsService

管理画面向けの統計データを集計します。

  • テナント数・ユーザー数・お問い合わせ数のサマリー
  • 日次・月次の時系列データ生成

RecaptchaService

Google reCAPTCHA v3 のトークン検証を行います。

php
$recaptchaService->verify(string $token): bool

SenterService

外部課金サービス「Senter」との API 通信を担当します。

  • サービスプラン・オプション・アドオン情報の取得
  • 請求書の取得
  • 未請求利用量の取得
  • Stripe 連携(顧客作成・SetupIntent・支払方法管理)

ActivityLogService

操作ログの記録を担当します。

record(BackedEnum $type, int $userId, ?int $tenantId, ?Request $request = null)

アクティビティログを1件記録します。

  • $type: ログの種別(ActivityLogType Enum の値)
  • $userId: 操作を行ったユーザーの ID
  • $tenantId: テナント ID(テナントコンテキスト外では null
  • $request: HTTP リクエスト(省略時は IP・UA が記録されない。スケジューラー・キュー等の非 HTTP コンテキストから呼ぶ場合は省略可)

AiEmbeddingService

ドキュメントをベクトル化してデータベースに保存し、AIチャットの RAG(検索拡張生成)を実現するサービスです。

インデックスの作成は php artisan lase:index-docs コマンドで実行します。

主なメソッド

メソッド説明
chunkText()Markdown をチャンクに分割する。Embeddings API に依存しない純粋関数
isIndexed()同一内容で既にインデックス済みかを返す
indexDocument()チャンク分割 → Embedding 生成 → DB 保存を行う
findRelevantChunks()クエリに近いチャンクを類似度の高い順に返す
pruneExcept()指定ソース一覧に含まれない孤立チャンクを削除する

チャンク分割の方針

  • 先頭の YAML フロントマターは除去し、本文のみを対象にする
  • 見出し(####)単位に分割する。コードブロック(``` / ~~~)内の # は見出しとして扱わない
  • 各チャンクの先頭に見出しパス(例: ログイン > パスワードを忘れた場合)を付与し、チャンク単体でも文脈が分かるようにする
  • 上限文字数を超えるセクションは段落単位で分割し、チャンク間に chunk_overlap 文字分の重複を持たせる

検索の仕様(ハイブリッド検索)

ベクトル検索と全文検索の結果を RRF(Reciprocal Rank Fusion) で融合します。

text
score = Σ 1 / (60 + 各検索での順位)

ベクトル検索は意味的な近さに強い一方、製品名・エラーコードのような固有語の完全一致に弱いという弱点があります。全文検索(MySQL の ngram パーサ)を併用することで、たとえば「E4021」のような語がベクトル的に一致しないチャンクも拾えるようになります。hybrid_enabledfalse にするとベクトル検索のみになります。

ベクトルは正規化(ノルム1)して保存するため、類似度計算は内積のみで済みます。similarity_threshold を下回るチャンクは無関係とみなして除外し、無関係な文書がプロンプトへ混入するのを防ぎます。クエリ側の Embedding は query_cache_ttl 秒間キャッシュされます。

WARNING

InnoDB の全文検索インデックスは未コミットの行を参照できません。インデックス作成と同一トランザクション内で検索した場合、全文検索側は0件となりベクトル検索のみに縮退します(テストで RefreshDatabase を使う場合が該当します)。

WARNING

Embedding 生成に失敗した場合は例外を投げます(ゼロベクトルを保存してインデックスを黙って壊さないため)。indexDocument() は Embedding 生成を完了させてから既存チャンクを差し替えるため、API 失敗時に既存インデックスを失うことはありません。

ベクトルの保存形式

embedding は正規化済みベクトルを float32 で並べた BLOB です。JSON 文字列に比べて次の効果があります(実測値)。

1536次元 JSON512次元 float32
1チャンクあたり32,794 B2,048 B
デコード(1000件)77.4 ms8.2 ms

次元数の削減は text-embedding-3-* の Matryoshka 表現を利用しており、1536→512 程度では検索精度の低下はごく僅かです。合わせて 約1/16のサイズ・約9.5倍のデコード速度になります。

embedding_model / dimensions を各行に保持しているため、モデルや次元数を変更すると:

  • 既存チャンクは SQL の段階で検索対象から除外されます(PHP 側で0点にするのではなく)
  • isIndexed()false を返すため、--force なしで自動的に再インデックスされます

設定

config/lase.phpai セクションで調整できます。

キー既定値説明
embedding_modeltext-embedding-3-smallEmbedding 生成に使うモデル
embedding_dimensions512ベクトルの次元数。0 でモデル既定値(次元数指定に非対応のモデル向け)
embedding_batch_size501リクエストにまとめるチャンク数
chunk_max_length1500チャンクの上限文字数
chunk_min_length20これ以下のチャンクは破棄する
chunk_overlap100分割時に重複させる文字数
top_k5検索で取得するチャンク数
similarity_threshold0.3この類似度を下回るチャンクは除外する
hybrid_enabledtrue全文検索を併用し RRF で融合する
candidate_multiplier4融合前に各検索から取得する候補数の倍率(top_k × この値)
query_cache_ttl3600クエリ Embedding のキャッシュ秒数(0 で無効)