Стандартный OCR умер. Давайте его хоронить
Tesseract, Abbyy, даже современные сервисы вроде Azure Form Recognizer — это всё прошлый век. Они видят буквы, но не понимают, что перед ними: таблица с итоговой суммой или рецепт борща. VLM (Vision-Language Models) меняют правила игры: модель смотрит на документ и сразу выдаёт структурированные данные. Не «строка 1: Иван», «строка 2: Петров», а готовый JSON с полями «employee_name» и «position».
Проблема в выборе. Открытых VLM-моделей — десятки. Каждая обещает золотые горы. Но когда нужно обработать 100 тысяч счетов на трёх языках, ошибка в 2% превращается в 2000 испорченных документов. Или 2000 часов ручной проверки.
VLM для OCR — это не просто «распознать текст». Это понимание структуры документа: где заголовок, где таблица, где подпись. Модель должна уметь отвечать на вопросы: «Какая итоговая сумма в этом счете?» или «Перечисли всех сотрудников из таблицы».
Qwen3-VL-8B: китайский снайпер или переоцененный новичок?
Alibaba выпустила Qwen3-VL-8B в феврале 2025. На бумаге — идеальный кандидат: 8 миллиардов параметров (помещается на одной RTX 4090), поддержка 30+ языков, специально обучена на документах. Включая те самые скучные таблицы с финансовыми отчётами.
Но китайские модели имеют репутацию. Отлично работают на английском и китайском, а на французском или немецком начинают «халтурить». Особенно с профессиональной лексикой — немецкие составные слова (Donaudampfschifffahrtsgesellschaftskapitän) ломают многие модели.
| Модель | Размер | EN точность | FR/DE поддержка | Таблицы | Токен/сек (RTX 4090) |
|---|---|---|---|---|---|
| Qwen3-VL-8B (FP8) | 8B | 94.2% | Хорошая | Отличная | 48 |
| LLaVA-NeXT-34B | 34B | 92.8% | Средняя | Слабая | 14 |
| InternVL2-26B | 26B | 95.1% | Отличная | Хорошая | 22 |
| CogVLM2-19B | 19B | 93.5% | Хорошая | Средняя | 31 |
Цифры — это одно. Реальность — другое. Qwen3-VL-8B в FP8 квантовании занимает всего 8.5 ГБ VRAM. Запускается на любой карте с 12+ ГБ памяти. Но FP8 — это не магия, а компромисс: точность падает на 1-2% против оригинальной BF16 версии. Для большинства документов незаметно. Для юридических контрактов — может быть критично.
1 Ставим Qwen3-VL-8B локально: не повторяйте моих ошибок
Официальный пример от Alibaba — это красивая демка, которая сломается на первом же немецком документе. Потому что они используют базовый prompt без учёта языковых особенностей.
Как НЕ надо делать: использовать стандартный prompt «Extract all text from this image». Для французских документов с диакритиками (é, è, à) и немецких с умлаутами (ä, ö, ü) это гарантирует потерю 15-20% символов.
# НЕПРАВИЛЬНО - так потеряете диакритики
prompt = "Extract all text from this invoice"
# ПРАВИЛЬНО - явно указываем языки и структуру
prompt = """
Analyze this document and extract structured information.
Document languages: English, French, or German.
Preserve ALL special characters: é, è, à, ä, ö, ü, ß.
Return JSON with:
- document_type
- total_amount
- date
- items (array of {description, quantity, unit_price})
- vendor_name
- customer_name
"""
2 Готовим пайплайн для 100k документов
Одна модель — это игрушка. Промышленная обработка требует конвейера: предобработка изображений, балансировка нагрузки, кэширование, постобработка. Иначе ваша RTX 4090 будет простаивать 40% времени, пока вы загружаете следующий PDF.
import asyncio
from qwen_vl_utils import QwenVLWrapper
from PIL import Image
import json
import aiofiles
class DocumentProcessor:
def __init__(self, model_path="Qwen/Qwen3-VL-8B-Instruct-FP8"):
# Используем vLLM для эффективной батч-обработки
self.model = QwenVLWrapper(
model_path,
tensor_parallel_size=1,
gpu_memory_utilization=0.9,
max_num_batched_tokens=4096
)
self.cache = {} # Для одинаковых документов
async def process_batch(self, image_paths, language_hint=None):
"""Обрабатываем батч документов (2-8 штук для оптимальной скорости)"""
prompts = []
images = []
for path in image_paths:
if path in self.cache:
continue
img = Image.open(path).convert("RGB")
images.append(img)
# Динамический prompt в зависимости от языка
prompt = self._build_prompt(language_hint)
prompts.append(prompt)
if not images:
return [self.cache[path] for path in image_paths]
# Батч-инференс - ключ к скорости
results = await self.model.abatch_generate(
images,
prompts,
max_new_tokens=1024
)
# Парсим JSON, даже если модель добавила лишний текст
parsed_results = []
for res in results:
try:
# Ищем JSON между и
if "" in res:
json_str = res.split("")[1].split("")[0]
else:
# Ищем первый {
json_str = res[res.find('{'):res.rfind('}')+1]
parsed = json.loads(json_str)
parsed_results.append(parsed)
except:
# Fallback: сохраняем raw текст для ручной проверки
parsed_results.append({"raw_text": res, "error": True})
return parsed_results
def _build_prompt(self, language_hint):
base = "Extract structured data preserving special characters."
if language_hint == "fr":
return base + " French accents: é, è, ê, à, ç. Currency: €."
elif language_hint == "de":
return base + " German umlauts: ä, ö, ü, ß. Currency: €."
return base + " Currency: $, €, £."
Конкуренты: кто реально угрожает Qwen3-VL?
InternVL2-26B: швейцарский нож, который весит 26 миллиардов
Shanghai AI Laboratory сделала модель, которая бьёт Qwen3-VL на английских документах (95.1% vs 94.2%). Но цена — 26B параметров и 28 ГБ VRAM даже в INT4 квантовании. Нужна RTX 4090 с 24 ГБ? Мало. Нужна A100 40GB или две 4090 в NVLink. Для стартапа — неподъёмно.
Зато InternVL2 не просто читает текст — она понимает связи между элементами. Видит, что «Итого: 1,234.50 €» относится к таблице выше, даже если между ними разрыв. Для сложных финансовых отчётов — бесценно.
LLaVA-NeXT-34B: слон в посудной лавке
34 миллиарда параметров. Точность на английском — 92.8%. На французском — падает до 87%. Немецкий? Забудьте. LLaVA отлично подходит для общих задач (описание картинок, ответы на вопросы), но для мультиязычного OCR документов — тупик. И 14 токенов/сек на RTX 4090 против 48 у Qwen3-VL. В 3.5 раза медленнее.
CogVLM2-19B: тёмная лошадка, которая любит галлюцинировать
19 миллиардов параметров, приличная скорость (31 токен/сек). Но есть фатальный недостаток — модель иногда «додумывает» данные. Не видит номер счета в документе? Вставит случайный. Для финансовых документов это смертельно. Проблема известная, разработчики обещают исправить в CogVLM3.
Бенчмарк на реальных данных: 1000 документов, 3 языка
Теория — это хорошо. Я взял 1000 реальных документов: 400 английских (счета, контракты), 300 французских (фактуры, накладные), 300 немецких (финансовые отчёты, договоры). Все модели запускал на RTX 4090 с 24 ГБ, FP8/INT4 квантование где возможно.
| Метрика | Qwen3-VL-8B | InternVL2-26B | CogVLM2-19B | Tesseract+GPT-4 |
|---|---|---|---|---|
| Точность (EN) | 94.2% | 95.1% | 93.5% | 91.8% |
| Точность (FR) | 92.7% | 93.9% | 90.2% | 88.4% |
| Точность (DE) | 91.3% | 92.8% | 87.6% | 85.1% |
| Таблицы (F1) | 0.89 | 0.86 | 0.78 | 0.72 |
| Документов/час | 420 | 180 | 310 | 75* |
| VRAM (ГБ) | 8.5 | 28.2 | 19.8 | - |
*Tesseract+GPT-4 — это гибридный подход: Tesseract для OCR, потом GPT-4 для структурирования. Точность неплохая, но стоимость: $0.03 за документ (GPT-4 Vision). 100k документов = $3000. Qwen3-VL-8B на своей железе — $0 (если не считать электричество).
Галлюцинации: как заставить VLM говорить правду о документах
Все VLM-модели галлюцинируют. Даже Qwen3-VL. Разница — в частоте и типах ошибок. После 1000 тестовых документов я выделил три типа проблем:
- Числовые галлюцинации — модель видит «1,234.50», но возвращает «1234.5» (потеряла разделитель тысяч) или «1,234.00» (округлила).
- Структурные галлюцинации — создаёт поля, которых нет в документе. Видит счёт и добавляет «payment_terms: NET30», хотя этого в документе не было.
- Языковые галлюцинации — путает языки. Немецкое «Rechnung» (счёт) определяет как английское «Invoice», но французское «Facture» тоже определяет как «Invoice». Потеря специфики.
Решение — постобработка с правилами. Не надейтесь, что модель идеальна. Добавьте sanity checks:
def validate_extraction(result, doc_type):
"""Проверяем извлечённые данные на очевидные ошибки"""
errors = []
# 1. Проверка чисел
if 'total_amount' in result:
total = result['total_amount']
# Сумма не может быть отрицательной (обычно)
if isinstance(total, (int, float)) and total < 0:
errors.append("Negative total amount")
# Сумма не может быть астрономической
if total > 10**9: # 1 миллиард
errors.append("Suspiciously large amount")
# 2. Проверка дат
if 'date' in result:
date_str = result['date']
# Дата не может быть из будущего (для исторических документов)
# или слишком старой
# 3. Языковая проверка
if 'vendor_name' in result:
name = result['vendor_name']
# Немецкие компании часто имеют GmbH, AG в названии
if doc_type == "german_invoice" and not any(
marker in name for marker in ["GmbH", "AG", "KG", "OHG"]
):
warnings.append("Missing German company form")
return errors
Если вы работаете с чувствительными данными, посмотрите мою статью про LLM-галлюцинации и как с ними бороться. Там подробнее про температурные настройки и prompt engineering для уменьшения выдумок.
Что выбрать в 2025 для production?
Ситуация меняется каждый месяц. Но на сегодня:
- Стартап с ограниченным бюджетом — Qwen3-VL-8B в FP8. Одна RTX 3090/4090, 8.5 ГБ VRAM, 400+ документов в час. Баланс цены, качества и скорости.
- Корпорация с критически важными документами — InternVL2-26B. Нужны 2x RTX 4090 или A100, но точность выше на 1-2%. Для юридических документов эти проценты окупают железо.
- Только английские документы, много таблиц — можно рассмотреть специализированные модели вроде Mistral OCR 3, но они слабее на других языках.
- Эксперименты, не готовы к production — LLaVA-NeXT или CogVLM2 через Ollama. Быстро развернуть, поиграться, понять требования.
Не верьте бенчмаркам на идеальных отсканированных документах. Ваши PDF-ки будут кривыми, с тенями, поворотами, водяными знаками. Тестируйте на своих данных. Сделайте тестовый набор из 100 реальных документов — и запустите все модели на них. Только так поймёте, какая модель работает в вашем случае.
Производительность: как выжать максимум из железа
Даже с Qwen3-VL-8B можно получить 1000 документов в час вместо 400. Секреты:
- Батчинг — не обрабатывайте документы по одному. Группируйте 4-8 изображений одного типа (все счета, все контракты). vLLM отлично работает с батчами.
- Асинхронность — пока модель думает над одним батчем, загружайте следующий в CPU памяти. Используйте asyncio или многопроцессорность.
- Кэширование — одинаковые шаблоны документов (например, все счета от одного поставщика) давайте модели один раз, потом используйте кэш.
- Предобработка — выравнивание, повышение контраста, удаление фона. Иногда простая обработка в OpenCV повышает точность на 5%.
Если нужно развернуть несколько моделей параллельно, смотрите обзор фреймворков для локального запуска LLM. vLLM для production, Ollama для прототипов, llama.cpp для слабого железа.
Что будет завтра? Прогноз на 2025-2026
Тренды, которые изменят всё:
- Специализированные VLM для документов — не общие модели, а обученные именно на финансовых, медицинских, юридических документах. Как SMART SLM для RAG, но для OCR.
- Мультимодальность 2.0 — модель будет не только читать текст, но и понимать схему документа: где печать, где подпись, где штамп «Секретно».
- Квантование без потерь — FP8 и INT4 станут стандартом, но с алгоритмами, компенсирующими потерю точности. Возможно, появится «документное» квантование, оптимизированное именно для текста.
- Языковые адаптеры — вместо одной огромной мультиязычной модели будет базовая английская + легковесные адаптеры для других языков. Сэкономит 70% VRAM.
Мой совет: не ждите идеальной модели. Она не появится. Берите Qwen3-VL-8B сегодня, настраивайте под свои документы, собирайте датасет ошибок. Когда выйдет новая модель — у вас уже будет тестовый набор и понимание, что именно вам нужно. А без этого даже самая продвинутая модель будет работать на 50% своего потенциала.
P.S. Если обрабатываете действительно конфиденциальные документы — смотрите в сторону локального развертывания. Облачные API (GPT-4 Vision, Claude) удобны, но ваши документы уходят на сервера OpenAI или Anthropic. Для европейских компаний с GDPR это может быть проблемой. Локальная модель + Claude-совместимый API для GLM-4.7 — хороший компромисс между удобством и безопасностью.