Ollama запускает модель локально, а официальная библиотека ollama даёт Python привычную функцию chat без платного API-ключа. Мы соберём терминальный чат с потоковым ответом, короткой историей и понятной диагностикой. Запросы пойдут в локальный сервис Ollama, а модель можно заменить одной переменной.
Локальный чат удобен для обучения и текста, который не нужно отправлять стороннему API. Но модель занимает память, первый запуск может быть медленным, а качество зависит от размера. Начните с компактного тега, проверьте ollama run и только затем добавляйте Python. Так проще отделить установку, модель и свой код.
Ollama хранит локальный тег и обслуживает запросы на компьютере.
Библиотека ollama передаёт messages локальному сервису.
Список ролей даёт модели контекст нескольких последних реплик.
Из каких частей состоит локальный чат
Ollama состоит из локального сервиса и моделей, загруженных отдельными тегами. Команда ollama pull получает файлы модели, ollama list показывает доступные теги, а ollama ps показывает, что сейчас загружено в память. Python-пакет является клиентом: он не содержит веса модели и не запускает магию внутри одного процесса. Функция chat отправляет список messages сервису Ollama. При stream=True ответ приходит небольшими частями, поэтому пользователь видит текст сразу, а программа параллельно собирает полную строку для истории.
| Слой | Команда или объект | Как проверить |
|---|---|---|
| Программа Ollama | ollama --version | Команда находится в PATH |
| Локальная модель | ollama pull gemma3:1b | Тег виден в ollama list |
| Сервис | ollama run gemma3:1b | Модель отвечает в терминале |
| Python-клиент | uv add ollama | Импорт проходит без ошибки |
| История | list[dict] с ролями | Второй ответ помнит первый вопрос |
Не начинайте диагностику с переустановки Python. Сначала добейтесь ответа через ollama run. Если он есть, сервис и модель работают, а искать ошибку нужно в имени тега, окружении проекта или структуре messages.

Python является клиентом локального сервиса. Полный ответ возвращается в историю
Пишем Python-цикл с потоковым ответом
Установите Ollama с официального сайта, выполните ollama pull gemma3:1b и проверьте ollama run gemma3:1b. Затем создайте проект: uv init local-chat и uv add ollama. Код ниже читает имя модели из переменной OLLAMA_MODEL, поэтому её можно заменить без правки файла. Команды /clear и /exit управляют историей. После каждого ответа в messages остаётся максимум шесть пар, чтобы учебный чат не разрастался бесконечно.
import os
from ollama import ResponseError, chat
MODEL = os.getenv("OLLAMA_MODEL", "gemma3:1b")
MAX_MESSAGES = 12
messages = [{
"role": "system",
"content": "Ты учебный помощник. Отвечай кратко и показывай один пример.",
}]
print(f"Локальный чат: {MODEL}")
print("Команды: /clear, /exit")
while True:
prompt = input("\nВы: ").strip()
if not prompt:
continue
if prompt == "/exit":
break
if prompt == "/clear":
messages = messages[:1]
print("История очищена")
continue
messages.append({"role": "user", "content": prompt})
chunks: list[str] = []
print("Бот: ", end="", flush=True)
try:
stream = chat(model=MODEL, messages=messages, stream=True)
for part in stream:
text = part.message.content or ""
print(text, end="", flush=True)
chunks.append(text)
print()
except ConnectionError:
print("\nOllama не отвечает. Запустите приложение или сервис.")
messages.pop()
continue
except ResponseError as error:
print(f"\nОшибка Ollama: {error}")
messages.pop()
continue
answer = "".join(chunks)
messages.append({"role": "assistant", "content": answer})
messages = messages[:1] + messages[-MAX_MESSAGES:]- Текст появляется частями, а не после ожидания всего ответа.
- Второй вопрос может ссылаться на предыдущую реплику благодаря messages.
- Команда /clear удаляет диалог, но сохраняет системную инструкцию.
- Если сервис не запущен или тег модели неверен, чат показывает понятное сообщение.

Смысл одинаков, ощущение разное. В истории оба режима дают одно сообщение assistant
Как messages превращается в продолжение разговора
Каждое сообщение имеет роль. system задаёт постоянную инструкцию, user хранит вопросы, assistant хранит полные ответы. Ollama читает весь переданный список при каждом новом запросе. Потоковые chunks нужны только для интерфейса: в историю добавляется одна склеенная строка, иначе диалог превратится в сотни мелких сообщений. Ограничение MAX_MESSAGES оставляет системное сообщение и последние реплики. Это простая стратегия окна, а не долгосрочная память. После /clear модель ничего не знает о предыдущем диалоге, потому что список был очищен.
| Роль или режим | Назначение | Типичная ошибка |
|---|---|---|
| system | Правила помощника | Добавляется заново после каждого ответа |
| user | Текущий вопрос | Не удаляется после сбоя запроса |
| assistant | Полный ответ | В историю кладут каждый chunk отдельно |
| stream=True | Показывает ответ постепенно | Chunks печатают, но не склеивают |
| MAX_MESSAGES | Ограничивает рост контекста | Случайно удаляет system |
На скорость влияют размер модели, RAM или VRAM, история и длина ответа. Сравнивайте одинаковый промпт после прогрева и смотрите ollama ps. Если система использует диск, выберите меньшую модель или сократите контекст. ConnectionError указывает на сервис, ResponseError на модель или запрос, ошибка импорта на Python-окружение.
Проверяем скорость, память и ошибки соединения
Запустите чат и задайте вопрос про список Python. Следом напишите «покажи ещё один пример» и убедитесь, что модель понимает ссылку. Выполните /clear и повторите второй вопрос: теперь контекста быть не должно. Остановите сервис Ollama и проверьте сообщение ConnectionError. Затем задайте OLLAMA_MODEL на отсутствующий тег и посмотрите ResponseError. Наконец, верните рабочую модель, задайте пять пар вопросов и выведите len(messages), чтобы увидеть работу ограничения истории.
- Проверьте модель сначала через
ollama run gemma3:1b. - Запустите Python-чат и задайте два связанных вопроса.
- Очистите историю и убедитесь, что ссылка на старый вопрос потерялась.
- Остановите Ollama и получите контролируемое сообщение о соединении.
- Укажите неверный тег модели и отделите ResponseError от ConnectionError.
- Смените MAX_MESSAGES на 4 и проследите длину списка после нескольких ответов.
- Модель отвечает через Python без API-ключа.
- Поток собирается в один assistant message.
- История ограничена и очищается командой.
- Ошибки сервиса и модели различаются в выводе.

Каждый сбой проверяется на своём слое. Не переустанавливайте всё сразу
Превращаем демо в аккуратный локальный инструмент
Чат можно перенести в Streamlit, добавить выбор модели или сохранить JSON. Улучшайте по одному. Для документов показывайте фрагменты контекста, для tools журналируйте имя и аргументы. Не храните общую messages для нескольких пользователей, каждому нужна сессия. Локальная модель тоже ошибается, поэтому факты, команды и код проверяйте.
Как изучить тему в Кодике
В Кодике начните с цикла while, списков и словарей Python. Затем научитесь ловить конкретные исключения и читать переменные окружения. Только после этого подключайте Ollama. Тогда messages будет обычным списком словарей, streaming станет циклом for, а управление командами окажется знакомым набором if.
| Шаг | Что изучить | Мини-проект |
|---|---|---|
| 1 | while, input и команды | Эхо-чат с /clear и /exit |
| 2 | Списки и словари | Хранить роли и тексты без модели |
| 3 | Исключения | Различать два вида сбоя |
| 4 | Итераторы и поток | Склеить chunks в строку |
| 5 | Ollama Python | Получить связанный диалог |
В тренажёре Кодика сначала реализуйте команды и обрезку истории на фиктивных строках. Затем замените генератор ответов одним вызовом chat. Такой порядок отделяет Python-логику от требований модели и сильно упрощает отладку.
Сначала отделите установку сервиса и модели от собственного кода.
Печатайте части сразу, но храните один собранный assistant answer.
Оставляйте системное сообщение и ограниченное число последних реплик.
Различайте недоступный сервис, ошибку модели и проблему окружения Python.
Что получится в итоге

Терминальный чат показывает ответ по мере генерации, помнит несколько последних реплик и остаётся управляемым при сбое сервиса или смене модели.
Нужен ли платный API-ключ для локального Ollama?
Нет, если используется локальный сервис и локально загруженный тег модели.
Почему chunks нужно склеивать?
Поток удобен для показа, но история должна содержать один полный ответ ассистента.
Является ли messages постоянной памятью?
Нет. Это контекст конкретного запуска. После очистки или завершения программы список исчезает, если вы его отдельно не сохранили.
Как понять, что проект действительно работает?
Проверьте основной сценарий, ошибочный ввод, повторный запуск и один граничный случай. Затем объясните вслух, где появляются данные, кто принимает решение и где хранится состояние.
Можно ли начать с готового кода из статьи?
Да. После первого запуска измените один параметр, добавьте одну проверку и повторите проект без подсказки. Так пример превращается в собственный навык.
Циклы, списки и исключения закрепите в курсе Python. Установку и выбор модели сверяйте со статьями про запуск Ollama и про выбор модели по памяти.
Когда терминальный цикл станет понятным, соберите интерфейс из статьи про Streamlit-приложение. В Кодике сначала воспроизведите работу messages на обычных строках, затем подключите модель.