Обращение к моделям в формате OpenAI-compatible -как это сделать?

💡 OpenAI API — программный интерфейс для работы с языковыми моделями (LLM) от компании OpenAI. Сегодня он фактически стал отраслевым стандартом. API упрощает работу разработчиков: не нужно разбираться в особенностях каждого сервиса, доступны многочисленные примеры и интеграции. Yandex AI Studio совместим с OpenAI API. Это означает, что приложения, написанные под OpenAI (например, на базе LangChain или LlamaIndex), можно легко адаптировать — достаточно изменить параметры подключения и названия моделей.В OpenAI-совместимом API доступны два интерфейса для работы с моделями:

  • Responses API (responses) — современный универсальный интерфейс (рекомендуется);
  • Chat Completions API (chat.completions) — классический интерфейс для обратной совместимости.

ЛогикаВ этом уроке основной упор сделан на Responses API. Вы узнаете, как подключить OpenAI-совместимый API, выполнять генерацию текста, вызывать функции и работать с эмбеддингами. Приступим!

Начало работы с OpenAI API

Взаимодействовать с OpenAI API можно напрямую, но для удобства лучше использовать официальный набор инструментов OpenAI SDK.Чтобы использовать модели Yandex AI Studio через OpenAI SDK, нужно задать базовый эндпоинт и указать данные для аутентификации в Yandex Cloud: ключ или токен.📚 Процесс получения данных для аутентификации подробно описан в документации.

from openai import OpenAI

YANDEX_CLOUD_FOLDER_ID = "<идентификатор_каталога>"
YANDEX_CLOUD_API_KEY = "<значение_API-ключа>"
YANDEX_CLOUD_MODEL = "<модель_для_выполнения_задачи>"

client = OpenAI(
    api_key=YANDEX_CLOUD_API_KEY,
    base_url="https://ai.api.cloud.yandex.net/v1",
    project=YANDEX_CLOUD_FOLDER_ID,
)
   

Генерация текста

Основная задача любой языковой модели (LLM) — генерировать текст. Модель получает на вход инструкции с описанием задачи и формирует ответ.Управлять генерацией можно через следующие параметры:

  • instructions — текстовые инструкции для модели, определяющие её роль, стиль ответа и правила поведения;
  • temperature — регулирует вариативность ответа: значения ближе к 0 делают ответ более предсказуемым, ближе к 1 — более креативным;
  • max_output_tokens — задаёт максимальную длину ответа в токенах;
  • stream — включает потоковую передачу ответа по мере его генерации.

Логика Давайте рассмотрим на примерах, как задавать эти параметры.

from openai import OpenAI

YANDEX_CLOUD_FOLDER_ID = "<идентификатор_каталога>"
YANDEX_CLOUD_API_KEY = "<значение_API-ключа>"
YANDEX_CLOUD_MODEL = "aliceai-llm"


client = OpenAI(
  api_key=YANDEX_CLOUD_API_KEY,
  base_url="https://ai.api.cloud.yandex.net/v1",
  project=YANDEX_CLOUD_FOLDER_ID,
)

response = client.responses.create(
  model=f"gpt://{YANDEX_CLOUD_FOLDER_ID}/{YANDEX_CLOUD_MODEL}",
  temperature=0.3,
  instructions="Ты — полезный ассистент. Отвечай кратко, по делу и без лишних пояснений.",
  input="Что умеют большие языковые модели?",
  max_output_tokens=500,
  stream=True,
)

print("Ответ модели:\n", end="", flush=True)

for event in response:
    if event.type == "response.output_text.delta":
        # Выведите каждую часть текста по мере генерации
        print(event.delta, end="", flush=True) 

Ниже представлен один из возможных вариантов ответа модели. Поскольку параметр stream установлен в True, ответ передаётся по мере генерации. Этот режим особенно удобен для интерактивных сценариев:

  • текстовые чаты — ответ отображается постепенно, позволяя пользователю начать чтение до завершения генерации;
  • голосовые интерфейсы — синтез речи может выполняться параллельно с генерацией текста.
Ответ модели:
— генерировать текст (статьи, рассказы, письма, код и т. д.);
— отвечать на вопросы;
— переводить тексты;
— суммировать информацию;
— поддерживать диалог;
— анализировать тональность текста;
— предлагать идеи и решения;
— выполнять простые логические и арифметические задачи;
— работать с шаблонами и формализованными данными.                              

В данном случае ответ модели полностью вместился в заданный лимит max_output_tokens. Если установленного значения недостаточно, генерация прекращается сразу после достижения лимита. В результате ответ может оборваться в произвольном месте.Например, если установить max_output_tokens=20, можно получить следующий результат:

Ответ модели:
— генерировать текст;
— отвечать на вопросы;
— переводить языки;
— суммировать    

💡 При обращении к моделям Yandex AI Studio необходимо передавать идентификатор вашего каталога как часть URI модели.

Структурированный формат ответа

Во многих сценариях ответ модели нужен не в виде свободного текста, а в заранее заданной структуре. Это удобно, если результат нужно обрабатывать программно: передавать в CRM, извлекать сущности из текста, выполнять классификацию, формировать параметры для вызова API или сохранять данные в бизнес-системах.В OpenAI-совместимом API структурированный ответ можно получить двумя способами:

  • явно задать JSON-схему ожидаемого ответа;
  • описать структуру данных через Pydantic-модель и получить уже распарсенный результат.

Ниже показан один и тот же пример в обоих вариантах. Модель получает текстовое описание небоскрёба и должна вернуть из него два поля: название и высоту.Пример с JSON-схемой:

from openai import OpenAI
import json

YANDEX_CLOUD_FOLDER_ID = "<идентификатор_каталога>"
YANDEX_CLOUD_API_KEY = "<значение_API-ключа>"
YANDEX_CLOUD_MODEL = "aliceai-llm"

client = OpenAI(
    api_key=YANDEX_CLOUD_API_KEY,
    base_url="https://ai.api.cloud.yandex.net/v1",
    project=YANDEX_CLOUD_FOLDER_ID,
)

json_schema = {
    "type": "object",
    "properties": {
        "skyscraper_name": {
            "type": "string",
            "description": "Название небоскрёба",
        },
        "skyscraper_height": {
            "type": "integer",
            "description": "Высота небоскрёба в метрах",
        },
    },
    "required": ["skyscraper_name", "skyscraper_height"],
    "additionalProperties": False,
}

response = client.responses.create(
    model=f"gpt://{YANDEX_CLOUD_FOLDER_ID}/{YANDEX_CLOUD_MODEL}",
    instructions=f"""Ты извлекаешь информацию о небоскрёбах из текста и структурируешь её согласно следующей JSON схеме:

{json.dumps(json_schema, ensure_ascii=False, indent=2)}

Извлеки все данные из текста и верни результат в формате JSON.""",
    input="Шанхайская башня — небоскрёб в Китае. Высота — 632 метра. В здании также 127 этажей.",
    text={
        "format": {
            "type": "json_schema",
            "name": "skyscraper",
            "schema": json_schema,
        }
    },
)

if response.status == "completed":
    # Поиск элемент с типом 'message'
    for output_item in response.output:
        if output_item.type == "message" and output_item.content:
            result = json.loads(output_item.content[0].text)
            print(json.dumps(result, ensure_ascii=False, indent=2))
            break
else:
    print(f"Ошибка: {response.error.message if response.error else 'Неизвестная ошибка'}") 

Ответ модели:

{"skyscraper_name": "Шанхайская башня", "skyscraper_height": 632} 

💡 При обращении к моделям Yandex AI Studio рекомендуется дублировать JSON-схему в тексте промпта для повышения качества ответов.Пример с заданием структуры через объект Pydantic

from openai import OpenAI
from pydantic import BaseModel

YANDEX_CLOUD_FOLDER_ID = "<идентификатор_каталога>"
YANDEX_CLOUD_API_KEY = "<значение_API-ключа>"
YANDEX_CLOUD_MODEL = "aliceai-llm"

client = OpenAI(
    api_key=YANDEX_CLOUD_API_KEY,
    base_url="https://ai.api.cloud.yandex.net/v1",
    project=YANDEX_CLOUD_FOLDER_ID,
)

class Skyscraper(BaseModel):
    skyscraper_name: str
    skyscraper_height: int

response = client.responses.parse(
    model=f"gpt://{YANDEX_CLOUD_FOLDER_ID}/{YANDEX_CLOUD_MODEL}",
    input="Шанхайская башня — небоскрёб в Китае. Высота — 632 метра. В здании также 127 этажей.",
    text_format=Skyscraper,
)

skyscraper_data = response.output_parsed

print(f"Название: {skyscraper_data.skyscraper_name}")
print(f"Высота: {skyscraper_data.skyscraper_height} м") 

Ответ:

Название: Шанхайская башня
Высота: 632 м 

Как выбрать подход

  • JSON Schema — подходит, когда схема задаётся извне или формируется динамически;
  • Pydantic — удобен при работе на Python, когда требуется сразу получить типизированный объект.

Вызов функций

💡 Function Calling — механизм, позволяющий модели вызывать внешние функции и использовать их результаты при формировании ответа. Это даёт возможность интегрировать модель с API, базами данных и другими системами.Общий процесс выглядит так:1️⃣ Разработчик описывает набор функций, которые модель может вызывать.2️⃣ Когда поступает запрос, модель выбирает, какую функцию из доступного набора вызвать, и передаёт ей необходимые параметры.3️⃣ Внешняя программа (например, агент) выполняет вызов функции с указанными моделью параметрами и возвращает результат выполнения модели.4️⃣ Модель использует полученные данные для генерации итогового ответа пользователю.Пример вызова функции:

from openai import OpenAI
import json
from typing import Optional

YANDEX_CLOUD_FOLDER_ID = "<идентификатор_каталога>"
YANDEX_CLOUD_API_KEY = "<значение_API-ключа>"
YANDEX_CLOUD_MODEL = "aliceai-llm"

client = OpenAI(
    api_key=YANDEX_CLOUD_API_KEY,
    base_url="https://ai.api.cloud.yandex.net/v1",
    project=YANDEX_CLOUD_FOLDER_ID,
)


def calculator(a: int, b: int) -> int:
    """
    Складывает два числа.
    
    Args:
        a: Первое число
        b: Второе число
        
    Returns:
        Сумма двух чисел
    """
    result = a + b
    print(f"[CALC] Выполнение вычисления: {a} + {b} = {result}")
    return result


def extract_text_from_response(response) -> Optional[str]:
    """
    Извлекает текстовый ответ из response объекта.
    
    Args:
        response: Объект ответа от API
        
    Returns:
        Текстовый ответ или None
    """
    if hasattr(response, 'output_text'):
        return response.output_text
    
    for output_item in response.output:
        if (hasattr(output_item, 'content') and 
            output_item.content and 
            hasattr(output_item.content[0], 'text')):
            return output_item.content[0].text
    
    return None


def run_conversation(user_input: str) -> str:
    """
    Обрабатывает сообщение пользователя с поддержкой вызова функций.
    
    Args:
        user_input: Сообщение пользователя
        
    Returns:
        Ответ модели
    """
    try:
        selected_model = f"gpt://{YANDEX_CLOUD_FOLDER_ID}/{YANDEX_CLOUD_MODEL}"

        # Описание инструмента - калькулятора
        tools = [
            {
                "type": "function", 
                "name": "calculator",
                "description": "Сложить два числа",
                "parameters": {
                    "type": "object",
                    "properties": {
                        "a": {"type": "integer", "description": "Первое число"},
                        "b": {"type": "integer", "description": "Второе число"}
                    },
                    "required": ["a", "b"],
                    "additionalProperties": False
                }
            }
        ]

        # 1. Создание списка ввода и добавление сообщения пользователя
        input_list = [
            {"role": "user", "content": user_input}
        ]

        print(f"[DEBUG] Пользователь спросил: {user_input}")

        # 2. Запрос к модели с определёнными инструментами
        response = client.responses.create(
            model=selected_model,
            tools=tools,
            input=input_list,
        )

        print(f"[DEBUG] Первый ответ модели получен")

        # 3. Сохранение вывода модели для последующих запросов
        input_list += response.output

        # 4. Обработка вызовов функций
        for item in response.output:
            if item.type == "function_call":
                if item.name == "calculator":
                    # Извлечение аргументов для калькулятора
                    arguments_str = item.arguments
                    print(f"[DEBUG] Модель запросила калькулятор с аргументами: {arguments_str}")

                    # Парсинг аргументы из JSON-строки
                    function_args = json.loads(arguments_str)
                    a = function_args.get("a")
                    b = function_args.get("b")
                    
                    # 5. Вызов функции калькулятора
                    calculation_result = calculator(a, b)
                    
                    # 6. Добавление результата выполнения функции в список ввода
                    input_list.append({
                        "type": "function_call_output",
                        "call_id": item.call_id,
                        "output": json.dumps({"result": calculation_result}, ensure_ascii=False)
                    })
                    
                    print(f"[DEBUG] Результат вычисления передан модели")

                    # 7. Отправление результата обратно модели
                    second_response = client.responses.create(
                        model=selected_model,
                        tools=tools,
                        input=input_list,
                    )

                    # 8. Извлечение финального текстового ответа
                    text_response = extract_text_from_response(second_response)
                    if text_response:
                        return text_response

        # Если вызовов функций не было, возвращается исходный ответ
        text_response = extract_text_from_response(response)
        if text_response:
            return text_response

        return "Не удалось получить ответ от модели"
    
    except json.JSONDecodeError as e:
        return f"Ошибка парсинга JSON: {e}"
    except Exception as e:
        return f"Произошла ошибка: {e}"


if __name__ == "__main__":
    # Тестирование работы с калькулятором
    result = run_conversation("Сколько будет 15 + 25?")
    print(f"\nИтоговый ответ:\n{result}")
 

Пример ответа:

[DEBUG] Пользователь спросил: Сколько будет 15 + 25?
[DEBUG] Первый ответ модели получен
[DEBUG] Модель запросила калькулятор с аргументами: {"a":15,"b":25}
[CALC] Выполняем вычисление: 15 + 25 = 40
[DEBUG] Результат вычисления передан модели

Итоговый ответ:
15 + 25 = 40 

Эмбеддинги

💡 Эмбеддинги (векторные представления) — это способ преобразования нечисловых данных (слов, изображений и т. д.) в числовые векторы. Самый частый сценарий применения эмбеддингов — поиск.Рассмотрите пример использования эмбеддингов для поиска. Требуется выполнить следующие шаги:1️⃣ Перевести поисковый запрос и тексты, по которым идёт поиск, в числовые векторы.2️⃣ Измерить сходство между вектором запроса и векторами текстов с помощью косинусной близости.3️⃣ Текст, вектор которого ближе всего к вектору запроса (имеет наибольшую косинусную близость), и будет лучшим ответом.

Изучите пример💡 В примере для работы с эмбеддингами использовались две разные модели:

  • emb://<идентификатор_каталога>/text-search-doc — ориентирована на векторизацию больших текстов исходных данных.
  • emb://<идентификатор_каталога>/text-search-query — предназначена для векторизации коротких текстов.

Модели

В OpenAI-совместимом API доступен метод для получения списка моделей, открытых пользователю. Это полезно при работе с фреймворками, поддерживающими OpenAI API, а также при автоматическом выборе модели во время выполнения приложения.

from openai import OpenAI

YANDEX_CLOUD_FOLDER_ID = "<идентификатор_каталога>"
YANDEX_CLOUD_API_KEY = "<значение_API-ключа>"

client = OpenAI(
    api_key=YANDEX_CLOUD_API_KEY,
    base_url="https://ai.api.cloud.yandex.net/v1",
    project=YANDEX_CLOUD_FOLDER_ID,
)
models = client.models.list()

print("Доступные модели:\n")
for model in models.data:
    print(f"{model.id} ({model.owned_by})") 

Ответ API будет отличаться для каждого пользователя, так как список включает общедоступные и пользовательские модели. Например, дообученные или развёрнутые в каталоге пользователя:

Доступные модели:

gpt://b1gmk1eb91166fgctcjj/aliceai-llm/latest (Yandex)
gpt://b1gmk1eb91166fgctcjj/deepseek-v32/latest (DeepSeek)
gpt://b1gmk1eb91166fgctcjj/gpt-oss-120b/latest (OpenAI)
gpt://b1gmk1eb91166fgctcjj/gpt-oss-20b/latest (OpenAI)
gpt://b1gmk1eb91166fgctcjj/gemma-3-27b-it/latest (Google)
gpt://b1gmk1eb91166fgctcjj/qwen3-235b-a22b-fp8/latest (Alibaba)
gpt://b1gmk1eb91166fgctcjj/qwen3.5-35b-a3b-fp8/latest (Alibaba)
gpt://b1gmk1eb91166fgctcjj/speech-realtime-250923/latest (Yandex)
emb://b1gmk1eb91166fgctcjj/text-search-doc/latest (Yandex)
emb://b1gmk1eb91166fgctcjj/text-search-query/latest (Yandex)
... 

📚 Актуальный список общедоступных моделей можно посмотреть в документации.

💻 Практика. Преобразование кулинарного рецепта в JSON

❗️Практическая часть курса предполагает использование облачных ресурсов, которые вы оплачиваете самостоятельно. Курс разработан так, чтобы расходы были минимальными, — часть из них покроет стартовый грант.Чтобы избежать лишних трат:— останавливайте ВМ в перерывах между практиками (это не снизит потребление до нуля, но заметно сократит расходы);— настройте бюджет и уведомления в разделе Биллинг;— удаляйте ресурсы после завершения курса;— необязательно выполнять все практики — сосредоточьтесь на релевантных.

ЛогикаПришло время практики! Напишите скрипт для OpenAI SDK, который преобразует текстовое описание рецепта в JSON с использованием моделей AI Studio. В результате вы получите структурированный ответ в удобном формате. 1️⃣ Установите OpenAI SDK через команду.

pip install openai 

2️⃣ Задайте базовый эндпоинт и укажите данные для аутентификации ключа или токена в Yandex Cloud. Также укажите ID каталога для обращения к моделям.

from openai import OpenAI 
import json

YANDEX_CLOUD_FOLDER_ID = "<идентификатор_каталога>"
YANDEX_CLOUD_API_KEY = "<значение_API-ключа>"
YANDEX_CLOUD_MODEL = "aliceai-llm"

client = OpenAI(
    api_key=YANDEX_CLOUD_API_KEY,
    base_url="https://ai.api.cloud.yandex.net/v1",
    project=YANDEX_CLOUD_FOLDER_ID,
) 

3️⃣ Опишите схему для преобразования рецепта из текста в JSON.

json_schema = {
    "type": "object",
    "properties": {
        "recipe_name": {"type": "string"},
        "preparation_time": {"type": "string"},
        "difficulty_level": {"type": "string", "enum": ["легкая", "средняя", "сложная"]},
        "ingredients": {
            "type": "array",
            "items": {
                "type": "object",
                "properties": {
                    "name": {"type": "string"},
                    "amount": {"type": "string"}
                },
                "required": ["name", "amount"]
            }
        },
        "cooking_steps": {
            "type": "array",
            "items": {"type": "string"}
        }
    },
    "required": ["recipe_name", "preparation_time", "difficulty_level", "ingredients", "cooking_steps"]
}
 

4️⃣ Опишите рецепт в отдельной переменной.

recipe_description = """
Название: Шоколадный фондан
Ингредиенты: 
- 100 г тёмного шоколада
- 100 г сливочного масла
- 2 яйца
- 60 г сахара
- 30 г муки
Время приготовления: 30 минут
Сложность: легкая
Шаги:
1 Растопить шоколад с маслом на водяной бане
2 Взбить яйца с сахаром до пены
3 Соединить шоколадную массу с яичной смесью
4 Добавить муку и перемешать
5 Разлить по формочкам и выпекать 15 минут при 180°C
""" 

5️⃣ Выполните запрос.

response = client.responses.create(
    model=f"gpt://{YANDEX_CLOUD_FOLDER_ID}/{YANDEX_CLOUD_MODEL}",
    instructions=f"""Ты извлекаешь информацию о рецепте из текста и структурируешь её согласно следующей JSON схеме:

{json.dumps(json_schema, ensure_ascii=False, indent=2)}

Извлеки все данные из текста и верни результат в формате JSON.""",
    input=recipe_description,
    text={
        "format": {
            "type": "json_schema",
            "name": "recipe",
            "schema": json_schema,
        }
    },
)

if response.status == "completed":
    # Поиск элемента с типом 'message'
    for output_item in response.output:
        if output_item.type == "message" and output_item.content:
            result = json.loads(output_item.content[0].text)
            print(json.dumps(result, ensure_ascii=False, indent=2))
            break
else:
    print(f"Ошибка: {response.error.message if response.error else 'Неизвестная ошибка'}") 

В результате текстовое описание рецепта преобразуется в JSON-формат:

{
  "recipe_name": "Шоколадный фондан",
  "preparation_time": "30 минут",
  "cooking_steps": [
    "Растопить шоколад с маслом на водяной бане",
    "Взбить яйца с сахаром до пены",
    "Соединить шоколадную массу с яичной смесью",
    "Добавить муку и перемешать",
    "Разлить по формочкам и выпекать 15 минут при 180°C"
  ],
  "difficulty_level": "легкая",
  "ingredients": [
    {
      "name": "тёмный шоколад",
      "amount": "100 г"
    },
    {
      "name": "сливочное масло",
      "amount": "100 г"
    },
    {
      "name": "яйца",
      "amount": "2"
    },
    {
      "name": "сахар",
      "amount": "60 г"
    },
    {
      "name": "мука",
      "amount": "30 г"
    }
  ]
} 

ЛогикаС практикой справились, значит, можно подводить итоги урока!

Итоги урока

AI Studio обеспечивает совместимость с OpenAI SDK, что позволяет быстро интегрировать существующие решения. Хотя совместимость пока не охватывает весь функционал OpenAI API, уже доступных возможностей достаточно для адаптации большинства приложений.📚 Команда AI Studio постоянно расширяет совместимость API. Уже сейчас вы можете переносить решения, а по мере добавления новых функций — легко обновлять их. Актуальный статус совместимости всегда можно проверить в документации.

Ссылка: https://practicum.yandex.ru/learn/yc-ml-services/courses/9ad788d2-6151-4f6f-82ff-5eb63d7925d7/sprints/932317/topics/36b1bc86-4cd6-442e-b1cf-a474ea0c905d/lessons/a6b597d2-3433-41f7-984f-e2f7d02afe68/

Рубрики: Uncategorized

0 комментариев

Добавить комментарий

Заполнитель аватара

Ваш адрес email не будет опубликован.