ИИ-инженерия: карта трека, что умеют модели и что от них ждать
Есть два разных ремесла, которые в вакансиях называют одинаково. Первое — машинное обучение: вы собираете датасет, выбираете архитектуру, крутите градиенты, боретесь с переобучением. Второе — ИИ-инженерия: модель уже обучена кем-то другим, у вас есть HTTP-эндпоинт, и ваша работа — превратить вероятностный текстовый генератор в предсказуемый компонент продакшн-системы.
Этот трек — про второе. Мы почти не будем обучать модели (кроме статьи про LoRA, где обсудим, когда это вообще оправдано). Мы будем заниматься тем, чем на практике занят ИИ-инженер: проектировать контекст, ограничивать вывод схемой, подмешивать свои данные, давать модели инструменты, ставить лимиты, считать деньги, ловить регрессии и не пускать в прод то, что ломается на 5% запросов.
Ключевой сдвиг мышления: LLM — это не функция, это подсистема с распределением исходов. Обычный код на одном входе даёт один выход. LLM на одном входе даёт распределение выходов, и ваша задача — сузить это распределение до приемлемого инженерными средствами: форматом ответа, схемой, валидацией, ретраями, проверками. Всё остальное в треке — техники сужения этого распределения.
Карта трека
Порядок статей не случаен: каждая следующая техника решает проблему, которую создала предыдущая. Промптинг упирается в неструктурированный вывод — приходит structured output. Structured output упирается в незнание ваших данных — приходит RAG. RAG упирается в необходимость действовать, а не только отвечать — приходят инструменты и агенты. Агенты упираются в невозможность понять, стало ли лучше — приходят evals. Evals упираются в счёт за API — приходит продакшн-экономика.
| # | Статья | Какую проблему решает |
|---|---|---|
| 01 | Основы LLM для инженера | «Почему это стоит столько и работает так медленно» |
| 02 | Основы промптинга | Модель отвечает не то и не в том формате |
| 03 | Продвинутые техники | Модель ошибается на многошаговых рассуждениях |
| 04 | Структурированный вывод | Ответ невозможно распарсить программно |
| 05 | RAG | Модель не знает ваших документов |
| 06 | Продвинутый RAG | Поиск возвращает мусор на сложных вопросах |
| 07 | Агенты и ReAct | Нужно действовать, а не только отвечать |
| 08 | Мультиагентные системы | Одна роль не тянет задачу целиком |
| 09 | MCP | Интеграции с инструментами не переиспользуются |
| 10 | Оценка и бенчмарки | Непонятно, стало лучше или хуже |
| 11 | Локальные модели | Данные нельзя отдавать наружу |
| 12 | Дообучение | Промпт не вмещает нужное поведение |
| 13 | Продакшн и стоимость | Счёт растёт быстрее выручки |
| 14 | Безопасность и инъекции | Пользователь перехватывает управление агентом |
| 15 | ИИ в жизненном цикле разработки | Как применить всё это к собственной работе |
Если вам не хватает фундамента под капотом — что такое трансформер, откуда берётся attention, как считается softmax — соседние треки закрывают этот слой: нейросети и машинное обучение. Здесь мы берём модель как чёрный ящик с известными свойствами.
Что модели умеют на самом деле
Маркетинг оперирует процентами на бенчмарках, инженерная практика — профилями надёжности. Разница принципиальная: 90% на бенчмарке означает, что каждый десятый ответ неверен, и вопрос лишь в том, дорого ли вам стоит этот десятый.
Полезнее делить задачи не по «сложности», а по стоимости ошибки и проверяемости результата.
Правый нижний и правый верхний квадранты — там, где живёт вся реальная ценность: результат можно проверить дешевле, чем произвести. SQL-запрос выполняется на тестовой базе. Патч прогоняется тестами. Извлечённые поля сверяются со схемой и суммами. Слева — зона, где LLM выглядит убедительно и ошибается незаметно; там нужен человек, а не более длинный промпт.
Про бенчмарки: как их читать
Цифры на публичных наборах устаревают за месяцы, поэтому запоминать конкретные проценты бессмысленно — важно понимать, что каждый бенчмарк меряет и как он врёт.
| Бенчмарк | Что меряет | Главная слабость |
|---|---|---|
| MMLU | Знания по 57 предметам, выбор из вариантов | Насыщен, часть вопросов с ошибками, утечка в претрейн |
| HumanEval | 164 маленькие функции на Python | Не про инженерию: нет репозитория, зависимостей, легаси |
| GPQA | Вопросы уровня PhD, «google-proof» | Узкие домены, малый объём |
| SWE-bench | Реальные issue из GitHub-репозиториев | Чувствителен к обвязке: скор меняется в разы от харнеса |
| τ-bench | Агент + инструменты + диалог с пользователем | Синтетические домены |
| ARC-AGI | Абстрактные визуальные закономерности | Не коррелирует с бизнес-задачами |
| Chatbot Arena | Слепые парные сравнения людьми | Меряет приятность ответа, а не корректность |
Историческая калибровка полезнее абсолютных чисел. В статье про SWE-bench (октябрь 2023) лучшая модель закрывала около 2% задач. Через два года ведущие модели с агентной обвязкой закрывают больше половины, и SWE-bench Verified из «невозможного» превратился в «показатель качества харнеса». Вывод для практики: разрыв между моделью и вашим результатом определяется обвязкой сильнее, чем выбором модели. Одна и та же модель с плохим и хорошим агентным циклом даёт разницу в разы.
Актуальные срезы смотрите на живых лидербордах: HELM, swebench.com, Chatbot Arena. И главное — свой датасет из 50 реальных запросов вашего продукта информативнее любого публичного бенчмарка; как его собрать, разбираем в статье про оценку.
Где модели ломаются
Это раздел, который отличает инженера от энтузиаста. Каждый пункт — предсказуемый режим отказа с известным контрмерами.
1. Уверенная выдумка. Модель обучена продолжать текст правдоподобно, а не воздерживаться. На вопрос о несуществующем API она сгенерирует красивую сигнатуру. Контрмеры: RAG с обязательными цитатами, инструмент проверки, chain-of-verification (статья 03).
2. Провал в середине контекста. Информация в середине длинного контекста используется хуже, чем в начале и конце — эффект показан в Lost in the Middle. Окно в миллион токенов не означает, что можно свалить туда всё. Контрмеры: реранжирование, сжатие контекста, помещать критичное в начало и конец.
3. Хрупкость к формулировке. Перестановка двух предложений в системном промпте меняет метрику на несколько процентов. Это не баг, а свойство: у вас нет градиента, только текстовый интерфейс. Контрмеры: версионирование промптов, регрессионный прогон на каждое изменение, никаких правок промпта «на глаз в проде».
4. Дрейф модели. Провайдер обновил модель — ваши промпты, откалиброванные под прошлую версию, поехали. Реальный пример из практики миграций: агрессивные формулировки вида CRITICAL: YOU MUST use this tool работали на моделях, которые плохо следовали инструкциям, и начинают переcрабатывать на моделях, которые следуют им буквально — инструмент вызывается там, где не нужен. Контрмеры: пин версии модели, прогон evals перед миграцией, документированный чек-лист изменений.
5. Prompt injection. Любой текст, попавший в контекст — письмо, веб-страница, содержимое файла — это потенциальная инструкция. Классическая работа: Not what you’ve signed up for. Если у агента есть инструменты, инъекция превращается в удалённое выполнение действий. Контрмеры: разделение каналов доверия, ограничение прав инструментов, подтверждение необратимых действий (статья 14).
6. Накопление ошибки в агентном цикле. Если каждый шаг верен с вероятностью $p$, то $n$ шагов подряд дают $p^n$. При $p = 0{,}95$ и $n = 20$ это уже 36%. Отсюда — вся дисциплина агентного дизайна: проверяемые шаги, откат, критик, ограничение глубины цикла.
7. Отсутствие калибровки уверенности. Модель не умеет надёжно сообщать «я не знаю». Просьба «оцени свою уверенность от 0 до 100» даёт число, слабо связанное с реальной вероятностью правоты. Контрмеры: внешние сигналы — согласованность нескольких прогонов (self-consistency), совпадение с найденными источниками, успешность выполнения сгенерированного артефакта.
Анатомия ИИ-приложения
Любое серьёзное LLM-приложение состоит из одних и тех же слоёв. Понимание этой схемы даёт словарь для всего трека.
rate limit, PII} G -->|отклонён| REJ[Отказ с объяснением] G -->|принят| R{Роутер} R -->|простой| CHEAP[Дешёвая модель] R -->|нужны знания| RET[Поиск по данным] R -->|нужны действия| AG[Агентный цикл] RET --> HYB[Гибридный поиск
BM25 + вектора] HYB --> RR[Реранкер] RR --> CTX AG --> TOOL[Инструменты] TOOL --> AG AG --> CTX CHEAP --> CTX[Сборка контекста
система + примеры + данные] CTX --> CACHE{Кэш префикса?} CACHE -->|попадание| LLM CACHE -->|промах| LLM[Вызов модели] LLM --> VAL{Валидация:
схема, цитаты, инварианты} VAL -->|провал, попытка < 2| CTX VAL -->|провал, лимит| FB[Фолбэк или эскалация] VAL -->|успех| OUT[Ответ] OUT --> LOG[(Трейс: промпт, ответ,
токены, латентность, вердикт)] LOG --> EVAL[Регрессионный датасет]
Три вещи, которые в этой схеме обычно забывают и потом дорого доделывают:
- Гейт на входе. Ограничение частоты, фильтрация PII, отсев заведомо неподходящих запросов. Дешевле отказать, чем сгенерировать.
- Валидация на выходе как часть контура, а не как логирование. Провал схемы должен приводить к повторной попытке с сообщением об ошибке, а не к 500-й пользователю.
- Трейс с самого первого дня. Логи вызовов — единственный источник будущего eval-датасета. Приложение без трейсов невозможно улучшать: вы не знаете, на чём оно ошибается.
Лестница возможностей: не поднимайтесь раньше времени
Самая частая и самая дорогая ошибка новичка — начать с мультиагентной системы там, где хватило бы одного промпта с JSON-схемой.
Правило простое: поднимайтесь на следующую ступень только после того, как текущая измеримо провалилась на вашем eval-датасете. Каждая ступень добавляет стоимость, латентность и площадь отказа. Anthropic формулирует это же в Building Effective Agents: большинство успешных продакшн-систем — это не агенты, а простые композиции вызовов.
Вертикальная граница на схеме — важнейшая архитектурная развилка. Слева от неё поток управления задан вашим кодом: его можно отладить, воспроизвести, покрыть тестами. Справа модель сама решает, что делать дальше: это даёт гибкость и одновременно означает, что вам нужны лимиты итераций, таймауты, ограничение прав инструментов и полная наблюдаемость.
| Ступень | Когда достаточно | Симптом, что пора выше |
|---|---|---|
| Промпт | Одношаговое преобразование текста | Ответ нельзя распарсить |
| Схема | Нужен машиночитаемый результат | Модель не знает фактов о вашем домене |
| RAG | Ответ выводится из документов | Нужно посчитать, записать, вызвать API |
| Workflow | Шаги известны заранее | Порядок шагов зависит от промежуточных результатов |
| Агент | Нужна адаптивная последовательность действий | Одна роль путает цели, качество не растёт с числом итераций |
| Мультиагент | Нужны разделение ролей и независимая проверка | — |
Первый рабочий пример
Возьмём типовую задачу: классификация входящего тикета поддержки со структурированным выводом. Это ступень 2 — и её достаточно для огромного числа продуктов.
import json
import anthropic
from pydantic import BaseModel, Field
from typing import Literal
client = anthropic.Anthropic() # ключ берётся из окружения
class TicketTriage(BaseModel):
"""Результат разбора тикета — контракт между моделью и вашим кодом."""
category: Literal["billing", "bug", "feature_request", "account", "other"]
severity: Literal["low", "medium", "high", "critical"]
# Строгие enum'ы вместо свободного текста: невалидное значение
# физически не пройдёт валидацию схемы на стороне API.
summary: str = Field(description="Одно предложение, не более 20 слов")
needs_human: bool = Field(description="true, если нужен живой оператор")
SYSTEM = """Ты — система разбора обращений в поддержку SaaS-платформы.
Классифицируй обращение строго по данным из текста.
Если данных для уверенной классификации не хватает — ставь category=other
и needs_human=true. Не додумывай факты, которых нет в обращении."""
def triage(ticket_text: str) -> TicketTriage:
response = client.messages.parse(
model="claude-opus-4-8",
max_tokens=1024,
system=[{
"type": "text",
"text": SYSTEM,
# Префикс стабилен между запросами — кэшируем его.
# Чтение из кэша примерно в 10 раз дешевле обычного ввода.
"cache_control": {"type": "ephemeral"},
}],
messages=[{"role": "user", "content": ticket_text}],
output_format=TicketTriage, # схема принуждает модель к валидному JSON
)
return response.parsed_output
Обратите внимание на четыре инженерных решения, а не на промпт:
- Схема как контракт.
Literalвместоstrозначает, что модель не может вернуть категорию"биллинг "с опечаткой и пробелом — она ограничена на уровне декодирования. - Явный путь отказа. Инструкция «не хватает данных → other + needs_human» превращает неопределённость в наблюдаемый сигнал вместо выдумки.
- Кэш префикса. Системный промпт неизменен, значит его можно закэшировать. Требование одно: префикс должен совпадать побайтово. Любая динамика внутри него — дата, имя пользователя, случайный ID — обнуляет кэш молча.
- Никакого
temperature. На новых моделях Anthropic (Opus 4.7/4.8, Sonnet 5) параметры сэмплирования удалены из API и возвращают 400. Поведение задаётся промптом и параметром усилия, а не температурой. Что это значит для воспроизводимости — разбираем в статье 01.
Тот же контракт на TypeScript:
import Anthropic from "@anthropic-ai/sdk";
import { z } from "zod";
import { zodOutputFormat } from "@anthropic-ai/sdk/helpers/zod";
const client = new Anthropic();
const TicketTriage = z.object({
category: z.enum(["billing", "bug", "feature_request", "account", "other"]),
severity: z.enum(["low", "medium", "high", "critical"]),
summary: z.string(),
needs_human: z.boolean(),
});
export async function triage(ticketText: string) {
const response = await client.messages.parse({
model: "claude-opus-4-8",
max_tokens: 1024,
system: [{ type: "text", text: SYSTEM, cache_control: { type: "ephemeral" } }],
messages: [{ role: "user", content: ticketText }],
output_config: { format: zodOutputFormat(TicketTriage) },
});
// parsed_output равен null, если разбор не удался — обрабатываем явно,
// а не через `!`, иначе редкий провал схемы уронит обработчик.
if (!response.parsed_output) {
throw new Error(`Схема не сошлась, stop_reason=${response.stop_reason}`);
}
return response.parsed_output;
}
Экономика: считайте до того, как писать код
ИИ-функция — единственная часть вашего продукта, у которой себестоимость линейна по трафику и видна в отдельном счёте. Считать её нужно на этапе дизайна.
Модель ценообразования у всех провайдеров одинакова: цена за миллион входных токенов и за миллион выходных, при этом выход дороже входа в 4–5 раз. Возьмём актуальный прайс Anthropic (документация) как рабочий ориентир — у других провайдеров порядок величин сопоставим:
| Модель | Вход, $/1M | Выход, $/1M | Контекст |
|---|---|---|---|
| Claude Opus 4.8 | 5.00 | 25.00 | 1M |
| Claude Sonnet 5 | 3.00 | 15.00 | 1M |
| Claude Haiku 4.5 | 1.00 | 5.00 | 200K |
Посчитаем реальную нагрузку: 100 000 запросов в сутки, 3000 входных токенов, 500 выходных.
Ежедневный объём: 300M входных + 50M выходных токенов.
| Конфигурация | Расчёт | В сутки | В месяц |
|---|---|---|---|
| Всё на Opus | 300·5 + 50·25 | 2750 $ | ~82 500 $ |
| Всё на Sonnet | 300·3 + 50·15 | 1650 $ | ~49 500 $ |
| Всё на Haiku | 300·1 + 50·5 | 550 $ | ~16 500 $ |
| Sonnet + кэш префикса (2500 из 3000 токенов стабильны) | 250·0.3 + 50·3 + 50·15 | 975 $ | ~29 250 $ |
| Роутинг: 70% Haiku, 30% Sonnet | 0.7·550 + 0.3·1650 | 880 $ | ~26 400 $ |
| Роутинг + кэш | — | ~600 $ | ~18 000 $ |
Из одной таблицы следуют три главных рычага продакшн-экономики, которым посвящена статья 13:
- Кэширование префикса — самый дешёвый по усилиям выигрыш. Запись в кэш стоит примерно 1.25× от обычного ввода, чтение — около 0.1×. Значит, окупаемость наступает уже со второго запроса с тем же префиксом. Условие — префикс неизменен побайтово, а рендер идёт в порядке
tools → system → messages. - Роутинг моделей — 70% запросов в типичном продукте тривиальны. Классификация, извлечение, форматирование прекрасно работают на младшей модели; старшая нужна для остатка.
- Сокращение выхода. Выходной токен в пять раз дороже входного и вдобавок в сотни раз медленнее (вход обрабатывается параллельно, выход — последовательно). Требование «отвечай одним абзацем без преамбулы» экономит и деньги, и время.
Отдельно: batch API даёт 50% скидки для всего, что не требует мгновенного ответа — ночная разметка, переиндексация, массовая генерация. Если задача терпит час, это бесплатная половина бюджета.
Латентность: где на самом деле уходит время
Интуиция «поиск медленный, модель быстрая» неверна ровно наоборот.
Разложение важно тем, что показывает бесполезность локальных оптимизаций. Ускорение векторного поиска с 40 до 10 мс даёт 0.3% выигрыша по общему времени. Реальные рычаги — другие:
- Стриминг. Не сокращает полное время, но снижает воспринимаемую задержку с 9 секунд до 0.8: пользователь видит первый токен и начинает читать. Для любого интерактивного интерфейса это обязательно.
- Сокращение объёма генерации. 500 токенов вместо 1500 — это минус 11 секунд напрямую.
- Кэш префикса — сокращает не только цену, но и время до первого токена: предзаполнение уже сделано.
- Параллелизация независимых вызовов. Если поиск и классификация намерения не зависят друг от друга, запускайте их одновременно.
- Прогрев кэша. Запрос с
max_tokens: 0на старте воркера прогревает кэш префикса, чтобы первый живой пользователь не платил за холодный старт латентностью.
Практическое следствие: проектируйте под TTFT (time to first token) и токен/с, а не под полное время ответа. Именно эти две метрики видит пользователь.
Агентный цикл: что происходит внутри
Забегая в статью 07 — вот минимальный цикл, который отличает агента от вызова модели. Схема из ReAct, 2022 год, и с тех пор принципиально не менялась.
таймаут — на стороне оркестратора,
не на стороне модели
Две детали, на которых спотыкаются все:
Результаты параллельных вызовов возвращаются одним сообщением. Если модель запросила три инструмента и вы отправите три отдельных сообщения с результатами, вы молча приучите её больше не вызывать инструменты параллельно — латентность вырастет в разы без единой ошибки в логах.
Провалившийся инструмент всё равно требует результата. Возвращайте tool_result с флагом ошибки и внятным текстом. Молча выброшенный вызов ломает соответствие идентификаторов и приводит к 400 от API либо к зацикливанию.
Дисциплина оценки: без неё это не инженерия
Если у вас нет способа измерить изменение, вы не разрабатываете — вы гадаете. Минимальный eval-контур строится за час и окупается на первой же миграции модели.
Каркас на 40 строк, которого достаточно для старта:
import json, statistics, concurrent.futures as cf
from dataclasses import dataclass
@dataclass
class Case:
input: str
expected: dict # эталон, размеченный человеком
tags: list[str] # для разреза метрик: "длинный", "на английском", "неоднозначный"
def load_cases(path: str) -> list[Case]:
"""Кейсы берутся из продовых трейсов, а не выдумываются:
выдуманные кейсы меряют ваше воображение, а не продукт."""
with open(path, encoding="utf-8") as f:
return [Case(**json.loads(line)) for line in f]
def score(actual: dict, expected: dict) -> float:
"""Начинайте с точных проверок. LLM-as-judge — только там,
где ответ принципиально неформализуем (см. статью 10)."""
keys = expected.keys()
return sum(actual.get(k) == expected[k] for k in keys) / len(keys)
def run_eval(fn, cases: list[Case], workers: int = 8) -> dict:
with cf.ThreadPoolExecutor(max_workers=workers) as pool:
results = list(pool.map(lambda c: (c, fn(c.input)), cases))
scores = [score(out.model_dump(), c.expected) for c, out in results]
by_tag: dict[str, list[float]] = {}
for (c, _), s in zip(results, scores):
for t in c.tags:
by_tag.setdefault(t, []).append(s)
return {
"n": len(scores),
"mean": round(statistics.mean(scores), 4),
# p10 важнее среднего: он показывает худшие 10% — именно они
# порождают тикеты в поддержку и отток пользователей.
"p10": round(sorted(scores)[len(scores) // 10], 4),
"by_tag": {t: round(statistics.mean(v), 4) for t, v in by_tag.items()},
"failures": [c.input[:80] for (c, _), s in zip(results, scores) if s < 1.0][:10],
}
Сложность: $O(n)$ вызовов модели на прогон, время — $O(n / w)$ при $w$ параллельных воркерах, память — $O(n)$ на хранение результатов. При 50 кейсах и 8 воркерах прогон занимает секунды и стоит центы. Это единственная метрика в треке, экономить на которой нельзя.
Три правила, выстраданные практикой:
- Разрезы важнее среднего. Средние 0.92 могут скрывать 0.60 на кейсах с длинным вводом. Тегируйте кейсы с первого дня.
- p10, а не mean. Пользователи запоминают худшие ответы, а не типичные.
- Список провалов — главный артефакт прогона. Не число, а конкретные входы, которые нужно прочитать глазами.
Типичные ошибки первых месяцев
Начинать с агента. Симптом: три недели отладки цикла для задачи, которая решалась одним вызовом со схемой. Лечение — лестница выше.
Промпт как строковая константа в коде. Промпт — это артефакт с версией, набором тестов и историей изменений. Правка «на глаз» без прогона — гарантированный регресс.
Игнорировать stop_reason. Обрезка по max_tokens выглядит как валидный ответ и молча теряет хвост. Всегда проверяйте причину остановки до чтения содержимого.
Тихая порча кэша. datetime.now() или UUID в системном промпте обнуляют кэш, и вы платите полную цену, не получая ошибки. Диагностика одна: если cache_read_input_tokens равен нулю на повторных запросах — ищите динамику в префиксе.
Экономить на младшей модели по своей инициативе. Выбор модели — продуктовое решение с явной ценой качества, а не оптимизация, которую инженер делает молча.
Считать RAG решением проблемы галлюцинаций. RAG заземляет ответ на документы, но модель по-прежнему может исказить найденное. Без обязательных цитат и проверки цитат вы получаете правдоподобную выдумку со ссылками.
Валидировать вывод логированием. Провал схемы — это ветка исполнения с ретраем и фолбэком, а не строка в логе.
Один длинный промпт вместо композиции. Промпт на 4000 слов, который делает пять вещей, отлаживать невозможно: изменение ради одной задачи ломает другую. Пять промптов по 200 слов тестируются независимо.
Как проходить трек
Трек рассчитан на инженера, который умеет писать код и разворачивать сервисы, но не занимался LLM системно. Формат каждой статьи одинаков: интуиция → строгое объяснение → рабочий код → замеры и trade-offs → типичные ошибки → продакшн-практика.
Практическая рекомендация: ведите один сквозной проект через весь трек. Возьмите реальную задачу — разбор ваших логов, поиск по вашей документации, ассистент по вашему API — и наращивайте её от статьи к статье. Каждая техника из трека будет применяться к тому же коду и тому же eval-датасету, и вы увидите настоящие дельты, а не учебные примеры.
Что понадобится: Python 3.11+ или Node 20+, API-ключ любого провайдера (бюджета в 20 $ хватит на весь трек), Docker для локальных моделей в статье 11, и git — потому что промпты и датасеты версионируются как код.
Мини-итог
- ИИ-инженерия — это управление распределением исходов вероятностной подсистемы инженерными средствами: схемой, валидацией, поиском, лимитами и evals.
- Бенчмарки говорят о моделях, а не о вашем продукте; разрыв между моделью и результатом определяется обвязкой сильнее, чем выбором модели.
- Ломается предсказуемо: выдумка, провал в середине контекста, хрупкость к формулировке, дрейф версий, инъекции, накопление ошибки $p^n$ в цикле.
- Поднимайтесь по лестнице промпт → схема → RAG → workflow → агент → мультиагент только после измеренного провала текущей ступени.
- Экономика решается тремя рычагами: кэш префикса, роутинг моделей, сокращение выхода. Вместе они дают снижение счёта в 3–4 раза.
- Латентность на 90% состоит из генерации: спасают стриминг, короткий ответ и параллелизация, а не быстрый векторный индекс.
- Без eval-датасета из реальных запросов вы не разрабатываете, а гадаете.
Источники
- Vaswani et al., Attention Is All You Need — архитектура, на которой всё стоит
- Hoffmann et al., Training Compute-Optimal LLMs (Chinchilla) — почему модели такие, какие есть
- Ouyang et al., Training language models to follow instructions (InstructGPT) — откуда взялась инструктивность
- Wei et al., Chain-of-Thought Prompting и Wang et al., Self-Consistency
- Yao et al., ReAct — базовая петля агента
- Lewis et al., Retrieval-Augmented Generation — исходная работа по RAG
- Liu et al., Lost in the Middle — почему длинный контекст не панацея
- Jimenez et al., SWE-bench — бенчмарк реальной инженерии
- Zheng et al., Judging LLM-as-a-Judge — границы применимости модели-судьи
- Greshake et al., Indirect Prompt Injection и OWASP Top 10 for LLM Applications
- Anthropic, Building Effective Agents — почему простое обычно выигрывает
- Документация Claude API и спецификация Model Context Protocol
- Kwon et al., PagedAttention / vLLM — как устроен быстрый инференс
Что дальше
Прежде чем писать промпты, нужно понимать, чем вы платите и что именно уходит в модель. Следующая статья разбирает LLM с точки зрения инженера: как текст превращается в токены, почему контекст стоит денег и деградирует к середине, что на самом деле делает температура и почему её убрали из новых API, и как считать стоимость запроса до его отправки.
Как устроена LLM с точки зрения инженера: токены, контекст, температура, стоимость