Яку модель Ollama обрати для агента з tool calling: порівняння і бенчмарки

Actualizado:
Яку модель Ollama обрати для агента з tool calling: порівняння і бенчмарки

Tool calling в Ollama — одна з найбільш неочевидних фіч локальних моделей. Не тому що API складний. А тому що між «модель підтримує tools» у документації і «модель стабільно викликає tools у продакшні» — велика різниця яку можна виявити тільки під навантаженням.

Одні моделі навчені на tool calling нативно: вони розпізнають JSON Schema, повертають структурований tool_calls і рідко помиляються з аргументами. Інші — знають про існування формату, але вирішують самостійно чи використовувати його. Треті — серіалізують tools у системний промпт і намагаються відповісти JSON-подібним текстом. Поведінка ззовні однакова. Результати — принципово різні.

Далі — конкретно: які моделі куди потрапляють, як це перевірити за одну команду і що робити коли навіть надійна модель мовчить.

Якщо ще не знайомий з тим як tool calling влаштований на рівні API — почни з Ollama REST API: інтеграція у свій застосунок, там є повний розбір циклу виклику з прикладами на Java, Python і JavaScript.

Що значить «підтримує tool calling» — і чому це не просто прапорець

В офіційній документації Ollama є сторінка Tool Calling з прикладами коду. Там є список моделей, є curl-приклади, є формат JSON Schema. Але документація не відповідає на головне питання: наскільки надійно конкретна модель викликає tools у реальних умовах?

Слово «підтримує» у контексті tool calling — розмите. Воно може означати три принципово різні речі, і зовні вони виглядають однаково.

Аналогія перш ніж до коду

Уяви що ти найняв трьох помічників і дав кожному з них інструкцію: «Якщо клієнт питає про погоду — подзвони до метеослужби і скажи мені результат. Якщо питає про курс валют — запроси банківський API.»

  • Перший помічник чітко розуміє коли дзвонити і завжди повертає тобі структурований результат — «дзвінок зроблено, відповідь: +18°C».
  • Другий помічник іноді дзвонить, іноді відповідає «ну, напевно тепло» без дзвінка — залежно від настрою.
  • Третій помічник взагалі не знає як дзвонити, але якщо ти детально пояснив йому у записці що саме писати — іноді він намагається скопіювати формат. Результат непередбачуваний.

У всіх трьох ти сказав одне і те саме. Поведінка — різна. Саме так виглядає «підтримка tool calling» у різних моделях Ollama.

Три рівні підтримки — технічно

1. Нативна підтримка (на рівні ваг)

Модель навчалась на даних де були приклади tool calling. Вона не просто «знає формат» — вона розуміє коли потрібно викликати зовнішню функцію, а коли відповісти текстом. JSON Schema сприймається як частина діалогу, а не як текст. Ollama передає tools через спеціальні токени — і модель реагує на них предметно.

Результат: стабільний tool_calls у відповіді, коректні аргументи, передбачувана поведінка при повторних запитах. Приклади: qwen3, llama3.1+, gemma4.

2. Часткова підтримка

Модель знає формат JSON Schema і може повернути tool_calls — але не завжди. Вона оцінює запит і сама вирішує чи «варто» викликати tool. Іноді ця оцінка правильна. Іноді — ні. Поведінка залежить від формулювання питання, від довжини промпту, від температури генерації.

Практичний наслідок: у простих тестових запитах все виглядає добре. Під реальним навантаженням з'являються «мовчазні» відповіді де tool_calls не прийшов, але і помилки немає. Агент зависає на кроці де мав щось зробити.

3. «Підтримка» через промпт-інжиніринг

Ollama серіалізує опис tools у звичайний текст і вставляє його у системний промпт. Модель бачить щось на кшталт: «У тебе є функція get_weather з параметрами city і units. Якщо потрібно — поверни JSON у форматі…». Модель відповідає на основі інструкції, а не навчання.

Результат: JSON може прийти у полі content як звичайний текст (часто у ```json ... ``` блоці), а не у структурованому tool_calls. Або JSON неповний. Або модель вирішила що питання «досить просте» і відповіла без будь-якого виклику. Парсити такий вивід — ненадійно.

Як виглядає різниця у відповіді

Один і той самий запит — «Яка погода у Харкові?» — з різними моделями:

Нативна підтримка (qwen3:8b):

{
  "message": {
    "role": "assistant",
    "content": "",
    "tool_calls": [
      {
        "function": {
          "name": "get_weather",
          "arguments": { "city": "Харків", "units": "celsius" }
        }
      }
    ]
  }
}

Промпт-інжиніринг (mistral-nemo):

{
  "message": {
    "role": "assistant",
    "content": "```json\n{\"tool\": \"get_weather\", \"city\": \"Kharkiv\"}\n```"
  }
}

Ігнорування (phi-4 на запиті без контексту):

{
  "message": {
    "role": "assistant",
    "content": "Зараз у Харкові помірна температура. Зазвичай влітку +20–25°C..."
  }
}

HTTP 200 у всіх трьох випадках. Код без явної перевірки на наявність tool_calls «проковтне» другий і третій варіант як успішну відповідь — і агент піде далі з неправильними або відсутніми даними.

Чому це важливо саме в продакшні

На одному тестовому запиті проблема непомітна. Навіть модель з частковою підтримкою спрацює правильно якщо питання чітке і коротке. Проблема проявляється коли:

  • Запитів багато і серед них є нетипові або довгі
  • Агент має зробити кілька послідовних кроків (multi-step)
  • Один пропущений tool call ламає весь подальший ланцюг
  • Немає явної перевірки що tool_calls прийшов перед тим як рухатись далі

Саме тому вибір моделі для агентного пайплайну — це не питання якості відповідей. Це питання надійності структурованого виводу під різними умовами. Різниця між першим і третім варіантом підтримки — це різниця між агентом який стабільно працює і агентом який ламається на другому кроці без жодного логу.

Як Ollama передає tools моделі: системний промпт vs native function calling

Коли ти відправляєш запит до /api/chat з масивом tools — Ollama не просто пересилає твій JSON далі. Він вирішує як саме передати опис функцій моделі. І це рішення залежить від того, чи підтримує модель нативний шлях. Два різних шляхи — два різних результати.

Аналогія перш ніж до деталей

Уяви що ти даєш завдання двом перекладачам. Першому ти передаєш завдання рідною мовою — він розуміє одразу, без зусиль, і відповідає точно у потрібному форматі. Другому ти передаєш завдання через перекладача-посередника який переформулює всю інструкцію у звичайний текст. Другий перекладач намагається — але посередник міг щось спростити, щось переформулювати не так. Результат менш передбачуваний.

Нативний шлях — це перший перекладач. Промпт-шлях — другий.

Нативний шлях: tools як частина мови моделі

Моделі з нативною підтримкою мають у своїй архітектурі спеціальні токени для опису функцій — так само як є токени для ролей user, assistant, system. Під час навчання модель бачила тисячі прикладів де ці токени з'являлись у певному контексті і за ними слідував структурований виклик.

Коли Ollama отримує запит з tools і розуміє що модель підтримує нативний шлях — він серіалізує JSON Schema у ці спеціальні токени і вставляє їх у правильне місце в шаблоні чату. Модель «читає» їх так само природно як читає повідомлення користувача.

Результат: модель сама вирішує коли викликати tool (і вирішує правильно у переважній більшості випадків), повертає структурований tool_calls з коректними аргументами, і не потребує додаткових підказок у системному промпті.

Схема нативного шляху:

Твій запит (tools + messages)
        ↓
    Ollama
        ↓ серіалізує tools у спеціальні токени моделі
[TOOL_DEF] get_weather(city: string) [/TOOL_DEF]
[USER] Яка погода у Харкові? [/USER]
        ↓
    Модель генерує:
[TOOL_CALL] {"name": "get_weather", "arguments": {"city": "Харків"}} [/TOOL_CALL]
        ↓
    Ollama парсить → повертає структурований tool_calls у відповіді

Промпт-шлях: tools як текстова інструкція

Якщо модель не підтримує нативний шлях — Ollama не може передати tools через спеціальні токени (їх просто немає у словнику моделі). Замість цього він конвертує весь опис функцій у звичайний текст і додає його до системного промпту.

Модель отримує щось на кшталт:

You have access to the following tools:

get_weather: Отримати поточну погоду для міста
Parameters:
  - city (string, required): Назва міста
  - units (string, optional): celsius або fahrenheit

If you need to call a tool, respond with JSON in this format:
{"tool": "tool_name", "arguments": {...}}

[USER]: Яка погода у Харкові?

Тепер модель намагається слідувати текстовій інструкції. Проблема в тому що ця інструкція — лише текст серед іншого тексту. Модель не «знає» що від неї чекають структурований виклик на рівні навчання. Вона просто генерує наступний токен на основі всього що бачить.

Тому результат може бути будь-яким:

  • Правильний JSON у полі content (але не у tool_calls)
  • JSON у ```json``` блоці — текст, який треба парсити вручну
  • Частковий JSON без закриваючої дужки
  • Відповідь текстом без будь-якого JSON — модель вирішила що «і так зрозуміло»
  • JSON з ключами які відрізняються від тих що ти описав ("tool_name" замість "name")

Схема промпт-шляху:

Твій запит (tools + messages)
        ↓
    Ollama
        ↓ конвертує tools у текстову інструкцію → додає до system prompt
"You have access to: get_weather(city)... respond with JSON..."
[USER] Яка погода у Харкові? [/USER]
        ↓
    Модель генерує текст (може бути JSON, може бути ні)
        ↓
    Ollama повертає все у полі content — tool_calls порожній або відсутній

Як визначити який шлях використовує твоя модель — одна команда

Ollama показує capabilities кожної моделі через ollama show. Наявність tools у секції — ознака нативної підтримки:

# Нативна підтримка — tools є у capabilities
ollama show llama3.1:8b

Model
  arch            llama
  parameters      8.0B
  context length  131072
  ...

Capabilities
  completion
  tools           ← є — Ollama використає нативний шлях
  vision
# Промпт-шлях — tools відсутній
ollama show mistral-nemo:latest

Model
  arch            mistral
  parameters      12.2B
  context length  131072
  ...

Capabilities
  completion      ← tools немає — буде fallback через промпт

Це перша команда яку варто виконати перед тим як будувати агентний пайплайн на новій моделі. Якщо tools немає у capabilities — не витрачай час на дебаг «чому не викликає» — модель просто не підтримує нативно.

Чи можна використовувати промпт-шлях у продакшні?

Технічно — так. На практиці — з великими застереженнями.

Промпт-шлях може спрацювати якщо:

  • У тебе один простий tool з одним-двома параметрами
  • Запити завжди чіткі і короткі
  • Ти готовий писати і підтримувати парсер для content замість tool_calls
  • Збій не є критичним — агент може спробувати ще раз

Але якщо у тебе кілька tools, складні параметри, multi-step агент або production де кожен збій коштує грошей і часу клієнта — обирай модель з нативною підтримкою. Це не питання переваг, це питання надійності.

Коротко: перевір ollama show <model> перед стартом. Є tools у capabilities — нативний шлях, стабільно. Немає — промпт-шлях, непередбачувано. Вибір моделі для агента починається з цієї перевірки.

Моделі з нативною підтримкою: хто реально викликає tools

Нижче — моделі з моєї локальної колекції та публічних даних, які підтверджено підтримують tool calling нативно через Ollama станом на травень 2026. Для кожної моделі — не просто «підтримує», а конкретно: що вона робить добре, де має обмеження, і для яких задач підходить найкраще.

Перш ніж пробувати будь-яку з цих моделей — перевір нативну підтримку: ollama show <model> і шукай tools у секції Capabilities. Навіть у межах однієї серії різні версії можуть відрізнятись.

Qwen3 (8b, 14b, 30b, 32b) — найстабільніший вибір у 2026

Qwen3 від Alibaba — зараз найстабільніша серія для tool calling серед моделей які запускаються локально. За даними Morph LLM benchmarks, Qwen3 має найнижчий відсоток «dropped tool calls» — модель рідко ігнорує tools або повертає невалідний JSON.

Що робить Qwen3 особливим для tool calling:

  • Thinking mode (think=True) — модель спочатку «думає» у прихованому блоці, потім генерує виклик. Це підвищує точність при складних multi-tool сценаріях де треба вибрати правильний tool з кількох варіантів.
  • Стабільний JSON — аргументи у tool_calls майже завжди валідні, типи відповідають схемі.
  • Широкий вибір розмірів — від 8B (5.2 GB, влазить у будь-який сучасний Mac) до 32B для тих у кого є потужне залізо.

qwen3:8b — мій поточний вибір для локальної розробки на Mac M1 16 GB. Запускається разом з nomic-embed-text для RAG без свопу на диск.

ollama pull qwen3:8b    # 5.2 GB — для 8–16 GB RAM
ollama pull qwen3:14b   # ~9 GB — якщо потрібна вища точність
ollama pull qwen3:32b   # ~20 GB — для потужного заліза

Коли обирати Qwen3: агенти з кількома tools, RAG-пайплайни де треба вибирати між searchDocuments / findDeadlines / extractContacts, будь-яка задача де важлива стабільність виклику.

Обмеження: thinking mode збільшує latency першої відповіді на 1–3 секунди. Якщо потрібна максимальна швидкість — можна вимкнути через "think": false у запиті.

Llama 3.1 / 3.2 / 3.3 / Llama 4 Scout — найширша екосистема

Llama 3.1 від Meta була однією з перших широкодоступних моделей з нативним tool calling — і з тих пір серія залишається стандартом де найбільше готових прикладів, туторіалів і підтримки у фреймворках.

llama3.1:8b (4.9 GB) — найбільш «вивчена» модель для tool calling: якщо ти шукаєш приклад інтеграції зі Spring AI, LangChain або LlamaIndex — у 90% випадків він буде саме на llama3.1. За даними Prompt Quorum, Llama 4 Scout (MoE архітектура, ~10 GB VRAM) — найсвіжіший варіант з найширшою підтримкою інструментів у лінійці Meta.

Ключова різниця між версіями серії:

Модель Розмір Tool calling Примітка
llama3.1:8b 4.9 GB ✅ Нативний Найбільше прикладів у екосистемі
llama3.2:3b 2.0 GB ✅ Нативний Для слабкого заліза; якість нижча
llama3.3:70b ~43 GB ✅ Нативний Максимальна якість; потрібно 48+ GB VRAM
llama4:scout ~10 GB ✅ Нативний MoE: 17B active / 109B total; найновіший
ollama pull llama3.1:8b   # стабільний вибір, широка підтримка фреймворків
ollama pull llama4:scout  # найновіший, MoE архітектура

Коли обирати Llama: якщо використовуєш Spring AI, LangChain або LlamaIndex і хочеш максимум готових прикладів. Llama 3.1 — найбезпечніший вибір для старту.

Обмеження: llama3.1:8b поступається qwen3:8b у надійності multi-tool викликів. На простих single-tool задачах різниця непомітна.

Gemma 4 (9b, 26b) — найнадійніший tool calling у своєму класі

Google проектував Gemma 4 з нативним function calling від початку — це не fine-tuning поверх базової моделі, а архітектурне рішення. На практиці це означає менше dropped tool calls і рідше невалідний JSON порівняно з моделями де tool calling додавався пізніше.

gemma4:latest є в моїй локальній колекції (9.6 GB, завантажив 3 тижні тому). З мого досвіду — найвища надійність серед 8–10B моделей: у тестах на 20 запитів з двома tools одночасно (searchDocuments і findDeadlines) повертала валідний tool_calls у ~90% випадків проти ~85% у qwen3:8b.

Додатковий бонус — vision підтримка з тими самими tools:

# Можна передати зображення І викликати tool в одному запиті
curl http://localhost:11434/api/chat \
  -d '{
    "model": "gemma4:latest",
    "messages": [{
      "role": "user",
      "content": "Що зображено на скані документу? Знайди дати.",
      "images": ["<base64_image>"]
    }],
    "tools": [{ ... "findDeadlines" ... }]
  }'
ollama pull gemma4:latest   # 9.6 GB — tool calling + vision, 12+ GB RAM
ollama pull gemma4:26b      # 18 GB — максимальна якість, 20+ GB RAM

Коли обирати Gemma 4: агенти де потрібна максимальна надійність виклику, multimodal задачі (документи + зображення + tools), production де збій коштує.

Обмеження: 9.6 GB — більший файл ніж qwen3:8b (5.2 GB) або llama3.1:8b (4.9 GB). На Mac M1 16 GB паралельно з nomic-embed-text можливий своп при тривалих сесіях.

Qwen2.5 / Qwen2.5-Coder — попереднє покоління, досі актуальне

Qwen2.5 підтримує tool calling нативно і досі є сенс розглядати його якщо Qwen3 з якихось причин не підходить. У моїй колекції є qwen2.5-coder:1.5b-base — але це base модель без instruction tuning. Base модель не навчена слідувати інструкціям, вона лише передбачає наступний токен. Для tool calling це означає: модель не «розуміє» що від неї чекають виклику функції — вона просто продовжує текст.

Важливо: для tool calling завжди потрібна instruct-версія моделі, а не base. Base — для fine-tuning. Instruct — для використання. Якщо бачиш -base у назві — це не та модель.
# Неправильно для tool calling:
ollama pull qwen2.5-coder:1.5b-base   # base — не підходить

# Правильно:
ollama pull qwen2.5:7b                # instruct варіант
ollama pull qwen2.5-coder:7b          # instruct + фокус на код

Коли обирати Qwen2.5: якщо Qwen3 недоступний або потрібна специфічна версія з підтримкою певного фреймворку. Qwen2.5-Coder:7b — хороший вибір для агентів що працюють з кодом.

DeepSeek-R1 (7b, 14b, 32b) — для складних reasoning задач

DeepSeek-R1 підтримує tool calling, але з архітектурною особливістю яку важливо розуміти: перед тим як повернути tool_calls, модель генерує розмірковування у прихованому блоці <think>...</think>.

Як це виглядає у відповіді:

{
  "message": {
    "role": "assistant",
    "content": "<think>\nКористувач питає про погоду. У мене є tool get_weather.\nТреба передати city='Харків'. units не вказано, використаю celsius за замовчуванням.\n</think>",
    "tool_calls": [
      {
        "function": {
          "name": "get_weather",
          "arguments": { "city": "Харків", "units": "celsius" }
        }
      }
    ]
  }
}

Блок <think> — це внутрішнє розмірковування моделі. Твій код має його ігнорувати і читати лише tool_calls. Але саме завдяки цьому розмірковуванню DeepSeek-R1 рідше помиляється з вибором аргументів і краще справляється з ambiguous запитами де незрозуміло який tool викликати.

Практичний наслідок для latency:

Модель Час до першого token у tool_calls Причина
llama3.1:8b 1.2–2.0 с Одразу генерує виклик
qwen3:8b (think=true) 1.5–2.5 с Коротке think-розмірковування
deepseek-r1:7b 3.0–6.0 с Довше think перед викликом
deepseek-r1:14b 5.0–10.0 с Ще довше thinking
ollama pull deepseek-r1:7b    # 4.5 GB — баланс якості і швидкості
ollama pull deepseek-r1:14b   # ~9 GB — для складних reasoning задач

Коли обирати DeepSeek-R1: агенти де важлива правильність вибору tool, а не швидкість. Наприклад: юридичний аналіз документів де модель має вирішити чи викликати checkCompliance чи extractKeyFacts — і помилка в виборі коштує.

Обмеження: latency першого виклику у 2–3 рази вища ніж у llama3.1:8b. Для real-time чат-агентів де важлива швидкість реакції — не найкращий вибір.

З особистого досвіду: як я обирав модель для AskYourDocs

Коли я реалізовував агентний пайплайн для AskYourDocs — RAG-сервісу де агент має викликати кілька tools (searchDocuments, extractKeyFacts, findDeadlines, extractContacts, checkCompliance) — я пройшов через кілька моделей перш ніж зупинився на робочому варіанті.

Спочатку я підключив qwen3:8b через Spring AI 2.0.0-M3 і Ollama. Модель приходила і… відповідала текстом. Жодного tool_calls. Проблема виявилась не в моделі — у Spring AI 2.0.0-M3 є обмеження як передаються tools до Ollama через ToolCallingChatOptions. Модель просто не отримувала tools у правильному форматі.

Після того як я розібрався з форматом передачі — порівняв кілька моделей на одному наборі тестових запитів:

  • qwen3:8b — після виправлення формату запрацював стабільно. Думаючий режим допоміг при складних запитах де треба вибрати між кількома tools.
  • llama3.1:8b — найпростіша інтеграція зі Spring AI, найбільше прикладів у документації фреймворку.
  • mistral-nemo — не спрацював нативно, відповідав текстом. Перевірка через ollama show підтвердила: немає tools у capabilities.

У підсумку для локальної розробки я використовую qwen3:8b, для production на Railway — deepseek/deepseek-chat через OpenRouter (для звичайних клієнтів) або anthropic/claude-3.5-sonnet (для юридичних клієнтів де важлива точність). Локальна модель для розробки і хмарна для продакшну — це стандартна практика коли залізо на сервері не тягне великі моделі локально.

Яку модель Ollama обрати для агента з tool calling: порівняння і бенчмарки

Моделі які «роблять вигляд»: відповідають текстом замість JSON

Якщо попередня секція — про тих хто реально викликає tools, то ця — про тих хто цього не робить, але і не повертає помилку. HTTP 200, текст у content, порожній tool_calls. Саме ці моделі забирають найбільше часу при дебагу — бо зовні все виглядає нормально.

Важливо: це не означає що ці моделі погані. Вони просто не призначені для агентних пайплайнів. У кожної є своя сильна сторона — і вона не тут.

Mistral Nemo — відмінний текстовий асистент, не агент

mistral-nemo:latest є в моїй локальній колекції (7.1 GB). Перевірка одразу дає відповідь:

ollama show mistral-nemo:latest

Capabilities
  completion    ← tools відсутній

Mistral Nemo не має нативного tool calling. Ollama використовує промпт-шлях — серіалізує опис функцій у текст системного промпту. Результат непередбачуваний: у ~30% тестових запитів модель повертала JSON у текстовому блоці ```json...``` всередині content, у решті — просто відповідала текстом як ніби tools не існують.

Де Mistral Nemo дійсно сильний: резюмування довгих документів, переклад, написання текстів, питання-відповідь без зовнішніх викликів. 12.2B параметрів у 7.1 GB — хороший розмір/якість для цих задач. Просто не для агентів.

ЗадачаMistral Nemo
Резюмування документів✅ Відмінно
Переклад і редагування тексту✅ Відмінно
Чат без зовнішніх викликів✅ Добре
Tool calling в агенті❌ Ненадійно
Multi-tool пайплайн❌ Не підходить

Phi-4 — аналітика так, агенти ні

Phi-4 від Microsoft — компактна модель (9.1 GB, 16K контекст) з сильними показниками на STEM і аналітичних задачах. За даними Computing for Geeks, Phi-4 займає високі позиції в бенчмарках з математики і reasoning — але явно слабка на tool calling і long-context retrieval.

Причина технічна: Phi-4 оптимізована для щільного знання на параметр, а не для instruction following у форматі function calling. Модель «розуміє» задачу, але не повертає структурований виклик стабільно.

Практичне правило: якщо потрібен локальний аналітичний асистент для числових даних, звітів або математичних задач без зовнішніх API — Phi-4 чудовий вибір. Якщо потрібен агент який викликає tools — шукай далі.

Gemma 3 — не плутати з Gemma 4

Це часта помилка: людина читає що «Gemma підтримує tool calling», встановлює gemma3:9b — і отримує текст замість tool_calls. Причина проста: нативний tool calling з'явився у Gemma 4, не в Gemma 3.

ollama show gemma3:9b
Capabilities
  completion
  vision        ← tool calling відсутній

ollama show gemma4:9b
Capabilities
  completion
  tools         ← є — нативна підтримка
  vision

Між поколіннями — принципова різниця в архітектурі навчання. Якщо у тебе встановлена gemma3:* і ти будуєш агента — оновлюйся до gemma4. Якщо оновитись не можна (обмеження по RAM або диску) — розглянь llama3.1:8b або qwen3:8b як альтернативу того ж розміру.

Старі кодові моделі — CodeLlama, StarCoder2, CodeGemma

Ці моделі проектувались для code completion — передбачення наступного рядка коду у файлі. Це фундаментально інша задача ніж instruction following або tool calling.

Code completion модель бачить незавершений код і продовжує його. Tool calling вимагає: зрозуміти запит природною мовою → вирішити який інструмент викликати → сформувати JSON з аргументами. Ці моделі не навчались цьому шляху.

У 2026 вони поступились місцем спеціалізованим instruct-моделям: qwen2.5-coder:7b для коду і kimi-k2.6 для складних агентних задач. CodeLlama і StarCoder2 — реліквії 2023 року, корисні для вузьких задач автодоповнення, але не для агентів.

Як швидко перевірити будь-яку нову модель

Перш ніж витрачати час на інтеграцію — два кроки перевірки:

Крок 1 — capabilities:

ollama show <model> | grep tools
# Якщо нічого не вивела — tools немає, промпт-шлях

Крок 2 — живий тест через curl (1 хвилина):

curl http://localhost:11434/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "model": "<your-model>",
    "messages": [{"role": "user", "content": "Яка погода у Києві?"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Отримати поточну погоду для будь-якого міста",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "Назва міста"}
          },
          "required": ["city"]
        }
      }
    }],
    "stream": false
  }' | python3 -m json.tool | grep -A5 "tool_calls"

Якщо у виводі є tool_calls з коректним name і arguments — модель підходить. Якщо вивід порожній або tool_calls відсутній — дивись capabilities і рости до наступної моделі зі списку в секції 3.

Бенчмарк: надійність, швидкість першого tool call, multi-tool

Документація каже «підтримує». Але скільки разів з 10 модель реально повертає валідний tool_calls? Скільки секунд минає до першого токена? Чи може модель викликати два tools паралельно — чи тільки один за раз? Саме ці три параметри визначають чи підходить модель для агентного пайплайну у реальних умовах, а не у тестовому curl-запиті.

Що і як вимірювалось

Бенчмарк гібридний: особисті тести на Mac M1 16 GB з моделями з моєї поточної колекції (ollama list), доповнені публічними даними від Morph LLM і Computing for Geeks (RTX 4090, Ollama 0.23.1, травень 2026).

Три параметри які мають значення для агентів:

1. Надійність tool call — відсоток запитів де модель повернула валідний tool_calls з коректними аргументами, а не текст у content. Вимірюється на 20 однотипних запитах з однаковим набором tools. Чому 20, а не 100: для локальної розробки 20 запитів достатньо щоб побачити системну поведінку. 100% на 5 запитах нічого не означає — подивись на 20.

2. Час до першого токена у tool_calls (TTFT) — скільки секунд проходить від відправки запиту до появи першого байта структурованої відповіді. Для стрімінгу — час до першого токена взагалі. Для агента який чекає результат tool перед наступним кроком — це пряма затримка UX.

3. Multi-tool (паралельний виклик) — чи може модель в одному запиті повернути кілька tool_calls одночасно. Наприклад: «Знайди документи про оренду ТА витягни ключові дати» — ідеально мало б стригернути і searchDocuments, і findDeadlines в одній відповіді. Якщо модель не підтримує multi-tool — вона викликає їх послідовно або взагалі ігнорує один із запитів.

Тест на Mac M1 16 GB — особистий

Тестовий запит: «Знайди документи про оренду та витягни ключові дати» з двома tools: searchDocuments (пошук по документам) і findDeadlines (пошук дат і дедлайнів). Обидва tools є в моєму реальному проєкті AskYourDocs — тому запит не синтетичний, це реальний агентний сценарій.

Умови: Ollama запущений локально, моделі завантажені в RAM перед тестом (щоб виключити cold-start), stream: false, температура за замовчуванням.

Модель Надійність TTFT Multi-tool Що спостерігав
qwen3:8b ~85% 1.5–2.5 с Думаючий режим додає ~0.5–1 с але знижує кількість помилок в аргументах. У 15% випадків відповідав текстом на неоднозначних формулюваннях.
llama3.1:8b ~80% 1.2–2.0 с Найшвидший TTFT серед протестованих. 20% — текстова відповідь, частіше на запитах де питання сформульоване неточно.
gemma4:latest ~90% 1.8–3.0 с Найвища надійність. Повільніший старт через більший розмір (9.6 GB). Multi-tool спрацьовував найстабільніше з усіх.
mistral-nemo:latest ~30% У 70% запитів — текст. У ~30% — JSON у текстовому блоці всередині content, не у tool_calls. Жодного разу не повернув два tools паралельно.
qwen3-ua:latest ~75% 2.0–3.5 с ⚠️ Модель адаптована під українську мову. Tool calling менш стабільний ніж у базового qwen3. Multi-tool спрацьовував через раз.

Відсотки надійності — наближені оцінки на 20 запитів кожної моделі. Реальні показники залежать від трьох факторів: точності формулювання запиту, якості description у JSON Schema функції, і версії Ollama. Погано написаний description може знизити надійність навіть найкращої моделі на 20–30%.

Що реально впливає на надійність — не тільки модель

Під час тестів я помітив: одна і та сама модель може дати 90% надійність на чіткому запиті і 60% — на розмитому. Модель — лише половина рівняння. Друга половина — якість опису функції.

Порівняй два описи одного і того самого tool:

// Поганий опис — модель часто ігнорує tool
{
  "name": "searchDocuments",
  "description": "Search documents",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {"type": "string"}
    }
  }
}
// Хороший опис — модель викликає стабільно
{
  "name": "searchDocuments",
  "description": "Шукає релевантні документи у базі знань за текстовим запитом. Викликай цей tool ЗАВЖДИ коли користувач питає про документи, договори, умови або будь-яку інформацію з бази.",
  "parameters": {
    "type": "object",
    "properties": {
      "query": {
        "type": "string",
        "description": "Текстовий запит для пошуку. Наприклад: 'умови оренди', 'дати платежів', 'відповідальність сторін'"
      },
      "topK": {
        "type": "integer",
        "description": "Кількість результатів. За замовчуванням 5."
      }
    },
    "required": ["query"]
  }
}

Різниця в надійності на qwen3:8b між цими двома описами — приблизно 20–25 відсоткових пунктів на тому самому наборі запитів. Перш ніж звинувачувати модель — перевір свій description.

Публічні дані: RTX 4090 (Morph LLM + Computing for Geeks, травень 2026)

Для тих у кого є потужне GPU або хто планує серверне розгортання — нижче дані на RTX 4090 (24 GB VRAM, CUDA 12.6). Tokens/sec — швидкість генерації відповіді після першого токена. VRAM — потреба при Q4_K_M квантизації і дефолтному розмірі контексту.

Модель Параметри Tokens/sec VRAM (Q4_K_M) Tool calling Для чого
gemma4:26b (MoE) 26B / 4B active ~55 tok/s ~18 GB ✅ Нативний Найкращий баланс якість/швидкість для агентів на GPU
qwen2.5-coder:32b 32B ~35 tok/s ~20 GB ✅ Нативний Агенти з кодом; найсильніша локальна coding модель у 2026
llama3.3:70b 70B ~18 tok/s ~43 GB ✅ Нативний Максимальна якість reasoning; потрібно 48+ GB VRAM
llama3.1:8b 8B ~50 tok/s ~6 GB ✅ Нативний Найшвидша 8B модель на GPU; стандартний вибір для dev-середовища
phi4:14b 14B ~40 tok/s ~10 GB ⚠️ Слабкий Швидко, але tool calling ненадійний — тільки для аналітики без tools

Зверни увагу на gemma4:26b MoE: 26B параметрів загалом, але активних лише 4B на кожен токен. Тому швидкість (~55 tok/s) вища ніж у dense 32B моделей, а VRAM менша. MoE архітектура — це не «маленька модель», це розумний розподіл обчислень.

Ключовий висновок по бенчмарку

Для локальної розробки (8–16 GB RAM, Apple Silicon або середній ноутбук): llama3.1:8b якщо важлива швидкість, gemma4:latest якщо важлива надійність, qwen3:8b — золота середина.

Для GPU-сервера з 20–24 GB VRAM: gemma4:26b — найкращий варіант для production агентів. MoE архітектура дає якість 26B при споживанні значно менших ресурсів.

І пам'ятай: 10–15% приросту надійності можна отримати просто покращивши description у JSON Schema — без зміни моделі.

Яку модель Ollama обрати для агента з tool calling: порівняння і бенчмарки

Порівняльна таблиця: модель / розмір / надійність / RAM

Зведена таблиця всіх моделей про які йшлося у статті. Призначена як швидкий довідник — щоб не гортати текст знову коли треба вибрати модель під конкретне залізо і задачу.

Позначення надійності tool calling: ✅ Нативний — стабільно 75%+, структурований tool_calls у відповіді. ⚠️ Частковий / Промпт — нестабільно, менше 50%, JSON може з'явитись у content. ❌ Відсутній — модель не повертає tool_calls у стандартних умовах.

Модель Розмір файлу RAM мін. Tool calling Multi-tool Надійність Найкраще для
gemma4:9b 9.6 GB 12 GB ✅ Нативний ~90% Агенти + vision; максимальна надійність у 8–10B класі
qwen3:8b 5.2 GB 8 GB ✅ Нативний ~85% Оптимальний баланс розмір/надійність; старт для більшості задач
llama3.1:8b 4.9 GB 8 GB ✅ Нативний ~80% Найширша підтримка фреймворків; найкращий TTFT серед 8B
llama4:scout ~10 GB 12 GB ✅ Нативний ~85% MoE; найновіший від Meta; найширша підтримка інструментів у лінійці
qwen3:14b ~9 GB 12 GB ✅ Нативний ~88% Крок вгору від 8B коли потрібна вища точність аргументів
gemma4:26b 18 GB 20 GB ✅ Нативний ~93% Production GPU; MoE; найвища надійність у таблиці
deepseek-r1:7b ~4.5 GB 8 GB ✅ Нативний ⚠️ ~80% Складні reasoning задачі де важлива правильність вибору tool
deepseek-r1:14b ~9 GB 12 GB ✅ Нативний ⚠️ ~85% Те саме що r1:7b але вища точність; latency 5–10 с до першого виклику
qwen3-ua:latest 5.2 GB 8 GB ✅ Нативний ⚠️ ~75% Українськомовні задачі; tool calling менш стабільний ніж базовий qwen3
mistral-nemo:latest 7.1 GB 8 GB ⚠️ Промпт ~30% Резюмування, переклад, чат без tools — не для агентів
phi4:14b 9.1 GB 12 GB ⚠️ Слабкий ~40% Аналітика, STEM, математика — не для агентів з tools
gemma3:9b ~5.5 GB 8 GB ❌ Відсутній Попереднє покоління; оновись до gemma4 для agents

Як читати таблицю під своє залізо

Mac / ноутбук 8 GB RAM:

  • Старт: llama3.1:8b або qwen3:8b
  • Разом з RAG (nomic-embed-text): qwen3:8b — обидві влазять без свопу
  • Уникай: gemma4:9b (потрібно 12 GB), llama4:scout (~10 GB)

Детальніше що саме запускається на 8 GB і як налаштувати Ollama щоб не свопити — в окремій статті: Ollama на 8 GB RAM: які моделі працюють у 2026 .

Mac M1/M2/M3 16 GB:

  • Оптимум для tool calling: gemma4:9b (~90% надійність) або qwen3:8b (~85%)
  • З RAG паралельно: qwen3:8b + nomic-embed-text — без свопу (5.2 + 0.27 GB)
  • Якщо потрібна вища точність: qwen3:14b (~9 GB) — працюватиме, але щільно. З RAG можливий своп.
  • Уникай: gemma4:26b (18 GB) і llama3.3:70b — не вміщуються

GPU-сервер 20–24 GB VRAM (RTX 3090 / 4090):

  • Production агент: gemma4:26b — ~93% надійність tool calling, ~55 tok/s завдяки MoE
  • Агент з фокусом на код: qwen2.5-coder:32b (~20 GB, найсильніша локальна coding модель у 2026)
  • Якщо залізо 20 GB і треба залишити буфер: qwen3:14b + RAG-модель паралельно

GPU-сервер 40+ GB VRAM:

  • Максимальна якість: llama3.3:70b (~43 GB при Q4_K_M)
  • Але зважай: ~18 tok/s на RTX 4090 — для real-time чату може бути замало. Для batch-обробки документів — прийнятно.
  • Альтернатива: два екземпляри gemma4:26b (~36 GB разом) з балансуванням навантаження — вища пропускна здатність ніж один 70B
Якщо не впевнений у своєму залізі — запусти ollama ps після завантаження моделі і перевір поле size_vram. Якщо значення менше ніж розмір моделі — частина завантажена у системну RAM і модель свопить. Для tool calling агента своп означає latency 5–15 с замість 1–2 с на перший виклик.

Рекомендації по розміру: 3B / 7–8B / 14B+ — де проходить межа якості

Розмір моделі — не єдиний фактор надійності tool calling, але він задає стелю. Навіть ідеально написаний description не витягне 3B модель до рівня 14B на складному multi-tool сценарії. Нижче — де проходить практична межа і як я до цього прийшов.

До 4B: для edge і тестування, не для продакшну

Маленькі моделі (1–4B) технічно можуть повернути tool_calls — але їхня здатність правильно інтерпретувати JSON Schema обмежена. Що конкретно ламається:

  • Опис функції довший за 2–3 рядки — модель «не дочитує» і пропускає параметри
  • Кілька tools у запиті — модель обирає перший і ігнорує решту
  • Нестандартне формулювання запиту — модель відповідає текстом замість виклику
  • Параметри зі складними типами (enum, nested object) — часто повертає невалідний JSON

Єдиний розумний виняток у 2026 — gemma4:2b (E2B варіант від Google). Це єдина sub-4B модель яка більш-менш надійно викликає tools завдяки нативній підтримці function calling в архітектурі. Але «більш-менш» — це все одно не production. Для edge-пристроїв або MVP де збій не критичний — ок. Для реального агента — ні.

Якщо у тебе є тільки 4–6 GB RAM і ти хочеш спробувати tool calling — llama3.2:3b або gemma4:2b дадуть відчуття механіки. Але не будуй на цьому продукт.

7–8B: «золота середина» для локального розгортання

Це мій робочий діапазон. На Mac M1 16 GB я розробляю агентний пайплайн для AskYourDocs саме з qwen3:8b (5.2 GB) і nomic-embed-text (274 MB) паралельно — обидві моделі в RAM одночасно, без свопу на диск.

Чому 7–8B — практична межа для більшості задач:

  • Вміщуються у 6–8 GB VRAM або 8–16 GB системної RAM
  • Дають 70–85% надійності tool calling на типових бізнес-запитах
  • Запускаються на більшості сучасних ноутбуків і MacBook без додаткового заліза
  • Single-tool і базовий multi-tool — стабільно. Складні 3+ tool ланцюги — вже гірше.

qwen3:8b і llama3.1:8b — стандартний вибір для цього класу. Якщо треба обрати між ними: llama3.1:8b якщо важлива сумісність зі Spring AI / LangChain і швидкий TTFT. qwen3:8b якщо важлива вища надійність і є час на налаштування thinking mode.

Критичне застереження про своп: якщо модель не вміщується у RAM і починає свопити на диск — швидкість генерації падає з 15–25 tok/s до 1–3 tok/s. Для агента це означає 10–30 секунд на один tool call замість 1–2. На практиці це робить агента непридатним для real-time взаємодії. Перевір після завантаження:

ollama ps
# NAME          SIZE    PROCESSOR    UNTIL
# qwen3:8b      5.5GB   100% GPU     4 minutes from now
#                       ↑ якщо тут CPU або частково CPU — модель свопить

14B+: для складних агентів і production

Якщо 8B дає 80–85% надійності — чи варто переходити на 14B? Залежить від задачі. Ось де різниця відчутна:

Сценарій 8B достатньо? Коментар
Single tool, чіткий запит ✅ Так Різниця між 8B і 14B мінімальна
2–3 tools, типові бізнес-запити ✅ Здебільшого 8B дає ~80%, 14B — ~88%
Ambiguous запит (незрозуміло який tool) ⚠️ Частково 14B значно рідше обирає неправильний tool
Hallucinated arguments (вигадані значення) ⚠️ Бувають 14B помиляється з аргументами рідше на ~30%
Multi-step агент (5+ кроків) ❌ Нестабільно 8B частіше «зависає» або йде в loop після 3–4 кроків
Production де збій = гроші/репутація ❌ Ризиковано 14B+ або хмарна модель (OpenRouter, Anthropic)

qwen3:14b (~9 GB) — оптимальний крок вгору від 8B: більша точність при помірному збільшенні розміру. gemma4:26b (MoE, 4B параметрів активних на токен) — найкращий вибір якщо є 20+ GB VRAM: якість 26B при споживанні ресурсів значно нижчому ніж у dense 26B моделей.

У своєму production-стеку для AskYourDocs я не використовую локальні моделі на сервері — Railway не дає GPU. Для production я використовую OpenRouter: deepseek/deepseek-chat для стандартних клієнтів і anthropic/claude-3.5-sonnet для юридичних клієнтів де потрібна максимальна точність при роботі з документами. Локальний Ollama — тільки для розробки і тестування нових tools перед деплоєм. Це чесна відповідь на питання «що використовувати в продакшні».

Практичне правило: алгоритм вибору

Замість загальних рекомендацій — конкретний алгоритм який я використовую:

  1. Починай з llama3.1:8b або qwen3:8b залежно від заліза.
  2. Запусти 20 тестових запитів зі своїм реальним набором tools.
  3. Підрахуй скільки разів прийшов валідний tool_calls.
  4. Якщо менше 80% — спочатку перепиши description функцій. Повтори тест.
  5. Якщо після покращення description все одно менше 80% — переходь на 14B.
  6. Якщо і 14B нестабільний на складних multi-step сценаріях — розглядай хмарну модель для production.
З мого досвіду: у половині випадків коли «модель не викликає tools» — проблема в поганому description, а не в розмірі моделі. Виправлення опису функції дешевше ніж перехід на більшу модель. Перевір це спочатку.

Типові помилки і як їх діагностувати

Більшість помилок з tool calling виглядають однаково: HTTP 200, порожній tool_calls, і повна тиша у логах. Нижче — сім конкретних сценаріїв які я зустрічав особисто або які регулярно з'являються у GitHub Issues Ollama. Для кожного — діагноз і рішення.

Помилка 1. Модель ігнорує tools і відповідає текстом

Як виглядає: відправляєш запит з tools, отримуєш нормальну текстову відповідь. tool_calls у відповіді немає або порожній масив.

Три причини в порядку частоти:

  1. Модель не підтримує tool calling нативно — перевір ollama show <model>, шукай tools у Capabilities
  2. Опис функції (description) нечіткий — модель не розуміє коли її викликати
  3. Фреймворк (Spring AI, LangChain) не передає tools у правильному форматі до Ollama

Діагностика — ізолюй фреймворк: протестуй напряму через curl. Якщо curl повертає tool_calls — проблема у фреймворку. Якщо ні — проблема у моделі або описі функції.

curl http://localhost:11434/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen3:8b",
    "messages": [{"role": "user", "content": "Яка погода у Харкові?"}],
    "tools": [{
      "type": "function",
      "function": {
        "name": "get_weather",
        "description": "Отримати поточну погоду для будь-якого міста. Викликай цей tool ЗАВЖДИ коли питають про погоду.",
        "parameters": {
          "type": "object",
          "properties": {
            "city": {"type": "string", "description": "Назва міста"}
          },
          "required": ["city"]
        }
      }
    }],
    "stream": false
  }' | python3 -m json.tool

Помилка 2. Модель повертає JSON у текстовому блоці замість tool_calls

Як виглядає:

{
  "message": {
    "role": "assistant",
    "content": "```json\n{\"tool\": \"get_weather\", \"city\": \"Харків\"}\n```"
  }
  // tool_calls — відсутній
}

Це промпт-шлях у дії (секція 2). Ollama не зміг передати tools через нативні токени і вставив їх у системний промпт як текст. Модель відповіла «як могла» — намагаючись повторити формат з інструкції.

Чому не варто парсити content вручну: формат непередбачуваний. Іноді ```json```, іноді просто {...}, іноді ключі називаються по-іншому ("tool" замість "name"). Будь-який парсер буде крихким.

Рішення: замінити модель на ту що має tools у Capabilities. Це єдине надійне рішення.

Помилка 3. Невалідний або неповний JSON у аргументах

Як виглядає: tool_calls є, але аргументи не те що очікуєш: відсутні обов'язкові поля, неправильний тип, або null там де має бути значення.

Найчастіша причина — мінімальний опис параметрів:

// ❌ Погано — модель не знає що передати
"parameters": {
  "type": "object",
  "properties": {
    "city": {"type": "string"}
  }
}

// ✅ Добре — детальний опис з прикладом і required
"parameters": {
  "type": "object",
  "properties": {
    "city": {
      "type": "string",
      "description": "Назва міста українською або англійською. Наприклад: 'Харків' або 'Kharkiv'"
    },
    "units": {
      "type": "string",
      "enum": ["celsius", "fahrenheit"],
      "description": "Одиниці температури. За замовчуванням celsius."
    }
  },
  "required": ["city"]
}

Поле required — не опціональне. Без нього модель може вирішити що всі параметри необов'язкові і не передасть жодного. Навіть якщо логічно зрозуміло що city потрібне — явно вкажи це у схемі.

Помилка 4. Нескінченний loop — модель викликає той самий tool знову і знову

Як виглядає: агент викликає searchDocuments, отримує результат, і… знову викликає searchDocuments з тим самим запитом. І знову. І знову. Без зупинки.

Причина: модель не отримала чіткого сигналу що задачу вирішено. Вона бачить результат tool у messages, але не розуміє що тепер треба дати фінальну відповідь — і продовжує генерувати наступний крок.

Два рішення:

1. Системний промпт з явною інструкцією:

Ти — агент який відповідає на питання користувача.
У тебе є доступ до інструментів для пошуку інформації.

Правила:
- Викликай tool тільки якщо потрібна зовнішня інформація
- Після отримання результату від tool — одразу давай фінальну відповідь
- Не викликай один і той самий tool двічі в одному діалозі
- Якщо отримав результат — НЕ роби додаткових викликів, одразу відповідай

2. Ліміт кроків на рівні коду (надійніше):

// Java: захист від нескінченного циклу
int maxSteps = 5;
int step = 0;

while (step < maxSteps) {
    var response = callOllama(messages);
    var toolCalls = response.getMessage().getToolCalls();

    if (toolCalls == null || toolCalls.isEmpty()) {
        // Модель дала фінальну відповідь — виходимо
        return response.getMessage().getContent();
    }

    // Виконуємо tool calls і додаємо результати в messages
    executeToolCalls(toolCalls, messages);
    step++;
}

// Якщо досягли ліміту — повертаємо що є
log.warn("Agent reached max steps limit: {}", maxSteps);
return "Не вдалося завершити за відведену кількість кроків.";

Помилка 5. Tool calling не працює у Spring AI 2.0.0-M3 з Ollama — моя особиста

Це та сама ситуація яку я описав у секції 3: я підключив qwen3:8b через Spring AI і модель просто відповідала текстом. Curl давав правильний tool_calls — значить модель підтримує. Проблема була у Spring AI.

Конкретно: Spring AI 2.0.0-M3 має відоме обмеження — ToolCallingChatOptions не завжди коректно серіалізує tools у формат який Ollama очікує для нативного виклику. Частина конфігурацій передавала tools у форматі специфічному для OpenAI, а не для Ollama — і Ollama мовчки ігнорував їх або переходив на промпт-шлях.

Що допомогло:

// ❌ Не завжди спрацьовує з Ollama
ToolCallingChatOptions options = ToolCallingChatOptions.builder()
    .toolCallbacks(toolCallbacks)
    .build();

// ✅ Передавай tools через стандартний Prompt
List<Message> messages = buildMessages(question);
Prompt prompt = new Prompt(messages,
    OllamaChatOptions.builder()
        .model("qwen3:8b")
        .build()
);
// tools реєструй через @Tool анотацію на методах,
// не через ToolCallingChatOptions

Детально про правильну інтеграцію Spring AI 2.0.0-M3 з Ollama — у статті 10г: Tool Calling в Ollama + Spring AI / LangChain: що реально працює.

Помилка 6. Модель «вигадує» аргументи яких немає (hallucinated arguments)

Як виглядає: tool_calls є, аргументи є, але значення не відповідають запиту. Наприклад, користувач питає про Харків — а модель передає "city": "Kyiv". Або передає "date": "2024-01-01" хоча ніякої дати в запиті не було.

Причина: мала модель (до 8B) при неоднозначному запиті «заповнює» відсутні аргументи своїми здогадками замість того щоб або запитати у користувача, або передати порожнє значення.

Рішення — три підходи:

  • Валідація аргументів перед виконанням: перевіряй що отримані аргументи логічно відповідають запиту користувача перед тим як передавати їх у реальну функцію
  • Обов'язкові поля з enum: якщо параметр має обмежений набір значень — завжди вказуй "enum": [...]. Модель значно рідше вигадує значення якщо бачить дозволений список
  • Перехід на 14B: hallucinated arguments — один з основних симптомів де 14B суттєво краще 8B

Помилка 7. Cold start — перший запит займає 10–30 секунд

Як виглядає: перший запит після запуску Ollama або після тривалої паузи займає в рази довше ніж наступні. Агент «завис» на першому кроці.

Причина: модель вивантажилась з RAM (за замовчуванням через 5 хвилин після останнього запиту) і тепер завантажується знову — це займає 5–15 секунд залежно від розміру моделі і швидкості диска.

Рішення — keep_alive:

// У кожному запиті — тримати модель в RAM 30 хвилин
{
  "model": "qwen3:8b",
  "messages": [...],
  "tools": [...],
  "keep_alive": "30m"   // або -1 щоб тримати постійно
}

// Або глобально через змінну середовища:
// OLLAMA_KEEP_ALIVE=30m ollama serve

Для агентного пайплайну де запити приходять пачками — "keep_alive": "30m" стандартне рішення. Для одиничних запитів або batch-задач де RAM важлива — "keep_alive": 0 вивантажить модель одразу після відповіді.

Швидка таблиця діагностики

Симптом Перша перевірка Найімовірніша причина
Відповідь текстом, немає tool_calls ollama show <model> → є tools? Модель без нативної підтримки або поганий description
JSON у content, не у tool_calls Перевір capabilities моделі Промпт-шлях — замінити модель
curl дає tool_calls, фреймворк — ні Перевір як фреймворк серіалізує tools Spring AI / LangChain передає tools у неправильному форматі
Неповні або неправильні аргументи Перевір required і description Мінімальний опис параметрів або маленька модель (до 8B)
Нескінченний loop Перевір системний промпт Немає інструкції «після результату — давай відповідь»
Вигадані значення аргументів Перевір enum у схемі Модель заповнює відсутні дані здогадками — 8B частіше ніж 14B
Перший запит 10–30 секунд ollama ps — чи є модель у RAM? Cold start — додай keep_alive

Яка найнадійніша модель для tool calling на Mac з 16 GB RAM?

Залежить від того що важливіше — надійність чи можливість запускати RAG паралельно.

Якщо тільки агент без RAG: gemma4:latest (9.6 GB) — найвища надійність у своєму класі (~90% на 20 тестових запитах). Google проектував Gemma 4 з нативним function calling від початку, тому multi-tool спрацьовує стабільніше ніж у конкурентів того ж розміру.

Якщо агент + RAG паралельно: qwen3:8b (5.2 GB) + nomic-embed-text (274 MB) — обидві вміщуються без свопу на M1 16 GB (разом ~5.5 GB, залишається буфер). Надійність ~85% — трохи нижча ніж Gemma 4, але для більшості бізнес-задач достатньо.

Я особисто використовую саме цю комбінацію для локальної розробки AskYourDocs: qwen3:8b як агент і nomic-embed-text для ембедингів. Обидві постійно в RAM, без cold start між запитами.

Якщо потрібна вища точність і RAM дозволяє: qwen3:14b (~9 GB) — але тоді паралельно запускати RAG-модель стане щільно, можливий своп.

Як перевірити чи підтримує модель tool calling нативно?

Один крок — ollama show:

ollama show qwen3:8b

# Model
#   arch            qwen3
#   parameters      8.2B
#   context length  40960
#
# Capabilities
#   completion
#   tools           ← є — нативна підтримка
#   thinking
ollama show mistral-nemo:latest

# Capabilities
#   completion      ← tools відсутній — промпт-шлях, ненадійно

Якщо хочеш перевірити одразу кілька моделей зі своєї колекції:

# Перевірити всі встановлені моделі на наявність tool calling
ollama list | awk 'NR>1 {print $1}' | while read model; do
  result=$(ollama show "$model" 2>/dev/null | grep -c "tools")
  if [ "$result" -gt 0 ]; then
    echo "✅ $model — tools підтримуються"
  else
    echo "❌ $model — tools відсутні"
  fi
done

Після цього — живий тест через curl (1 хвилина) щоб підтвердити на практиці. Деталі у секції 4.

Чи можна змусити модель без нативного tool calling все одно викликати tools?

Технічно — так. Детальний системний промпт де описуєш формат JSON Schema і просиш відповідати у чіткій структурі іноді спрацьовує:

system: """
Коли потрібна зовнішня інформація — відповідай ТІЛЬКИ у форматі:
{"tool": "назва_функції", "arguments": {"параметр": "значення"}}
Доступні функції: get_weather(city: string), get_rate(currency: string)
Нічого більше не пиши — тільки JSON.
"""

На практиці — нестабільно. З мого досвіду з mistral-nemo: у ~30% запитів модель повертала щось схоже на JSON у content. Але формат міг відрізнятись від запиту до запиту, ключі іноді називались інакше ніж описано, іноді приходив неповний JSON. Парсер для цього складніше підтримувати ніж просто замінити модель.

Коли промпт-підхід виправданий: якщо у тебе один простий tool, чіткі запити і MVP де швидкість розробки важливіша за надійність. Для production — не рекомендується. Заміна моделі на qwen3:8b або llama3.1:8b займе 30 хвилин і вирішить проблему назавжди.

Mistral підтримує tool calling?

Залежить від версії — і це головна пастка:

Модель Tool calling Перевірка
mistral:7b-instruct-v0.3 ✅ Нативний tools є у capabilities
mistral-small:latest (Small 3.1) ✅ Нативний tools є у capabilities
mistral-nemo:latest ❌ Промпт-шлях tools відсутній у capabilities
mixtral:8x7b ⚠️ Часткова Залежить від версії тегу

mistral-nemo:latest є в моїй колекції (7.1 GB) — я перевіряв особисто. Відмінна модель для текстових задач, але для агентів — ні. Якщо хочеш Mistral для tool calling — бери mistral-small:latest, не Nemo. І завжди перевіряй конкретну версію через ollama show перед тим як будувати пайплайн.

DeepSeek-R1 підходить для агентів?

Підходить — але з чіткою сферою застосування. Це не «загальний» агент, це агент для задач де важлива правильність рішення, а не швидкість реакції.

Latency: перший токен у tool_calls з'являється через 3–10 секунд (залежно від розміру моделі і складності запиту) — бо спочатку генерується <think> блок. Для real-time чату де користувач чекає відповідь — це забагато. Для batch-обробки документів де ніхто не дивиться на годинник — норм.

Де виграє: ambiguous запити де незрозуміло який tool викликати. Наприклад, «перевір чи договір відповідає законодавству» — модель має вирішити між checkCompliance і extractKeyFacts. DeepSeek-R1 завдяки thinking рідше помиляється з таким вибором.

Мій висновок: для юридичних клієнтів AskYourDocs де документи складні і помилка у виборі tool коштує — я б розглядав DeepSeek-R1:14b. Для звичайних клієнтів де важлива швидкість — Qwen3 або Llama 3.1.

Чому curl повертає tool_calls, а Spring AI — ні?

Це найбільш заплутана ситуація і я сам через неї пройшов. Коли curl з тим самим запитом і тою самою моделлю повертає правильний tool_calls, а Spring AI — текст, це майже завжди означає що фреймворк передає tools не у тому форматі.

У Spring AI 2.0.0-M3 конкретна проблема: ToolCallingChatOptions в деяких конфігураціях серіалізує tools у формат OpenAI, а не у формат який Ollama очікує для нативного виклику. Ollama мовчки переходить на промпт-шлях — і модель відповідає текстом.

Діагностика — увімкни debug логування запиту до Ollama:

# application.properties
logging.level.org.springframework.web.reactive.function.client=DEBUG

Знайди у логах тіло запиту і перевір чи є там поле tools у правильному форматі. Якщо tools немає або формат відрізняється від того що ти передаєш у curl — проблема у серіалізації фреймворку.

Детально про правильну конфігурацію — у статті 10г: Tool Calling в Ollama + Spring AI / LangChain.

Яка різниця між qwen3:8b і qwen3-ua:latest для tool calling?

qwen3-ua:latest є в моїй колекції (5.2 GB) — це адаптована версія Qwen3 з покращеною підтримкою української мови. Для текстових задач українською — помітно краща якість відповідей.

Але для tool calling — базовий qwen3:8b стабільніший. З моїх тестів: qwen3:8b давав ~85% надійності, qwen3-ua:latest — ~75% на тому самому наборі запитів. Multi-tool у UA-версії спрацьовував через раз.

Мій підхід для україномовних проєктів: qwen3:8b для агентної частини (tool calling), і налаштування мови через системний промпт («Відповідай виключно українською мовою»). Базова модель розуміє українські запити — просто генерує відповіді англійською якщо не вказати мову явно.

Скільки tools можна передати в одному запиті?

Ollama формально не обмежує кількість tools у запиті. Але на практиці є межа де якість починає падати — і вона залежить від розміру моделі.

Розмір моделі Рекомендована кількість tools Що відбувається при перевищенні
До 4B 1–2 tools Модель ігнорує більшість tools, викликає перший або жодного
7–8B 3–5 tools При 6+ починаються пропуски і неправильний вибір
14B+ до 8–10 tools Стабільно на більшості запитів

У AskYourDocs у мене 5 tools: searchDocuments, extractKeyFacts, findDeadlines, extractContacts, checkCompliance. На qwen3:8b це на межі — інколи модель не викликає checkCompliance на запитах де він потрібен. Якщо б інструментів було 8–10 — переходив би на 14B.

Висновки

  • Перевіряй capabilities перед вибором: ollama show <model> одразу покаже чи є нативна підтримка tools.
  • Для 8 GB RAM: qwen3:8b або llama3.1:8b — надійний старт.
  • Для Mac 16 GB + RAG: qwen3:8b + nomic-embed-text — обидві вміщуються без свопу.
  • Для максимальної надійності tool calling: gemma4:latest (якщо є 12+ GB RAM) або gemma4:26b (20+ GB).
  • Mistral Nemo і Phi-4 — відмінні моделі для своїх задач, але не для agents з tools.
  • Якщо модель ігнорує tools — спочатку тестуй через curl напряму, щоб відокремити проблему фреймворку від проблеми моделі.
  • В продакшні з складними агентними пайплайнами — qwen3:14b або gemma4:26b. Різниця у надійності між 8B і 14B+ відчутна при multi-tool і довгих ланцюгах викликів.

Наступний крок: якщо використовуєш Spring AI або LangChain — читай статтю 10г: Tool Calling в Ollama + Spring AI / LangChain: що реально працює. Там детально про те як правильно передавати @Tool методи через Spring AI 2.0.0-M3 і які моделі реально тригерять виклики у Java-додатках.

Джерела

Останні статті

Читайте більше цікавих матеріалів

Яку модель Ollama обрати для агента з tool calling: порівняння і бенчмарки

Яку модель Ollama обрати для агента з tool calling: порівняння і бенчмарки

Tool calling в Ollama — одна з найбільш неочевидних фіч локальних моделей. Не тому що API складний. А тому що між «модель підтримує tools» у документації і «модель стабільно викликає tools у продакшні» — велика різниця яку можна виявити тільки під навантаженням. Одні моделі...

GPT-5.3-Codex-Spark: real-time кодинг у 2026 — що це і навіщо

GPT-5.3-Codex-Spark: real-time кодинг у 2026 — що це і навіщо

12 лютого 2026 року OpenAI випустила GPT-5.3-Codex-Spark — і більшість розробників одразу запитали одне й те саме: «Це новий додаток? Мені треба щось перевстановлювати?» Ні. Spark — це модель всередині Codex App яку ти вже маєш. Просто інша модель у model picker — але з принципово іншим принципом...

Codex від OpenAI: повний гід 2026

Codex від OpenAI: повний гід 2026

OpenAI Codex у 2026 році — це не той інструмент, про який ви, можливо, читали кілька років тому. Оригінальний Codex API (2021–2023) був моделлю для автодоповнення коду на базі GPT-3, яка живила ранні версії GitHub Copilot. OpenAI закрила той API у березні 2023 року. Те, що існує сьогодні —...

Ollama REST API: інтеграція у свій застосунок — Java, Python, JavaScript

Ollama REST API: інтеграція у свій застосунок — Java, Python, JavaScript

Ollama — це не тільки CLI-інструмент для запуску моделей у терміналі. Це повноцінний локальний сервер з REST API, який слухає на порту 11434 і приймає запити від будь-якого застосунку — Spring Boot, Node.js, Python, або будь-якої мови з підтримкою HTTP. У цій статті — повний практичний...

Ollama vs ChatGPT vs Claude: яка задача вимагає хмари

Ollama vs ChatGPT vs Claude: яка задача вимагає хмари

Питання «Ollama чи ChatGPT?» — неправильне питання. Правильне: «яку задачу я зараз вирішую — і де її краще вирішувати?» Ця стаття не про те, що краще. Вона про те, як обирати без фанатизму. Якщо ще не знайомий з Ollama — почни з вступної статті про те, що таке Ollama і навіщо вона...

DeepSeek V4 Pro у 2026: повний розбір — архітектура, бенчмарки і коли переходити вигідно

DeepSeek V4 Pro у 2026: повний розбір — архітектура, бенчмарки і коли переходити вигідно

TL;DR за 30 секунд: DeepSeek V4 Pro — найбільша open-weight модель у світі: 1.6T параметрів (49B активних), контекст 1M токенів, MIT-ліцензія. Вийшла 24 квітня 2026 як preview. Коштує $3.48/M output токенів — у 7 разів дешевше за GPT-5.5 і в 6 разів дешевше за Claude Opus 4.7. На...