Разработчик собрал RAG-систему на локальных моделях и поднял точность поиска с 20% до 53%
Разработчик (автор проекта на GitHub под ником tzar26) собрал полностью自хостинговую RAG-систему для анализа новостей — без единого обращения к OpenAI или Anthropic. Весь стек — локальные модели Qwen 2.5 14B и BGE-M3 через Ollama, база на PostgreSQL. Главная цель — независимость от внешних провайдеров и полный контроль над данными. Сначала поиск по 12 000 собранных статей работал только на векторных эмбеддингах, и на запрос «золото» система выдавала новости про фигуриста, который взял золото на соревнованиях, а не про цены на металл. Разработчик добавил классический текстовый поиск BM25 и склеил его с векторным через алгоритм RRF — в результате доля релевантных статей в топ-5 выдачи выросла с 20% до 53%. Отдельно переписали промпт для классификации тем: раньше модель из страха ошибиться сваливала 74% статей в мусорную категорию «other», после правки — только 0,03%, а ручная проверка подтвердила точность разметки в 85%. • Агент на LangGraph сам выбирает из трёх инструментов: поиск по тексту, SQL-агрегация метрик и поиск по упомянутым компаниям с тональностью • Переход с LangChain на прямой клиент Ollama ускорил пайплайн в 9 раз • Настройка Ollama (два параллельных запроса вместо одного) ускорила классификацию статей в 1,5 раза
AI-обработка оригинала Habr AI; редакция Hamidun News
Разработчик под ником tzar26 выложил на GitHub разбор своей системы для анализа новостей — полностью автономной, без единого вызова облачных API вроде OpenAI или Anthropic. Все модели крутятся локально через Ollama: Qwen 2.5 14B для рассуждений и классификации, BGE-M3 для векторных представлений текста. Причина такого подхода прямо названа в статье: устойчивость к санкциям и независимость от внешних провайдеров. Получившийся стек — Python, FastAPI, PostgreSQL с расширением pgvector, Celery для фоновых задач, LangGraph для агента и Langfuse для мониторинга — автор собрал в Docker-контейнерах и покрыл тестами через GitHub Actions.
Почему обычный векторный поиск провалился на омонимах
Система собрала больше 12 000 статей и для начала искала по ним только через косинусное расстояние между эмбеддингами BGE-M3. На простых запросах всё работало нормально, но сложные темы вроде «ключевая ставка ЦБ» выдавали мусор. Нагляднее всего это показал запрос «золото»: вместо новостей о ценах на металл поиск честно находил статьи про фигуриста, который взял золото на соревнованиях — классическая путаница из-за того, что у слова несколько значений, а вектор не различает контекст.
Решением стал гибридный поиск: к векторному сравнению добавили точный текстовый поиск BM25 на базе PostgreSQL (через встроенный tsvector), а результаты обоих методов объединили алгоритмом RRF (Reciprocal Rank Fusion) — он берёт позиции документа в каждой из выдач и считает общий ранг. BM25 хорошо ловит точные термины типа «ОПЕК» или «ставка», а векторный поиск — синонимы и смысловые связи. В сумме доля релевантных документов в первой пятёрке результатов поиска (метрика Recall@5) выросла с 0,2 до 0,53, то есть больше чем в два раза.
Как перестать сваливать всё в мусорную категорию
Отдельная проблема возникла при автоматической классификации статей по темам. В первой версии промпта модель отправляла 74% всех статей в категорию «other» — то есть почти три четверти базы оказались без полезной метки. Причина оказалась простой: в инструкции была фраза «если сомневаешься — выбирай other», и модель из страха ошибиться массово ею пользовалась.
Разработчик переписал промпт: добавил чёткие описания для каждой категории, включая розничную торговлю (retail), макроэкономику (macro) и инциденты (incident), и убрал саму формулировку про сомнения. После этого доля неклассифицированных статей упала до 0,03%. Чтобы убедиться, что цифры не врут, автор дополнительно вручную проверил случайную выборку размеченных статей — точность классификации составила 85%.
Агент, который считает, а не просто ищет
Обычный поиск по базе отвечает на вопросы вроде «что пишут про нефть», но для аналитики этого мало. Поэтому автор построил на LangGraph агента с тремя инструментами на выбор:
- `search_articles` — обычный гибридный поиск по тексту
- `get_metrics` — SQL-агрегация, например подсчёт количества статей про энергетику за последние три дня
- `search_by_entity` — поиск по извлечённым именам компаний с учётом тональности текста (результат отдельных NER- и сентимент-моделей)
На вопрос «есть ли негативные новости про ЦБ» агент сам решает, какой инструмент вызвать — ему не нужно явно указывать, что требуется посчитать тональность, а не просто найти текст. Для отладки этой логики развернули self-hosted Langfuse — он показывает каждый шаг цепочки «планировщик → вызов инструмента → финальный ответ», сколько токенов ушло на каждый шаг и какие именно аргументы модель передала в функции.
Технические грабли на локальном железе
Запуск моделей локально принёс свои проблемы, нетипичные для облачных API:
- Ollama выгружала модели из видеопамяти при переключении между ними, и один запрос мог занимать до 60 секунд — починили переменной `OLLAMA_MAX_LOADED_MODELS=2`
- Библиотека LangChain внутри использует потоковую агрегацию ответов, которая давала девятикратное замедление — её выкинули из пайплайна в пользу прямого клиента `ollama.AsyncClient`
- SQLAlchemy привязывает пул соединений к циклу событий (event loop), и когда Celery прерывал задачу, соединения оставались «зомби» — решилось вызовом `await engine.dispose()` после каждой задачи
- Ollama по умолчанию обрабатывает запросы последовательно; классификация одной статьи занимала около 10 секунд, а увеличение параметра `OLLAMA_NUM_PARALLEL` с 1 до 2 ускорило процесс минимум в полтора раза
Проект сейчас в статусе публичного MVP и выложен в открытом доступе на GitHub. Следующий шаг, по словам автора, уже закрытый — привязка упоминаемых компаний к тикерам Мосбиржи (вроде SBER и GAZP) и построение прогнозных дашбордов по конкретным акциям. Для инженеров, которые рассматривают локальный стек вместо облачных API, главный практический вывод звучит так: экономия на API-вызовах реальна, но платить за неё придётся временем на тюнинг инфраструктуры — от настройки параллелизма Ollama до борьбы с управлением соединениями в асинхронном коде.
- 29 окт. 2026 г.Claude в Houdini на Windows: два бага в панели агента и жеода за 31 ноду
- 29 окт. 2026 г.Технокафе собрало видеоэссе кодом: 73 секунды за $10 токенов Claude Code
- 29 окт. 2026 г.Как OpenAI удержала Azure Cosmos DB под нагрузкой 1 млрд пользователей ChatGPT
- 29 окт. 2026 г.Modal выросла выше $1 млрд ARR и оценена в $16 млрд на спросе на песочницы
Вопросы и ответы по материалу
Что известно по теме: почему обычный векторный поиск провалился на омонимах?
Система собрала больше 12 000 статей и для начала искала по ним только через косинусное расстояние между эмбеддингами BGE-M3. На простых запросах всё работало нормально, но сложные темы вроде «ключевая ставка ЦБ» выдавали мусор. Нагляднее всего это показал запрос «золото»: вместо новостей о ценах на металл поиск честно находил статьи про фигуриста, который взял золото на соревнованиях — классическая путаница из-за того, что у слова несколько значений, а вектор не различает контекст. Решением стал гибридный поиск: к векторному сравнению добавили точный текстовый поиск BM25 н
Что известно по теме: как перестать сваливать всё в мусорную категорию?
Отдельная проблема возникла при автоматической классификации статей по темам. В первой версии промпта модель отправляла 74% всех статей в категорию «other» — то есть почти три четверти базы оказались без полезной метки. Причина оказалась простой: в инструкции была фраза «если сомневаешься — выбирай other», и модель из страха ошибиться массово ею пользовалась. Разработчик переписал промпт: добавил чёткие описания для каждой категории, включая розничную торговлю (retail), макроэкономику (macro) и инциденты (incident), и убрал саму формулировку про сомнения. После этого доля н
Что известно по теме: агент, который считает, а не просто ищет?
Обычный поиск по базе отвечает на вопросы вроде «что пишут про нефть», но для аналитики этого мало. Поэтому автор построил на LangGraph агента с тремя инструментами на выбор: `search_articles` — обычный гибридный поиск по тексту `get_metrics` — SQL-агрегация, например подсчёт количества статей про энергетику за последние три дня `search_by_entity` — поиск по извлечённым именам компаний с учётом тональности текста (результат отдельных NER- и сентимент-моделей) На вопрос «есть ли негативные новости про ЦБ» агент сам решает, какой инструмент вызвать — ему не нужно явно указыва
Соберите рабочего ИИ-агента или сервис своими руками без ручного кода
В Академии Жемала Хамидуна (academy.hamidun.com) открыт бесплатный 72-часовой тест-драйв: интерактивные скетч-уроки по Claude Code и Cursor, живой Tech Radar и готовые шаблоны агентов.
Главное из мира ИИ — раз в неделю
7 ключевых событий недели, отобранных вручную. Без шума, репостов и пресс-релизов.
Готово! Проверьте почту — мы отправили подтверждение.