Экспресс-курс · No. 27
Сырая языковая модель возвращает свободный текст — приятный человеку для чтения, бесполезный твоему коду для опоры. Чтобы строить настоящий софт на модели, нужны две вещи: вывод, которому твоя программа реально может доверять (структурированный вывод), и безопасный способ для модели дотянуться за пределы текста и действовать (использование инструментов). Вместе они превращают чат-бота в надёжный компонент внутри твоей системы.
Только суть · Один образ на идею · Инженерия важнее магии
Первый шаг к построению на модели — осознать несоответствие: она говорит прозой, но твоей программе нужны данные и действия. Перекрыть этот разрыв — о чём весь этот курс.
Проза для людей; коду нужны данные
Рукописный абзац, описывающий заказ, против заполненной формы с помеченными ячейками — человек легко читает абзац, но только форму может подшить машина.
По умолчанию языковая модель выводит свободный текст — абзац, объяснение, прозу. Это идеально человеку-читателю и бесполезно твоему коду, которому нужны предсказуемые, структурированные значения, на которых можно действовать: число тут, категория там, «да или нет». Программа не может надёжно вытащить «клиент хочет возврат $40» из предложения, что модель сформулировала как ей вздумалось. Проза и данные — разные вещи, а код работает на данных.
Парсинг прозы хрупок и ломается
Пытаться извлечь сумму из письма, что может сказать «$40», «сорок долларов» или «возврат сорока баксов», — твои правила работают, пока однажды формулировка не сдвинется, и тогда всё рушится.
Наивная починка — пусть модель пишет текст, а ты парсишь его своим кодом — хрупка. Модель недетерминирована; она сформулирует одно и то же десятью способами, добавит дружелюбное вступление или обернёт ответ в markdown. Твой парсер обрабатывает случаи, что ты видел, и разлетается на том, что не видел. Строить на парсинге прозы модели — это строить на песке: работает на демо и падает в проде.
Цель: сделать модель надёжной частью
Двигатель становится полезен машине, только когда у него стандартные крепления и разъёмы — предсказуемые интерфейсы, к которым остальная машина может уверенно прикрутиться.
Чтобы строить софт на модели, надо превратить её из болтливого оракула в компонент с предсказуемыми интерфейсами — вывод, которому твой код может доверять, и действия, что он может безопасно совершать. Это ровно две половины курса: структурированный вывод (данные, не проза) и использование инструментов (действие, а не только разговор). Получи их, и модель перестанет быть демо и станет надёжной частью, вокруг которой можно инженерить, как вокруг любой другой.
Модель говорит прозой; твоему коду нужны данные и действия. Парсинг свободного текста хрупок — цель в том, чтобы сделать модель надёжным компонентом, с выводом, которому доверяешь, и действиями, что она может совершать.
Первая половина превращения модели в компонент — заставить её возвращать данные в форме, что задаёт твой код, каждый раз — не прозу, которую надо угадывать, а предсказуемую структуру.
Проси схему, а не предложение
Вручить кому-то форму с помеченными ячейками вместо чистого листа — он заполняет ровно те поля, что тебе нужны, в нужном порядке, без лишнего.
Структурированный вывод (structured output) — это просьба к модели вернуть данные в заданном формате — обычно JSON, совпадающий со схемой (schema), что ты задал: эти поля, эти типы, эта форма. Вместо «расскажи мне про этот заказ» ты говоришь «верни {customer, amount, reason}», и получаешь назад данные, что твой код может использовать напрямую. Ты задаёшь форму; модель её заполняет. Это единственный ход, что превращает вывод модели из прозы в то, на что программа может опереться.
Модель можно ограничить валидным выводом
Железнодорожная стрелка, что физически может отправить поезд только по одному из заданных путей, — нет способа оказаться где-то за пределами карты.
Современные модели поддерживают ограниченную (constrained) генерацию: их можно вынудить произвести вывод, что реально совпадает с твоей схемой — валидный JSON, нужные поля, верные типы, — а не просто вежливо попросить. Это закрывает разрыв, где модель «в основном» возвращает нужную форму, но изредка дрейфует. С выводом, ограниченным схемой, твой код может рассчитывать, что структура на месте, — а это и делает модель пригодной как настоящий строительный блок.
Структурированный вывод — это мост к твоему коду
Переводчик, что превращает высказанные пожелания гостя в точный, стандартизированный тикет заказа, на котором кухня может действовать, — тот же смысл, теперь в форме, что система может использовать.
Структурированный вывод — это мост между языковой способностью модели и нуждой твоего софта в данных. Он даёт модели делать то, в чём она блестяща, — понимать грязный человеческий ввод — и вручить результат твоему коду как чистые, типизированные значения. Классификация, извлечение, маршрутизация, заполнение форм — всё становится надёжным, когда вывод структурирован. Модель читает хаос; схема доставляет порядок. Эта передача — где живёт большинство реальных LLM-фич.
Структурированный вывод значит, что модель возвращает данные, совпадающие со схемой, что ты задал, ограниченные валидной формой, — мост, что превращает её языковую способность в типизированные значения, на которые код может опереться.
Структурированный вывод даёт тебе предсказуемую форму, но форма — не правильность. Прежде чем твой код доверится тому, что вернула модель, он должен это проверить — та же дисциплина, что и для любого недоверенного ввода.
Валидная форма — не валидное содержимое
Форма, заполненная аккуратно, каждая ячейка завершена, — но дата невозможна, а сумма не сходится. Опрятно — не то же, что верно.
Схема гарантирует форму — нужные поля и типы — но не то, что значения осмысленны. Модель может вернуть идеально оформленный JSON с отрицательным количеством, несуществующей категорией или суммой, что она выдумала. Структурированный вывод решает «может ли мой код это прочесть»; он не решает «верно ли это». Относись к хорошо оформленному ответу как к отправной точке для проверки, а не как к гарантии верного.
Валидируй до того, как что-то на нём действует
Таможенная проверка между странами — ничто не переходит в следующую систему, пока не осмотрено против правил и не признано безопасным.
Так что ты валидируешь структурированный вывод модели, прежде чем твой код его использует: насаждаешь схему строго, проверяешь, что значения в допустимых диапазонах и множествах, подтверждаешь, что всё, на что ссылаются, реально существует. Эта проверка идёт в твоём коде, на границе между моделью и остальной системой, потому что модель — недетерминированный компонент, которому нельзя целиком доверять. Тот же урок, что в безопасности: вывод модели — недоверенный ввод следующего этапа, пока ты его не проверил.
Никогда не направляй сырой вывод во что-то опасное
Ты не льёшь нефильтрованный поток прямо в питьевую систему — что было выше по течению, теперь в каждом кране, без шанса его поймать.
Правило становится строгим, когда вывод течёт куда-то значимое. Никогда не скармливай сырой вывод модели прямо в запись в базу, команду шелла, запрос или другую систему без валидации и экранирования сперва — так галлюцинация или внедрённая инструкция становится настоящим багом или прорывом. Структурированный вывод плюс строгая валидация — вот что даёт безопасно действовать на том, что модель произвела. Структура делает его читаемым; валидация делает его доверенным.
Валидная схема гарантирует форму, не правильность. Валидируй вывод модели на границе — диапазоны, множества, существование — до того, как какой-либо код на нём действует, потому что вывод модели недоверен, пока не проверен.
Структурированный вывод даёт модели возвращать данные. Другая половина превращения её в компонент — дать ей делать вещи: дотягиваться за пределы текста, чтобы искать, считать, доставать и действовать в реальном мире. Это использование инструментов.
Дай модели функции, что она может вызывать
Умный ассистент, что сам не может открыть шкаф с документами, — но может точно сказать, какой ящик и файл достать, и использовать то, что ты принёс.
При использовании инструментов (tool use, также function calling) ты описываешь функции, что модели позволено запросить, — search_orders, send_email, get_weather, — и когда модель решает, что одна нужна, она возвращает структурированный вызов, называющий функцию и её аргументы. Это структурированный вывод, применённый к действиям: вместо данных модель выдаёт запрос сделать что-то. Так LLM дотягивается за пределы своего текста в твои системы и в мир.
Модель решает; твой код делает
Прораб, что показывает и говорит ровно, что надо сделать, — но бригада, а не прораб, реально управляет машинами и держит контроль над площадкой.
Разделение труда — это ключ: модель решает, что делать и с какими аргументами; твой код решает, делать ли это вообще и как. Когда модель возвращает вызов инструмента, твой код выполняет функцию (или нет), получает результат и скармливает его назад в контекст, чтобы модель продолжила. Модель никогда не трогает твои системы напрямую — она запрашивает, твой код исполняет. Эта граница — где ты держишь контроль и безопасность.
Результат скармливается назад в цикл
Исследователь просит документ, читает принесённое и использует это, чтобы решить следующий вопрос, — туда-сюда, а не один выстрел.
Использование инструментов — это цикл: модель запрашивает инструмент, твой код его выполняет и возвращает результат в контекст, и модель рассуждает дальше с этой новой информацией — возможно, вызывая другой инструмент. Этот цикл ровно и превращает модель в агента (курс об агентах копает вглубь). Инструменты — это руки; цикл — это упорство. Пока что ключевая идея в том, что использование инструментов даёт модели собрать нужное и действовать, шаг за шагом, вместо того чтобы отвечать вслепую из памяти.
Использование инструментов даёт модели запрашивать функции — структурированный вывод для действий. Модель решает, что делать; твой код решает, делать ли и как, и скармливает результат назад.
Модель выбирает и использует инструменты по тому, как ты их описываешь, так что дизайн инструментов — часть получения надёжного поведения. Несколько принципов отделяют инструменты, что работают, от тех, что путают модель.
Ясные имена и описания направляют выбор
Ящик инструментов, где каждый ясно помечен тем, для чего он, — работник хватает нужный мгновенно, вместо того чтобы гадать по ряду непомеченных рукояток.
Модель выбирает, какой инструмент вызвать, почти целиком по его имени и описанию. Так что это не документация для людей — это инструкции, из которых модель рассуждает. Расплывчатое или вводящее в заблуждение описание ведёт к не тому инструменту, не тем аргументам или к проигнорированному инструменту, когда он был нужен. Пиши имена и описания инструментов так же тщательно, как писал бы промпт, потому что для модели это ровно он и есть.
Несколько острых инструментов бьют гигантское меню
Кухня с несколькими хорошо подобранными, ясно различными инструментами работает быстрее, чем с пятьюдесятью пересекающимися гаджетами, через которые повар должен перебираться каждый раз.
Дать модели слишком много инструментов — или несколько, что пересекаются — делает труднее выбрать хорошо, каждый ход. Маленький набор острых, ясно различных инструментов надёжнее раскоряченного меню. Если два инструмента делают почти одно, модель иногда выберет не тот; если их сорок, выбор сам становится источником ошибки. Курируй набор инструментов так же, как курируешь контекст: только то, что нужно задаче.
Не доверяй описанию инструмента как поверхности безопасности
Новичок, что без вопросов следует надписи на каждой коробке, — так что тот, кто пишет надписи, по сути управляет тем, что он делает.
Поскольку модель доверяет описаниям и выводам инструментов, они — часть твоей поверхности безопасности, а не нейтральная сантехника. Отравленное описание или инструмент, что возвращает контролируемый атакующим текст, могут рулить поведением модели — «отравление инструментов». Проверяй инструменты, что подключаешь, урезай каждый до минимума, что нужно (инструмент только-чтение не должен мочь удалять), и относись к тому, что инструмент возвращает, как к недоверенному вводу. Возможность, что ты даёшь инструменту, — это возможность, что запутанная или угнанная модель может злоупотребить.
Модель выбирает инструменты по их именам и описаниям, так что пиши их как промпты. Держи инструменты немногочисленными и острыми, урезай каждый до наименьших привилегий и относись к описаниям и выводам как к поверхности безопасности.
По мере того как инструменты множатся, соединять каждую модель с каждой системой руками не масштабируется. Возник стандарт того, как модели дотягиваются до инструментов и данных, — а с ним новый слой, что надо понять и защитить.
Стандартный способ выставлять инструменты моделям
До стандартных вилок и розеток каждому прибору нужна была своя кастомная проводка — универсальный стандарт означал, что любое устройство может подключиться к любой розетке без штучной работы.
Model Context Protocol (MCP) — это набирающий силу стандарт того, как модели соединяются с инструментами и источниками данных. Вместо того чтобы связывать каждую модель с каждой системой кастомным кодом, MCP задаёт общий способ выставлять инструменты, так что любая совместимая модель может использовать любой совместимый инструмент. Это универсальная розетка эпохи агентов — слой коннекторов, что даёт экосистеме инструментов и моделей соединяться без разовых интеграций каждый раз.
Он стандартизирует сантехнику агентов
Энергосеть: стандартизирована так, что новый прибор просто включается и работает, а новый источник питания просто питает ту же сеть, — стандарт и делает всю сеть составной.
MCP важен, потому что делает инструменты и данные составными (composable): инструмент, построенный раз, может использоваться многими моделями и агентами, а новый агент может немедленно использовать всю экосистему существующих инструментов. Это большая часть того, почему агенты так быстро стали мощными, — сантехника стандартизировалась, так что возможности защёлкиваются вместе. Когда ты даёшь агенту доступ к своим системам сегодня, MCP всё чаще тот слой, что это делает.
Слой коннекторов — это поверхность атаки
Новая сантехника, быстро проведённая через весь дом, — и обследование находит, что большой доле вентилей так и не поставили замок.
Этот новый слой — также новое место для прорыва. MCP-коннекторы выставляют реальные действия и данные, и спешка их принять оставила многие развёрнутыми со слабой или отсутствующей безопасностью — большая доля удалённых MCP-серверов выкатилась вообще без аутентификации. Так что относись к коннектору как к двери, которой он и является: аутентифицируй, урезай то, что он выставляет, держи вне публичного интернета, если он там не должен быть, и инвентаризуй то, что подключил. Мощная сантехника требует базовых замков.
MCP стандартизирует то, как модели дотягиваются до инструментов и данных, делая экосистему составной. Тот же слой коннекторов — реальная поверхность атаки: аутентифицируй его, урезай и инвентаризуй.
Структурированный вывод и использование инструментов — это средства, что делают модель компонентом, но тянуться к ним хорошо всё равно значит подниматься по лестнице — используя наименее мощную часть, что решает твою проблему.
Структурированный вывод сперва, инструменты — когда надо действовать
Ты не вручаешь кому-то ключи от машины, когда всё, что было нужно, — это ответ, — ты даёшь ровно ту возможность, что требует задача, не больше.
Есть лестница возможностей. Обычный промпт отвечает; структурированный вывод делает этот ответ пригодным для кода; инструменты дают модели доставать и действовать; полный цикл агента даёт ей преследовать многошаговую цель. Каждая ступень добавляет мощь и новые способы сбоить. Поднимайся лишь настолько высоко, насколько нужно задаче: если тебе просто нужны чистые данные, структурированного вывода хватит — не давай модели инструменты, и уж точно не цикл, когда ограниченный ответ это решает. Большинству фич верхняя ступень не нужна никогда.
Валидируй всё, что переходит назад
Стол возвратов, что осматривает каждый предмет, приходящий назад, прежде чем он попадёт на полку, — ничто не входит в систему заново без проверки, как бы доверенным ни казался клиент.
Объединяющая привычка через обе половины — недоверие на границе: валидируй структурированный вывод модели, прежде чем твой код его использует, и держи свой код в контроле над тем, запускать ли инструмент, что запросила модель. Модель — блестящий, недетерминированный компонент, и ты относишься ко всему, что переходит из неё в твою систему, как к вводу для проверки. Эта дисциплина границы и даёт надёжно строить на чём-то, что фундаментально ошибается.
- Нужны ли моему коду данные — получаю ли я структурированный вывод по схеме, а не парсю прозу? - Валидирован ли вывод — значения проверены, а не просто хорошо оформлены, до того как что-то действует? - Нужно ли ей действовать — и выставил ли я это как инструмент, с моим кодом в контроле над запуском? - Немногочисленны, остры и хорошо описаны ли инструменты, и урезаны до наименьших привилегий? - Если используешь MCP, аутентифицирован, урезан и инвентаризован ли каждый коннектор? - На низшей ли я ступени, что работает, — вывод, инструменты или полный цикл только если нужно?
- free text / структурированный вывод — проза для людей против данных, на которые код может опереться. - schema / JSON / constrained — форма, что ты задаёшь и вынуждаешь модель совпасть.
- валидация / граница — проверка, что значения верны, до того как код им доверится. - tool use / function calling — дать модели запрашивать действия, что твой код выполняет. - описание инструмента / tool poisoning — как модель выбирает инструменты и риск безопасности в них. - MCP — стандартный слой коннекторов для выставления инструментов и данных моделям. - наименьшие привилегии — урезать каждый инструмент до минимума, что ему нужно.
- Ты получаешь структурированный вывод по схеме вместо парсинга прозы модели. - Ты валидируешь вывод на границе до того, как какой-либо код на нём действует. - Модель запрашивает инструменты, а твой код держит контроль над их запуском. - Твои инструменты немногочисленны, остры, хорошо описаны и с наименьшими привилегиями. - Ты поднимаешься лишь до ступени, что нужна задаче, и относишься к MCP-коннекторам как к защищённой двери.
Чтобы строить на модели, сделай её компонентом: структурированный вывод, которому код доверяет, валидированный на границе, и инструменты, что она запрашивает, но твой код контролирует, — наименее мощная ступень, что решает задачу.