Ollama Embeddingsの検証設計

CHATGPT / AIChatGPTなどの生成AIを活用して運営・記事制作・更新を行っています。制作方針

Ollama v0.32.6の埋め込みAPIを対象に、model digestと評価集合を固定し、batch size、dimensions、truncate、keep_aliveを一変数ずつ変えて、recall、時間、memory、error率を比較する机上検証計画です。

同じModelを固定し、次元と切り詰めを別々に動かして検索品質の原因を分ける図

先に結論

Ollama Embeddingsの評価では、batchを大きくした速さと、dimensionsやtruncateを変えた検索品質を同じ比較へ混ぜないことが重要です。model tagだけでなくlocal digest、入力集合、chunk、query、正解文書、Ollama versionを固定し、まず完全次元・truncate: falseのbaselineを作ります。その後、batch size、dimensions、truncate、keep_aliveを一つずつ変え、recall、client/server時間、peak memory、error率を別々に記録します。

確認日時: 2026年8月10日(Asia/Tokyo)
対象version: Ollama v0.32.6、commit c82ebbd。Embed APIとEmbeddings capabilityの現行文書を2026年8月10日に確認。
検証区分: 公式文書に基づく机上調査・測定計画です。Ollama、embedding model、評価datasetを実行しておらず、実測値や性能の優劣は示しません。
適用外: 特定modelの最適次元、最大batch、言語別品質、GPU/CPUの優劣、vector databaseのindex方式、生成modelを含むRAG全体の品質。

前提:再現単位をmodel名より細かくする

公式Embeddings文書は、/api/embedがL2-normalized vectorを返し、indexとqueryで同じembedding modelを使うよう案内しています。しかし、同じtag文字列でも後日のpullでartifactが変われば、保存済みindexと新queryの意味空間が同一とは限りません。評価runごとにGET /api/tagsのmodel名、digest、size、format、family、parameter size、quantization levelを保存し、Ollama versionと一緒にrun IDへ結びます。

固定する入力は次のとおりです。

区分固定するもの理由
runtimeOllama v0.32.6、OS、CPU/GPU、driver、thread、他process時間とmemoryの差を設定差から分ける
modelname、local digest、取得日時tag更新によるvector変化を検出する
corpus元文書hash、chunk規則、順序、文字数/token数bucketbatchごとの入力差をなくす
queryquery ID、text、期待するrelevant document IDrecallを再計算できるようにする
APIdimensions、truncate、keep_alive、optionsserver defaultの変化を避ける
measurementwarm-up、反復数、同時request、timeout、採時点cold/warmとqueueを分ける

正解集合は、各queryに対して「関連あり」と人が判断したdocument IDを少なくとも1件持たせます。model自身の上位結果を正解にすると循環するため、事前に人が作った小さなrelevance setを使います。重複文やほぼ同じchunkはsplit前に同一groupへまとめ、train的な調整用queryと最終test queryを分離します。

Baselineを先に成立させる

baselineはbatch size 1、APIが返す完全な次元、truncate: false、固定したkeep_aliveで作ります。dimensionsを省略した時の実次元数をresponseから記録し、すべてのvectorについて有限値、同一次元、L2 normが1に近いことを検査します。

品質は少なくとも次を記録します。

  • Recall@k: 上位k件に正解documentが1件以上入ったqueryの割合
  • MRR: 最初の正解documentの順位の逆数をquery間で平均した値
  • 無回答扱い: 正解なし、API error、空vector、非有限値を成功から除外せず別欄に残す
  • 近接score: score自体の大小だけで合否にせず、同じmodel/次元内の順位監査に使う

処理時間は、client側のwall timeとAPI responseのtotal_durationload_durationを別々に保存します。公式APIはこれらをnanosecondsで返しますが、network、JSON parse、queueなどclient側の時間をすべて表すわけではありません。prompt_eval_countも入力量監査に使い、異なる入力token数のrunを同じ速度比較へ混ぜません。

memoryは同じ時点でprocess RSS、GPU割当量、system空き容量を観測し、model load前、load直後、warm-up後、steady state、解放後へ分けます。Ollama APIが返すdurationだけからmemoryを推測しません。

一変数ずつ比較する

Batch size

1、8、32などの候補は例であり、最適値ではありません。各batchで同じ文書集合と順序を使い、総document数が割り切れない末尾batchも成功数へ含めます。測るのはdocuments/秒、client wall time、server duration、peak memory、timeout/error率です。

batchを増やしてもvectorの意味が変わらないことを確認するため、batch size 1のvectorと大きいbatchの同一text vectorを比較します。浮動小数点差を完全一致で落とさず、cosine similarityと検索順位の変化を記録します。batch化の速度差と品質差が同時に出た場合は、入力順、padding、error retryによる重複を先に疑います。

Dimensions

公式Embed APIにはdimensions fieldがありますが、任意の値をすべてのmodelが同じように扱うとは限りません。省略時の完全次元をbaselineにし、候補値ごとにHTTP status、返却次元、有限値、norm、Recall@k、MRR、保存容量を測ります。unsupportedな値がerrorになる場合は失敗を隠さず、そのmodel/revisionの適用外として記録します。

次元削減はvector一件あたりの保存量とdistance計算量を減らし得ますが、検索品質との交換です。indexだけを小さくしてqueryを完全次元のまま使うことはできません。同じdimensionsでcorpusを再indexし、queryも同じ設定で作り直します。異なる設定のindexを上書きせず、model digest + dimensions + preprocessing versionをnamespaceにします。

Truncate

公式APIではtruncateの既定値がtrueで、context windowを超えた入力を切り詰めます。baselineはfalseで超過をerrorとして可視化します。その後、長さbucketごとにtrueを比較し、成功率だけでなく、末尾に正解根拠がある文書でrecallがどう変わるかを測ります。

切り詰め後の実際のtoken範囲がresponseから直接確認できない場合は「どこまで残った」と断定しません。長文を意味単位でchunk化する経路と、serverへ切り詰めを任せる経路を別experimentにし、chunk overlap、元文書ID、開始位置を保存します。

Keep alive

keep_aliveはmodelをmemoryへ保持する時間を指定するfieldです。品質変数ではなく、cold start、resident memory、同居workloadへの影響を測る運用変数として分離します。各条件で最初のrequestと2回目以降を混ぜず、load_duration、最初の成功までのwall time、idle後のmemory、再loadを記録します。

実験matrixと合格gate

全組合せを一度に探索すると原因が分からなくなります。次の順で段階的に進めます。

  1. 完全次元、batch 1、truncate: falseでAPIとquality baselineを確定
  2. batchだけを変え、同じvector/順位を保ったまま処理効率を比較
  3. batchをbaselineへ戻し、dimensionsだけを変えてqualityと保存量を比較
  4. 長文bucketだけでtruncateとchunkingを比較
  5. 採用候補の設定を固定し、keep_aliveと同時requestを運用負荷として測定

各runは次のschemaで保存すると差分を監査しやすくなります。

{
  "runId": null,
  "ollamaVersion": "0.32.6",
  "modelName": "embeddinggemma",
  "modelDigest": null,
  "batchSize": 1,
  "dimensions": null,
  "truncate": false,
  "keepAlive": null,
  "corpusHash": null,
  "querySetHash": null
}

nullはrun開始時に実値を取得できなければ、そのrunを比較対象へ入れない必須項目です。架空のdigestや測定値で埋めません。合格thresholdも一律に捏造せず、既存検索のSLOへ結びます。最低限、API error率が許容内、vector検査が全件合格、Recall@kがbaselineから許容幅内、peak memoryとwall timeが運用上限内、同一runを再実行して判断が逆転しないことをpromotion gateにします。

Trade-offと適用外

大きいbatchはrequest overheadを減らせる一方、peak memory、tail latency、失敗時の再処理範囲を増やし得ます。小さいdimensionsは保存とdistance計算を軽くし得ますが、意味情報を失ってrecallを下げる可能性があります。truncate: trueは長文errorを減らしても、根拠部分を落とした成功responseを増やすことがあります。keep_aliveを長くすればcold startを避けやすい一方、他modelへ渡せるmemoryを占有します。

ここで得た設定は、同じmodel digest、言語、文書domain、chunk、query分布にだけ適用します。model更新時は古いvectorと新しいvectorを同じindexへ混ぜず、shadow indexを作って固定queryを再評価します。vector database固有の近似index parameter、reranker、生成model、prompt、回答の事実性は別の評価層です。

最小のAPI操作から始める場合は、Ollama埋め込みAPI入門で、3文書と1質問を同じmodelへ送り、返却数・次元・単位長・最上位文書を確認してください。Ollamaとllama.cppの運用境界を選ぶ段階なら、Ollamaとllama.cppの用途別比較も役割を分けて参照できます。

参考資料

  • Ollama Embeddings(現行文書を2026年8月10日確認。L2正規化、同一model、batch、cosine similarityを確認)
  • Ollama Embed API(現行文書を2026年8月10日確認。truncate既定値、dimensionskeep_alive、duration fieldを確認)
  • Ollama List models API(現行文書を2026年8月10日確認。local model digestとdetails fieldを確認)
  • Ollama v0.32.6 release(commit c82ebbd、2026年8月4日公開、2026年8月10日確認)