A B C D E F G H I J K L M N O P Q R S T V W Y Z А Б В Г Е И К Л М О П С Т Ц

Ollama

Ollama

 

Ollama это инструмент для локального запуска и обслуживания больших языковых моделей (large language model, LLM) через связку CLI-клиента и REST API сервера, который поднимается на обычном ноутбуке или на собственном сервере без похода в облако. Разработчик скачивает готовую квантованную (quantized) модель одной командой, обращается к ней через локальный HTTP-эндпоинт и получает поведение, похожее на облачный API, но с весами на своём диске. Разбираемся, как устроена эта связка изнутри, что происходит с запросом от момента вызова до потокового ответа и где Ollama уместна, а где нет.

 

Что такое Ollama

По устройству Ollama это пара «клиент плюс сервер». Команда ollama serve поднимает локальный процесс, который слушает REST API на порту 11434 и принимает запросы от CLI, от python-клиента или от любого HTTP-клиента вроде curl. Проверить, что сервер жив, можно одним запросом.

# проверка живости локального сервера Ollama
curl -s http://localhost:11434/api/tags

Ответ приходит в JSON со списком уже скачанных моделей. Официальная документация проекта (docs.ollama.com) описывает раздельными разделами CLI, REST API с эндпоинтами chat, generate, embeddings и models management, а также Modelfile для кастомизации модели поверх готовых весов. Такое разделение подсказывает, что CLI и API это два независимых входа в один и тот же сервер, а не два разных продукта.

Отдельная особенность Ollama против облачных провайдеров это формат хранения моделей. По официальной документации по импорту моделей, веса на диске лежат в формате GGUF, уже квантованном контейнере весов, токенизатора и метаданных модели, и сервер не переобучает и не дообучает их, а только загружает в память и прогоняет через них запрос. Проект развивается очень активно. На момент подготовки статьи актуальный релиз v0.33.2 вышел 27 августа 2026 года, а до него релизы выходили почти ежедневно, поэтому конкретный номер версии в статье быстро устареет и приводится только для ориентира.

 

Архитектура и ключевые особенности Ollama

Схема ниже собирает компоненты, с которыми реально работает разработчик, а именно клиентский слой (CLI и REST API клиенты вроде python-библиотеки), сервер Ollama, движок инференса (inference engine) внутри него и GGUF-модели на диске, которые сервер подгружает в память по запросу.

Схема архитектуры Ollama: CLI и REST API клиенты, сервер Ollama, движок инференса, GGUF-модели на диске

Python-клиент, пакет ollama, не содержит собственной логики инференса. Он собирает HTTP-запрос к тем же эндпоинтам, что доступны через curl, и разбирает JSON-ответ в удобные объекты. Это видно по коду демо в разделе «Практика». Вызов ollama.chat() внутри делает POST на /api/chat, а ollama.show() и ollama.list() дергают эндпоинты информации о моделях. Ключевая особенность такого устройства в том, что любой язык программирования с HTTP-клиентом может работать с Ollama напрямую, без официальной библиотеки.

Второй компонент, важный для практики, это Modelfile, механизм кастомизации модели поверх уже скачанных весов. Он не меняет параметры модели и не запускает дообучение, а навешивает system-промпт, параметры генерации вроде температуры и шаблон общения. Питон-клиент открывает тот же механизм через вызов ollama.create(), что подробно разобрано в разделе про квантование ниже.

ИИ-агенты для оптимизации бизнес-процессов

Код курса
AGENT
Ближайшая дата курса
26 октября, 2026
Продолжительность
24 ак.часов
Стоимость обучения
66 000

 

Как Ollama запускает и обслуживает модели

Жизненный цикл одного запроса к /api/chat выглядит так же для CLI, для curl и для python-клиента, потому что все они бьют в один и тот же эндпоинт. Схема ниже показывает эту последовательность от вызова API до потокового ответа.

Последовательность обработки запроса в Ollama: от вызова API до потоковой генерации ответа моделью

Сначала сервер проверяет, загружена ли нужная модель в память. Если нет, он читает GGUF-файл с диска и держит модель в памяти до следующего таймаута простоя, поэтому загрузка весов с диска всегда медленнее ответа от уже прогретой модели. На стенде qwen2.5:7b была прогрета ещё с прошлых демо, и первый вызов chat в скрипте занял 0.66 секунды, то есть это время самого инференса без загрузки весов с диска.

Дальше запрос обрабатывается в одном из двух режимов. Обычный вызов возвращает готовый ответ целиком одним JSON-объектом, а флаг stream=True переключает тот же самый эндпоинт на потоковую передачу NDJSON, где каждая строка ответа это один сгенерированный фрагмент токенов. В прогоне на стенде потоковый ответ на вопрос про REST API пришёл за 49 фрагментов за 3.97 секунды, и текст собирается на клиенте по мере поступления кусков, а не ждёт полной генерации.

Третий режим, вызов инструмента (tool calling), устроен иначе, чем можно ожидать. Модель не выполняет функцию сама, она возвращает структурированный tool_calls с именем функции и аргументами, а вызов реального кода и подстановка результата обратно в диалог остаются на стороне клиента. В демо модель на запрос «Какая погода в Дубае?» вернула структурированный вызов get_weather с аргументом city «Дубай», клиентский код подставил заглушку с результатом «+34°C, ясно» отдельным сообщением с ролью tool, и только вторым обращением к серверу пришёл связный текстовый ответ на языке пользователя. Без этого второго вызова диалог остаётся на уровне сырого JSON с аргументами функции.

 

Квантование в Ollama как компромисс размера, скорости и качества

Формат GGUF, в котором Ollama хранит модели, поддерживает несколько степеней квантования одного и того же набора весов, и выбор степени напрямую определяет, сколько модель займёт места на диске и в памяти. Прогон на стенде сравнил три тега одной и той же модели Qwen2.5 0.5B-instruct с одинаковым числом параметров, 494.03 миллиона, но разной степенью сжатия.

Тег модели Quantization level Размер на диске
qwen2.5:0.5b-instruct-q4_0 Q4_0 336 МБ
qwen2.5:0.5b-instruct-q8_0 Q8_0 506 МБ
qwen2.5:0.5b-instruct-fp16 F16 948 МБ

Разница между крайними точками почти трёхкратная при одинаковом числе параметров. Q4_0 хранит веса 4-битными числами и даёт наименьший размер ценой точности, F16 хранит их в исходной 16-битной точности и занимает почти втрое больше места, а Q8_0 лежит между ними как промежуточный вариант. Метаданные квантования, поле quantization_level, доступны через ollama.show() без похода в сеть, они лежат прямо в манифесте модели, а вот размер файла на диске это поле отдаёт только ollama.list(), что видно в коде демо ниже.

Modelfile-механизм из предыдущего раздела работает поверх любого из этих тегов, потому что он не трогает сами веса. В демо создание кастомной модели wiki-ollama-demo с системным промптом поверх тега q4_0 не требует повторной загрузки полного набора весов с диска, потому что операция навешивает только промпт и параметры генерации, а не копирует и не пересчитывает веса заново.

 

Сценарии использования и когда Ollama не подходит

Ollama закрывает три частых сценария, а именно локальную разработку и отладку промптов без счёта за токены облачного провайдера, прототипирование агентов с вызовом инструментов до переноса на прод-стек и работу с приватными данными, которые нельзя отправлять во внешний API. Тема вызова инструментов и агентных сценариев подробнее разобрана в курсе «ИИ-агенты для оптимизации бизнес-процессов», который прямо упоминает Ollama в своей программе.

Честное ограничение видно на цифрах из собственного прогона. Небольшая модель размером 0.5 миллиарда параметров игнорирует инструкцию про язык ответа. В демо-запуске Modelfile она ответила на вопрос про столицу Франции иероглифами вместо ожидаемого текста на русском, хотя системный промпт требовал отвечать одним словом без пояснений. Модель qwen2.5:7b размером побольше в одном из вызовов соскользнула с русского на английский прямо на стыке слова, что видно в реальном выводе в разделе «Практика». Это не баг демо-скрипта, а типичное поведение локальных моделей такого масштаба, и статья фиксирует его как есть, а не сглаживает. С учётом этого поведения границы применимости Ollama выглядят так.

  • Стоит применять. Локальная разработка, тестирование промптов и прототип агента с tool calling до переноса в прод-инфраструктуру.
  • Стоит применять. Работа с чувствительными данными, которые по требованиям безопасности не должны покидать контур компании.
  • Не подходит или избыточна. Production-сервис с множеством одновременных пользователей и требованием к суммарной пропускной способности GPU. Задачу пакетного обслуживания параллельных запросов решают специализированные inference-движки, а не однопоточный по своей сути локальный сервер.
  • Не подходит без оговорок. Сценарии, где нужна гарантированно предсказуемая формулировка ответа малой моделью. Квантование и малый размер модели снижают устойчивость к инструкциям про формат и язык ответа, что видно на примерах выше.

Граница между «стоит» и «не стоит» проходит по числу параллельных пользователей и по тому, насколько критична предсказуемая формулировка ответа. Более широкий разбор эксплуатации моделей в проде, включая переход от локального прототипа к production-обслуживанию, дан в материале о том, как LLMOps расширяет практики MLOps.

Разработка и внедрение ML-решений

Код курса
MLOPS
Ближайшая дата курса
9 ноября, 2026
Продолжительность
24 ак.часов
Стоимость обучения
66 000

 

Практика

По традиции весь код используемый в статье выкладываем на наш GitHub репозиторий

Ollama from airflow import DAG from airflow.operators.bash import BashOperator from datetime import datetime with DAG( dag_id="spark_submit_demo", start_date=datetime(2025, 1, 1), schedule="@daily", catchup=False ) as dag: run = BashOperator( task_id="run_job", bash_command="spark-submit app.py" ) GitHub code example Ollama

Первый файл, chat_tools.py, показывает три режима одного и того же эндпоинта /api/chat, а именно обычный вызов, потоковую генерацию и вызов инструмента с заглушкой функции получения погоды.

# ollama (python client) 0.6.2, сервер ollama 0.32.13, прогнано на стенде 2026-08-30
"""
Жизненный цикл запроса к Ollama через REST API (обёрнутый python-клиентом):
обычный вызов chat, потоковая генерация токен за токеном, вызов инструмента (tool calling).
Модель qwen2.5:7b уже загружена на стенде.
"""
import time

import ollama

MODEL = "qwen2.5:7b"


def demo_chat():
    # Один запрос-ответ: клиент шлёт POST /api/chat, сервер грузит модель в память
    # (если ещё не загружена) и возвращает готовый ответ целиком.
    t0 = time.time()
    response = ollama.chat(
        model=MODEL,
        messages=[{"role": "user", "content": "Сколько будет 17 умножить на 6? Ответь только числом."}],
    )
    elapsed = time.time() - t0
    print(f"[chat] {elapsed:.2f} с -> {response['message']['content'].strip()}")


def demo_stream():
    # stream=True переключает тот же эндпоинт на потоковую передачу: сервер отдаёт
    # NDJSON построчно, каждая строка - один сгенерированный фрагмент токенов.
    print("[stream] ", end="", flush=True)
    t0 = time.time()
    chunk_count = 0
    for chunk in ollama.chat(
        model=MODEL,
        messages=[{"role": "user", "content": "Объясни в одном предложении, что такое REST API."}],
        stream=True,
    ):
        print(chunk["message"]["content"], end="", flush=True)
        chunk_count += 1
    elapsed = time.time() - t0
    print(f"\n[stream] {chunk_count} фрагментов за {elapsed:.2f} с")


def get_weather(city: str) -> str:
    # Заглушка вместо реального похода в погодный API - интересен сам механизм
    # вызова инструмента, а не источник данных.
    fake_data = {"Москва": "-3°C, снег", "Дубай": "+34°C, ясно"}
    return fake_data.get(city, "нет данных")


def demo_tool_calling():
    # Модель не вызывает функцию сама - она возвращает structured tool_calls,
    # а выполнение и подстановку результата обратно в диалог делает клиентский код.
    tools = [
        {
            "type": "function",
            "function": {
                "name": "get_weather",
                "description": "Текущая погода в городе",
                "parameters": {
                    "type": "object",
                    "properties": {"city": {"type": "string", "description": "Название города"}},
                    "required": ["city"],
                },
            },
        }
    ]
    messages = [{"role": "user", "content": "Какая погода в Дубае?"}]
    response = ollama.chat(model=MODEL, messages=messages, tools=tools)
    tool_calls = response["message"].get("tool_calls") or []
    if not tool_calls:
        print("[tools] модель не запросила вызов инструмента:", response["message"]["content"])
        return

    call = tool_calls[0]
    args = call["function"]["arguments"]
    result = get_weather(args["city"])
    print(f"[tools] модель запросила get_weather({args}) -> {result}")

    # Результат инструмента возвращается модели отдельным сообщением с role="tool",
    # только после этого второго вызова получается связный ответ на языке пользователя.
    messages.append(response["message"])
    messages.append({"role": "tool", "content": result})
    final = ollama.chat(model=MODEL, messages=messages)
    print(f"[tools] финальный ответ -> {final['message']['content'].strip()}")


if __name__ == "__main__":
    demo_chat()
    demo_stream()
    demo_tool_calling()

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

[chat] 0.66 с -> 102
[stream] REST API - это методика разработки приложений, основанная на принципах выделения
различных функций в отдельные ресурсы и использование HTTP-запросов для их взаимодействия.
[stream] 49 фрагментов за 3.97 с
[tools] модель запросила get_weather({'city': 'Дубай'}) -> +34°C, ясно
[tools] финальный ответ -> В Дубае сейчас погода ясная с температурой +34°C. Будьте осторожны на улице и увлажняйте организмadequate hydration is important in such weather conditions.

Смешение языков посреди слова «организм/adequate» это не опечатка при вставке в статью, а дословный вывод модели qwen2.5:7b на этом конкретном прогоне.

Второй файл, modelfile_quantization.py, создаёт кастомную модель через ollama.create(), аналог Modelfile, поверх готового квантованного тега, а затем читает метаданные квантования у трёх тегов одной модели с разной степенью сжатия.

# ollama (python client) 0.6.2, сервер ollama 0.32.13, прогнано на стенде 2026-08-30
"""
Механизм Modelfile (кастомизация модели поверх готового GGUF-веса) и то, как Ollama
хранит и отдаёт метаданные квантования. Теги qwen2.5:0.5b-instruct-{q4_0,q8_0,fp16}
уже скачаны на стенде.
"""
import ollama

CUSTOM_MODEL = "wiki-ollama-demo"
BASE_MODEL = "qwen2.5:0.5b-instruct-q4_0"
QUANT_TAGS = [
    "qwen2.5:0.5b-instruct-q4_0",
    "qwen2.5:0.5b-instruct-q8_0",
    "qwen2.5:0.5b-instruct-fp16",
]


def demo_modelfile():
    # Modelfile не переобучает и не меняет веса - он навешивает system-промпт и
    # параметры генерации поверх уже скачанного GGUF-файла, поэтому create() занимает
    # секунды, а не время полной загрузки модели.
    for _ in ollama.create(
        model=CUSTOM_MODEL,
        from_=BASE_MODEL,
        system="Отвечай всегда одним словом, без пояснений.",
        parameters={"temperature": 0},
        stream=True,
    ):
        pass  # прогресс создания не нужен статье, важен факт готовности модели

    response = ollama.chat(
        model=CUSTOM_MODEL,
        messages=[{"role": "user", "content": "Столица Франции?"}],
    )
    print(f"[modelfile] кастомная модель '{CUSTOM_MODEL}' ответила: {response['message']['content'].strip()}")

    ollama.delete(CUSTOM_MODEL)
    print(f"[modelfile] '{CUSTOM_MODEL}' удалена, базовый тег {BASE_MODEL} не тронут")


def demo_quantization_metadata():
    # Один и тот же набор весов Qwen2.5 0.5B-instruct, три степени квантования GGUF.
    # ollama show отдаёт эти метаданные без похода в сеть - они лежат в манифесте модели.
    print("[quant] тег -> quantization_level | parameter_size | размер на диске")
    for tag in QUANT_TAGS:
        info = ollama.show(tag)
        details = info.details
        size_mb = _model_size_mb(tag)
        print(f"  {tag:<32} {details.quantization_level:<8} {details.parameter_size: str:
    # ollama.show() не отдаёт размер файла на диске - это поле есть только в ответе
    # /api/tags (то есть в ollama.list()), поэтому размер берётся оттуда отдельно.
    for m in ollama.list().models:
        if m.model == tag:
            return f"{m.size / 1024 / 1024:.0f}"
    return "?"


if __name__ == "__main__":
    demo_modelfile()
    demo_quantization_metadata()

Вывод этого файла подтверждает, что кастомизация через Modelfile не трогает базовый тег и что три степени квантования дают заметно разные размеры на диске при одинаковом числе параметров.

[modelfile] кастомная модель 'wiki-ollama-demo' ответила: 巴黎
[modelfile] 'wiki-ollama-demo' удалена, базовый тег qwen2.5:0.5b-instruct-q4_0 не тронут
[quant] тег -> quantization_level | parameter_size | размер на диске
  qwen2.5:0.5b-instruct-q4_0       Q4_0     494.03M    336 МБ
  qwen2.5:0.5b-instruct-q8_0       Q8_0     494.03M    506 МБ
  qwen2.5:0.5b-instruct-fp16       F16      494.03M    948 МБ

Ответ «巴黎» вместо ожидаемого «Париж» на прямой вопрос про столицу Франции при системном промпте «отвечай одним словом» это тот же эффект малой модели, что описан в разделе про сценарии применения выше, только зафиксированный на реальном коде, а не пересказанный.

 

Заключение

Ollama сводит запуск локальной LLM к паре команд, потому что берёт на себя загрузку GGUF-весов в память, REST API поверх них и Modelfile для лёгкой кастомизации без переобучения. Прогон на стенде показал обе стороны этого удобства. С одной стороны, один и тот же эндпоинт /api/chat одинаково легко отдаёт обычный ответ, поток и структурированный вызов инструмента, а квантование даёт предсказуемый компромисс между размером на диске и точностью модели. С другой стороны, локальные модели такого масштаба, особенно младшие теги вроде 0.5B, ведут себя менее предсказуемо, чем крупные облачные модели, и это стоит закладывать в план перед тем, как строить на них прод-сценарий, а не выяснять постфактум.

 

Референсные ссылки

  • docs.ollama.com/llms.txt, карта официальной документации Ollama с разделами CLI, API, Modelfile, hardware support и context length.
  • docs.ollama.com/import, официальное описание формата GGUF и импорта моделей в Ollama.
  • github.com/ollama/ollama/releases, официальные release notes проекта, номер актуальной версии и даты выпусков.
  • docs.ollama.com, корень официальной документации Ollama.