Навіщо сучасним AI-системам потрібні контекстні та knowledge-графи
Як CTO UPSTARS, IT-компанії, що стрімко зростає, я щодня проводжу десятки зустрічей, приймаю багато рішень — і часто бачу таку картину: інструменти є, ChatGPT/Codex/Claude/Claude Code відкритий у кожному браузері, на кожному десктопі, але відповіді на однакові питання подекуди суперечать одна одній, а потрібний контекст губиться.
Це біль багатьох компаній, які активно використовують АІ — і справа не в моделі, а в тому, що більшість корпоративних знань живе в документах, тікетах і чатах — інформація нікуди не зникає, але зв’язки між подіями, рішеннями та людьми доводиться тримати в голові.
Вирішити це лише пошуком по документах не вийде — потрібна інша структура. В цьому блозі я пояснюю, чому векторного пошуку недостатньо, як працюють контекстні та knowledge-графи і з чого починати компанії, яка хоче зробити AI справді корисним інструментом.
Як це виглядає на практиці — наш пілот
В UPSTARS ми запустили внутрішнього бота, який ходить на дейлі, ретроспективи та планування разом із командами: він підключається до зустрічей як окремий учасник, робить транскрипцію, готує нотатки й аналізує обговорення.
Пайплайн:
- транскрипція;
- резюме;
- теги;
- векторизація;
- граф рішень із звʼязками між людьми, командами та подіями;
- MCP-агент, до якого можна звернутися.
Архітектура
Схематично цей пайплайн реалізований через окремі асинхронні воркери, що обмінюються повідомленнями, і кілька спеціалізованих сховищ — кожне під свою задачу:

Стек
Усе це побудовано на Python 3.13 з FastAPI та Pydantic v2, а робота з базою даних відбувається через SQLAlchemy 2.x у асинхронному режимі та Alembic для міграцій. За асинхронні задачі відповідають httpx та APScheduler, логування — через structlog, а Playwright дозволяє боту заходити на зустрічі як окремому учаснику.
Дані зберігаються у чотирьох сховищах:
- PostgreSQL 17 — під основні дані;
- Valkey 8 — під черги та locks;
- FalkorDB (на основі Graphiti) — під граф знань;
- Qdrant — під вектори для RAG.
Фронтенд написаний на React 19 з Vite, Tailwind v4, shadcn/ui, RTK Query та React Router. Для звернень до LLM використовуються SDK OpenAI, Anthropic та Google — з можливістю використовувати власний ключ користувача (BYO-ключ).
А для команди все виглядає просто — тіммейт відкриває бота і питає: «Що ми вирішили минулого тижня щодо команди X?» або «Які блокери найчастіше згадувалися на ретроспективах за останній квартал?». І отримує відповідь із посиланнями на конкретні зустрічі та рішення.
Для мене це стало особливо помітним через значний обсяг інформації: за 10 місяців бот транскрибував близько 1300 моїх зустрічей. Наводжу цю цифру, щоб показати, скільки знань компанія створює щодня — і як легко вони губляться, якщо немає системи, яка вміє їх накопичувати, пов’язувати між собою і повертати в потрібний момент.
LLM не пам’ятає — і це особливість архітектури
На цьому місці зазвичай виникає логічне запитання: якщо всі зустрічі вже транскрибовані, чому просто не залити їх ChatGPT?
Проблема в тому, що мовні моделі самі по собі нічого не пам’ятають, а працюють лише з тим контекстом, який отримують у конкретний момент часу, а те, що часто називають «пам’яттю», насправді є контекстним вікном — набором даних, які модель бачить під час виконання запиту.
Головний принцип: модель — це рушій міркування над заземленими даними, а не джерело фактів. Тому довіра до відповіді будується не на одному промпті, а на кількох незалежних шарах — наприклад, якщо факт у графі має термін дії, модель просто не побачить застарілий зв’язок і не зможе видати його за актуальний. Так навіть якщо модель захоче вигадати, система це впіймає або не дасть відповіді.
Саме тому між відповідями на кшталт «знайди документ про інтеграцію» і «поясни, чому ми обрали саме це рішення та що було після» лежить велика різниця: у другому випадку потрібен доступ до тексту та пам’ять про зв’язки між людьми, подіями, рішеннями та їхніми наслідками. І тут проблема в тому, де і як зберігається цей контекст.
Де ламається стандартний підхід
Коли компанія вперше думає про те, як підключити AI до своїх знань, первинна думка майже завжди однакова — векторний пошук: система знаходить документи, які найбільше схожі на запит за змістом, і передає їх моделі як контекст. Для простих задач це працює добре — наприклад, коли потрібно знайти політику відпусток або інструкцію для нового тіммейта, але є кілька місць, де цей підхід починає давати збої.
1. Схожість не означає правду
Векторний пошук повертає схожі шматки тексту, а не факти, і якщо в одному документі написано «Олег — керівник відділу», а в іншому «Олег був керівником відділу до березня 2024», система віддасть обидва. Модель не знає, який актуальний, тому складе відповідь, яка суперечить сама собі.
Граф вирішує це тоді, коли зберігає час дії факту: наприклад, коли зв’язок виник і коли перестав бути дійсним — без часової валідності граф так само легко віддасть застарілу відповідь, як і векторне сховище, бо структура сама по собі не робить факт актуальним.
2. Зв’язки між подіями ніде не існують
Уявіть два інциденти в різних командах із різницею в квартал, у яких спільна причина, що ніде не зафіксована. Для векторного сховища це просто два окремі документи, а зв’язок між ними не зафіксований ніде: щоб його відновити, потрібен конкретний інженер, який пам’ятає обидва випадки, а звільниться він — і зв’язок зникне разом з ним.
У всіх цих випадках проблема однакова: система бачить текст, але не бачить зв’язків між фактами, тому може знайти потрібний документ, але не завжди здатна пояснити, як одне рішення пов’язане з іншим. Тут і починається роль графа.
Що змінює граф і навіщо він взагалі потрібен
Контекстний граф (knowledge graph, а підхід, що поєднує його з пошуком, називають GraphRAG) — це граф, побудований навколо конкретної компанії, який зберігає зв’язки між людьми, командами, рішеннями, проєктами та подіями. Якщо векторний пошук шукає схожі документи, то граф доповнює його: вектор знаходить релевантний текст, а граф додає структуру — хто що зробив, коли це сталося і як одна подія пов’язана з іншою.
Різницю між «лише пошуком» і «пошуком плюс граф» найпростіше показати на прикладі: запит «Що в нас по інтеграції X?»
- Векторний пошук — поверне кілька тікетів, документів або листів, де згадується ця інтеграція.
- Граф — поверне поточний статус, відповідального, блокери, пов’язані рішення, залежні сервіси та інциденти, які могли вплинути на проєкт.
Чому це важливо для AI
Коли моделі не вистачає фактів, вона починає добудовувати відповідь за ймовірністю, але граф зменшує цю проблему: замість кількох схожих фрагментів тексту модель отримує структуровані факти та зв’язки між ними, і через це їй значно рідше доводиться заповнювати прогалини припущеннями.
Граф не безкоштовний і не безпомилковий: його хтось має будувати й підтримувати, а зв’язки з транскриптів витягують ті самі LLM, які теж помиляються. Тому граф — не магія, що сама себе наповнює, а актив, який треба обслуговувати. Саме тому, до речі, я нижче раджу не починати з графа: спершу варто переконатися, що питання, на які він має відповідати, реально існують.
А навіщо це бізнесу?
Часто чую питання: «У нас є Confluence, Notion і Jira — люди й так знаходять потрібну інформацію. Навіщо ще щось?». Якщо справді знаходять швидко — можливо, поки не потрібно, але якщо відповідь на важливе питання вимагає десяти хвилин пошуку, значить частина знань уже існує поза системами. Confluence зберігає текст, Jira зберігає тікети, а зв’язки між ними часто живуть лише у головах людей — граф робить ці зв’язки частиною системи.
Як запустити контекстний граф і не вбити ідею на старті
Найпоширеніша помилка — починати не з проблеми, а з інфраструктури: купити vector DB, найняти Head of AI, побудувати архітектуру. Але якщо незрозуміло, які питання люди реально будуть ставити системі, вся ця робота може залишитися дорогим експериментом.
Починати варто з іншого: подивитися, які зв’язки вже існують, але ніде не зафіксовані. Співробітники є в HR-системі та Jira, але між собою не пов’язані, інциденти живуть у Confluence, алерти — у Prometheus, а граф починається з того, що ці зв’язки нарешті отримують форму.
Якщо говорити про компанію на 50 людей, я б рухався так:
1. Спочатку MVP — зберіть транскрипти або будь-які структуровані дані, зробіть резюме і базовий пошук, покажіть одній команді, головне — дати людям відчути користь на маленькому масштабі.
2. Дайте попиту зʼявится самостійно — коли інші команди самі починають питати «а можна й нам?», масштабувати рішення значно простіше.
3. Тільки тоді — граф — коли вже є накопичені дані і зрозумілий патерн запитів.
Окремо варто подумати про доступи: граф містить рішення, домовленості та зв’язки між подіями — фактично це концентрат чутливих знань компанії, і ризик тут вищий, ніж у розрізнених документах: одним запитом можна дістати картину, яку раніше ніхто не бачив цілісно. Тому права доступу мають діяти на рівні самих зв’язків (хто які вузли й ребра може бачити), а не лише на рівні «є доступ до бота / немає». Питання власності та захисту даних потрібно вирішувати від самого початку.
І ще одна річ: команду неможливо змусити полюбити новий інструмент через регламент — працює тільки реальна користь. У нас так було із сервісами для нотаток зустрічей: спочатку багато скепсису, а потім хтось побачив, що це економить 20 хвилин підготовки, і сам попросив доступ. Люди не люблять нові інструменти, але люблять, коли зникає рутина.
Замість висновку — просте запитання
Якщо завтра з вашої компанії підуть п’ять ключових людей — скільки знань піде разом з ними? Рішення, контекст, причини, домовленості й усе те, що живе в головах, а не в системах.
LLM не вирішить цю проблему сама по собі — вона інтерфейс, а не інтелект. Але якщо за нею стоїть граф, який наповнюється на основі реальних подій всередині компанії, ви отримаєте інший інструмент і рівень рішень. Із власного досвіду скажу: починати варто вже тоді, коли є перше питання, на яке система могла б відповісти краще й швидше за людину.
7 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарівДякую за матеріал. Додам з боку бізнес-аналітики: у нашому випадку вузьким місцем була не структура зберігання знань, а дисципліна їх фіксації. Я працюю BA над аналітичним продуктом для енергоринку, де рішення накопичуються місяцями й кожне може вплинути на числа у звіті.
У нас кілька механізмів стали обов’язковими.
Реєстр рішень
Кожне рішення має ID, автора, дату, статус і посилання на рішення, яке його замінило. Рішення не існує, якщо воно залишилося лише в коментарі до тікета: такий коментар не переживає ротацію людей.
Історія термінів у глосарії
Вилучений термін позначається як заборонений із посиланням на актуальну заміну. Інакше система продовжує впевнено повертати стару термінологію як чинну.
Заморожування критеріїв до запуску
Умови проходження фіксуються до перегляду результату, щоб критерій не можна було підігнати під уже отримане число.
Власність документації
У кожного розділу є власник. Інші ролі не редагують його напряму, а піднімають питання власнику. Це той самий контроль доступу, але реалізований на рівні процесу.
Ці механізми ловили цілком практичні помилки. В одному випадку розрахунок непомітно використав вхідні дані за інший рік: результат виглядав правдоподібно й пройшов перегляд. Помилку знайшли лише під час повторного трасування до джерела.
В іншому випадку отримали два значення однієї метрики, тому що один запуск виконувався зі старої гілки без перевірки commit SHA.
Ви пишете, що зв’язок може мати строк дії, а в коментарях уточнюєте, що кожен факт зберігає свій час і джерело. Тоді питання на рівень глибше: чи розділені в реалізації час події, час запису факту та період його чинності? Ці три часові атрибути розходяться саме там, де рішення переглядають заднім числом.
І друге, чого в тексті немає: статус самого рішення. Строк дії зв’язку не відрізняє «обговорили» від «вирішили», «відхилили» та «скасували». Хто і в який момент проставляє цей статус?
Без цього транскрипт зустрічі може стати швидким способом отримати скасоване або непідтверджене рішення з високою впевненістю.
Було б цікаво прочитати продовження саме про експлуатацію графа: governance, валідацію фактів і виправлення помилкових зв’язків.
Класний коментар. Дякую, що знайшли час поділитися своїм досвідом — це справді цінно.
Ваші думки цілком слушні. Наш граф поки що лише пілот, і йому ще належить пройти всі етапи.
Щодо рішень: чи вважати їх прийнятими, система визначатиме на основі фактів і контексту. Якщо в межах певного кола рішення вже обговорюється як прийняте, то де-факто воно таким і є.
Щодо застарівання інформації. Кожен вузол графа має як дату створення, так і дату останнього оновлення. Крім того, він містить лічильник згадок і контекст, де й коли був згаданий.
Вогінь!
Треба і нам таке на фірмє запілити )))
Не до кінця зрозуміло що то за граф такий.
Це якийсь набір даних який будується по вхідному ключу (тікет?) і ви його вставляєте в контекст? напевно це просто json документ у вас?
Що робити коли той граф дуже великий, як ви це контролюєте? Як вирішужте що саме має входити у граф щоб не було забагато контексту?
Це не JSON і не будується по тікету. JSON для кожної зустрічі (учасники/рішення/саммарі) у нас лежить окремо — у Postgres. А граф — це граф знань (FalkorDB + Graphiti)), який надбудовується над усіма зустрічами: люди, проєкти й теми стають вузлами, зв’язки між ними — фактами, і кожен факт пам’ятає свій час і джерело (конкретну зустріч). Entity resolution «зшиває» одну людину чи проєкт в один вузол через усі зустрічі, а не створює окрему копію для кожної.
Весь граф у контекст не потрапляє. При отриманні інформації відбувається семантичний пошук за запитом → у промпт летять тільки top-N релевантних фактів. Контекст задає top-k, а не розмір графа. Тому великий граф — це норма; сам граф масштабується як база даних: через пагінацію пошуку, партиціонування за часом і шардинг за тенантом.
У граф записується структуроване саммарі зустрічі, а не сирий транскрипт. У контекст потрапляють лише релевантні top-N факти з урахуванням порогу за скором і скоупу доступу (з ізоляцією за користувачем). «Розпухання», як таке, відсутнє «бай-дизайн».
Повністью згоден, що графи, дерева будуть все більше використовуватися в агентах ШІ. Цікаво було б почути, чи є якісь напрацювання по GrafRAG? Може, open source продукти.. Гадаю, з часом з’являться якись стандарти на цю тему. А Fine tuning моделі не працює в схожему напрямку? Не дивилися в цю сторону?
Дякую за коментар!
Ми працюємо в цьому напрямку, але поки що це лише внутрішні напрацювання, і вони ще не в open source. Думаю, що до кінця цього року або вже наступного з’являться і стандарти, і сучасні зрілі рішення для GraphRAG.
Щодо fine-tuning моделі, то це, по-перше, дороге задоволення. По-друге, моделі потрібно регулярно донавчати. А по-третє, fine-tuning вирішує дещо іншу задачу. GraphRAG — це про те «де взяти знання», тоді як fine-tuning — «як змінити поведінку моделі».
Fine-tuning добре підходять, скажімо, для вирішення дуже вузьких завдань. Зокрема для класифікації. Але, знову ж таки: операційна підтримка та вартість.