Настройка таймаутов и логирования Ollama + Continue для генерации кода в 2026 | AiManual
AiManual Logo Ai / Manual.
26 Янв 2026 Гайд

Когда Ollama зависает на полуслове: как настроить таймауты и логирование для генерации сложного кода

Практическое руководство по настройке таймаутов, логированию ошибок и оптимизации Ollama с Continue для генерации сложного кода на локальных LLM. Решаем проблем

Проблема: ваш код-ассистент засыпает на сложных задачах

Вы пишете промпт для генерации сложного модуля на Python. Qwen3-Coder через Ollama думает. Думает. Думает еще. Проходит 30 секунд, минута, две. Continue в VSCodium показывает вечный спиннер. В логах - тишина. Вы не знаете, упал ли запрос, зависла ли модель, или она просто медленно генерирует 500 строк кода. Знакомо?

Это классическая проблема локальных LLM для кодирования: отсутствие видимости и контроля над выполнением. В отличие от облачных API, где таймауты и логирование - стандартная функциональность, в локальной связке Ollama + Continue эти настройки спрятаны или вообще отсутствуют.

Ключевой момент: когда модель Qwen3-Coder или аналогичная пытается сгенерировать сложный код, она может уйти в "размышления" на несколько минут. Без правильных таймаутов вы не отличите это от зависания.

Почему это происходит? Анатомия зависания

Три слоя, где может сломаться процесс:

  1. Уровень модели: Qwen3-Coder 72B (актуальная версия на 26.01.2026) требует значительных ресурсов. При генерации сложного кода она может "зациклиться" на определенных конструкциях.
  2. Уровень Ollama: По умолчанию у Ollama нет жестких таймаутов на генерацию. Модель может генерировать до бесконечности (или пока не кончится память).
  3. Уровень Continue: Расширение имеет собственные настройки таймаутов, которые могут конфликтовать с Ollama.

Я видел случаи, где разработчики часами ждали ответа от локальной модели, не понимая, что она уже давно "сошла с рельсов". Как в той статье про длинные промпты, где модели теряют контекст и начинают генерировать бессмыслицу.

Решение: настраиваемый стек мониторинга и контроля

Мы построим трехслойную систему:

  • Таймауты на уровне Ollama API
  • Детальное логирование всех запросов и ответов
  • Настройки Continue для адекватного поведения при таймаутах
💡
Важно: перед настройкой убедитесь, что у вас установлены актуальные версии на 26.01.2026. Ollama 0.5.0+ и Continue 0.3.0+ имеют улучшенную поддержку таймаутов.

1 Настраиваем Ollama: таймауты и логирование

Ollama работает как сервер с REST API. Нам нужно настроить его для контроля времени выполнения.

Запуск Ollama с параметрами таймаута

Вот как НЕ надо делать:

# Старый способ - без контроля
ollama serve
ollama run qwen2.5-coder:14b

Проблема: модель может генерировать бесконечно. Нет логов, нет возможности прервать кроме как kill-сигналом.

Правильный способ с системой логирования:

# Создаем директорию для логов
mkdir -p ~/.ollama/logs

# Запускаем Ollama сервер с логированием и переменными окружения
OLLAMA_DEBUG=1 OLLAMA_LOG_LEVEL=debug \
OLLAMA_NUM_PARALLEL=1 \
ollama serve > ~/.ollama/logs/server_$(date +%Y%m%d_%H%M%S).log 2>&1 &

# В отдельном терминале запускаем модель с ограничениями
ollama run qwen2.5-coder:14b \
  --verbose \
  --timeout 120 \
  --num-predict 2048

Ключевые параметры: --timeout 120 устанавливает максимальное время генерации в секундах. --num-predict 2048 ограничивает максимальное количество токенов в ответе. Это предотвращает бесконечную генерацию.

Конфигурационный файл Ollama

Для постоянных настроек создайте конфигурационный файл:

# ~/.ollama/config.yaml
# Актуальный формат на 26.01.2026

server:
  host: "127.0.0.1"
  port: 11434
  timeout: 300  # Таймаут сервера в секундах
  
logging:
  level: "info"
  format: "json"
  output: "/home/user/.ollama/logs/ollama.json"
  rotation:
    max_size: "100MB"
    max_backups: 5

models:
  qwen2.5-coder:14b:
    parameters:
      temperature: 0.2
      top_p: 0.95
      num_predict: 2048
      timeout: 120
    
  llama3.2-coder:8b:
    parameters:
      temperature: 0.3
      timeout: 90

Этот конфиг дает нам структурированные JSON-логи с ротацией и индивидуальные настройки для каждой модели.

2 Настройка Continue: клиентские таймауты и обработка ошибок

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

Конфигурация Continue для VSCodium/VSCode

Откройте настройки Continue (файл ~/.continue/config.json или в workspace):

{
  "models": [
    {
      "title": "Qwen2.5 Coder Local",
      "provider": "ollama",
      "model": "qwen2.5-coder:14b",
      "apiBase": "http://localhost:11434",
      "contextLength": 16384,
      "timeout": 150000, // 150 секунд в миллисекундах
      "requestOptions": {
        "timeout": 150000,
        "maxRetries": 2,
        "retryDelay": 3000
      },
      "completionOptions": {
        "temperature": 0.2,
        "topP": 0.95,
        "maxTokens": 2048
      }
    }
  ],
  "tabAutocompleteModel": {
    "title": "Qwen2.5 Coder Autocomplete",
    "provider": "ollama",
    "model": "qwen2.5-coder:7b", // Меньшая модель для автодополнения
    "timeout": 30000 // 30 секунд для автодополнения
  },
  "logging": {
    "enabled": true,
    "level": "debug",
    "directory": "/home/user/.continue/logs",
    "maxFiles": 10
  }
}

Обратите внимание на ключевые моменты:

  • "timeout": 150000 - таймаут в миллисекундах (150 секунд)
  • "maxRetries": 2 - повторные попытки при таймаутах
  • Отдельная конфигурация для автодополнения с меньшим таймаутом
  • Встроенное логирование Continue

Важно: таймаут в Continue должен быть НЕМНОГО больше, чем таймаут в Ollama. Если Ollama настроен на 120 секунд, а Continue - на 100, вы получите таймаут клиента до того, как сервер вернет ошибку.

3 Мониторинг и анализ логов

Настроили таймауты? Отлично. Теперь нужно понять, что происходит при срабатывании таймаута.

Скрипт для мониторинга логов в реальном времени

#!/usr/bin/env python3
# monitor_ollama.py
# Актуальный код для мониторинга на 26.01.2026

import json
import time
from pathlib import Path
from datetime import datetime
import threading
from collections import defaultdict

class OllamaMonitor:
    def __init__(self, log_dir="~/.ollama/logs"):
        self.log_dir = Path(log_dir).expanduser()
        self.timeout_threshold = 30  # Считаем проблемой запросы дольше 30 секунд
        self.stats = defaultdict(list)
        
    def tail_logs(self):
        """Отслеживаем новые записи в логах Ollama"""
        log_files = sorted(self.log_dir.glob("*.log"), 
                          key=lambda x: x.stat().st_mtime, 
                          reverse=True)
        
        if not log_files:
            print("Логи не найдены. Запущен ли Ollama с логированием?")
            return
            
        current_file = log_files[0]
        print(f"Мониторим файл: {current_file}")
        
        # Простая реализация tail -f
        with open(current_file, 'r') as f:
            f.seek(0, 2)  # Переходим в конец файла
            
            while True:
                line = f.readline()
                if not line:
                    time.sleep(0.1)
                    continue
                    
                self.analyze_log_line(line)
    
    def analyze_log_line(self, line: str):
        """Анализируем строку лога на предмет проблем"""
        try:
            if line.strip():
                # Ollama может писать как JSON, так и plain text
                if line.startswith('{'):
                    log_entry = json.loads(line)
                    self.process_json_log(log_entry)
                else:
                    self.process_text_log(line)
        except json.JSONDecodeError:
            self.process_text_log(line)
    
    def process_json_log(self, entry: dict):
        """Обрабатываем структурированные логи"""
        level = entry.get("level", "info").lower()
        msg = entry.get("msg", "")
        duration = entry.get("duration_ms", 0) / 1000  # в секунды
        
        if level == "error":
            print(f"[ERROR] {msg}")
            self.stats["errors"].append({
                "time": datetime.now().isoformat(),
                "message": msg
            })
        
        if "generate" in msg.lower() and duration > self.timeout_threshold:
            print(f"[WARNING] Долгий запрос: {duration:.1f}с - {msg}")
            self.stats["slow_requests"].append({
                "time": datetime.now().isoformat(),
                "duration": duration,
                "message": msg
            })
        
        if "timeout" in msg.lower():
            print(f"[TIMEOUT] Обнаружен таймаут: {msg}")
            self.stats["timeouts"].append({
                "time": datetime.now().isoformat(),
                "message": msg
            })
    
    def process_text_log(self, line: str):
        """Обрабатываем текстовые логи"""
        if "timeout" in line.lower():
            print(f"[TIMEOUT] {line.strip()}")
        elif "error" in line.lower():
            print(f"[ERROR] {line.strip()}")
        
    def print_stats(self):
        """Печатаем статистику"""
        print("\n" + "="*50)
        print("СТАТИСТИКА МОНИТОРИНГА OLLAMA")
        print("="*50)
        
        for stat_type, entries in self.stats.items():
            print(f"\n{stat_type.upper()}: {len(entries)} событий")
            if entries:
                # Показываем последние 3 события
                for entry in entries[-3:]:
                    if "duration" in entry:
                        print(f"  - {entry['time']}: {entry['duration']:.1f}с")
                    else:
                        print(f"  - {entry['time']}: {entry['message'][:100]}...")

if __name__ == "__main__":
    monitor = OllamaMonitor()
    
    # Запускаем мониторинг в отдельном потоке
    monitor_thread = threading.Thread(target=monitor.tail_logs, daemon=True)
    monitor_thread.start()
    
    # Периодически выводим статистику
    try:
        while True:
            time.sleep(60)  # Каждую минуту
            monitor.print_stats()
    except KeyboardInterrupt:
        print("\nЗавершение мониторинга...")
        monitor.print_stats()

Этот скрипт дает реальное понимание того, что происходит с вашей локальной LLM. Вы увидите:

  • Какие запросы вызывают таймауты
  • Среднее время генерации
  • Паттерны проблемных промптов

Продвинутые техники: когда базовых таймаутов недостаточно

Динамические таймауты на основе сложности промпта

Фиксированные таймауты - это хорошо, но не идеально. Простой промпт "напиши функцию hello world" не должен ждать 120 секунд. Сложный промпт с архитектурным описанием - должен.

Решение: middleware-прокси между Continue и Ollama:

# timeout_proxy.py - простой прокси с динамическими таймаутами
from flask import Flask, request, jsonify
import requests
import time
import re

app = Flask(__name__)
OLLAMA_URL = "http://localhost:11434/api/generate"

# Эвристики для определения сложности
COMPLEXITY_PATTERNS = [
    (r'архитектур[а-я]*|микросервис[а-я]*|сложн[а-я]*', 180),  # 3 минуты
    (r'полный|весь|целый|систем[а-я]*', 120),  # 2 минуты
    (r'функци[я-я]*|метод[а-я]*|класс[а-я]*', 60),  # 1 минута
    (r'пример|простой|базов[а-я]*', 30),  # 30 секунд
]

def estimate_timeout(prompt: str) -> int:
    """Оцениваем необходимый таймаут на основе промпта"""
    prompt_lower = prompt.lower()
    
    # Базовая эвристика: длинный промпт = больше времени
    word_count = len(prompt_lower.split())
    base_timeout = min(word_count // 10 * 10, 300)  # Макс 5 минут
    
    # Корректировка по ключевым словам
    for pattern, added_time in COMPLEXITY_PATTERNS:
        if re.search(pattern, prompt_lower):
            base_timeout = max(base_timeout, added_time)
            
    return min(base_timeout, 300)  # Ограничиваем 5 минутами

@app.route('/api/generate', methods=['POST'])
def proxy_generate():
    data = request.json
    prompt = data.get('prompt', '')
    
    # Динамический таймаут
    dynamic_timeout = estimate_timeout(prompt)
    
    print(f"Промпт: {prompt[:100]}...")
    print(f"Оцененный таймаут: {dynamic_timeout}с")
    
    # Модифицируем запрос к Ollama
    ollama_data = data.copy()
    ollama_data['options'] = ollama_data.get('options', {})
    ollama_data['options']['timeout'] = dynamic_timeout * 1000  # в миллисекундах
    
    # Проксируем с нашим таймаутом
    try:
        response = requests.post(
            OLLAMA_URL, 
            json=ollama_data,
            timeout=dynamic_timeout + 5  # Немного больше, чем у Ollama
        )
        return jsonify(response.json())
    except requests.exceptions.Timeout:
        return jsonify({
            "error": f"Таймаут после {dynamic_timeout} секунд",
            "prompt_preview": prompt[:200]
        }), 408

if __name__ == '__main__':
    app.run(port=11435)  # Запускаем на другом порту

Теперь настройте Continue на использование этого прокси:

// В конфиге Continue
{
  "models": [
    {
      "title": "Qwen2.5 Coder через прокси",
      "provider": "ollama",
      "model": "qwen2.5-coder:14b",
      "apiBase": "http://localhost:11435", // Наш прокси!
      "timeout": 310000 // 310 секунд (5 минут + запас)
    }
  ]
}

Типичные ошибки и как их избежать

Ошибка Причина Решение
Continue показывает "Request timeout" через 30 секунд Таймаут Continue меньше таймаута Ollama Увеличить timeout в config.json Continue
Модель генерирует бесконечно Нет ограничения num_predict Добавить --num-predict 2048 к запуску модели
Логи не пишутся OLLAMA_DEBUG не установлен Запускать Ollama с переменными окружения
Автодополнение работает медленно Используется большая модель Настроить отдельную модель для tabAutocompleteModel

Когда таймауты - это симптом, а не проблема

Иногда постоянные таймауты указывают на более глубокие проблемы:

  1. Слишком сложные промпты: Если вы просите "написать всю систему управления складом", даже Qwen2.5-Coder 72B будет страдать. Разбивайте задачи. Как в статье про неосознанный вайб-кодинг - ИИ не заменяет архитектурное мышление.
  2. Проблемы с аппаратным обеспечением: RTX 5090 - это мощно, но если у вас всего 16GB VRAM для 72B модели в 4-битном квантовании, она будет работать на пределе. Мониторьте использование памяти.
  3. Конфликтующие расширения: Другие AI-расширения в VSCodium могут конфликтовать с Continue. Проверьте, нет ли у вас установленного LMStudio модифицированного VSCode или других инструментов.

Мой совет: начните с агрессивных таймаутов (30-60 секунд) и увеличивайте их только для действительно сложных задач. Если модель регулярно не укладывается в 60 секунд - возможно, вам нужна другая модель или подход к промптингу.

💡
На 26.01.2026 лучшие модели для кодирования с балансом качества и скорости: Qwen2.5-Coder 14B (для большинства задач), DeepSeek-Coder 33B (для сложного кода), и новые специализированные модели вроде CodeLlama 3 13B. Экспериментируйте!

Что дальше? От мониторинга к оптимизации

Собрав данные из логов неделю-две, вы сможете:

  • Построить графики времени ответа по типам промптов
  • Выявить "слабые места" вашей модели (например, она плохо генерирует SQL-запросы)
  • Настроить автоматическое переключение между моделями: быстрая 7B модель для простых задач, мощная 72B - для сложных
  • Создать базу знаний с оптимальными промптами для вашей кодовой базы

Помните историю про пьяного стажера? Так вот, с правильными таймаутами и логированием ваш "стажер" хотя бы будет работать предсказуемо. А предсказуемость в разработке - это уже половина успеха.

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

Но начинать нужно с основ. Настройте таймауты. Включите логирование. Поймите, как работает ваша локальная LLM. Только тогда вы перестанете гадать, "работает ли она или зависла", и начнете эффективно генерировать код.