Извлечение и структурирование данных через go2llm: классификация, парсинг и батч на дешёвых моделях
При извлечении данных вход доминирует: вы подаёте модели документ на тысячи токенов, а получаете JSON на несколько десятков. go2llm считает такой сценарий по профилю 85 / 10 / 5, и в нём разрыв между дешёвой и дорогой моделью максимален: glm-5.3-flash стоит $0,02148 за 1M смешанных токенов, claude-opus-5 — $0,681063, в 31,7 раза больше.
Дата публикации: 11 сентября 2026, каталог цен v38. Часть обзора сценариев go2llm.
Задача
Разложить поток неструктурированного текста по полям: вытащить из письма сумму, контрагента и срок; отнести тикет к одной из 12 категорий; разобрать резюме в JSON; проставить тональность отзыва; нормализовать адрес. Работа однотипная, объёмная и не требующая рассуждений — ровно тот случай, где дорогая модель не даёт выигрыша в качестве, зато даёт его в счёте.
Почему здесь не работает профиль кодинг-агента 10/5/85. У агента неизменный префикс читается из кэша десятки раз подряд, поэтому 85% объёма уходит в дешёвую статью cache. При извлечении данных всё зеркально: каждый документ уникален, кэшируется только инструкция и схема (сотни токенов), а тело документа каждый раз тарифицируется по полной ставке in. Профиль, выведенный из бюджета одного документа на 4 000 токенов:
| Статья | Что входит | Токенов на документ | Доля |
|---|---|---|---|
| input | тело документа + инструкция + JSON-схема | 3 400 | 85% |
| output | извлечённый JSON | 400 | 10% |
| cache read | повторное чтение общего префикса инструкции | 200 | 5% |
Формула: mixed = in × 0,85 + out × 0,10 + cache × 0,05.
Какие модели подходят и почему
Раз 85% счёта — это вход, выбирайте по колонке in. Смешанные цены по профилю 85/10/5:
| Модель | in | out | cache | mixed 85/10/5, $/1M | Кому |
|---|---|---|---|---|---|
glm-5.3-flash | 0,018 | 0,06 | 0,0036 | 0,02148 | массовая классификация |
deepseek-v4-flash | 0,0226 | 0,0679 | 0,00072 | 0,026059 | рабочий дефолт |
minimax-m3 | 0,0396 | 0,158 | 0,00792 | 0,049839 | альтернатива дефолту |
gpt-5.6-luna | 0,04 | 0,24 | 0,004 | 0,0582 | OpenAI-протокол |
mimo-v2.5 | 0,056 | 0,112 | 0,00112 | 0,058856 | простые поля |
deepseek-v4-pro | 0,066 | 0,198 | 0,0022 | 0,07601 | документы сложнее |
gemini-3.5-flash-lite | 0,07 | 0,583 | 0,007 | 0,118158 | Google-семейство |
glm-5.3 | 0,141 | 0,442 | 0,0261 | 0,165356 | многошаговое извлечение |
claude-haiku-4-5 | 0,13 | 0,65 | 0,013 | 0,176149 | сложная семантика |
claude-sonnet-5 | 0,329 | 1,64 | 0,0329 | 0,445294 | эталон для разметки выборки |
claude-opus-5 | 0,503 | 2,51 | 0,05025 | 0,681063 | не для потока |
Разворот для glm-5.3-flash: 0,018 × 0,85 = 0,0153; 0,06 × 0,10 = 0,006; 0,0036 × 0,05 = 0,00018. Сумма — $0,02148.
Неочевидное: gpt-5.6-luna и mimo-v2.5 в этом профиле стоят почти одинаково ($0,0582 против $0,058856), хотя по входу gpt-5.6-luna дешевле почти на треть (0,04 против 0,056) — разницу компенсирует более дорогой выход у luna (0,24 против 0,112). В профиле чат-бота, где выход весит 25%, разрыв стал бы заметным; здесь он весит только 10%.
Практический приём: разметьте 200 документов на claude-sonnet-5 как эталон, а поток гоняйте на glm-5.3-flash. go2llm даёт обе модели по одному ключу gk_sk_… — переключение это одна строка в коде.
Как подключить
Извлечение в JSON по фиксированной схеме, OpenAI SDK, base URL https://go2llm.tech/v1:
import json
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://go2llm.tech/v1")
SCHEMA = """Верни ТОЛЬКО JSON без пояснений:
{"counterparty": string, "amount_rub": number, "due_date": "YYYY-MM-DD", "category": "invoice"|"act"|"other"}"""
def extract(document: str) -> dict:
r = client.chat.completions.create(
model="qwen3-8-flash",
max_tokens=400,
temperature=0,
messages=[
{"role": "system", "content": SCHEMA},
{"role": "user", "content": document},
],
)
print(r.usage) # у go2llm здесь есть cost_usd
return json.loads(r.choices[0].message.content)
Батч у go2llm делается вашей конкурентностью: отдельного endpoint'а для батчей в опубликованном списке (/v1/messages, /v1/chat/completions, /v1/images/generations) нет. Лимит по умолчанию — 20 RPM на ключ, поэтому воркер должен уважать Retry-After, а не долбить в ретраях:
import asyncio, os
from openai import AsyncOpenAI
client = AsyncOpenAI(api_key=os.environ["GO2LLM_API_KEY"],
base_url="https://go2llm.tech/v1")
sem = asyncio.Semaphore(4)
total_cost = 0.0
async def one(doc: str):
global total_cost
async with sem:
for attempt in range(5):
try:
r = await client.chat.completions.create(
model="qwen3-8-flash", max_tokens=400, temperature=0,
messages=[{"role": "user", "content": doc}],
)
total_cost += getattr(r.usage, "cost_usd", 0.0)
return r.choices[0].message.content
except Exception:
await asyncio.sleep(2 ** attempt) # backoff, учитывая Retry-After
return None
async def main(docs):
out = await asyncio.gather(*(one(d) for d in docs))
print(f"потрачено ${total_cost:.4f} на {len(docs)} документов")
return out
Поддержку response_format: {"type": "json_object"} и structured outputs мы пока не документировали — напишите в @go2llm_support, ответим и дополним страницу. Пока закладывайте валидацию ответа на своей стороне: парсить JSON в try, на ошибке — один повтор с более жёсткой инструкцией в system-промпте.
Batch-endpoint'а с пониженной ставкой у go2llm нет: опубликованы только /v1/messages, /v1/chat/completions и /v1/images/generations, и все они тарифицируются по одному прайсу. Параллелить извлечение приходится на своей стороне — как в коде выше, с оглядкой на лимит 20 RPM на ключ.
Важное ограничение: текстовые endpoint'ы go2llm не принимают изображения, PDF и бинарные данные — вернётся 400 unsupported_content_type. Сканы и PDF надо прогонять через свой OCR и подавать в go2llm уже текстом.
Сколько это стоит
Объём: 100 000 документов в месяц по 4 000 токенов = 400M токенов. По профилю 85/10/5 это 340M входа, 40M выхода, 20M чтения кэша.
glm-5.3-flash:
- вход: 340 × $0,018 = $6,12
- выход: 40 × $0,06 = $2,40
- чтение кэша: 20 × $0,0036 = $0,072
- итого $8,592 ≈ 742 ₽ по курсу ЦБ 86,3793 ₽/$ на 01.09.2026
deepseek-v4-flash на том же объёме: 340 × 0,0226 = $7,684; 40 × 0,0679 = $2,716; 20 × 0,00072 = $0,0144 → $10,4238.
claude-sonnet-5: 340 × 0,329 = $111,86; 40 × 1,64 = $65,60; 20 × 0,03288 = $0,6576 → $178,1176.
claude-opus-5: 340 × 0,503 = $171,02; 40 × 2,51 = $100,40; 20 × 0,05025 = $1,005 → $272,425 ≈ 23 532 ₽. Это в 31,7 раза дороже glm-5.3-flash за ту же работу.
Отдельный, ещё более выпуклый расчёт — чистая классификация: 500 токенов на вход, 10 токенов на выход («категория: 7»). Миллион классификаций = 500M входа + 10M выхода.
glm-5.3-flash: 500 × 0,018 = $9,00; 10 × 0,06 = $0,60 → $9,60 ≈ 829 ₽ за миллион классификаций.claude-sonnet-5: 500 × 0,329 = $164,50; 10 × 1,64 = $16,40 → $180,90. В 18,8 раза дороже.
Стоимость одного документа на glm-5.3-flash — $8,592 ÷ 100 000 = $0,00008592. Welcome-грант go2llm в $1 при регистрации — это 1 ÷ 0,00008592 ≈ 11 639 документов. Пилот на реальной выборке помещается в грант целиком.
Как контролировать расход
Батч опасен тем, что ошибка в цикле стоит денег мгновенно и в больших количествах. Рычаги go2llm на ключ: квота в долларах, список разрешённых моделей, IP allow-list, срок действия, лимит 20 RPM по умолчанию.
Рецепт для батча:
- отдельный ключ на джобу со сроком действия — истёк, и забытый cron не съест баланс;
- квота с запасом 20% к расчёту: $10,31 при расчёте $8,59 выше;
- в allowed models оставить только
glm-5.3-flash— тогда опечаткаclaude-opus-5в конфиге даст403 model, а не счёт на $272,43; max_tokensстрого по схеме (400, а не 4096): выход — 10% счёта, но обрезать его дешевле, чем объяснять;temperature: 0— для извлечения полей вариативность не нужна.
Списание у go2llm двухфазное: резерв оценочной стоимости до вызова, потом списание фактической и освобождение остатка. Баланс не уходит ниже нуля, при нехватке приходит 402 insufficient_balance — батч должен уметь остановиться, а не потерять очередь.
Считайте фактическую цену сами: суммируйте usage.cost_usd по прогону, как в коде выше, и сравнивайте с оценкой. go2llm отдаёт это поле в каждом ответе.
Грабли
429 rate_limit на десятой секунде батча. 20 RPM на ключ — это 20 документов в минуту с одного ключа. Проектируйте конкурентность и backoff заранее, уважайте Retry-After.
400 unsupported_content_type. Попытались скормить PDF или скан в /v1/chat/completions. go2llm на текстовых endpoint'ах бинарь не принимает.
Модель вернула JSON в markdown-заборе. json.loads падает. Пока не подтверждён JSON-режим, чистите ``` `json ``` обёртку и валидируйте схему на своей стороне.
404 model_not_found. Каталог версионируется; точный ID берите из curl https://go2llm.tech/v1/models — без ключа.
400 model_protocol_mismatch. Модель вызвана не на своём endpoint'е. Нужный указан в /v1/models.
502 upstream_unavailable. Безопасный текстовый запрос можно повторить с задержкой — в извлечении данных запросы идемпотентны по смыслу. Полный справочник — коды ошибок go2llm.
FAQ
Дешёвая модель не испортит качество извлечения? Проверяется за час: размечаете 200 документов на claude-sonnet-5, гоняете ту же выборку на glm-5.3-flash, считаете расхождения по полям. Если точность сопоставима — разница в счёте 21× (по расчёту выше $8,59 против $178,12) окупает любую проверку.
Можно ли подать в go2llm PDF или скан напрямую? Нет. go2llm публикует /v1/messages, /v1/chat/completions и /v1/images/generations; на текстовые endpoint'ы изображения и PDF не принимаются (400 unsupported_content_type). Embeddings и обработка документов в опубликованный список тоже не входят.
Что с приватностью извлекаемых данных? go2llm не сохраняет промпты и ответы в продуктовых логах: технический лог содержит метаданные, usage, стоимость, маршрут, статус и очищенную ошибку. Подробные request logs хранятся до 90 дней.
Дальше
Кодинг-агент · Чат-бот и поддержка · Генерация контента · Командный доступ · Документация · Цены