Реклама
Перетяжка // Коробка 3.0

Как подключить Qwen3.6-27B к ИИ-агенту: тестируем immers.cloud и запускаем инструменты

Публичный API, частный эндпоинт на двух RTX 4090 и ИИ-агент, который считает логи — сквозной тест Qwen3.6-27B на immers.cloud.

Обложка: Как подключить Qwen3.6-27B к ИИ-агенту: тестируем immers.cloud и запускаем инструменты

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

Мы решили протестировать каталог нейросетевых моделей immers.cloud, чтобы проверить, как работает в нём Qwen3.6-27B на прикладном сценарии от начала до конца. Сначала прогнали модель на задачах для разработчиков в чате, затем вызвали её через API и подключили к тестовому ИИ-агенту с локальными инструментами. По ходу теста сравнили публичный и частный эндпоинты, запустили сгенерированный код, зафиксировали время, расходы и ошибки.

immers.cloud — облачный провайдер вычислений для ИИ: аренда GPU-серверов и готовых инференс-эндпоинтов с посекундной оплатой. Сервис строит инфраструктуру на иммерсионном охлаждении оборудования и позиционирует его как способ держать тарифы ниже рынка — в нашем тесте час конфигурации на двух RTX 4090 стоил 171,77 ₽, а весь сквозной прогон обошёлся в 192,97 ₽. Сервис подходит тем, кому нужен доступ к открытым моделям вроде Qwen без закупки железа: для разовых запусков и прототипов — публичный API, для постоянной нагрузки и изоляции — частный эндпоинт.

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

Прежде чем собирать такой цикл, мы проверили базовый слой: как одна и та же Qwen3.6-27B отвечает в публичном чате, работает через API и запускается в частном инстансе immers.cloud. Это позволяет не смешивать проблемы модели, интерфейса и инфраструктуры с ошибками собственного агентного кода.

Что именно мы проверяли

  • интерфейс публичного чата Qwen3.6-27B, точное название модели и доступность настроек генерации;
  • три задачи разной сложности: исправление факториала, анализ JSONL-логов и ревью скрипта переименования фотографий;
  • публичный OpenAI-совместимый API через Python SDK;
  • создание частного эндпоинта на двух RTX 4090 и прохождение всех этапов запуска;
  • те же задачи на частной модели и работоспособность сгенерированного кода;
  • ИИ-агента с двумя локальными инструментами: нативные вызовы через tool_calls, выполнение функций в Python и возврат результатов модели;
  • запасной сценарий с JSON-диспетчером, а также обработку неверных аргументов, отсутствующих файлов и неизвестных инструментов;
  • фактические расходы и прекращение тарификации после удаления частного инстанса.

Почему взяли Qwen3.6-27B

Для сравнения публичного и частного режима важно использовать одну и ту же модель. Иначе разница в качестве или скорости может быть связана с архитектурой и размером LLM, а не с вариантом размещения. Поэтому в обоих случаях мы выбрали Qwen3.6-27B в четырёхбитной AWQ-квантизации.

Проверяем публичный чат

Публичный чат открывается со страницы модели. В интерфейсе отображается название «Инференс Модели Qwen3.6-27B», поле промпта и кнопка отправки. Отдельных настроек температуры, длины ответа или переключателя thinking mode мы не увидели.

При этом модель выводила блок «Here's a thinking process» прямо внутри ответа. В JSON публичного API поле message.reasoning оставалось null: рассуждение приходило обычным текстом в message.content. Для будущего агента это важная деталь — такой блок нельзя автоматически считать отдельным структурированным каналом reasoning.

У использованного эндпоинта параметр reasoning_parser не был включён. Это заметнее в сценариях без агента, где текст рассуждения приходится разбирать вручную, тогда как агент справляется с таким ответом и без отдельного канала reasoning. Однако есть эндпоинты, где параметр доступен, например: Qwen/Qwen3.5-35B-A3B-GPTQ-Int4 и google/gemma-4-26B-A4B-it.

Три задачи для модели

Задачи подобраны так, чтобы последовательно проверить короткое рассуждение, генерацию исполняемого проекта и способность критиковать собственный код.

Как подключить Qwen3.6-27B к ИИ-агенту: тестируем immers.cloud и запускаем инструменты_15

При анализе логов программа прочитала requests.jsonl, пропустила невалидную строку с предупреждением в stderr и вернула ожидаемую статистику:

{"total": 6, "errors": 2, "average_latency_ms": 168.3, "p95_latency_ms": 400}

Мы запускали решение на штатном Python 3.9.6 в macOS, хотя в промпте требовали Python 3.11. Использованных возможностей стандартной библиотеки хватило, и четыре теста завершились за 0,001 секунды. Это подтверждает работоспособность конкретного ответа, но не заменяет проверку на заявленной версии Python и собственных данных проекта.

Почему ревью модели всё равно нужно перепроверять

Самая показательная часть теста — ревью скрипта: там модель ошиблась увереннее всего, хотя с факториалом справилась гладко. Модель уверенно назвала итог «готовым к merge», хотя в коде сохранились технические дефекты:

  • смещения ASCII-значений EXIF разрешались относительно среза ExifIFD, хотя формат TIFF хранит их относительно начала TIFF-блока;
  • проверка повторного запуска не распознавала уже переименованные файлы и могла добавлять дату к имени ещё раз;
  • тест коллизий не создавал настоящую коллизию двух источников;
  • последовательное переименование не было транзакционным: прерывание процесса могло оставить каталог в частично изменённом состоянии.

Вывод для агентного сценария простой: LLM удобно использовать для анализа и подготовки патча, но выполнение потенциально разрушительных действий должно оставаться за контроллером. Нужны dry run, валидация схемы, тесты, журнал операций и отдельное подтверждение пользователя.

Подключаемся к публичному API

На странице Qwen3.6-27B доступны примеры для cURL, PowerShell и Python. Мы использовали Python-клиент OpenAI и поменяли только токен. Ключ передавали через переменную окружения, чтобы он не попадал в исходный файл и историю команд.

			import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["IMMERS_API_KEY"],
    base_url=(
        "https://chat.immers.cloud/v1/endpoints/"
        "Qwen3.6-27B-AWQ-INT4-VGALY-120626/generate/"
    ),
)
response = client.chat.completions.create(
    model="qwen3.6-27b",
    messages=[
        {"role": "system", "content": "You are a helpful assistant."},
        {"role": "user", "content": "Say this is a test"},
    ],
)
print(response.choices[0].message.content)

		

На macOS окружение и запуск выглядели так:

			python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip openai
read -s "IMMERS_API_KEY?Вставьте API-токен: "; echo
export IMMERS_API_KEY
time python qwen_api_test.py
unset IMMERS_API_KEY

		

Запрос прошёл с openai 2.48.0. Первый запуск занял 6,5 секунды по time, повторный вывод полного JSON — 4,278 секунды. В ответе были указаны модель qwen3.6-27b, 26 входных и 197 выходных токенов. Thinking process снова находился в message.content, а поле reasoning было null.

Запускаем частный эндпоинт

Частный вариант нужен, когда команде важны выделенные ресурсы, предсказуемая конфигурация и собственный жизненный цикл инстанса. Для чистого сравнения мы оставили ту же модель и выбрали конфигурацию rtx4090-2.16.64.160:

  • 2 × RTX 4090 по 24 ГБ;
  • 16 vCPU и 64 ГБ RAM;
  • SSD на 160 ГБ;
  • контекст 262 144 токена;
  • один инстанс и посекундная оплата;
  • 171,77 ₽ в час по странице модели и тарифу сервиса.

Запуск: около десяти минут до AVAILABLE

Запуск начался в 10:13. Сначала кабинет показал создание виртуальной машины, затем остальные стадии подготовки. В 10:23 эндпоинт перешёл в AVAILABLE, а рядом появилась ссылка на чат. Навигация в кабинете оказалась понятной: модель, контекст, конфигурация, статус и API-адрес собраны на одной странице.

На частной модели мы повторили те же задания. Факториал и анализ логов снова дали рабочий результат; четыре теста прошли без исправлений. Субъективно частный вариант отвечал почти так же, как публичный. Показатели TPS в интерфейсе также были близкими, но прямое сравнение времени сложных ответов некорректно: модель генерировала тексты разной длины.

Для более глубокой оценки производительности эндпоинта имеет смысл зайти на виртуальную машину по SSH и запустить нагрузочный прогон vLLM:

			sudo docker exec vllm-server vllm bench serve \

  --dataset-name random \

  --num-prompts 500 \

  --percentile-metrics ttft,tpot,itl,e2el \

  --request-rate 10

		

Первый запуск при этом включает прогрев модели и заметно увеличивает TTFT — это касается и публичных, и частных эндпоинтов.

Публичный и частный режимы: что показал тест

Как подключить Qwen3.6-27B к ИИ-агенту: тестируем immers.cloud и запускаем инструменты_39

В наших запросах message.reasoning оставалось null. При создании частного эндпоинта параметр reasoning_parser не включался, поэтому этот результат нельзя трактовать как отсутствие поддержки отдельного структурированного канала reasoning. В протестированной конфигурации рассуждение возвращалось внутри message.content. Чтобы получить рассуждение в message.reasoning отдельно от основного ответа, нужно включить reasoning parser в настройках частного эндпоинта.

Частный инстанс в этом тесте не дал заметного выигрыша в качестве: обе конфигурации решили одинаковое число проверяемых задач. Его практическая ценность здесь — в выделенной конфигурации и контроле над размещением. Для прототипа и одиночных запросов публичного API достаточно; частный вариант имеет смысл оценивать под постоянную нагрузку, требования к изоляции и прогнозируемое число параллельных запросов.

Сколько стоил тест

Начальный баланс в нашем кабинете составлял 10 000 ₽. После неудачного запуска, успешного развёртывания, трёх задач на частной модели и удаления эндпоинта осталось 9 807,03 ₽. Фактический расход всего теста — 192,97 ₽.

После удаления список активных эндпоинтов опустел. Мы повторно проверили баланс спустя время — он не изменился. Значит, в нашем сценарии тарификация после удаления прекратилась. Это наблюдение относится к конкретному тесту; перед длительным запуском всё равно стоит сверить текущие правила биллинга и доступные действия Shelve, остановки и удаления.

От модели к ИИ-агенту

Проверенный API уже можно использовать как модельный слой приложения. Но один вызов chat.completions ещё не делает программу агентом. Для агентного цикла нужны четыре компонента:

  • модель — Qwen3.6-27B через OpenAI-совместимый API;
  • реестр инструментов — функции с понятными именами, аргументами и JSON-схемами;
  • контроллер — код, который принимает запрос модели, проверяет аргументы, вызывает разрешённую функцию и возвращает результат;
  • политика безопасности — лимиты итераций, dry run для изменений, журналирование и подтверждение опасных действий.

Выбираем полезный сценарий

Вместо демонстрационного агента, который только пересказывает промпт, возьмём разбор инцидента по requests.jsonl. Модель должна решить, какие данные запросить, а точные вычисления оставит локальным функциям.

Как подключить Qwen3.6-27B к ИИ-агенту: тестируем immers.cloud и запускаем инструменты_50

Адаптер Qwen, который уже проверен

Начнём с небольшого слоя, который изолирует адрес immers.cloud и имя модели от остального кода агента. Этот вариант использует тот же способ подключения, который прошёл наш API-тест:

			import os
from openai import OpenAI

MODEL = "qwen3.6-27b"
BASE_URL = (
    "https://chat.immers.cloud/v1/endpoints/"
    "Qwen3.6-27B-AWQ-INT4-VGALY-120626/generate/"
)
client = OpenAI(
    api_key=os.environ["IMMERS_API_KEY"],
    base_url=BASE_URL,
)

def ask_qwen(messages, **options):
    return client.chat.completions.create(
        model=MODEL,
        messages=messages,
        temperature=0,
        **options,
    )

		

Как будет работать агентный цикл

  1. Пользователь просит проанализировать requests.jsonl и предложить действия.
  2. Контроллер передаёт Qwen историю диалога и описания доступных инструментов.
  3. Если модель возвращает tool_calls, контроллер проверяет имя функции и аргументы по схеме.
  4. Локальная функция выполняется без участия модели; её JSON-результат добавляется в messages с ролью tool.
  5. Qwen получает факты и формирует итоговый разбор. Цикл завершается при обычном ответе или по лимиту итераций.

Тестируем полный агентный цикл

Во втором этапе мы подключили Qwen3.6-27B с публичного эндпоинта immers.cloud к агенту разбора инцидентов. Целью было не получить ещё один текст от модели, а проверить всю цепочку: структурированный вызов функции, валидацию аргументов, выполнение локального кода, возврат результата в контекст и безопасное завершение.

Агент работал с теми же тестовыми данными requests.jsonl. Модель не читала файл напрямую и не считала перцентиль сама. Она могла вызвать только три функции из реестра: calculate_log_metrics, lookup_runbook и prepare_incident_report.

Как устроен контроллер

Мы передали описания функций в параметре tools и включили tool_choice="auto". Если Qwen возвращала структурированный tool_calls, контроллер проверял имя функции по белому списку, разбирал аргументы, валидировал их по JSON Schema и только затем выполнял локальный код. Результат возвращался модели сообщением с ролью tool.

			for _ in range(MAX_ITERS):
    response = client.chat.completions.create(
        model=MODEL,
        messages=messages,
        tools=TOOLS,
        tool_choice="auto",
    )
    message = response.choices[0].message
    messages.append(message.model_dump())

    if not message.tool_calls:
        break

    for call in message.tool_calls:
        name = call.function.name
        args = json.loads(call.function.arguments)
        result = dispatch(name, args)
        messages.append({
            "role": "tool",
            "tool_call_id": call.id,
            "name": name,
            "content": json.dumps(result, ensure_ascii=False),
        })

		

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

Как воспроизвести запуск

Рядом с agent.py должен лежать файл requests.jsonl. Токен, как и в базовом API-тесте, передаётся через переменную окружения и не сохраняется в исходнике.

			python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade openai jsonschema
read -s "IMMERS_API_KEY?Вставьте API-токен: "; echo
export IMMERS_API_KEY
python agent.py --mode native
unset IMMERS_API_KEY

		

Первая версия прошла технически, но ошиблась по смыслу

В первом запуске нативный tool calling уже работал: API возвращал структурированные вызовы, имена функций и аргументы проходили схему, цикл дошёл до финального ответа. Но контракт calculate_log_metrics отдавал только агрегаты — число ошибок, среднюю задержку и p95. В нём не было фактических пар route + status для ошибочных записей.

Qwen заметила нехватку данных и прямо написала, что не знает, для каких маршрутов нужно искать runbook. Затем всё же начала подбирать варианты. Кроме реальных /api/orders + 500 и /api/orders + 503 она запросила несуществующие в логе пары /api/payments + 500 и /api/users + 500. Все вызовы были формально валидными, но два из них опирались на выдуманные факты.

Практический вывод. Успешный обмен tool_calls ещё не означает, что агент решает задачу правильно. Если результат одного инструмента должен стать аргументом следующего, контракт обязан возвращать все необходимые факты в машиночитаемом виде.

Добавляем error_records и запрещаем догадки

Мы расширили ответ calculate_log_metrics полем error_records и сгруппировали в нём только реальные ошибки из файла. Для тестового набора функция вернула:

			"error_records": [
    {"route": "/api/orders", "status": 500, "count": 1},
    {"route": "/api/orders", "status": 503, "count": 1}
]

		

В системной инструкции закрепили ещё одно правило: пары для lookup_runbook можно брать только из error_records. После этой правки модель перестала угадывать маршруты. Количество итераций и структурированных вызовов сократилось с шести до четырёх. Суммарное время ожидания ответов API в одном прогоне снизилось с 66,76 до 20,81 секунды. Это наблюдение одного запуска, а не бенчмарк производительности.

Как подключить Qwen3.6-27B к ИИ-агенту: тестируем immers.cloud и запускаем инструменты_74

Что вернул нативный режим

Исправленный цикл завершился за четыре итерации. На первой Qwen вызвала calculate_log_metrics. На второй вернула сразу два lookup_runbook в одном ответе — для кодов 500 и 503. На третьей собрала черновик через prepare_incident_report с apply=false. На четвёртой вызовов инструментов уже не было: модель сформировала итоговый текст.

Как подключить Qwen3.6-27B к ИИ-агенту: тестируем immers.cloud и запускаем инструменты_77

Метрики совпали с отдельным тестом утилиты: шесть корректных записей, две ошибки, средняя задержка 168,3 мс, p95 — 400 мс, одна пропущенная строка. В черновик вошли только реальные проблемы: /api/orders + 500 и /api/orders + 503 — вместе с соответствующими инструкциями runbook.

По телеметрии прогона API вернул четыре нативных вызова, текстовых псевдовызовов не было. Все четыре набора аргументов прошли схему; неизвестных инструментов, ошибок локальных функций, попыток apply=true и выхода на лимит итераций не возникло.

Проверяем запасной режим без tool_calls

Для fallback мы намеренно не передавали tools в API. Вместо этого системный промпт требовал вернуть обычным текстом один JSON-объект с действием tool_call или final. Контроллер извлекал последний валидный объект, проверял его по тому же реестру и вызывал ту же локальную функцию.

Запасной путь тоже завершил задачу: пять итераций, четыре извлечённые JSON-команды и тот же корректный отчёт. Однако Qwen не соблюдала требование «только JSON» буквально — перед объектом она печатала длинный thinking process. Парсер справился, но такой протокол зависит от разбора свободного текста и остаётся более хрупким. Сумма времени пяти ответов составила 62,72 секунды против 20,81 секунды в нативном прогоне. По одному запуску нельзя делать вывод о постоянной разнице скорости, но с точки зрения контракта tool_calls предпочтительнее.

Негативные проверки контроллера

Отдельный faultcheck не обращался к модели: мы напрямую передавали диспетчеру ошибочные вызовы и проверяли, выполнится ли что-нибудь опасное.

Как подключить Qwen3.6-27B к ИИ-агенту: тестируем immers.cloud и запускаем инструменты_85

Даже если модель запросит apply=true, тестовый диспетчер принудительно заменит значение на false. Это защита на уровне кода, а не надежда на системный промпт. Для реального агента к ней нужно добавить права на уровне ОС или сервиса, таймауты, лимиты размера результата, идемпотентность и подтверждение пользователя перед необратимой операцией.

Что показал второй этап

Публичный эндпоинт Qwen3.6-27B в нашем тесте корректно работал с нативным tool calling через стандартный Python SDK: модель вернула структурированные вызовы, приняла результаты с ролью tool и завершила цикл обычным ответом. Значит, проверенный ранее API можно использовать не только для одиночного чата, но и как модельный слой агента.

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

Граница эксперимента: мы провели функциональный прогон на небольшом локальном файле и одном публичном эндпоинте. Это не нагрузочный тест, не проверка SLA и не доказательство одинакового поведения на любых промптах. Реальную запись отчёта тоже не включали: весь сценарий завершился в режиме dry run.

Для прототипа этого достаточно, чтобы двигаться дальше: подключать реальные runbook и источники наблюдаемости, добавлять трассировку и пользовательское подтверждение действий. Для production остаётся главное правило агентной разработки: модель планирует, а контроллер проверяет и исполняет.

Итог

immers.cloud отработал предсказуемо на всех трёх уровнях — публичном чате, публичном API и агентном цикле с tool_calls: везде задача решилась без обходных путей. Узким местом оказалась не модель, а код вокруг неё: проверка аргументов, полный контракт результата инструментов и dry run по умолчанию определили, можно ли доверять результату.

Совместимость с OpenAI SDK здесь помогла конкретно: код, прошедший базовый API-тест, перешёл в агента без единой правки. Для прототипа этого достаточно как отправной точки — дальше стоит добавить трассировку вызовов и подтверждение опасных действий человеком, то, что в проде отличает контролируемый цикл от рабочего образца.

Источники и страницы продукта

Реклама. Рекламодатель: ООО «ДТЛ» ИНН 9717073792, erid: 2W5zFHSiVzq

Рекомендуем