RU ▾
Получить API-ключ

Ollama API в Python и хостинг-альтернатива

API Ollama на Python занимает около десяти строк, и та же структура кода работает и с хостинг-эндпоинтом. В этой статье показаны оба варианта и объясняется, когда какой выбрать.

Обновлено

Ключевые моменты

  • Ollama слушает порт 11434 и предлагает нативный API, а также OpenAI-совместимый эндпоинт /v1.
  • Пакет ollama, обычный requests и OpenAI SDK работают; OpenAI SDK — самый переносимый.
  • Переход на хостинг API означает изменение базового URL, ключа и имени модели.
  • Локальный вариант лучше для офлайн-работы и фиксированного оборудования; хостинг проще, если у вас нет GPU.
Локальный компьютер, соединённый светящимся кабелем с облачным сервером, символизирующий локальные и облачные LLM API

Краткая версия

Если вы ищете ollama api python, вам обычно нужно одно из трёх: вызвать модель, работающую на вашей собственной машине, потоково передавать токены из неё или заставить тот же скрипт работать где-то ещё. Ollama даёт все три возможности. Она запускает локальный сервер, по умолчанию по адресу http://localhost:11434, и вы общаетесь с ним через пакет ollama для Python, через обычный HTTP или с любым клиентом OpenAI, настроенным на путь /v1.

Подвох в том, что модель должна работать на вашем оборудовании. Ноутбук без хорошего GPU будет медленным с большими моделями, а сервер без него — не лучший выбор. В этом случае OpenAI-совместимый хостинг API — более простой путь, и поскольку формат запросов одинаков, переключение займёт три строки конфигурации. Оба варианта рассмотрены ниже с кодом, который можно скопировать.

Вызов локальной модели пакетом ollama

Установите Ollama, загрузите модель и убедитесь, что сервер запущен. Затем установите Python-клиент:

pip install ollama
ollama pull llama3.2

Базовый вызов чата выглядит так. Имя модели — то, которое вы загрузили через pull; llama3.2 — лишь пример.

import ollama

response = ollama.chat(
    model="llama3.2",
    messages=[{"role": "user", "content": "Explain DNS in two sentences."}],
)
print(response["message"]["content"])

Потоковая передача

Передайте stream=True, и вы получите итератор чанков вместо одного ответа. Каждый чанк содержит часть ответа в message.content.

import ollama

stream = ollama.chat(
    model="llama3.2",
    messages=[{"role": "user", "content": "Write a haiku about servers."}],
    stream=True,
)
for chunk in stream:
    print(chunk["message"]["content"], end="", flush=True)
print()

Указание клиента на другой компьютер

Если Ollama работает на другом хосте, создайте клиент с явным адресом, например ollama.Client(host="http://192.168.1.20:11434"). По умолчанию сервер слушает только локальную машину, поэтому для удалённого доступа нужно явное изменение настроек на стороне сервера. Не выставляйте его в публичный интернет без прокси и аутентификации, так как нативный API не имеет собственной проверки ключа.

Обычный HTTP с requests

Пакет не нужен вообще. Нативный эндпоинт чата — POST /api/chat. Потоковая передача включена по умолчанию, и поток состоит из JSON-строк, разделённых новой строкой, а не SSE. Установите "stream": false, если хотите получить один объект.

import requests

r = requests.post(
    "http://localhost:11434/api/chat",
    json={
        "model": "llama3.2",
        "messages": [{"role": "user", "content": "Name three HTTP status codes."}],
        "stream": False,
    },
    timeout=120,
)
r.raise_for_status()
print(r.json()["message"]["content"])

Установите большой таймаут. Первый запрос после pull должен загрузить модель в память, и это может занять гораздо больше времени, чем последующие запросы.

Чтение потока вручную занимает всего несколько строк. Вызовите requests.post(..., stream=True), перебирайте r.iter_lines(), пропускайте пустые строки и запускайте json.loads на каждой. Каждый объект содержит небольшую часть ответа, а последний имеет "done": true. Это удобно в минимальном контейнере, где вы не хотите устанавливать ещё один пакет, и это ясно показывает, что делает библиотека. Размещённый API передаёт поток иначе: строками SSE, начинающимися с data:, что ещё одна причина позволить OpenAI SDK разбирать поток за вас в переносимом коде.

Использование OpenAI SDK с Ollama

Ollama также предоставляет OpenAI-совместимый эндпоинт в /v1. Это означает, что работает официальный пакет openai, а также большинство программ, позволяющих задать пользовательский базовый URL. Ключ требуется SDK, но игнорируется локальным Ollama, поэтому подойдёт любая строка.

from openai import OpenAI

client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
resp = client.chat.completions.create(
    model="llama3.2",
    messages=[{"role": "user", "content": "Give me a one-line summary of TCP."}],
)
print(resp.choices[0].message.content)

Это самая полезная форма, так как она разделяет ваш код и сервер. Одна и та же функция может работать с локальной моделью сегодня и с чем-то другим завтра, об этом следующий раздел.

Тот же код для хостинг-API

Здесь размещённый вариант — это API, совместимый с OpenAI, с одной моделью uncensored, предоставляемый независимым провайдером и настроенный на ответы без отказов по контенту для законного использования взрослыми. Это только текст. Базовый URL — https://api.ollamaapi.cc/v1, а аутентификация осуществляется с помощью Bearer-ключа со страницы API-ключ.

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

import os
from openai import OpenAI

client = OpenAI(
    base_url=os.getenv("LLM_BASE_URL", "https://api.ollamaapi.cc/v1"),
    api_key=os.getenv("LLM_API_KEY", "YOUR_API_KEY"),
)
MODEL = os.getenv("LLM_MODEL", "uncensored")

resp = client.chat.completions.create(
    model=MODEL,
    messages=[
        {"role": "system", "content": "You are a concise assistant."},
        {"role": "user", "content": "List four uses of a message queue."},
    ],
    temperature=0.7,
)
print(resp.choices[0].message.content)

Для локальных запусков установите LLM_BASE_URL=http://localhost:11434/v1, LLM_API_KEY=ollama и LLM_MODEL=llama3.2. В быстром старте представлена та же настройка для curl и Node.

Потоковая передача, JSON-режим и инструменты на стороне хостинга

Хостинг-эндпоинт поддерживает потоковую передачу через SSE, JSON-режим, вызов функций и стандартные параметры сэмплирования (temperature, top_p, stop, seed и штрафы). Потоковая передача с SDK — тот же цикл, который вы бы написали для любого OpenAI-совместимого сервера:

stream = client.chat.completions.create(
    model="uncensored",
    messages=[{"role": "user", "content": "Tell a two-paragraph story about a lighthouse."}],
    stream=True,
    stream_options={"include_usage": True},
)
for chunk in stream:
    if chunk.choices and chunk.choices[0].delta.content:
        print(chunk.choices[0].delta.content, end="", flush=True)

Для структурированного вывода установите response_format={"type": "json_object"} и укажите в промпте, что хотите JSON. Всегда разбирайте ответ внутри блока try; модель всё ещё может вернуть то, чего вы не ожидали.

Одно отличие от локального использования важно в коде: лимиты. Полный ключ позволяет 8 параллельных запросов и 300 запросов в минуту, а потоковый запрос удерживает слот до конца потока. Если вы распараллеливаете запросы потоками, ограничьте пул значением 8 и выполняйте повторную попытку при HTTP 429, используя заголовок Retry-After, если он присутствует.

Продолжение разговора

Ни локальный, ни хостинг-эндпоинт чата не запоминают ничего между вызовами. Сервер видит только сообщения, которые вы отправляете, поэтому чат-бот — это список, к которому вы добавляете сообщения и отправляете снова. Паттерн идентичен для обеих целей, что является ещё одной причиной оставить OpenAI-совместимый клиент по умолчанию.

history = [{"role": "system", "content": "You are a helpful assistant."}]

def ask(text):
    history.append({"role": "user", "content": text})
    resp = client.chat.completions.create(model=MODEL, messages=history)
    answer = resp.choices[0].message.content
    history.append({"role": "assistant", "content": answer})
    return answer

print(ask("Pick a name for a hiking app."))
print(ask("Give me a tagline for it."))

Два практических замечания. Во-первых, локальные модели имеют длину контекста, которую вы задаёте, и которую должна удерживать память; если история диалога превышает этот лимит, старые реплики обрезаются или вызов завершается ошибкой в зависимости от настроек. Хостинговая модель поддерживает контекстное окно на 100 000 токенов, включая ответ модели, что гораздо больше, чем нужно большинству чатов, но длинные истории всё равно потребляют входные токены при каждом шаге. Во-вторых, когда история становится длинной, резюмируйте самые старые реплики в одно короткое сообщение, а не отправляйте их все заново. Это поддерживает стабильные задержки и стоимость на обеих платформах.

Вежливые повторные попытки

На хостинговом API временная перегрузка возвращает HTTP 429 с заголовком Retry-After: 5. Небольшая обёртка обрабатывает это:

import time
from openai import RateLimitError

def chat_with_retry(messages, tries=4):
    for attempt in range(tries):
        try:
            return client.chat.completions.create(model=MODEL, messages=messages)
        except RateLimitError:
            time.sleep(5 * (attempt + 1))
    raise RuntimeError("still rate limited")

Локальный Ollama не ограничивает вас, но он ставит запросы в очередь, когда модель занята, поэтому та же обёртка не повредит там.

Локальный или хостинг: как выбрать

Нет однозначно лучшего варианта. Используйте пункты ниже в качестве контрольного списка.

  • Выберите локальный Ollama, если вам нужно работать автономно, если данные никогда не должны покидать устройство, если вы уже владеете подходящим GPU или если вы хотите быстро попробовать множество различных открытых моделей.
  • Выберите хостинг-API, если у вас нет GPU, если вы работаете на маленьком VPS или в CI, если несколько людей или сервисов делят один бэкенд, или если вам нужно длинное контекстное окно без самостоятельного подбора памяти. Хостинговая модель поддерживает до 100 000 токенов промпта плюс ответ модели.
  • Используйте оба варианта во время разработки: итерируйте локально, а затем направьте продакшн-окружение на размещённый URL через переменные окружения.

Хостинг оплачивается за токен, по $0,15 за 1M входных токенов и $0,50 за 1M выходных токенов из предоплаченного баланса. На странице тарифов указаны суммы пополнения, а новые аккаунты могут получить $0,50 пробного баланса в один клик, без карты. Промпты не используются для обучения.

Ошибки, с которыми вы столкнётесь

СимптомВероятная причинаИсправление
Отказ в соединении на порту 11434Сервер Ollama не запущенЗапустите приложение или выполните ollama serve
Модель не найденаМодель никогда не была получена (pull), либо в имени допущена опечаткаВыполните ollama list, затем ollama pull имя, которое вы используете
Первый вызов завершается таймаутомМодель всё ещё загружаетсяУвеличьте тайм-аут или отправьте запрос для прогрева
Ошибка аутентификации в хостинговом APIОтсутствует или неверен Bearer-ключПроверьте LLM_API_KEY и базовый URL
HTTP 429 с кодом concurrencyБолее 8 одновременных запросов (2 для пробного ключа)Снизьте количество воркеров
HTTP 429 с кодом rate_limitedПревышен лимит запросов в минутуПодождите и повторите попытку

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

Вопросы и ответы

Каков адрес Ollama API по умолчанию?

Локальный сервер Ollama слушает на http://localhost:11434. Нативные эндпоинты находятся по пути /api, например /api/chat, а эндпоинт в стиле OpenAI находится по пути /v1.

Могу ли я использовать Python SDK от OpenAI с Ollama?

Да. Установите base_url в http://localhost:11434/v1 и передайте любую строку в качестве API-ключа. SDK затем отправляет стандартные запросы chat completions к вашей локальной модели.

Как перейти с Ollama на хостинговый API?

Измените базовый URL, ключ и имя модели. Если ваш код считывает их из переменных окружения, изменения кода не потребуется.

Работает ли хостинговый API без GPU на моей стороне?

Да. Модель работает у провайдера, поэтому вашему скрипту требуется только подключение к интернету и Bearer-ключ. Вы платите за токены из предоплаченного баланса.

Ключ — в одной форме от вас

Создайте аккаунт, скопируйте ключ, измените базовый URL. Это вся настройка.

Получить API-ключ