Skip to content
This page has been auto-translated and may contain errors.View in English

エンベディング

docs.scrimba.com

まず言葉の定義から。エンベディング は、テキストの代わりになる数字のリストで、その意味を捉えており、似た意味のテキストは似た数字になります。この章では、言葉をコンピューターが比較できるものに変える方法を学べます。これにより、検索はキーワードではなく意味を照合できるようになります。

テキストをベクトルとして

コンピューターはどのようにして「犬」と「子犬」が関連していて、「犬」と「ホチキス」は関連していないと知るのでしょうか?単語は重要な共通の文字を持ちません。

コツは、テキストを意味を捉えた数字に変換することです。そうすると、似た意味は似た数字になります。その数字のリストが エンベディング で、ベクトルとも呼ばれます。モデルがテキストを読んでベクトルを出力します。

数字を自分で解釈する必要はありません。重要なのは、数字同士の関係です。

ラフなメンタルモデル:テキストの各部分を空間上の点として考えてみてください。似た意味のものが近くに位置します。「犬」と「子犬」は同じ地域に位置します。「ホチキス」はずっと離れた場所にあります。実際のエンベディングは2~3次元ではなく、数百~数千の次元を使いますが、直感は変わりません:近さは類似性を意味します。

その数字はどこから来ているのか、なぜ意味と一致するのか?エンベディングモデルは、LLMの仕組みから説明される予測モデルのいとこで、膨大なテキストで訓練されています。そのタスクに優れるために、どの単語と考えが似たコンテキストに現れるかを学ぶ必要がありました。これは「単語を知るには、それが属する会社を見よ」という古い観察です。

「犬」と「子犬」は同じ種類の文に現れるので、モデルはそれらを似たように表現することを学びました。「ホチキス」は異なる会社に属するので、別の場所に位置します。数百の数字は学習された意味の方向で、それぞれがテキストがどのように変化するかについての何らかの軸を捉えています。人間が読めるようにラベル付けされていません。数字をデコードすることはなく、2つのベクトルがどれだけ近いかだけを測定します。

Junoテキストをベクトルとして エンベディングはテキストの意味を表す数字のリスト(ベクトル)で、膨大なテキストで訓練されたモデルで生成されます。モデルは似たコンテキストに現れる単語と考えを近くに配置することを学んだので、似た意味は似たベクトルになります。数字を読むことはなく、2つのベクトルがどれだけ近いかだけを測定し、近さは意味を反映します。

キーワードではなく意味で照合する検索が必要なので、「お金を返して」が返金について述べている行を見つけます。その方法は、各テキストを ベクトル に変換することです。固定長の数字のリストで、似た意味が近く配置されます。エンベディングモデルはテキストを読んでそのベクトルを出力し、ポイント全体は、ベクトル間の距離が意味の類似性を表すということです。

ベクトルは設定された長さ(次元)を持ち、多くの場合、数百~数千の数字です。同じモデルで埋め込むすべてのテキストは同じ長さで出力されます。これにより、任意の2つを比較できます。これらの次元は意味の学習された方向で、人間がラベルした「カテゴリ」ではないため、次元47を「形式性」として読むことはしません。ベクトルを1つの不透明な点として扱い、距離を測定します。

何か実際のものを埋め込む前に、全体が機能するかどうかを決定するステップがあります:チャンキング。ドキュメント全体を1つのベクトルとして埋め込むことはめったにありません。20ページのマニュアルに対して1つのベクトルは、その中のすべてのトピックを1つの平均的なポイントにぼかし、何とも照合できません。代わりに、ドキュメントを チャンク に分割します。これは段落から1ページ程度のテキストで、各チャンクを単独で埋め込みます。ドキュメント全体ではなく、チャンクを埋め込んで、各ベクトルが1つの焦点を絞った考えを取り込むようにしてください。

チャンクサイズは、意識的に設定する現実のトレードオフです。大きすぎるチャンクは複数の考えを平均化し、あいまいに検索されます。小さすぎるチャンクは、文に意味を与えた周囲のコンテキストを失います。一般的な開始点は、チャンクあたり数百トークンで、隣同士に小さな重複があります。そうすれば、境界を越えた文も1つのチャンクに完全に表示され、その後、実際の検索が返すものに基づいて調整します。

Junoテキストをベクトルとして エンベディングはテキストを固定長のベクトルに変換し、距離は意味の類似性を表し、同じモデルからのすべてのベクトルは長さを共有するため、それらを比較できます。次元は学習された方向で、ラベルではないため、ベクトルを1つの不透明な点として扱います。最も重要なポイント:ドキュメントを段落サイズのテキストにチャンキングして、各チャンクを埋め込みます。ドキュメント全体に対して1つのベクトルはすべてを平均化してどろどろになるからです。

意味に基づく検索は1つのアイデアに基づいています:テキストを ベクトル空間 (固定次元の座標空間で、各点が数字のリスト)にマップしますので、セマンティック類似性が幾何学的近接性になります。エンベディングモデルはそのマップです。テキストを読んでベクトルを返します。

その上に構築するすべては、インデックス作成、検索、ランキングで、これらのベクトルの幾何学です。マッピングを間違えると、ダウンストリームの何もそれを回復しません。

最初の設計レバーは、何を埋め込むかで、それはチャンキングです:埋め込む前にソースドキュメントをテキストに分割します。ドキュメント全体を埋め込むのではなく。理由は、エンベディングが入力を1つのポイントへのロッシー圧縮なので、チャンクに含まれる異なる考えが多いほど、それらはあいまいな重心に平均化され、鮮い結果を検索しません。チャンクをユーザーが尋ねる単位(通常、数百トークンのテキスト)に適切なサイズに設定してください。境界をまたぐ事実が少なくとも1つのチャンクで生き残るように小さな重複があります。

チャンクの戦略は、モデルの選択よりも、検索品質が勝つか負けるかの場所です:

  • 固定サイズのウィンドウ は安いですが、文を途中で切ります。
  • 構造対応の分割 (見出し、段落、またはコードブロック上)は、各チャンクを一貫性のあるものに保ち、より良い検索傾向を持ち、より複雑なパイプラインのコストがかかります。

何を選んでも、チャンクのソースと位置をベクトルの隣に保存してください。検索時に、事実がどこから来たのかを指し示す必要があり、ベアベクトルはそれを教えてくれません。

も1つの財産を内在化する:エンベディング次元は解釈可能な軸ではないため、ベクトルを読んで検索をデバッグすることはできません。検索結果を検査して埋め込みをデバッグします。数字を読んでいません。クエリが間違ったチャンクを引き出すとき、修正はチャンキング、モデル、またはクエリで、検索された結果を通じて検査されます。座標そのものではなく。

Junoテキストをベクトルとして エンベディングモデルはテキストをベクトル空間にマップし、セマンティック類似性が幾何学的距離になり、後の各ステップはこれらのポイントの幾何学です。チャンキングはユーザーが尋ねることの単位にチャンクをサイズに設定するレバーです。できるだけ構造上で分割してください。各チャンクのソースと位置をベクトルの隣に保存してください。事実を追跡できるようにしてください。ベクトルを読んでデバッグすることはできないため、検索が横転するときは、数字ではなく、返ってきたものを検査してください。

エンベディングを生成する

エンベディングモデルにベクトルを尋ねます。通常のモデル呼び出しのようですが、異なるエンドポイントと異なるモデルです。

python
from openai import OpenAI

client = OpenAI()

EMBED_MODEL = "text-embedding-3-small"  # エンベディングモデル用のスワップポイント

def embed(text):
    response = client.embeddings.create(model=EMBED_MODEL, input=text)
    return response.data[0].embedding  # 数字のリスト

vector = embed("小さくてじゃれた犬")
print(len(vector))  # 例:1536の数字

結果は数字のリストです。すべての上に1つのルールが重要です:常に 同じモデル で作られたエンベディングを比較してください。異なるモデルからのベクトルは異なる空間に存在し、異なるユニットでの測定のように比較できません。モデルを混ぜると、毎回ナンセンスなスコアが出ます。

そして、すべてのモデル呼び出しのように、トークンで課金されます。大規模なドキュメントコレクションの埋め込みは、数千のドキュメント全体で実行する前に事前に見積もる価値のあるコストを持ちます。

Junoエンベディングを生成する エンベディングを生成するには、エンベディングモデルを呼び出し、テキストの数字のリストを返します。同じモデルで作られたベクトルを常に比較してください。異なるモデルは比較できないベクトルを生成するためです。センチメートルとインチのようなものです。エンベディングはトークンで課金されるため、大きなコレクションには実際の確認する価値のあるコストがあります。

呼び出し自体は、チャット呼び出しと同じ形の異なるエンドポイントです:テキストを送信してベクトルを取得します。

python
from openai import OpenAI

client = OpenAI()

EMBED_MODEL = "text-embedding-3-small"

def embed_batch(texts):
    # 多くのテキストを1つのリクエストに送信し、テキストごとに1つのベクトルを取得
    response = client.embeddings.create(model=EMBED_MODEL, input=texts)
    return [item.embedding for item in response.data]

chunks = ["小さくてじゃれた犬", "若い犬", "オフィス用品"]
vectors = embed_batch(chunks)  # チャンクごとに1つのベクトル、入力と同じ順序

シェイプはプロバイダーによって異なりますが、リクエスト応答の考え方はどこでも同じです。基本的な呼び出しを超えた2つの実用的なポイント。まず、バッチで 埋め込みます:ほとんどのエンドポイントは1つのリクエストでテキストのリストを受け取り、各テキストに対して1つのベクトルを返します。これは1チャンクあたり1呼び出しより高速で安いです。リクエストオーバーヘッドが少なく、レート制限に当たらないからです。大規模なコーパスをインデックスするとき、バッチ処理はコストと実時間を合理的に保つものです。

2番目に、同じモデルルールにはパートナーがあります:モデルと次元は選択です。デフォルトではありません。より大きなエンベディングモデルとより多くの次元は、より細かい区別をキャプチャしますが、計算、保存、比較のコストが増えます。データをまだ分離する最小のモデルと次元を選択します。

一部のモデルでは、短いベクトルをリクエストして、精度を少し犠牲にして、より安い保存とより速い検索と引き換えにすることもできます。選択したものが契約になります:後でモデルを変更すると、保存されたすべてのベクトルを再生成する必要があります。

Junoエンベディングを生成する エンベディングはテキストを取得してベクトルを返す1つのリクエストで、同じシェイプはプロバイダーの間で機能します。できるときにテキストを1つの呼び出しにバッチしてください。リクエストオーバーヘッドと大規模コーパス全体のレート制限圧力が削減されるからです。モデルと次元は実際の選択です:データをまだ分離する最小のものを選択し、モデルが契約になることを覚えてください。変更は、保存したものすべてを再埋め込みすることを意味するからです。

APIサーフェスは小さいです。テキストを送信してフロートベクトルを取得し、その呼び出しの興味深い決定は呼び出しの中ではなく、呼び出しの周りにあります。

python
from openai import OpenAI

client = OpenAI()

EMBED_MODEL = "text-embedding-3-small"

def embed_batch(texts):
    # 1つのリクエスト、多くのベクトルを返して、入力順序で
    response = client.embeddings.create(model=EMBED_MODEL, input=texts)
    return [item.embedding for item in response.data]

リクエストと応答シェイプはプロバイダーによって異なりますが、すべてのエンベディングエンドポイントはこの同じバッチイン、ベクトルアウト契約です。バッチ処理は規模でのいい話ではなく、インデックスジョブが完了してスロットルされないジョブとの違いです:各リクエストは固定オーバーヘッドとレート制限に対してカウントされるため、大きなバッチを送信してから、大きなジョブが当たる部分的な失敗時にバックオフして再試行することでアモルティゼします。

モデルと次元はロングテールを持つアーキテクチャの約束です。高次元ベクトルはより多くの区別を保存しますが、本番で重要なすべての軸でより多くのコストがかかります:ベクトルあたりのストレージ、インデックスのメモリ、比較あたりの時間。すべて次元でスケールします。一部のモデルは Matryoshkaエンベディング (より短い長さに切り詰めて使用できるベクトル)をサポートしており、精度のための完全なベクトルを保持し、安い最初のパス検索のための切り詰められたプリフィックスを提供できます。コーパスが十分に大きいとき、ストレージとクエリレイテンシ、モデル品質ではなく、バインディング制約の場合は価値があります。

後で噛みつく約束はバージョンです。保存されたエンベディングは永遠に1つの正確なモデルバージョンに結び付けられます。

2つのモデルバージョンからのベクトルは比較できないため、新しいモデルで新しいクエリを埋め込んで、古いモデルで構築されたインデックスと比較することはできません。結果は静かです:スコアは妥当に見え、ランキングは間違っています。モデルバージョンをインデックスのスキーマの一部として扱い、ベクトルの隣に保存してください。このチャプターの後半で説明される新鮮さの議論に含まれる、計画的な移行として再埋め込みを扱います。

Junoエンベディングを生成する エンベディング呼び出しはバッチイン、ベクトルアウト契約で、プロバイダーによってシェイプが異なりますが、考え方は異なりません。バッチ処理と再試行は、大規模なインデックスジョブが完了する代わりにスロットルするものです。モデルと次元はストレージ、メモリ、クエリレイテンシをスケールするため、品質ではなくスケールが制約の場合は、切り詰め可能なベクトルを使用します。バージョンは永遠の約束です:異なるモデルバージョンからのベクトルは静かに比較に失敗するため、バージョンをスキーマに保存し、再埋め込みを計画された移行として扱います。

類似性を測定する

2つのテキストがどの程度関連しているかを見つけるために、ベクトルがどれだけ近いかを測定します。標準的な測定値は コサイン類似度 で、-1から1の数字を返します。1に近いほど似ており、0に近いほど関連がありません。それを使用するために背後の数学を知る必要はありません。2つのベクトルが指す方向を比較すると考えてください。

方向は意味をここに運ぶ方法で、コサインは生の距離ではなく角度を比較する理由です。返金についての2つのテキストは、1つが短いフレーズであるか長いパラグラフであるかに関わらず同じ方法をポイントします。

python
import math

def cosine_similarity(a, b):
    dot = sum(x * y for x, y in zip(a, b))
    mag_a = math.sqrt(sum(x * x for x in a))
    mag_b = math.sqrt(sum(x * x for x in b))
    return dot / (mag_a * mag_b)

dog = embed("小さくてじゃれた犬")
puppy = embed("若い犬")
stapler = embed("紙を綴じるためのオフィス用品")

print(cosine_similarity(dog, puppy))    # 高い、2つは意味が近い
print(cosine_similarity(dog, stapler))  # 低い、2つは関連がない

数字は直感を確認します:犬と子犬のスコアが高く、犬とホチキスのスコアが低いです。クエリのベクトルを保存されたベクトルと比較することは、セマンティック検索の中心です。その1つの関数は、チャプターの残りが構築するムーブです。

Juno類似性を測定する コサイン類似度は2つのベクトルがどれだけ近いかを-1から1でスコアリングし、1に近いほど似ています。数学なしで使用できます。2つのベクトルが指す方向を比較します。これは、同じトピックについての短いフレーズと長いパラグラフが異なる大きさのベクトルを持っていても、まだマッチするスコアです。クエリのベクトルを保存されたベクトルと比較することは、セマンティック検索のコアムーブです。

ベクトルがあります。今、2つがどれだけ近いかを言う数字が必要です。標準は コサイン類似度 です:2つのベクトル間の角度を測定し、その長さを無視し、-1から1の値を返します。ここで高いほど似ています。角度は、長いテキストと短いフレーズが異なる大きさのベクトルを持っていても、同じトピックについては似たようなスコアを得るべきなので、あなたが望むものです。

python
def dot(a, b):
    return sum(x * y for x, y in zip(a, b))

# ベクトルが長さ1に正規化されている場合、コサイン類似度は内積と等しい
score = dot(query_vector, doc_vector)  # 除算は不要

規模で支払う移動は:保存時に 正規化 してベクトルを長さ1にしてください。すべてのベクトルが同じ長さを持つと、コサイン類似度の除算が消え、スコアはプレーンな内積になります。これは次元ごとに1回の乗算加算で、大きなセット全体で実行するのは非常に高速です。保存時に1回正規化し、内積で比較します。多くのエンベディングモデルは既に正規化されたベクトルを返しますが、それを仮定しないでください。確認してください。

おもちゃの例からのもう1つのシフト:単一の最も近いマッチが必要になることはめったにありません。トップk 検索が必要です。最も高いスコアの結果。通常3~10。1つのベクトルがニアミスでいる可能性がある一方、2番目と3番目は一緒に答えを保持し、小さなセットを返すと、次のステージで動く部屋が与えられます。上位1つだけを返すと、保持していることに感謝するコンテキストを捨てます。

Juno類似性を測定する コサイン類似度は2つのベクトル間の角度を-1から1で比較し、長さを無視するため、短いフレーズと長いテキストが同じトピックについてはまだマッチします。保存時にベクトルを長さ1に正規化すると、比較は高速な内積に折りたたまれます。大きなセット全体で加算されます。トップkの3~10の結果を取得します。最高のものだけではなく。答えは多くの場合、最初のいくつかに広がっているため。

類似性メトリックが必要です。コサイン類似度 (2つのベクトル間の角度の余弦、範囲は-1から1)はデフォルトです。ドキュメント長がトピックを圧倒しないため、大きさを無視します。その選択はパフォーマンスの結果を持っています:生のベクトルの上のコサインはドット積プラス2つの大きさ計算ごとに比較のコスト、あなたはすべてのクエリでインデックス内のすべてのベクトルに対してそれを支払います。

python
import numpy as np

# 書き込み時に正規化、ベクトルごとに1回
def normalize(v):
    v = np.asarray(v, dtype=np.float32)
    return v / np.linalg.norm(v)

# クエリ時に、正規化されたベクトルの上のコサインは単一のマトリックス-ベクトル積
def search(query_vec, matrix):
    return matrix @ query_vec  # 行ごとに1つのスコア、ベクトル化

最適化は、書き込み時に 正規化 してすべてのベクトルをユニット長にすることです。これにより、コサイン類似度は内積と同じになり、Pythonループの代わりに、1つのマトリックス-ベクトル乗算として全コーパスをスコアリングできます。書き込み時に正規化し、類似度は一度に全インデックスの内積です。これはブルートフォースベースラインです。正確で直接的で、コーパスサイズで線形です。これは、数百万程度のベクトルまで問題ありませんが、その上で失敗します。これは、後で説明する近似インデックスに移動するキューです。

おもちゃのメトリックが完全に隠すトの2つの本番現実。1番目は、argmaxを望むことはめったにありません。トップkと閾値スコアを望みます。最初と2番目の結果の間のギャップはマッチがどれだけ自信があるかを教えてくれるためです。そして、まだ低いスコアを付ける上位の結果はコーパスで実際に質問に答えたものが何もないことを意味します。これを「良い試合がない」として返すのではなく、最悪の行を渡します。2番目に、コサイン類似度は相対的であり、絶対的ではありません。0.4のスコアは、コーパスとモデルが生成するスコアの分布に対してのみ意味があります。ブログ投稿から魔法の数字をコピーするのではなく、インデックスごとに経験的に閾値を較正します。

Juno類似性を測定する コサイン類似度は大きさを無視するため長さは話題に溺れません。しかしブルートフォースコサインはスケールで死に、数百万のベクルの低い数字の上に、あなたは近似最近傍を走ります。書き込み時に正規化し、メトリックは全コーパス上で一度にマトリックス-ベクトル乗算として実行できるドット積になります。閾値付きトップkを検索し、低い上位スコアを最悪の行ではなく、マッチがないとして扱ってください。そして、ブログから数字をコピーするのではなく、インデックスごとに閾値を較正してください。数字は相対的です。

セマンティック検索

ピースを一緒に置き、キーワードではなく意味で検索できます。ドキュメントを一度埋め込み、ベクトルを保存します。クエリが来たときに、それも埋め込み、ベクトルが最も近いドキュメントを返します。

python
docs = [
    "アカウント設定ページからパスワードをリセットしてください。",
    "当社の返金ポリシーは30日以内の返品を許可しています。",
    "請求に関する質問についてはメールでサポートにお問い合わせください。",
]

# すべてのドキュメントを一度埋め込み、事前に
index = [{"text": text, "vector": embed(text)} for text in docs]

def search(query):
    query_vector = embed(query)
    scored = [{"text": item["text"], "score": cosine_similarity(query_vector, item["vector"])} for item in index]
    return sorted(scored, key=lambda x: x["score"], reverse=True)[0]  # 最も近いマッチ

print(search("お金を取り戻すにはどうすればいいですか?"))
# クエリと重要な単語を共有しないにもかかわらず、返金ポリシー行を返します

クエリ「お金を取り戻すにはどうすればいいですか?」は、それと重要な言葉を共有しない返金行を見つけます。セマンティック検索は綴りではなく意味で照合します。キーワード検索はそれを完全に見逃していたでしょう。クエリとドキュメントは重要な言葉を持ちません。

シェイプは常に同じです:一度埋め込み、ベクトルを保持し、リクエスト時にクエリを埋め込み、スコア、ソート、最も近いを返す。それが セマンティック検索 ループで、ハンドブックの残りをそれを再利用します。

Junoセマンティック検索 セマンティック検索はドキュメントを一度埋め込み、ベクトルを保存してから、入力クエリを埋め込み、コサイン類似度で最も近いドキュメントを返します。意味で照合するため、「お金を取り戻す」は単語を共有しない「返金ポリシー」行を見つけます。その意味ベースの照合は、キーワード検索ができないものです。

おもちゃの版はPythonリストにベクトルを保存し、各クエリですべてをスコアリングします。これはデモ向けに機能し、コーパスが成長します。破れます。線形スキャンは、すべてのクエリについてすべてのベクトルの全比較を実行するためです。また、すべての再起動でメモリでインデックスを再構築しています。

修正は ベクトルデータベース です:ベクトルを保持し、「このクエリベクトルに最も近いk番目を見つけます」をすばやくディスクから答えるために構築されたストア。独自のリストとループの代わりに、ベクトルを一度書き込んで、データベースはそれが検索、永続性、個別エントリ更新を処理します。

python
# ベクトルDBによってシェイプは異なりますが、パターンはどこでも同じです
index.upsert([
    {"id": "doc-1", "vector": embed(chunk), "metadata": {"source": "faq.md", "section": "refunds"}}
    for chunk in chunks
])

results = index.query(vector=embed(user_question), top_k=5)  # 最も近い5、1つだけではなく

データベースがリストに与えないことが2つあります:

  • トップk の結果を1つの呼び出しで返します。複数の最も近い、単一の最高ではなく、次のステージ。
  • それぞれの隣に メタデータ を保存します:ベクトル、ソースファイル、セクション、タイムスタンプ。そのため結果はそこから来たものを指すことができ、それでフィルタリングできます。

ベクトルをベクトルDBに保存してください。Pythonリストではなく。実データを持つ瞬間。リストは仕組みを学ぶためです。実際の実行ではありません。

Junoセマンティック検索 セマンティック検索は埋め込み一度、保存、クエリを埋め込み、最も近いを返しますが、Pythonリストとループはデモだけで生き残ります。すべてのクエリについてすべてのベクトルをスキャンし、再起動時に再構築は成長しません。実データを持つ瞬間にベクトルデータベースに移動:ディスクから高速トップk検索を行い、メタデータをベクトルの隣に保存してから、結果がソースを指すことができます。リストは仕組みを教え、データベースはそれを実行します。

参照ループ。埋め込み一度、保存、クエリを埋め込み、スコア、ソート、返す。正しく、スケールと連絡先で生き残りません。ブルートフォーススキャンはコーパスサイズごとのクエリで線形であるため、100万のベクトルと任意の実際のクエリレートで、検索するCPU秒を費やしていないので。本番検索のすべてはクエリをすべてのベクトルに対して比較しないことについてです。

それが 近似最近傍 検索が買うものです(ANN:すべてのベクトルをスキップすることは正確ですが、迅速に最も近いベクトルを見つけるが、真の最も近いアルゴリズムは実行します)。2つの家族が支配します:

  • HNSW (階層型ナビゲート可能小世界)はベクトルのレイヤー化グラフを構築し、粗から細へ歩み、低クエリレイテンシを与える高メモリのコストで。
  • IVF (逆転ファイル)クラスタベクトルとのみ最も近いクラスタを検索し、メモリを使用するが、データシフトがそのクラスタセンターを再訓練する必要があるため。

数百万のベクルの上で、ANNはオプションではありません。インデックスです。チューニングしているトレードオフは リコール (インデックスが実際に返す真の最近傍の割合)対レイテンシとメモリ:リコールを1.0に向けてプッシュし、クエリが遅くなり、それを緩和し、関連チャンクを静かに見逃します。

おもちゃループが完全に隠すフェイルモードは新鮮さです。インデックスはスナップショットです。ソースドキュメントが変わったときに、その保存されたベクトルは古く、現在のように取得される続けます。ドキュメント変更でキーにされた再埋め込みパイプラインが必要です:編集を検出し、そのドキュメントを再チャンクして再埋め込みし、新しいベクトルをアップセットしながら古いものを削除します。理想的には、実際に変更されたものだけを再埋め込みするのではなく、古いもの以上すべてのコーパスではなく、コンテントハッシュで追跡されます。古いベクトルは、検索システムが嘘をつき始めるための静かな方法です。

最後のギャップは完全一致です。ベクトル検索は見逃すために構築されています:注文「A-10293」またはエラーコードのクエリは、あいまいな領域に埋め込まれ、その文字列を含む1つのドキュメントを表示しません。ハイブリッド検索 はキーワード検索(正確なトークンを釘でとめます)とベクトル検索(意味を釘でとめます)一緒に実行し、ランキングをマージするため、識別子、名前、および希少用語はセマンティックブラーに失われません。ユーザーが正確な文字列を入力するコーパスがある場合、それに到達します。

Junoセマンティック検索 ブルートフォーススキャンはスケールで死に、数百万のベクトルの上で、近似最近傍を実行します。低レイテンシのためのHNSWまたは逆のためのIVF。そしてレイテンシに対するリコールをチューニングしています。より高いリコールはコストの速度を知ります。ドキュメント変更でキーにされた再埋め込みパイプラインを構築してください。コンテントハッシュで、インデックスはスナップショットで、古いベクトルは現在のように取得される続けるためです。そして、ユーザーが注文番号のような正確な文字列を入力するコーパスがある場合、ハイブリッドキーワードプラスベクトル検索を追加してください。純粋なベクトル検索はそれら右にぼかします。

エンベディングが何ではないか

エンベディングは類似性ツールで、思考ツールではありません。いくつかの 制限 は、正しいツールに到達するので心に留めています:

  • 彼らはしません 完全一致。正確な注文番号またはエラーコードを見つけるには、プレーンキーワードまたはデータベース検索がよりよいです。
  • 彼らは 理由 しません。2つのことが関連していることを教えてくれますが、なぜかは教えません。1つが論理的に他から続くかどうかも同様です。
  • 彼らは 古い 行きます。ドキュメントが変わったら、それらを再埋め込みするか、検索は古いコンテンツを指しています。

エンベディングは関連があるもの見つけます。彼らは本当のか現在のかを判断しません。これらのギャップの各々は、より良いツールを持ち、どちらを使用するかは知識がスキルの半分です。

Junoエンベディングが何ではないか エンベディングは類似性を測定します。理由ではなく完全一致を行いません。正確な注文番号またはエラーコードの場合は、代わりにキーワードまたはデータベース検索を使用します。そしてドキュメントが変わったときに、それらを再埋め込みするか、検索は古いコンテンツを指しています。

この程度まで機能するツールを持つトラップはどこでも到達することです。3つの制限は、どこで停止し、何か他のものを選ぶかを目立たせます。

完全一致は最初です。エンベディングは注文IDまたはエラーコードを、他のすべてのようなセマンティック空間にマップします。A-10293 は他の注文形ストリング、正確にそれ自体の近くにはランド。識別子、コード、ユーザーが文字通りに入力する値の場合は、キーワードまたはデータベース検索が正しいツールで、ハイブリッド検索 (キーワードとベクトル検索はまとめて実行)は一度にどちらでも方法です。

推論は2番目です。類似性は推論ではありません:2つのチャンク高いスコアは彼らが関連することについてであることを意味します。1つが質問に答えるか論理的に他から続くかではなく。推論は、取得モデルで発生します。チャンクを取得しない。取得候補を見つけます。モデルは考えています。

新鮮さは3番目で、静かに噛みつくことです。インデックスはいつ埋め込んだかのスナップショットですから。編集されたドキュメントは再埋め込みするまで古いワードを返し続けます。変更時に再埋め込みをシステムの一部として扱い、誰かが間違った答えに気づいたときに手で行うことではありません。

Junoエンベディングが何ではないか エンベディングは類似性ツールです。彼らは注文IDのような正確一致を見逃します。これらは、両方のハイブリッドのキーワード検索または理由を望みます。モデルはテキスト内のチャンク充填をします。静かなものは新鮮さです:インデックスはスナップショットです。編集されたドキュメントは再埋め込みするまで古いワードを返し続けます。誰かが間違った答えに気づくのを待つのではなく、システムに再埋め込みを構築してください。

エンベディングがどこで停止するかを知ることは、検索システムの信頼性を保つことです。本番で3つの境界が問題です。

完全一致は調整問題ではなく、構造的な盲点です。エンベディングは意味の隣近所に圧縮入力なので、識別子、コード、SKU、希少適切な名詞は自分たちにランドするのではなく、類似している見ストリングを向かいます。純粋なベクトル検索はニアミスを正確なヒット上で順位します。修正はハイブリッド取得で、語彙インデックス(キーワードまたはBM25、古典的な用語周波数ランキング)をベクトルインデックスの融合します。正確なトークンは正確にマッチしながら、意味は意味的にマッチし、幾何学の注文検索のギャンブルをしません。

ドリフトは静かに侵食される境界です。エンベディングドリフト は、インデックスの背後にあるモデルバージョンが変わったときに得るミスマッチです。2つのバージョンからのベクトルは異なる空間を占めて比較できません。古いモデルに対して構築されたインデックスに対して新しいモデルで埋め込みクエリはもっともらしく見えるナンセンスを返します。モデルバージョンをインデックススキーマにピンしてください。モデルアップグレードを完全再埋め込み移行として扱ってください。ドロップインではありません。静かに悪い結果だけがあるからです。エラーがスロー。

評価は、取得がすでに失敗するまでスキップされる境界です。取得が好むかどうかを眼球できません。測定します:既知の関連チャンクを持つクエリセットを保持し、リコール@k (正しいチャンクは上位kに着地しますか)と精度(スコア)を返しました。あなたが取得はリコール@kを測定していない場合は、作業しません。そのeval集合はまた、新しいチャンク戦略、モデル、またはハイブリッド重み付けが実際に役立つ場合は、あなたに伝えます。別のフェイルセットを交換せずに。まだ気付いていません。取得品質はRAGが立っている基盤なので、気付く検査なく、実際のテストを稼ぎます。

Junoエンベディングが何ではないか エンベディングは正確一致で構造的な盲点を持ちます。識別子とコードのために語彙インデックスをベクトルと融合します。幾何学に信頼するのではなく。エンベディングドリフトは静かなものです:異なるモデルバージョンからのベクトルは比較しません。バージョンをピンして、フルリエンベディングとしてアップグレードを扱ってください。そしてホールドアウトセットでリコール@kで取得を測定してください。眼球できないので、それはまた、実際の改善を見分ける場合は、あなたに伝えます。横の移動から。

実践中

完全なフロー上記のsearch関数に住んでいます:小さなFAQエントリを埋め込み一度、次に意味別のクエリに答えてください。パターンは任意のサイズで同じです。保存のみが成長時に変わります。

次のチャプターで、最も近いマッチを取得して、モデルにフィード。その答えメモリの代わりにドキュメントから。そのテクニックは RAG で、ここに書いた直接的に構築されています。

Juno実践中 セマンティック検索は完全なフロー:ドキュメントを埋め込み一度、その後各クエリについて埋め込み、コサイン類似度で最も近いを返します。これらのマッチを最も近いモデルにフィード。メモリの代わりにドキュメントから答えられます。これが検索で、次のチャプター。直接構築に。

メカニズムは決済:チャンク、バッチ埋め込み、ベクトルDBに保存、類似度でトップk取得。本番に変わるのは、周囲の配管です。変更時の再埋め込み。フィルタ対象のメタデータ。ピンモデルバージョン。

取得チャンクは終わりではありません。次のチャプターでは、冷凍トレーニングの代わりにドキュメントから答えるため、モデルにコンテキストしてフィード。それは RAG で、質問取得品質。ここの構築された上限はそれらの答えです。

Juno実践中 ループは、チャンク。バッチ埋め込み、ベクトルDBに保存。類似度でトップk。本番は周囲配管です:変更時の再埋め込み。メタデータフィルタ。ピンモデルバージョン。それらの取得チャンクはモデルの次のチャプターのコンテキストを導く。それはRAGです。答えはここの取得に設定する上限です。

すべてここ:チャンク。正規化。ANNインデックス。ハイブリッド取得。新鮮さ。リコール@k評価。これは取得層。答えが何か良いか静かに決定するAIシステムの一部。モデル上にすることができるのみ、取得されたハンド理由。自信がある間違った答え。通常、取得フェイル:生成コスチュームを着ている。

それは次のチャプターへの橋です。RAG はこの取得層フィード基礎を置いたコンテキストにモデルします。すべての失敗モード:ここ、古いベクトル、見逃した正確一致、低いリコール。表面は間違った答えしてもそこえ。古いベクトル。見逃した正確一致は実際のバグです。取得層を測定して新鮮に構築してください。RAGは立つものの固体を持ちます。

Juno実践中 取得層:チャンクでリコール@kを通じて。答えの何が良いか決める。モデルは取得。手渡す理由。誤った答えについて自信。通常、取得の失敗。偽装。それで古いベクトル。見逃した正確一致は実際のバグ。RAGを次のに。層フィード。モデル。固体に立つ上限。