Skip to content

init#6

Open
Menzorg wants to merge 23 commits intomainfrom
rag-proto
Open

init#6
Menzorg wants to merge 23 commits intomainfrom
rag-proto

Conversation

@Menzorg
Copy link
Copy Markdown
Owner

@Menzorg Menzorg commented Mar 12, 2026

rag integration prototype and fixes

@Menzorg
Copy link
Copy Markdown
Owner Author

Menzorg commented Mar 12, 2026

@claude проанализируй правки в этом плуреквесте и дай отчет.

2 similar comments
@Menzorg
Copy link
Copy Markdown
Owner Author

Menzorg commented Mar 12, 2026

@claude проанализируй правки в этом плуреквесте и дай отчет.

@Menzorg
Copy link
Copy Markdown
Owner Author

Menzorg commented Mar 12, 2026

@claude проанализируй правки в этом плуреквесте и дай отчет.

@claude
Copy link
Copy Markdown

claude bot commented Mar 12, 2026

Claude finished @Menzorg's task in 2m 17s —— View job


Анализ PR: RAG Integration Prototype

  • Чтение изменённых файлов
  • Анализ RAG-интеграции
  • Анализ миграций БД
  • Анализ изменений планировщика
  • Анализ прочих изменений
  • Формирование итогового отчёта

Обзор

PR содержит 1362 добавленных / 31 удалённых строк в 18 файлах. Изменения охватывают три основные области:

  1. RAG-интеграция — реализация гибридного поиска по документам
  2. Планировщик задач — подключение утренних опросов и вечерних отчётов
  3. Документация — отчёт по альфа-фичам и технический долг

1. RAG-интеграция

Схема БД (012_rag_schema.sql)

Добавлены 3 новые таблицы:

  • rag_docs — документ с summary_embedding (vector(768)), TSV-индексом (setweight A/B по title/summary), HNSW-индексом по embedding
  • chunks — текстовые чанки с embedding (vector(768)), HNSW + GIN TSV
  • tables_rows_chunks — отдельная таблица для строк табличных документов

Также: ALTER TABLE user_files ADD COLUMN content_hash TEXT с уникальным индексом для дедупликации по организации.

Хорошо: структура продумана, HNSW-индексы с vector_cosine_ops, каскадные DELETE.

Проблема — content_hash без заполнения: Миграция добавляет колонку и тут же делает SET NOT NULL через UPDATE ... SET content_hash = ''. Но логика вычисления хэша при загрузке файлов в PR не добавлена — поле останется пустым для новых файлов, уникальный индекс не будет работать по назначению. Fix this →

Поисковые функции (013_rag_functions.sql)

6 PL/pgSQL функций реализующих двухуровневый гибридный поиск (Reciprocal Rank Fusion):

Функция Тип
search_concrete_chunks TSV-first, RRF с векторным переранжированием
search_abstract_chunks Vector-first, TSV как дополнительный сигнал
search_concrete_table_rows TSV-first для табличных строк
search_abstract_table_rows Vector-first для табличных строк
search_related_docs Поиск релевантных документов (2 режима)
search_rag Unified dispatcher → чанки или табличные строки
get_expanded_context Расширение окна вокруг лучшего чанка

Хорошо: корректная логика fallback (TSV → vector, concrete → abstract), GREATEST(p_top_k * 10, 50) как pool size, STABLE пометка функций.

Проблема — хардкод порогового расстояния: В search_related_docs (abstract-ветка, строка ~465) стоит WHERE r.vec_dist < 0.5. При отсутствии близких документов результат будет пустым — без возможности контроля из Python. Fix this →

Проблема — несогласованность tsquery: search_concrete_chunks использует websearch_to_tsquery, остальные функции — plainto_tsquery. Для однородного поведения лучше использовать один вариант. Fix this →

RAG Tool (rag_tool.py)

Полная реализация вместо стаба: двухэтапный поиск — сначала search_related_docs (до 3 документов), затем search_rag для каждого документа.

Критическая проблема — создание пула на каждый вызов:

# rag_tool.py:46-47
pool = await asyncpg.create_pool(Config.get_postgres_dsn(), min_size=1, max_size=2)

Каждый вызов rag_search создаёт новый asyncpg connection pool и закрывает его в finally. Это крайне неэффективно: установка соединения с PostgreSQL занимает ~50-200ms, а при параллельных запросах создаётся множество коннектов. Нужно передавать существующий пул из EngineService. Fix this →

Проблема — импорт внутри функции:

# rag_tool.py:129
import concurrent.futures

Импорт внутри функции вместо верхнего уровня модуля — нарушает соглашения PEP 8.

Проблема — asyncio.run в потоке:

# rag_tool.py:130-135
with concurrent.futures.ThreadPoolExecutor(max_workers=1) as executor:
    future = executor.submit(asyncio.run, _search_rag_async(...))
    return future.result(timeout=120)

Workaround корректен для синхронного LangChain tool в async FastAPI, но вместе с проблемой создания нового пула это удваивает накладные расходы. Fix this →

Конфигурация (config.py)

EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "nomic-embed-text-v2-moe:latest")

Добавлен get_vector_dsn() для psycopg3 формата (не используется текущей реализацией RAG, где применяется asyncpg через get_postgres_dsn()).


2. Планировщик задач (scheduler_service.py)

Ключевое изменение: Подключены _run_morning_polls_for_org и _run_evening_reports_for_org — задачи, которые ранее числились как "не подключены" в alpha-features-report.

Логика корректна:

  • Timezone-aware: использует ZoneInfo для определения локального часа организации
  • Idempotent: проверяет существование опроса через create_daily_poll()
  • Вечерние отчёты генерируются для всех admin'ов организации

Небольшая проблема в list_distinct_assignees (task_storage.py:124): запрос фильтрует status NOT IN ('done'), но не исключает 'overdue'. Значит сотрудникам с просроченными задачами будут ежедневно создаваться утренние опросы — возможно это ожидаемое поведение (опрос нужен чтобы обновить статус), но стоит убедиться. Fix this →


3. AgentExecutor (executor.py)

Добавлена инъекция org_id и user_id в RunnableConfig для всех агентов:

config = RunnableConfig(configurable={
    "org_id": str(role.org_id) if role.org_id else "",
    "user_id": str(user_id) if user_id else "",
})

Это необходимо для RAG tool. Правильный подход.

Также добавлен TODO-комментарий (строки 89-96) для инъекции correction rules через RAG — это технический долг, зафиксированный явно, что хорошо.


4. Storage additions

task_storage.py: добавлены list_distinct_assignees() и list_active_for_polls() — необходимы для планировщика.

user_storage.py: добавлен list_admins_by_org() — для вечерних отчётов. Корректно фильтрует is_system = false, исключая AI-пользователей.


5. Requirements

-psycopg2-binary>=2.9.0
-langchain-postgres>=0.0.12
+langchain-community>=0.3.0

Убраны psycopg2-binary и langchain-postgres (видимо, были попытки использовать PGVector через LangChain, но финальная реализация использует сырой asyncpg). Добавлен langchain-community.


6. Документация

docs/alpha-features-report.md — подробный статус всех альфа-фич с таблицей готовности. Полезно.

docs/tech-debt.md — список проблем в deploy.sh (6 пунктов для rugpt, 4 для webclient). Критичные: нет set -e, нет рестарта uvicorn, нет автомиграций при деплое.


Итоговая оценка

Область Статус Комментарий
RAG схема БД ✅ Хорошо Продуманная структура, правильные индексы
RAG SQL функции ⚠️ Есть замечания Хардкод порога 0.5, несогласованность tsquery
RAG tool Python ❌ Критично Создание нового пула на каждый вызов
Планировщик ✅ Хорошо Корректная timezone-aware реализация
content_hash ⚠️ Незавершено Колонка добавлена, но не заполняется
Документация ✅ Хорошо Ценные отчёты по состоянию системы

Главное к исправлению перед мержем: переработать rag_tool.py для переиспользования существующего pool вместо создания нового на каждый запрос.

@Menzorg
Copy link
Copy Markdown
Owner Author

Menzorg commented Mar 12, 2026

@claude ты можешь создать коммит в этом пуллреквесте который бы исправлял проблему с созданием нового пулла на каждый вызов?

@claude
Copy link
Copy Markdown

claude bot commented Mar 12, 2026

Claude finished @Menzorg's task in 3m 18s —— View job


Исправление: пул соединений в rag_tool.py

  • Анализ задачи
  • Чтение rag_tool.py, engine_service.py, executor.py
  • Реализация исправления
  • Коммит и пуш

Коммит 717903e запушен в ветку rag-proto.

Что изменено

src/engine/agents/tools/rag_tool.py

  • Добавлен модульный синглтон _pool: Optional[asyncpg.Pool] = None
  • Добавлена функция init_rag_pool(pool) — вызывается один раз при старте движка
  • _search_rag_async теперь использует _pool напрямую: ни создания, ни закрытия пула на каждый вызов
  • rag_search переведён в async — убраны ThreadPoolExecutor и asyncio.run (LangChain и LangGraph корректно обрабатывают async инструменты)
  • Убран неиспользуемый импорт concurrent.futures

src/engine/services/engine_service.py

  • В initialize(), после инициализации всех хранилищ, вызывается init_rag_pool(self.user_file_storage.pg_pool) — RAG tool получает готовый пул без создания нового

Почему так

Существующий user_file_storage.pg_pool создаётся в том же event loop, что и вся остальная логика FastAPI/LangGraph, поэтому его безопасно передавать в async-инструмент. Переход на async tool устранил необходимость в обходном пути с ThreadPoolExecutor + asyncio.run, который и порождал создание нового event loop (а с ним — и нового пула соединений) при каждом вызове.
| Branch: rag-proto

github-actions bot and others added 22 commits March 12, 2026 14:50
- Add module-level _pool singleton and init_rag_pool() initializer
- Make rag_search an async tool (removes ThreadPoolExecutor + asyncio.run overhead)
- Remove per-call asyncpg.create_pool / pool.close in _search_rag_async
- Wire user_file_storage.pg_pool into RAG tool during engine initialization
- Remove unused concurrent.futures import

Co-authored-by: Menzorg <Menzorg@users.noreply.github.com>
…_timezone fix: it was implemented in python, but not in migrations until now
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants