
Коротко о главномРазвернутьСвернуть
- К 2026 году ИИ-агенты становятся привычным звеном бизнеса: они снижают издержки на рутинные операции, сокращают время между задачей и результатом и высвобождают команду для решений, которые нельзя автоматизировать.
- В основе агента лежит модель с выстраиваемым вокруг неё кодом.
- Код проверяет её запросы к инструментам, вызывает нужные функции и возвращает результат обратно.
К 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.
Три задачи для модели
Задачи подобраны так, чтобы последовательно проверить короткое рассуждение, генерацию исполняемого проекта и способность критиковать собственный код.
При анализе логов программа прочитала 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 — это касается и публичных, и частных эндпоинтов.
Публичный и частный режимы: что показал тест
В наших запросах 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 . Модель должна решить, какие данные запросить, а точные вычисления оставит локальным функциям.
Адаптер 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,
)Как будет работать агентный цикл
- Пользователь просит проанализировать requests.jsonl и предложить действия.
- Контроллер передаёт Qwen историю диалога и описания доступных инструментов.
- Если модель возвращает tool_calls, контроллер проверяет имя функции и аргументы по схеме.
- Локальная функция выполняется без участия модели; её JSON-результат добавляется в messages с ролью tool.
- 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 секунды. Это наблюдение одного запуска, а не бенчмарк производительности.
Что вернул нативный режим
Исправленный цикл завершился за четыре итерации. На первой Qwen вызвала calculate_log_metrics . На второй вернула сразу два lookup_runbook в одном ответе — для кодов 500 и 503. На третьей собрала черновик через prepare_incident_report с apply=false . На четвёртой вызовов инструментов уже не было: модель сформировала итоговый текст.
Метрики совпали с отдельным тестом утилиты: шесть корректных записей, две ошибки, средняя задержка 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 не обращался к модели: мы напрямую передавали диспетчеру ошибочные вызовы и проверяли, выполнится ли что-нибудь опасное.
Даже если модель запросит 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-тест, перешёл в агента без единой правки. Для прототипа этого достаточно как отправной точки — дальше стоит добавить трассировку вызовов и подтверждение опасных действий человеком, то, что в проде отличает контролируемый цикл от рабочего образца.
Источники и страницы продукта
- Страница Qwen3.6-27B в каталоге immers.cloud
- Руководство immers.cloud по каталогу и эндпоинтам
- FAQ immers.cloud
- Тарифы и конфигурации RTX 4090
- О компании и заявленные особенности иммерсионного охлаждения
Реклама. Рекламодатель: ООО «ДТЛ» ИНН 9717073792, erid: 2W5zFHSiVzq


