Зачем локальной модели видеть больше трёх файлов?
Вы скачали свежую модель для кода, запустили её через Ollama, задали вопрос про свой проект. В ответ получили красивое, логичное и абсолютно неверное объяснение. Модель не знает ваши структуры данных, не видит импорты, не понимает архитектуру. Она гадает. Проблема не в глупости модели, а в слепоте. Вы дали ей три строки кода из файла utils.py и ждёте, что она поймёт всю систему.
Облачные конкуренты вроде GitHub Copilot или Cline в 2026 году умеют заглядывать в соседние файлы, потому что у них есть доступ ко всей вашей репозитории. Локальная модель работает в вакууме. Её контекстное окно пусто, пока вы его не заполните. Вот как это исправить.
Не делайте так: копируете 50 строк кода в чат и спрашиваете: «Почему здесь ошибка?». Модель утонет в токенах, забудет начало и начнёт галлюцинировать. Контекст нужно структурировать.
Три слона, на которых держится понимание кода
Есть три подхода, которые работают в 2026 году. Каждый со своей болью и своей магией.
1. Ручной контекст: для маленьких проектов и быстрых правок
Вы вручную собираете сниппеты кода и подкладываете их в промпт. Звучит примитивно, но это основа. Модели вроде Qwen2.5 Coder 32B Instruct (последняя версия на март 2026) имеют контекст до 128K токенов. Вы можете засунуть туда несколько ключевых файлов. Но просто скопировать – недостаточно.
2. Индексация и RAG: когда проект больше 10 файлов
Вы разбиваете код на куски (чанки), создаёте для каждого векторное представление (эмбеддинг) и складываете в базу. Когда задаёте вопрос, система ищет самые похожие чанки и подставляет их в контекст. Это уже не ручная работа, а автоматический поиск.
3. Инструменты и агенты: полный цикл
Система сама читает вашу кодовую базу, строит карту зависимостей, понимает, какие файлы нужны для ответа. В 2026 году это делают агенты на базе локальных моделей с поддержкой Tool Calling, о которых мы уже писали. Они могут запускать grep, читать package.json, анализировать стектрейсы.
Практика: строим систему индексации за час
Теория надоела. Давайте сделаем систему, которая будет искать нужные куски кода по запросу и подставлять их в промпт. Вам понадобится Python, немного терпения и модель для эмбеддингов.
1 Выбираем модель для эмбеддингов
Не используйте большие языковые модели для создания векторов. Это стрельба из пушки по воробьям. Возьмите специальную маленькую модель, обученную на коде. На 2026 год я рекомендую BGE-Code-Embeddings-v2.5 или её более свежий аналог. Она понимает синтаксис Python, JavaScript, Go лучше, чем универсальные модели.
# Качаем модель через Ollama, если есть версия
ollama pull bge-code-embedding:latest
# Или используем через sentence-transformers в Python
2 Разбиваем код на умные чанки
Не режьте код построчно. Режьте по логическим блокам: функция, класс, связанная группа функций. Иначе поиск будет возвращать мусор.
import ast
from pathlib import Path
def chunk_python_file(file_path: Path):
"""Разбивает Python файл на функции и классы."""
with open(file_path, 'r') as f:
content = f.read()
chunks = []
tree = ast.parse(content)
for node in ast.walk(tree):
if isinstance(node, (ast.FunctionDef, ast.ClassDef, ast.AsyncFunctionDef)):
# Берём код ноды с отступами
chunk = ast.unparse(node)
chunks.append({
'text': chunk,
'file': str(file_path),
'type': type(node).__name__
})
return chunks
Не забудьте про импорты и глобальные переменные. Вынесите их в отдельный чанк для каждого файла, иначе модель не поймёт, откуда берутся requests или CONFIG.
3 Создаём векторную базу в памяти
Используйте chromadb или faiss. Первый проще для начала. Не нужно разворачивать отдельный сервер, можно хранить всё в памяти.
import chromadb
from sentence_transformers import SentenceTransformer
# Загружаем модель для эмбеддингов кода
embedder = SentenceTransformer('BAAI/bge-code-embedding-v2.5')
# Создаём клиент ChromaDB в памяти
chroma_client = chromadb.Client()
collection = chroma_client.create_collection(name="code_chunks")
# Для каждого чанка создаём эмбеддинг и сохраняем
for chunk in all_chunks:
embedding = embedder.encode(chunk['text']).tolist()
collection.add(
embeddings=[embedding],
documents=[chunk['text']],
metadatas=[{'file': chunk['file'], 'type': chunk['type']}],
ids=[f"{chunk['file']}_{len(ids)}"]
)
4 Ищем релевантные чанки и спрашиваем модель
Когда у вас есть вопрос по коду, превращаете его в запрос, ищете топ-5 похожих чанков и подставляете их в промпт для большой модели.
def ask_llm_about_code(question: str, main_model: str = "qwen2.5-coder:7b"):
# Шаг 1: Ищем релевантные чанки
query_embedding = embedder.encode(question).tolist()
results = collection.query(
query_embeddings=[query_embedding],
n_results=5
)
# Шаг 2: Формируем контекст
context = "\n\n".join(results['documents'][0])
# Шаг 3: Создаём промпт с инструкцией
prompt = f"""Ты — эксперт по коду. Используй предоставленный контекст для ответа.
Контекст (фрагменты кода из проекта):
{context}
Вопрос: {question}
Ответ (будь конкретен, ссылайся на код):"""
# Шаг 4: Отправляем в локальную LLM через Ollama API
import requests
response = requests.post('http://localhost:11434/api/generate',
json={
'model': main_model,
'prompt': prompt,
'stream': False
})
return response.json()['response']
Где всё ломается: нюансы, о которых молчат
Индексация кода – не серебряная пуля. Вот что может пойти не так.
| Проблема | Причина | Как исправить |
|---|---|---|
| Модель не видит связи между чанками | Векторный поиск находит похожие по тексту, но не по смыслу, фрагменты | Добавляйте в метаданные информацию о соседних файлах, увеличивайте размер чанка (но не слишком) |
| Поиск возвращает одно и то же | Некоторые функции встречаются часто (например, logger.info) |
Используйте мета-фильтры в запросе, исключайте слишком общие фрагменты |
| Эмбеддинги для кода работают плохо на новом языке | Модель не обучалась на, скажем, языке Hare или на вашем DSL | Разбивайте код на токены как обычный текст, используйте универсальную модель (но хуже) |
Самая частая ошибка – перегрузить контекст. Вы нашли 10 релевантных чанков, каждый по 100 строк. Это уже 1000 строк кода в промпте. Модель с контекстом 8K токенов не переварит. Даже модель на 128K будет тупить. Нужно фильтровать жёстче.
А что, если не хочется писать код?
Писать свою систему индексации каждый раз – занятие для фанатов. Есть готовые инструменты, которые уже в 2026 году умеют работать с локальными моделями.
- Continue.dev – расширение для VS Code, которое умеет индексировать код и использовать локальные модели через Ollama. Но, как мы уже разбирали, у него есть нюансы с прокси.
- Cursor с локальным режимом – в 2026 году он научился работать полностью offline, используя llama.cpp под капотом. Индексирует проект в фоне.
- Windsurf – новый игрок, который изначально заточен под RAG для кода и поддерживает все популярные локальные модели.
Но у всех этих инструментов общая болезнь: они пытаются быть умными и скрывают от вас процесс индексации. Когда что-то ломается, вы не понимаете почему. Моя самописная система из 100 строк кода хотя бы прозрачна.
Совет, который вы не просили
Не гонитесь за размером модели. Qwen2.5 Coder 7B с правильно загруженным контекстом сделает для вашего проекта больше, чем гигантская 72B модель, которая видит только два файла. Контекст важнее параметров.
И ещё. Локальные LLM для кода в 2026 году – это не про то, чтобы полностью заменить мозг. Это про то, чтобы иметь под рукой мгновенную справку по вашему собственному коду, который никуда не утекает. Начните с ручного подкладывания контекста. Потом автоматизируйте. Через месяц вы будете удивляться, как раньше жили без этого.
Если вы уже настроили базовый стек с Ollama, как в нашей статье про идеальный стек, то добавление индексации кода – следующий логический шаг. Не пытайтесь прыгнуть сразу в агентов. Сначала научите модель видеть.