Архив рубрики ~Обо всем~

Структурированный вывод с использованием LLM: режим JSON, вызов функций и когда использовать каждый из них.

Структурированный вывод с использованием LLM: режим JSON, вызов функций и когда использовать каждый из них.
Структурированный вывод с использованием LLM: режим JSON, вызов функций и когда использовать каждый из них.

Как получить достоверные и понятные ответы в рамках вашей магистерской программы и как выбрать подходящий инструмент.

Делиться

Изображение создано автором с помощью ChatGPT Images 2.0

В моих последних постах мы много говорили о популярных методах оптимизации производительности и стоимости приложений ИИ, таких как потоковая передача ответов или кэширование подсказок. Сегодня я хочу поговорить о чем-то немного другом, но не менее важном для создания реальных приложений ИИ. А именно, о структурированных, машиночитаемых выходных данных .

В большинстве приведенных мною примеров мы имели дело с ответами в свободной текстовой форме от модели ИИ. Пользователь задает вопрос, модель отвечает на естественном языке, и мы просто отображаем этот ответ пользователю каким-либо образом. Довольно просто и понятно. Но что происходит, когда нам нужно, чтобы модель возвращала данные в определенном формате (например, в виде объекта JSON), чтобы мы могли программно обработать их позже? Что если нам нужно, чтобы модель извлекала определенные поля из текста или изображения, заполняла запись в базе данных или запускала последующее действие на основе своего ответа? В таких случаях получение в ответ сплошного текста будет не очень удобно. 🤔

К счастью, существует несколько решений этой проблемы. Для получения структурированных машиночитаемых результатов из LLM-системы есть два основных подхода: режим JSON и вызов функций (также называемый использованием инструментов). Эти два подхода часто путают друг с другом (что неудивительно, поскольку оба работают со структурированными результатами), но они служат совершенно разным целям. Кроме того, OpenAI представила более строгий вариант вызова функций, называемый структурированными результатами , который, как мы увидим, еще больше усиливает контроль за схемой. В этой статье мы более подробно рассмотрим все три подхода, разберемся, как каждый из них работает «под капотом», и выясним, когда следует использовать каждый из них.

Итак, давайте посмотрим!

1. Что такое режим JSON?

Режим JSON — это более простой подход для получения машиночитаемых результатов от LLM. По сути, это параметр, который можно установить в API-запросе, чтобы указать модели всегда возвращать допустимый JSON-объект. И это, собственно, всё! Тем не менее, эта простота имеет свою цену, поскольку нет никаких гарантий относительно структуры или схемы JSON (помните, мы не определяли никаких схем, имен полей, типов и тому подобного), только то, что это будет допустимый, разборчивый JSON.

Например, используя API OpenAI в Python, мы можем включить режим JSON, добавив параметр response_format={"type": "json_object"} к вызову модели. Более конкретно, это будет выглядеть примерно так:

 from openai import OpenAI client = OpenAI(api_key="your_api_key") response = client.chat.completions.create( model="gpt-4o-mini", response_format={"type": "json_object"}, messages=[ { "role": "system", "content": "You are a helpful assistant. Always respond in JSON format." }, { "role": "user", "content": "Extract the name, age, and city from this text: 'Maria is 32 years old and lives in Athens.'" } ] ) print(response.choices[0].message.content)

И ответ будет выглядеть примерно так:

 { "name": "Maria", "age": 32, "city": "Athens" }

И вуаля! ✨ Всего лишь одно простое изменение параметра — и мы каждый раз получаем корректный JSON. Нет необходимости в разборе строк или странных ухищрениях с регулярными выражениями.

Однако есть один нюанс. Режим JSON гарантирует, что выходные данные будут корректными в формате JSON, но он не гарантирует конкретную структуру. Если мы запустим один и тот же пример несколько раз, мы можем каждый раз получать немного разные имена полей или немного разную структуру. Например, один запуск может вернуть "name" , а другой — "full_name" . Это проблема, если мы пытаемся надежно извлечь определенные поля программным способом.

Кроме установки response_format={"type": "json_object"} , рекомендуется всегда явно указывать модели, что она должна отвечать в формате JSON, в системном запросе. В приведенном выше примере обратите внимание, как мы добавили в системный запрос также опцию «Всегда отвечать в формате JSON». Без этого модель может иногда возвращать корректный JSON, но не всегда, поскольку ее поведение может стать непредсказуемым.

2. Что такое вызов функции?

Вызов функций (или использование инструментов) — это более продвинутый подход к получению структурированных, машиночитаемых выходных данных от LLM. Вместо того чтобы просто просить модель отформатировать ответ в формате JSON, мы определяем конкретную схему . То есть, мы явно определяем формальное описание структуры, которой должен соответствовать вывод, и таким образом модель более ограничена в возврате данных, точно соответствующих этой схеме. Другими словами, при вызове функций мы заранее определяем, какие поля мы ожидаем, какого типа должны быть эти поля, какие из них обязательны, а какие нет, и так далее.

Вот как бы выглядел тот же пример извлечения данных с использованием вызова функции:

 from openai import OpenAI import json client = OpenAI(api_key="your_api_key") # define the schema of the output we expect tools = [ { "type": "function", "function": { "name": "extract_person_info", "description": "Extract personal information from a text", "parameters": { "type": "object", "properties": { "name": { "type": "string", "description": "The full name of the person" }, "age": { "type": "integer", "description": "The age of the person" }, "city": { "type": "string", "description": "The city the person lives in" } }, "required": ["name", "age", "city"] } } } ] response = client.chat.completions.create( model="gpt-4o-mini", tools=tools, tool_choice={"type": "function", "function": {"name": "extract_person_info"}}, messages=[ { "role": "user", "content": "Extract the name, age, and city from this text: 'Maria is 32 years old and lives in Athens.'" } ] ) # parse the structured output tool_call = response.choices[0].message.tool_calls[0] result = json.loads(tool_call.function.arguments) print(result)

В результате получится примерно следующее:

 { "name": "Maria", "age": 32, "city": "Athens" }

Результат выполнения этого примера с вызовом функции идентичен результату, полученному в режиме JSON. Тем не менее, ключевое отличие заключается в том, что, в отличие от режима JSON, при вызове функции результат будет согласованным; он всегда будет точно соответствовать определенной схеме, с согласованными именами полей, типами и любыми другими атрибутами, которые мы в ней определим.

🍨 DataCream — это информационная рассылка, предлагающая статьи и обучающие материалы по искусственному интеллекту, данным и технологиям. Если вас интересуют эти темы, подпишитесь здесь!

Бонус: Еще немного о вызове функций.

Прежде чем перейти к структурированным результатам, стоит остановиться и подробнее остановиться на первоначальной мотивации и применении вызова функций, который выходит далеко за рамки простого получения структурированных результатов. По сути, концепция вызова функций является основой рабочих процессов агентного ИИ. Более конкретно, в агентной среде LLM не просто отвечает на вопрос пользователя, а решает, какое действие предпринять дальше, основываясь на вводимых пользователем данных.

Например, представим себе помощника службы поддержки клиентов, который может либо найти заказ, либо оформить возврат средств, либо передать запрос оператору, в зависимости от запроса пользователя. С помощью вызова функций мы можем определить все три варианта действий как «инструменты» (функции), и выходные данные модели будут определять, какую из них вызвать и с какими аргументами, исходя из входных данных.

 tools = [ { "type": "function", "function": { "name": "lookup_order", "description": "Look up the status of a customer order", "parameters": { "type": "object", "properties": { "order_id": {"type": "string", "description": "The order ID"} }, "required": ["order_id"] } } }, { "type": "function", "function": { "name": "issue_refund", "description": "Issue a refund for a customer order", "parameters": { "type": "object", "properties": { "order_id": {"type": "string"}, "reason": {"type": "string"} }, "required": ["order_id", "reason"] } } } ] response = client.chat.completions.create( model="gpt-4o-mini", tools=tools, messages=[ {"role": "user", "content": "I want a refund for order #12345, it arrived broken."} ] ) tool_call = response.choices[0].message.tool_calls[0] print(tool_call.function.name) # "issue_refund" print(tool_call.function.arguments) # '{"order_id": "12345", "reason": "arrived broken"}'

Таким образом, объект ответа API выглядит примерно так:

 ChatCompletionMessage( content=None, role='assistant', tool_calls=[ ChatCompletionMessageToolCall( id='call_abc123', type='function', function=Function( name='issue_refund', arguments='{"order_id": "12345", "reason": "arrived broken"}' ) ) ] )

А в результате выполнения этих инструкций по печати, предположительно, будет выведено следующее:

 issue_refund {"order_id": "12345", "reason": "arrived broken"}

Итак, что же здесь происходит? Модель возвращает объект tool_calls вместо обычного текстового ответа (обратите внимание, что content равен None ). Внутри объекта tool_calls мы видим, что модель решила вызвать issue_refund (а не lookup_order ) и самостоятельно заполнила аргументы на основе того, что сказал пользователь. Затем мы анализируем эти аргументы и выполняем фактическую логику возврата средств в нашей системе.

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

Но давайте теперь вернемся к машиночитаемым результатам, а о рабочих процессах агентного ИИ и вызове функций мы поговорим подробнее в другой статье.

3. А что насчет структурированных результатов?

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

  • Поле, помеченное как обязательное, фактически опускается, если модель не может определить его значение.
  • Добавляются дополнительные поля, не определенные в нашей схеме.
  • Поле, определенное как integer возвращается в виде строки "32" вместо 32 «.

…и так далее.

Это происходит потому, что при вызове функции модель пытается следовать схеме, но это всё ещё генерация по принципу «наилучших усилий». Как и в любом другом случае, результат здесь по сути представляет собой предсказание токенов по одному, а схема является лишь приблизительной подсказкой. Всё ещё существует большая вероятность того, что эта пошаговая генерация токенов может быть нарушена на каком-то этапе и привести к результатам, отклоняющимся от заданной схемы.

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

Функция структурированного вывода OpenAI активируется простым указанием параметра strict: true в определении функции:

 tools = [ { "type": "function", "function": { "name": "extract_person_info", "strict": True, # enables Structured Outputs "parameters": { "type": "object", "properties": { "name": {"type": "string"}, "age": {"type": "integer"}, "city": {"type": "string"} }, "required": ["name", "age", "city"], "additionalProperties": False } } } ]

Но опять же, это имеет свою цену. Функция структурированного вывода доступна на моделях GPT-4o и более поздних версиях, а более старые модели переключаются в режим JSON. Поддерживаются не все структуры JSON, и это может быть немного медленнее, поскольку OpenAI предварительно обрабатывает результаты.

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

Но разве это не одно и то же?

Режим JSON, вызов функций и структурированные выходные данные могут показаться одинаковыми, поскольку все они, по сути, возвращают вам JSON из модели. Тем не менее, как мы уже видели, они существенно различаются по тому, что гарантируют и для чего предназначены. В частности:

  • Принудительное соблюдение схемы : режим JSON возвращает допустимый JSON, но без каких-либо структурных гарантий. Вызов функции возвращает допустимый JSON, соответствующий определенной схеме, с учетом конкретных имен полей, типов и обязательных полей, но отклонения все еще возможны. Структурированные выходные данные идут еще дальше, обеспечивая соблюдение этой схемы на уровне генерации, что делает отклонения невозможными.
  • Пример использования : режим JSON предназначен для случаев, когда нам нужен машиночитаемый ответ, но мы можем обойтись переменным форматом. Вызов функций был разработан в первую очередь для случаев, когда модели необходимо запустить действие или передать аргументы внешнему инструменту, поэтому по сути это общий случай машиночитаемых выходных данных. Структурированные выходные данные — это вызов функций с гарантией надежности, что делает его идеальным для производственных конвейеров, где необходима согласованность выходных данных.
  • Простота настройки: режим JSON — самый простой в настройке; требуется всего лишь изменение одного параметра без определения схемы. С другой стороны, для вызова функций и структурированных выходных данных нам также необходимо продумать и настроить схему JSON.

Тем не менее, сама компания OpenAI рекомендует по возможности всегда использовать структурированные выходные данные вместо режима JSON, как правило.

0714971de1c4ff001185b6c460c92259

В моих мыслях

Получение машиночитаемых результатов от LLM и выбор соответствующего подхода к этому может существенно повлиять на надежность и удобство сопровождения любого приложения ИИ. Ответы в свободной текстовой форме отлично подходят для диалоговых интерфейсов, но как только наш LLM становится компонентом более крупной системы (например, для передачи данных, запуска действий, заполнения баз данных и т. д.), структурированные ответы становятся необходимыми. Режим JSON, вызов функций и структурированные выходные данные могут обеспечить такие результаты, каждый с разным уровнем строгости. Как и во многих решениях в разработке ИИ, правильный выбор зависит от того, что вы создаете и насколько вы готовы мириться с изменчивостью.

Если вы дочитали до этого места, вам может пригодиться платформа pialgorithms — та, которую мы разрабатываем, чтобы помочь командам безопасно управлять организационными знаниями в одном месте.

Понравилась эта статья? Присоединяйтесь ко мне на 💌 Substack и 💼 LinkedIn

Все изображения предоставлены автором, если не указано иное.

Мария Мушуци Посмотреть все от Марии Мушуци

Источник: towardsdatascience.com

❌ Нет похожих статей с такими тегами

Оцените материал:

Поделиться
Понравилась статья? Расскажите другим
ВКонтакте
Читайте также
Архив рубрики ~Идей копилка~ Нейросети для бизнеса: лучшие AI-инструменты для автоматизации работы в 2026 году Архив рубрики ~Лента новостей~ AI-ассистент поддержки: Mindbox навели порядок в базе знаний и генерируют ее с помощью нейросети Новости робототехники Агенты искусственного интеллекта, занимающиеся программированием, научили роботов устанавливать графические процессоры и разрезать пластиковые стяжки. Архив рубрики ~Лента новостей~ В основе мини-ПК ACEMAGIC Kron Mini K5 расположится процессор Intel Core 5 320 Архив рубрики ~Лента новостей~ Мои ученики не умеют читать Архив рубрики ~Полезное~ Список сервисов, которые отгружают пробные лимиты, имеют бесплатные тарифы, дают токены стартапам и студентам Архив рубрики ~Лента новостей~ Источник: Elastic договорилась о покупке компании DeductiveAI, поддерживаемой CRV, за сумму до 85 миллионов долларов. Новости робототехники Ultimate Robot Knockout Legend Новости робототехники Фреймворк для «красных» процессоров и модель «издатель — подписчик». Работаем с флотом ИИ-агентов на своей машине Архив рубрики ~Лента новостей~ Антропическая «басня» доказывает: мы открыли ящик Пандоры искусственного интеллекта. Что дальше? | Натан Э. Сандерс и Брюс Шнайер Архив рубрики ~Лента новостей~ «МойОфис» обновил «Документы Настольные» с ИИ-помощником Архив рубрики ~Лента новостей~ Midjourney Medical: что-то новенькое Архив рубрики ~Лента новостей~ Atlas от OpenAI. Стоит ли переходить на новый AI‑браузер? Архив рубрики ~Лента новостей~ Компания Adobe добавила своего ИИ-помощника в Premiere, Illustrator и InDesign. Архив рубрики ~Идей копилка~ Нейросети для бизнеса: лучшие AI-инструменты для автоматизации работы в 2026 году Архив рубрики ~Лента новостей~ AI-ассистент поддержки: Mindbox навели порядок в базе знаний и генерируют ее с помощью нейросети Новости робототехники Агенты искусственного интеллекта, занимающиеся программированием, научили роботов устанавливать графические процессоры и разрезать пластиковые стяжки. Архив рубрики ~Лента новостей~ В основе мини-ПК ACEMAGIC Kron Mini K5 расположится процессор Intel Core 5 320 Архив рубрики ~Лента новостей~ Мои ученики не умеют читать Архив рубрики ~Полезное~ Список сервисов, которые отгружают пробные лимиты, имеют бесплатные тарифы, дают токены стартапам и студентам Архив рубрики ~Лента новостей~ Источник: Elastic договорилась о покупке компании DeductiveAI, поддерживаемой CRV, за сумму до 85 миллионов долларов. Новости робототехники Ultimate Robot Knockout Legend Новости робототехники Фреймворк для «красных» процессоров и модель «издатель — подписчик». Работаем с флотом ИИ-агентов на своей машине Архив рубрики ~Лента новостей~ Антропическая «басня» доказывает: мы открыли ящик Пандоры искусственного интеллекта. Что дальше? | Натан Э. Сандерс и Брюс Шнайер Архив рубрики ~Лента новостей~ «МойОфис» обновил «Документы Настольные» с ИИ-помощником Архив рубрики ~Лента новостей~ Midjourney Medical: что-то новенькое Архив рубрики ~Лента новостей~ Atlas от OpenAI. Стоит ли переходить на новый AI‑браузер? Архив рубрики ~Лента новостей~ Компания Adobe добавила своего ИИ-помощника в Premiere, Illustrator и InDesign.

Оставить комментарий