Проблема: ваш код-ассистент засыпает на сложных задачах
Вы пишете промпт для генерации сложного модуля на Python. Qwen3-Coder через Ollama думает. Думает. Думает еще. Проходит 30 секунд, минута, две. Continue в VSCodium показывает вечный спиннер. В логах - тишина. Вы не знаете, упал ли запрос, зависла ли модель, или она просто медленно генерирует 500 строк кода. Знакомо?
Это классическая проблема локальных LLM для кодирования: отсутствие видимости и контроля над выполнением. В отличие от облачных API, где таймауты и логирование - стандартная функциональность, в локальной связке Ollama + Continue эти настройки спрятаны или вообще отсутствуют.
Ключевой момент: когда модель Qwen3-Coder или аналогичная пытается сгенерировать сложный код, она может уйти в "размышления" на несколько минут. Без правильных таймаутов вы не отличите это от зависания.
Почему это происходит? Анатомия зависания
Три слоя, где может сломаться процесс:
- Уровень модели: Qwen3-Coder 72B (актуальная версия на 26.01.2026) требует значительных ресурсов. При генерации сложного кода она может "зациклиться" на определенных конструкциях.
- Уровень Ollama: По умолчанию у Ollama нет жестких таймаутов на генерацию. Модель может генерировать до бесконечности (или пока не кончится память).
- Уровень Continue: Расширение имеет собственные настройки таймаутов, которые могут конфликтовать с Ollama.
Я видел случаи, где разработчики часами ждали ответа от локальной модели, не понимая, что она уже давно "сошла с рельсов". Как в той статье про длинные промпты, где модели теряют контекст и начинают генерировать бессмыслицу.
Решение: настраиваемый стек мониторинга и контроля
Мы построим трехслойную систему:
- Таймауты на уровне Ollama API
- Детальное логирование всех запросов и ответов
- Настройки Continue для адекватного поведения при таймаутах
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 |
Когда таймауты - это симптом, а не проблема
Иногда постоянные таймауты указывают на более глубокие проблемы:
- Слишком сложные промпты: Если вы просите "написать всю систему управления складом", даже Qwen2.5-Coder 72B будет страдать. Разбивайте задачи. Как в статье про неосознанный вайб-кодинг - ИИ не заменяет архитектурное мышление.
- Проблемы с аппаратным обеспечением: RTX 5090 - это мощно, но если у вас всего 16GB VRAM для 72B модели в 4-битном квантовании, она будет работать на пределе. Мониторьте использование памяти.
- Конфликтующие расширения: Другие AI-расширения в VSCodium могут конфликтовать с Continue. Проверьте, нет ли у вас установленного LMStudio модифицированного VSCode или других инструментов.
Мой совет: начните с агрессивных таймаутов (30-60 секунд) и увеличивайте их только для действительно сложных задач. Если модель регулярно не укладывается в 60 секунд - возможно, вам нужна другая модель или подход к промптингу.
Что дальше? От мониторинга к оптимизации
Собрав данные из логов неделю-две, вы сможете:
- Построить графики времени ответа по типам промптов
- Выявить "слабые места" вашей модели (например, она плохо генерирует SQL-запросы)
- Настроить автоматическое переключение между моделями: быстрая 7B модель для простых задач, мощная 72B - для сложных
- Создать базу знаний с оптимальными промптами для вашей кодовой базы
Помните историю про пьяного стажера? Так вот, с правильными таймаутами и логированием ваш "стажер" хотя бы будет работать предсказуемо. А предсказуемость в разработке - это уже половина успеха.
Следующий шаг - автоматизация. Представьте систему, которая анализирует промпт, выбирает оптимальную модель и таймаут, генерирует код, проверяет его статическим анализом, и только потом показывает вам. Это уже не фантастика - это следующий уровень локальных ИИ-агентов.
Но начинать нужно с основ. Настройте таймауты. Включите логирование. Поймите, как работает ваша локальная LLM. Только тогда вы перестанете гадать, "работает ли она или зависла", и начнете эффективно генерировать код.