Граф Связей Пользователя (User Fact Knowledge Graph)
Граф Связей Пользователя (User Fact Knowledge Graph)
Помимо классической истории диалогов, ForjBot Engine в процессе взаимодействия строит Динамический Граф Знаний о Пользователе (UserFact + FactRelation).
graph TD
subgraph UserNode ["Пользователь (ID: 48291)"]
U["User: Алексей\n(metric_score: 85)"]
end
subgraph FactNodes ["Узлы Графа Фактов (UserFact)"]
F1["Имя: Алексей\n(category: personal | imp: 10)"]
F2["Работа: Senior Developer\n(category: career | imp: 9)"]
F3["Питомец: Кот Барсик\n(category: pets | imp: 8)"]
F4["Хоби: Велоспорт & Триатлон\n(category: interests | imp: 7)"]
F5["Город: Санкт-Петербург\n(category: location | imp: 8)"]
end
subgraph RelationsEdge ["Ребра и Связи (FactRelation)"]
U -->|has_fact| F1
U -->|has_fact| F2
U -->|has_fact| F3
U -->|has_fact| F4
U -->|has_fact| F5
F1 -.->|owns / weight: 0.95| F3
F1 -.->|works_as / weight: 0.90| F2
F1 -.->|lives_in / weight: 0.85| F5
F2 -.->|relates_to / weight: 0.60| F4
end
subgraph MemoryInject ["Инъекция в Системный Промпт"]
GraphSearch["get_fact_graph(user_id)"] --> Format["Форматирование узлов и связей"] --> PromptBlock["{user_facts} + {retrieved_facts}"]
end
Структура Данных Графа
1. Узлы Фактов (UserFact)
Каждый узел представляет извлеченный факт со следующими атрибутами:
category: Категория факта (personal,career,interests,pets,family,preferences,location).key: Уникальный ключ факта для пользователя (job_title,pet_name,favorite_color,city).value: Значение факта (“Разработчик Python”, “Кот Барсик”, “Санкт-Петербург”).importance: Важность факта по шкале от 1 до 10 (влияет на приоритет подстановки в промпт).confidence: Коэффициент уверенности модели (0.0 – 1.0).source_message_id: Ссылка на оригинальное сообщение пользователя.
2. Связи и Ребра Графа (FactRelation)
Граф объединяет отдельные факты в смысловую сеть:
source_fact_id: ID исходного факта.target_fact_id: ID целевого факта.relation: Тип связи (owns,likes,works_at,family_with,located_in).strength: Вес/прочность связи (0.0 – 1.0).
Извлечение и Запрос Графа (get_fact_graph)
При каждом вызове модель обращается к хранилищу через функцию get_fact_graph(session, user_id):
async def get_fact_graph(session: AsyncSession, user_id: int) -> tuple[list[UserFact], list[FactRelation]]:
facts = await get_user_facts(session, user_id)
fact_ids = {f.id for f in facts}
if not fact_ids:
return [], []
result = await session.execute(
select(FactRelation).where(
FactRelation.source_fact_id.in_(fact_ids) & FactRelation.target_fact_id.in_(fact_ids)
)
)
relations = list(result.scalars().all())
return facts, relations
Авто-Обновление при Conflict (upsert_user_fact)
При изменении факта (например, пользователь сменил работу) система выполняет атомарный UPSERT:
- Если факт с ключом
(user_id, key)уже существует, обновляетсяvalue,importanceи времяupdated_at. - Если узел новый — создается новая запись в графе.