コンテンツにスキップ

PageClassifier and ChunkClassifier

文書ごとではなく、ページごと・チャンクごとに尋ねられる分類器のポート。

英語版が原文です。

プロトコル:

  • PageClassifier.id: ClassifierId
  • PageClassifier.classify(text: str) -> Mapping[str, tuple[LabelScore, ...]]
  • PageClassifierProvider.page_classifiers() -> tuple[PageClassifier, ...]
  • ChunkClassifier.id: ClassifierId
  • ChunkClassifier.classify(text: str) -> Mapping[str, tuple[LabelScore, ...]]
  • ChunkClassifierProvider.chunk_classifiers() -> tuple[ChunkClassifier, ...]

これらは DocumentClassifier の単位だけを変えたもので、他は何も変わりません。同じ classify(text) のシグネチャ、同じファセットから LabelScore への回答、同じ予約キー。ただし文書全体に一度ではなく、ページごとに一度、あるいはチャンクごとに一度尋ねられます。

単位こそがこれらの存在理由です。表紙が申請書で本文が往復書簡である一件書類には、単一の文書種別がありません。法令を引用するチャンクは、それについて論じる段落と同じ種類のテキストではありません。それに対する文書レベルの回答は、間違っているというより、述べる価値のあることを述べられないのです。

出荷済みの 3 つの分類器は、文書用のポートに加えてこの 2 つのポートからも、それぞれ 1 つのオブジェクトを 3 つのフックで宣言しています。これらが存在するのは、分類器を単位で分割したことがエンティティ抽出の場所を作ったからであり、その格子のラベル側の半分を作らずに残せば、この分割が単位についてではなくエンティティについてのものに見えてしまうからです。

代替案は target フィールドを持つ 1 つのポートで、それはマージ規則で破綻します。DocumentClassifier はファセットを「有効化された最初のものが勝つ」で解決します。これは回答が文書全体についてのときは正しく — 一件書類の文書種別は 1 つです — ページごとには誤りです。異なるページについて答えた 2 つの分類器が 1 つのファセットで衝突し、最初のものが黙って文書全体を取ってしまいます。呼ばれ方によってマージ規則が変わるポートは、誤ってマージされるポートです。

単位をプロトコルに織り込むと、規則は設定されるものではなく型から導かれるものになります。文書のファセットは回答が 1 つ、単位ごとのファセットはブロックで引ける写像です。各実装のコストも明瞭になります。単位ごとに 1 コール要するモデルは DocumentClassifier では 1 コール、ChunkClassifier では数百コール要し、その違いは呼び出し側が発見するのではなく選ぶべきものです。

入力は 1 つの単位の全文です。リーダーが生成したままのページのテキストか、チャンカーが切ったままのチャンクのテキスト。サンプルではありません。サンプリングは契約を離れており、縛りが必要な実装は自前のものを適用します(ADR-0033)。

ChunkClassifier はチャンク粒度を要します。CHUNK を求めていないリクエストでこれを名指しすることは、ソース取得前の 422 です。分類すべきチャンクが存在せず、空の回答は意見なしに見えてしまうからです。ページ分類器にはこの要件がありません。ページは常に生成されるからです。

ID は 5 つの分類器・抽出器ポートすべてにまたがる 1 つの名前空間なので、ページ分類器がチャンク分類器や抽出器と ID を共有することはできず、レジストリは構築時にその衝突を拒否します。未知の ID と data_residency 下の external な実装は、DocumentClassifier とまったく同じように、取得前に、同じ理由で拒否されます。

raise はソースではなく分類器についての判定です。エグゼキューターはログに残し、その単位を飛ばし、次の分類器に尋ねます。devicecost_usdbuiltin はプロトコルの外にあり、既定値付きで読まれます。これは変わりません。

  • 渡されたテキストについてだけ答え、他については答えない。ページ分類器は文書を見られず、一方から他方を推論するのは文書レベルのポートの仕事です。
  • 推測するくらいならファセットを省き、各ファセットを降順に並べる。
  • 縛りが必要なら自分の入力を自分で縛り、それを自分の設定で述べる。もう隠れられる契約上の上限はありません。
  • モジュールスコープを安価に保つ。検出はスナップショット構築中にすべてのプロバイダーモジュールをインポートするため、エンジンのインポートは classify() の内側に置く。
  • 動けないときは何も公表しない。エクストラなし、モデルなしなら、壊れた分類器ではなく分類器なし。
  • 何度も尋ねられることを前提にする。単位ごとのポートはページごと、チャンクごとに呼ばれるので、呼び出しごとの準備は呼び出しの中ではなく最初の呼び出しの背後に置く。

DocumentExecutor.encode は取得前に有効化された ID を解決してレジデンシーを確認し、文書を読み、有効化された各分類器に各単位をリクエスト順で尋ねます。ページの回答は各ページブロックの metadataCLASSIFICATION_METADATA_KEY として書かれ、チャンクの回答は文書ブロックに CHUNK_CLASSIFICATION_METADATA_KEY として、チャンクブロック ID で引ける形で書かれます。チャンクブロックはメタデータを持たないからです(ADR-0031)。あるファセットについて意見を持つ最初の分類器が、その単位についてそれを取ります。文書についてではありません。

何も読めなかったページは分類されず、キーを持ちません。キーは EncodeRequest.metadata で予約されたままです。

POLICY_VERSION は動きません。ラベルは出力への注釈です。機能スナップショット ID も動きません。これらの ID を名指しするフィールドは広告であり、コンテンツハッシュから除外されているので、1 つインストールしても既存の計画は無効になりません。