tei-mcp v0.3: кодировать в TEI, не переписывая источник

5 мая 2026 г.·
Clément Godbarge
Clément Godbarge
· 4 мин. для прочтения
post Цифровые гуманитарные науки

Когда я впервые писал о tei-mcp, цель была одна: отучить ИИ-ассистентов галлюцинировать разметку TEI. Заземление на схему решило часть проблемы: имея прямой, инструментальный доступ к спецификации P5, модели больше не нужно гадать, что означает элемент и какие атрибуты он принимает. Результат проходит валидацию.

Но у галлюцинации в кодировании TEI два лица, и схема ловит лишь одно. Валидация по спецификации говорит, что разметка корректна. О тексте, который эта разметка обёртывает, она не говорит ничего. А именно там — в самом тексте — живут самые разрушительные галлюцинации. Сборка по закреплённым отрезкам (span-locked composition), главная новинка v0.3, придумана специально, чтобы их не допускать.

Содержание

Галлюцинация, которую схема поймать не может

Попросите модель закодировать французское письмо XVI века — и нередко получите документ TEI безупречного вида. Заголовок заполнен, теги <persName> расставлены правильно, <dateline> оформлен как положено. Прогоните его через validate_document — он пройдёт.

А потом сравните основной текст с источником.

mesme превратилось в même. Запятая переехала. luy тихо осовременили до lui. Фразу, которую трудно было разобрать в рукописи, «исправили» во что-то более гладкое. Ни одного из этих изменений никто не просил. Ни одно не помечено. Документ валиден по схеме и тихо неверен.

Для архивного процесса — где закодированный текст становится постоянной записью, на которую опираются последующие читатели, поисковые индексы и цитаты, — это самый важный вид сбоя. Кривой тег раздражает. Осовремененное написание, которого никто не замечает пять лет, — это порча.

Сборка по закреплённым отрезкам

Новый выпуск (v0.3) содержит механизм предотвращения галлюцинаций, нацеленный ровно на этот сбой. Цель конструкции — сделать галлюцинации в основном тексте невозможными по самому устройству, а не просто маловероятными.

Идея проста: модель никогда не набирает основной текст.

Вместо этого процесс выглядит так:

  1. Модель вызывает get_source("letter_001") и получает исходный простой текст в виде неизменяемой строки.
  2. Для каждого тега, который она хочет поставить, она вызывает tag_span("letter_001", start, end, element_path, attrs), регистрируя элемент TEI на диапазоне символов источника.
  3. Закончив, она вызывает compose("letter_001"). Сервер переплетает записанные теги с исходным простым текстом, отрисовывает итоговый TEI и затем проверяет байт за байтом, что плоское текстовое содержимое полученного документа равно источнику.

Если байты совпадают, документ возвращается. Если нет — если теги модели каким-то образом подразумевают основной текст, отличающийся от источника хотя бы на один символ, — compose() выбрасывает исключение вместо того, чтобы вернуть испорченный документ.

В этом процессе нет пути, на котором модель выдала бы документ TEI с основным текстом, отличным от источника. Инвариант механический, а не поведенческий. Вам не нужно верить, что модель не станет галлюцинировать; нужно верить лишь проверке == между двумя байтовыми строками.

Что это такое — и чем это не является

Сборка по закреплённым отрезкам дополняет заземление на схему, а не заменяет его. Инструменты заземления (validate_document, lookup_element, valid_children и остальные из первоначальных шестнадцати) помогают модели выдавать валидный 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

Имя каждого файла без расширения становится идентификатором документа (letter_001.txtletter_001).

Исходный код, полная документация и заметки о конструкции инварианта: github.com/Pantagrueliste/tei-mcp

Clément Godbarge
Authors
Преподаватель цифровых гуманитарных наук
Клеман Годбарж — преподаватель цифровых гуманитарных наук в Университете Сент-Эндрюс. Его исследования посвящены науке и искусству управления в Европе раннего Нового времени. В готовящейся книге он рассматривает, как врачи при французских и итальянских дворах XVI века утверждали себя в качестве политических экспертов нового типа. Его работу поддерживали Фонд Эндрю У. Меллона, Комиссия Фулбрайта, Американское общество Ренессанса и Гарвардский университет.