Ты запускаешь qwen3-coder-next, отправляешь промпт с вызовом функции, а в ответ получаешь философское эссе о природе кода вместо четкого JSON. Знакомо? На стартовых тестах в марте 2026 модель показывала успешность в 6.75%. Шесть целых семьдесят пять процентов. Это не ошибка. Это провал.
Потом появилась презентация с Qwen Korea Meetup. Там не было магии, только методология. И она подняла метрику до 100%. Не близко к ста, а ровно сто. Я раздобыл черновик и сейчас разберу его по косточкам.
Почему qwen3-coder-next вообще не звонит?
Прежде чем чинить, нужно понять, что сломано. Основная проблема не в модели, а в том, как мы с ней разговариваем. Qwen3-coder-next – это не универсальный чат-бот, а специфичный инструмент для агентской работы. Ты же не используешь отвертку, чтобы забивать гвозди?
Вот типичная ошибка, которая убивает function calling:
# Как НЕ надо делать
functions = [
{
"name": "calculate_sum",
"description": "Сложить два числа",
"parameters": {
"type": "object",
"properties": {
"a": {"type": "number"},
"b": {"type": "number"}
}
}
}
]
prompt = "Пожалуйста, если тебе не сложно, можешь посчитать сумму 5 и 3?"
Здесь три смертных греха: вежливость, неоднозначность и отсутствие контекста. Модель воспринимает это как запрос на генерацию текста, а не на выполнение действия. Она начнет рассуждать: "Пользователь просит вежливо, значит, нужно дать развернутый ответ..."
Запомни: qwen3-coder-next, как и большинство код-ориентированных моделей на начало 2026, требует директивных, структурированных команд. Вежливость она интерпретирует как слабость сигнала.
Еще одна причина провала – неправильная квантование модели. Если ты используешь Q4_K_M в llama.cpp, когда нужен Q5_K_S, ты теряешь критические для function calling веса. Это все равно что пытаться собрать IKEA без отвертки – детали есть, а скрутить не получается.
Методология из зала: четыре столпа успеха
В презентации корейской команды не было сложных диаграмм. Были четыре принципа, которые перевернули ситуацию.
1 Синтаксис важнее семантики
Не объясняй модели, что такое функция. Покажи, как она выглядит в действии. Используй шаблоны из реального кода, а не абстрактные JSON-схемы.
# Работающий шаблон для function calling
system_prompt = """
Ты – агент выполнения. Твоя задача – анализировать запрос и вызывать строго соответствующую функцию.
Доступные функции и их сигнатуры:
1. Функция: calculate_sum(a: int, b: int) -> int
Назначение: Возвращает сумму двух целых чисел.
Пример вызова: calculate_sum(5, 3) -> 8
2. Функция: get_weather(city: str) -> dict
Назначение: Возвращает текущую погоду для указанного города.
Пример вызова: get_weather("Сеул") -> {"city": "Сеул", "temp": 22}
Формат ответа ТОЛЬКО такой:
{"function": "имя_функции", "arguments": {"arg1": value1, "arg2": value2}}
Не рассуждай. Не комментируй. Не добавляй текст. Только JSON.
"""
Видишь разницу? Здесь нет места для интерпретаций. Есть четкие инструкции, примеры и железный формат вывода. Модель не думает, что ответить – она ищет, какую функцию вызвать.
2 Температура: 0.0 или война
Большинство разработчиков в 2026 все еще играются с temperature=0.7, потому что так написано в старых туториалах. Для function calling это смерть. Любая случайность в выводе сломает парсинг JSON.
--temp 0 --top_k 1. Это отключает стохастичность и заставляет модель выбирать единственный наиболее вероятный токен. Да, ответы будут менее "креативными", но function calling – это не про креативность, а про точность.Если ты работаешь через OpenAI-совместимый API, выставляй temperature=0.0 и seed=42 (или любое другое фиксированное число). Детерминизм – твой лучший друг.
3 Контекстная загрузка, а не описание
Не заставляй модель гадать, какие аргументы куда передавать. Вставляй в промпт реальные значения из текущего диалога. Это называется "in-context learning", и для qwen3-coder-next это работает лучше, чем многословные инструкции.
# Плохо
user_query = "Какая погода в Москве?"
# Хорошо
user_query = "[ЗАПРОС: Какая погода в Москве?] [ПАРАМЕТР: city = Москва]"
# Идеально (шаблон из презентации)
user_query = """
[EXECUTE]
FUNCTION: get_weather
INPUT: {"city": "Москва"}
[/EXECUTE]
"""
Ты явно указываешь модели: вот тег действия, вот имя функции, вот готовый JSON. Ей не нужно ничего парсить – только скопировать структуру. Это снижает когнитивную нагрузку на LLM и резко повышает точность.
4 Последовательная валидация чейном
Самый важный принцип. Не надейся, что модель с первого раза вернет валидный JSON. Вместо этого построй цепочку валидаций:
- Модель генерирует ответ.
- Второй промпт (или простая функция) проверяет синтаксис JSON.
- Если ошибка – модель получает сообщение об ошибке и просьбу исправить.
- Цикл повторяется до успеха или лимита попыток (обычно хватает 3).
В презентации показали, что эта техника сама по себе поднимает успешность на 40%. Потому что qwen3-coder-next отлично учится на своих ошибках, если ты ей их покажешь в структурированном виде.
Пошаговый план: от 6.75% к 100% за 15 минут
Теория – это хорошо, но код – лучше. Вот точная последовательность действий, которую ты можешь запустить прямо сейчас.
Шаг 0: Подготовка модели. Убедись, что у тебя актуальная версия qwen3-coder-next (на март 2026 это Qwen3-Coder-Next-32B-Instruct). Используй квантование Q5_K_S или выше для максимальной точности. Если сомневаешься, сверься с настройками llama.cpp.
Шаг 1: Создай жесткий system prompt. Возьми шаблон выше и адаптируй под свои функции. Не добавляй ничего лишнего. Каждое лишнее слово – это шанс модели сбиться.
Шаг 2: Оберни пользовательский запрос. Преврати "Привет, сколько будет 2+2?" в "[EXECUTE] FUNCTION: calculate_sum INPUT: {"a": 2, "b": 2} [/EXECUTE]". Сначала это можно делать простым правилом, потом – маленькой моделью-классификатором.
Шаг 3: Настрой генерацию. Temperature=0, Top-p=1, Top-k=1. Все флаги на детерминизм.
# Пример запуска через llama.cpp
./main -m ./qwen3-coder-next-Q5_K_S.gguf \
--temp 0 \
--top-k 1 \
--top-p 1 \
--ctx-size 8192 \
--repeat-penalty 1.0 \
-p "[INST] {{SYSTEM_PROMPT}} \n\n {{USER_QUERY}} [/INST]"
Шаг 4: Добавь валидационный цикл. Вот код, который перезапрашивает модель при ошибке парсинга:
import json
import re
def validate_and_retry(model_call, max_attempts=3):
for attempt in range(max_attempts):
response = model_call()
# Ищем JSON в ответе, даже если есть мусор вокруг
json_match = re.search(r'\{.*\}', response, re.DOTALL)
if json_match:
try:
parsed = json.loads(json_match.group())
# Проверяем обязательные поля
if "function" in parsed and "arguments" in parsed:
return parsed
except json.JSONDecodeError:
pass
# Если дошли сюда, что-то пошло не так
error_prompt = f"""
Последний ответ был некорректен: {response}
Исправь и верни ТОЛЬКО JSON в формате: {{"function": "имя", "arguments": {{...}}}}
"""
model_call.set_prompt(error_prompt)
raise ValueError(f"Не удалось получить валидный JSON после {max_attempts} попыток")
Шаг 5: Протестируй на 100 разных запросах. Не на 10, а на 100. Метрика успешности – это процент абсолютно валидных вызовов функций, которые твоя система может распарсить и выполнить. Цель – 100%.
Ошибки, которые все еще делают в 2026 году
Даже с методологией люди умудряются все испортить. Вот топ-3 провала:
| Ошибка | Почему это плохо | Как исправить |
|---|---|---|
| Использование общих промптов для всех моделей | Qwen3-coder-next не понимает промпты, написанные для ChatGPT. У нее другой токенизатор и тренировочные данные. | Пиши промпты с учетом специфики Qwen. Тестируй, итерация за итерацией. |
| Игнорирование формата вывода в истории диалога | Модель учится на контексте. Если в истории были свободные ответы, она продолжит их генерировать. | Всегда включай в историю 1-2 примера корректных вызовов функций перед реальным запросом. |
| Попытка вызвать 10 функций одновременно | Даже 32B-модель на март 2026 не справляется с множественным выбором. Это перегружает ее внимание. | Ограничь список доступных функций 3-4 наиболее релевантными для текущего контекста. Динамически подгружай функции при необходимости. |
Вопросы, которые ты хотел задать, но стеснялся
В: А если мне нужен не JSON, а вызов Python-функции напрямую?
О: Тогда тебе нужен не чистый function calling, а агентская среда вроде Qwen Coder Next как агент. Но принципы те же: четкие инструкции, низкая температура, валидация.
В: Эта методология работает для других моделей, например, IQuestCoder-40B?
О: Работает, но с поправкой. Более крупные модели вроде IQuestCoder-40B могут быть более терпимы к неидеальным промптам, но и они сломаются, если temperature будет выше нуля. Основные принципы универсальны.
В: Я видел, как кто-то добился 100% успешности на старых моделях. Это реально?
О: Нет. На моделях 2024-2025 годов потолок был около 85-90% из-за архитектурных ограничений. Qwen3-coder-next (2026) – первая модель, где 100% достижимо без хаков. Потому что ее дообучили specifically на function calling датасетах.
В: Что дальше? Движемся к 101%?
О: Следующий рубеж – не процент успешности, а latency. Как снизить время вызова с 2 секунд до 200 миллисекунд. И здесь спасет не методология промптов, а оптимизация железа и инференса. Но это уже совсем другая история.
Главный вывод? Function calling – это не магия, а инженерия. Перестань надеяться на интеллект модели и начни проектировать систему. Жесткие правила, детерминизм, валидация. Шесть процентов превращаются в сто не по волшебству, а потому что кто-то сел и разобрался, как работает машина.