Вечно третий: почему классический RAG — это боль
Раньше, чтобы накормить локальную LLM свежими данными из интернета, приходилось городить огород: поднимать ChromaDB, писать ретривер, резать HTML на чанки, тащить эмбеддеры... Знакомо? А теперь представьте, что ваша модель умеет сама сходить на сайт, стянуть текст и даже запустить shell-команду. Без посредников. Это не фантастика — это новые встроенные инструменты llama.cpp server.
-DLLAMA_NATIVE_TOOLS=ON.Две кнопки, которые меняют всё
Внутри llama-server появилось два нативных инструмента уровня model function call:
- web_fetch — принимает URL, качает HTML, чистит от тегов, возвращает текст (до 16 КБ по умолчанию). Идеально для RAG без векторной базы.
- exec_shell_command — выполняет любую shell-команду на сервере. Да, ту самую. Да, с риском RCE, если не ограничить доступ.
Оба инструмента объявляются моделью через стандартный OpenAI-compatible tools API. То есть вы можете общаться с LLM обычным чатом, а когда ей понадобится контекст — она сама вызовет нужный инструмент.
Как включить и не сломать себе жизнь
1 Сборка с нативными тулами
git clone https://github.com/ggerganov/llama.cpp
cd llama.cpp
mkdir build && cd build
cmake .. -DLLAMA_NATIVE_TOOLS=ON -DLLAMA_CUDA=ON # если есть GPU
make -j$(nproc) llama-server
Флаг LLAMA_NATIVE_TOOLS включает поддержку curl (для web_fetch) и popen (для exec_shell). Без него инструменты не появятся.
2 Запуск сервера с белым списком
./llama-server -m /path/to/model.gguf \
--host 0.0.0.0 --port 8080 \
--tools web_fetch,exec_shell_command \
--allow-domains wikipedia.org,example.com \
--allow-commands "ls,cat,echo,git" \
--tool-timeout 30
⚠️ Безопасность превыше всего
Никогда не запускайте exec_shell_command без --allow-commands — модель может выполнить rm -rf / по неосторожности. История с RCE-уязвимостью в llama.cpp показала: лучше перебдеть.
3 Подготовка модели к tool calling
Не каждая LLM умеет вызывать инструменты. Проверенные модели на май 2026:
- Qwen 3.5 (отлично работает с tool calling, есть готовый чат-шаблон)
- Llama 4 8B Instruct
- Mistral Small 3.1 24B
- Command R+ 104B (требует много VRAM)
Важно: шаблон чата должен поддерживать функцию tool_calls в ответе. Для Qwen 3.5 используйте кастомный шаблон из статьи выше.
Живой пример: RAG по документации Python
Допустим, вы хотите узнать последние изменения в asyncio. Вместо того чтобы гуглить, пишете:
Какие новые функции появились в asyncio в Python 3.13? Загрузи страницу docs.python.org/3.13/whatsnew/3.13.html и выдели все, что связано с asyncio.
Модель вызывает web_fetch с URL, получает текст, анализирует его и формирует ответ. Всё — без ручного копирования. Пример лога:
{
"tool_calls": [{
"id": "call_web_1",
"type": "function",
"function": {
"name": "web_fetch",
"arguments": "{\"url\":\"https://docs.python.org/3.13/whatsnew/3.13.html\"}"
}
}]
}
Когда exec_shell_command спасает — и когда он опасен
Сценарии, где shell-инструмент незаменим:
- Генерация сниппетов, которые сразу проверяются: попроси модель написать скрипт и выполнить его через
python -c "...". Только убедитесь, что--allow-commandsвключаетpython. - Debagging инфраструктуры: модель может сама выполнить
df -hилиnvidia-smiи проанализировать нагрузку. - Агенты, которые управляют Git: мы уже обсуждали, как встроенные знания LLM о Git и терминале заменяют сложные пайплайны.
Но помните: любой вызов exec_shell_command — это потенциальная брешь. Поэтому:
- Используйте
--allow-commandsс точным списком бинарников. - Запускайте сервер от пользователя с минимальными правами (никакого root!).
- Оберните в Docker c read-only rootfs.
Как НЕ надо: хардкод URL в конфиге
Некоторые пытаются прописать --web-fetch-urls в надежде ограничить инструмент, но это работает не так. Ниже — типичная ошибка:
# НЕПРАВИЛЬНО: модель всё равно может вызвать web_fetch с произвольным URL
./llama-server --tools web_fetch --web-fetch-urls '["https://example.com/page1"]'
Правильный путь — использовать --allow-domains и, если нужно, предварительно загружать страницы через web_fetch из клиентского кода. Кстати, если вам нужно встроить llama.cpp в свой проект напрямую — смотрите как встроить движок LLM прямо в свой проект.
Автоматизация повторяющихся запросов: терминальный ассистент
Если вы часто просите модель выполнить одни и те же команды (например, найти PID процесса), можно написать скрипт, который сохраняет промпт с вызовом exec_shell_command. Подобный подход описан в статье "Терминальный амнезиак" — 50 строк Python, которые заставят LLM помнить команды за вас.
💡 Совет профи
Для production-сценариев используйте --tool-timeout 30, чтобы модель не зависала на медленных сайтах. И обязательно включите --no-prompt-cache, иначе кеш промпта может содержать результаты предыдущих вызовов — это опасно с исполнительными командами.
Схема работы на пальцах
| Этап | Что происходит | Участники |
|---|---|---|
| 1. Промпт | Пользователь пишет: "Скачай статью X и перескажи" | Клиент → Server |
| 2. Вызов инструмента | Модель решает, что нужен web_fetch, возвращает tool_call | Server → Клиент |
| 3. Исполнение | Клиент (или сам сервер в streaming-режиме) выполняет web_fetch | Server → curl → Server |
| 4. Ответ | Результат передаётся модели, она формирует финальный ответ | Server → Клиент |
Что дальше? Есть ли жизнь без RAG-пайплайна?
Нативные инструменты — это не серебряная пуля. web_fetch не умеет ходить по ссылкам внутри страницы, обходить JS-рендеринг или авторизацию. Если ваш RAG требует глубокого краулинга — придётся оставить классический ретривер. Но для 80% случаев "мне нужно быстро узнать, что написано на одном сайте" — этого более чем достаточно.
exec_shell_command же открывает дверь к настоящим агентам, которые могут самостоятельно разворачивать контейнеры, анализировать логи и чинить ошибки. Главное — не забыть про изоляцию. Как сказал один мой коллега: "Доверяй, но верифицируй — особенно если LLM может вызвать sudo".
Кстати, если хотите протестировать инструменты на мощном GPU без покупки карты — рекомендую арендовать сервер с A100 на Timeweb Cloud. Там можно запустить Qwen 3.5 32B и проверить web_fetch на полную катушку.
А вы уже используете нативные инструменты в llama.cpp? Делитесь в комментариях, какие сценарии оказались самыми неожиданными.