tei-mcp v0.3:原文を書き換えずにTEIを付ける

初めてtei-mcpについて書いたとき、目標はAIアシスタントにTEIマークアップをでっち上げさせないことでした。スキーマによるグラウンディングで、問題の一部は片づきました。P5仕様をツール経由で直接引けるようになれば、モデルは要素の意味や受け入れる属性を当て推量しなくて済む。出力は検証を通ります。
しかしTEIエンコーディングにおけるハルシネーションには二つの顔があり、スキーマが捉えるのはその一つだけです。仕様に照らした検証が教えてくれるのは、マークアップが整っていることまで。そのマークアップが包むテキストについては何も語りません。そして害の大きいハルシネーションが潜んでいるのは、まさにそこ――テキストそのもの――なのです。v0.3の目玉であるスパン固定合成は、これを防ぐためだけに設計されました。
目次
スキーマが捉えられないハルシネーション
モデルに16世紀のフランス語書簡をエンコードさせると、見たところ非の打ちどころのないTEI文書が返ってくることがよくあります。ヘッダーは埋まり、<persName>タグは正しい位置にあり、<dateline>も整っている。validate_documentにかければ通ります。
そこで本文を原文と突き合わせてみてください。
mesmeがmêmeになっています。コンマが一つ移動している。luyはいつの間にかluiに現代化されている。写本で読みにくかった節は、もっと読みやすいものに「訂正」されている。どれも頼んだ覚えのない変更です。どれにも印はつきません。文書はスキーマ上は妥当で、しかしひっそりと間違っている。
エンコードされたテキストがそのまま恒久的な記録となり、後続の読者、検索インデックス、引用のよりどころになるアーカイブのワークフローにとって、これこそもっとも重大な故障の型です。壊れたタグは腹立たしい。しかし5年間誰も気づかない現代化された綴りは、汚損なのです。
スパン固定合成
新リリース(v0.3)は、まさにこの故障の型を狙い撃ちにしたハルシネーション防止の仕組みを搭載しています。設計目標は、本文のハルシネーションを単に起こりにくくするのではなく、構造上ありえなくすることです。
考え方は単純です。モデルは本文を一文字も打たない。
代わりに、ワークフローはこう進みます。
- モデルは
get_source("letter_001")を呼び、原文のプレーンテキストを不変の文字列として受け取ります。 - 付けたいタグごとに
tag_span("letter_001", start, end, element_path, attrs)を呼び、原文上の文字範囲にTEI要素を登録します。 - 終わったら
compose("letter_001")を呼びます。サーバーは記録されたタグを元のプレーンテキストに織り込んで最終的なTEIを描画し、そのうえで、描画された文書の平文の内容が原文と等しいことをバイト単位で検証します。
バイトが一致すれば、文書が返ってきます。一致しなければ――モデルのタグがどういうわけか、原文と1文字でも違う本文を含意していれば――compose()は汚損した文書を返す代わりに例外を投げます。
このワークフローには、モデルが原文と本文の異なるTEI文書を生み出す経路が存在しません。この不変条件は機械的なもので、モデルの振る舞い頼みではありません。モデルがハルシネーションを起こさないと信じる必要はない。信じるべきは、二つのバイト列の==比較だけです。
これは何で、何でないか
スパン固定合成はスキーマ・グラウンディングを補うものであって、置き換えるものではありません。スキーマ・グラウンディングのツール群(validate_document、lookup_element、valid_children、そして元の16個の残り)は、モデルが妥当なTEIを作る助けになります。スパン固定合成は、そのTEIの中の本文が原文に忠実であることを保証します。実運用に耐えるエンコーディングのワークフローは両方の軸を満たさなければならず、いまや両方が一つのサーバーで賄えます。
万能薬でもありません。compose()はまだ、登録されたタグが読み込み済みのODDカスタマイズのもとで許されるかどうかを確認しません。これは次の課題です。記録されたタグはプロセスのメモリ上にあり、再起動すると消えます。また原文ファイルは、サーバーが動く場所から読める必要があります。いずれも対処可能ですし、中核の不変条件を揺るがすものではありません。
TEIの外でも大事な理由
このパターンは一般化できます。モデルにテキストの注釈付け、変換、ラッピングを頼むとき――そして、モデルがテキストを「改善」する力よりも元のテキストの完全性のほうが大事なときはいつでも――同じ形の解決策が使えます。モデルにテキストを打ち直させてはいけません。テキストに対する指示を出させ、決定論的なコンポーザーに、等価性の不変条件のもとでそれを適用させるのです。
とりわけデジタル版にとって、これは責任をもってモデルに任せられる仕事の範囲を変えます。エンコーディングは突如として、出力をいちいち原文と手作業で突き合わせなくても委ねられる仕事になる。退屈な道は機械が引き受け、編集者は綴りではなくマークアップを点検すればよいのです。
アップデートの入手
すでにtei-mcpを入れている場合:
uvx tei-mcp@latest
新規なら:
pip install tei-mcp
スパン固定合成を使うには、原文プレーンテキストのディレクトリをサーバーに指定します。
export TEI_MCP_SPAN_SOURCE_ROOT=/path/to/sources
uvx tei-mcp
各ファイルのステム(拡張子を除いた名前)が文書IDになります(letter_001.txt →
letter_001)。
ソースコード、完全なドキュメント、不変条件の設計ノート: github.com/Pantagrueliste/tei-mcp
