English translation is not available yet. Showing Russian content.
Как вы делаете retrieval для структурированных данных (SQL, Knowledge Graph)?
Краткий тезис
Retrieval для структурированных данных принципиально отличается от векторного поиска по тексту: вместо эмбеддингов и косинусной близости используется перевод естественно-языкового запроса в формальный язык запросов (SQL для реляционных баз, SPARQL/Cypher для графов знаний). Ключевая задача — точное понимание схемы данных и генерация корректного запроса, результаты которого затем подаются LLM как контекст. Такой подход позволяет отвечать на точные фактологические вопросы, агрегации и запросы по связям, недоступные при поиске по чанкам.
1. Термин: Структурированные данные в контексте RAG
Структурированные данные — это данные, организованные по строгой схеме: таблицы с колонками и типами (SQL) или графы с узлами, рёбрами и свойствами (graph|Knowledge Graph). В отличие от неструктурированного текста, они требуют точного соответствия между запросом и схемой. Ошибка в имени таблицы или синтаксисе запроса делает результат бесполезным.
Зачем нужен отдельный подход
- поиск|Векторный поиск по сериализованным таблицам (например, «превратить строку таблицы в текст») теряет структуру и связи.
- LLM не может напрямую «выполнить» SQL — нужен промежуточный шаг генерации запроса.
- Результаты структурированного retrieval — это не чанки, а строки, ячейки или пути графа, которые затем форматируются для LLM.
2. Text-to-SQL: общий пайплайн
Text-to-SQL — задача преобразования естественного языка в SQL-запрос. Пайплайн:
- Пользовательский запрос (NL): «Сколько заказов сделал клиент с ID 42 в марте 2024?»
- Формирование промпта: LLM получает схему БД (таблицы, колонки, типы, внешние ключи) + запрос + инструкцию.
- Генерация SQL: LLM выводит, например,
SELECT COUNT(*) FROM orders WHERE customer_id = 42 AND order_date BETWEEN '2024-03-01' AND '2024-03-31'. - Выполнение SQL на реальной БД (с проверкой безопасности).
- Форматирование результата: строки таблицы превращаются в текст или Markdown-таблицу.
- Передача контекста LLM для финального ответа.
Пример промпта (упрощённо):
Ты — SQL-генератор. Схема БД:
Таблица orders: id (INT), customer_id (INT), order_date (DATE), total (FLOAT)
Таблица customers: id (INT), name (VARCHAR)
Запрос пользователя: "Покажи общую сумму заказов для клиента 'Иван' за 2024 год."
Сгенерируй только SQL-запрос.
LLM ответит: SELECT SUM(o.total) FROM orders o JOIN customers c ON o.customer_id = c.id WHERE c.name = 'Иван' AND YEAR(o.order_date) = 2024.
3. Проблемы Text-to-SQL и их решения
| Проблема | Описание | Решение |
|---|---|---|
| Неверная генерация SQL | LLM путает имена таблиц/колонок, синтаксис | Few-shot примеры, fine-tuning на датасетах (Spider, WikiSQL), проверка через парсер |
| SQL-инъекции | Злонамеренный запрос в NL может сгенерировать опасный SQL | Использовать параметризованные запросы (не конкатенацию), ограничить права БД (только SELECT) |
| Сложные запросы | Много JOIN, подзапросов, оконных функций | Разбивать на подзадачи (агентный подход), использовать chain-of-thought |
| Ошибки выполнения | БД возвращает ошибку (несуществующая колонка, деление на ноль) | Повторная генерация с сообщением об ошибке в промпте |
| Неоднозначность | «клиенты из Москвы» — что значит «из Москвы»? (город в адресе или регион?) | Уточняющий диалог с пользователем или жёсткое правило в промпте |
Fine-tuning на специализированных датасетах (например, Spider, Bird) повышает точность генерации SQL. Self-consistency (генерация нескольких SQL, выполнение, выбор по большинству) снижает риск единичной ошибки.
4. Retrieval из Knowledge Graph (KG)
Knowledge Graph — это графовая структура, где узлы — сущности (люди, компании, фильмы), рёбра — отношения (работает_в, снялся_в), а свойства — атрибуты (возраст, дата). Для извлечения данных используются языки запросов:
- SPARQL — для RDF-графов (Wikidata, DBpedia).
- Cypher — для Neo4j.
- Gremlin — для графовых БД общего назначения.
Пайплайн аналогичен Text-to-SQL:
- NL запрос → LLM генерирует SPARQL/Cypher.
- Выполнение запроса к графовой БД.
- Результат (список узлов, путей, агрегаций) → контекст для LLM.
Запрос: «Какие фильмы снял режиссёр Кристофер Нолан?»
Промпт содержит схему графа: узлы Person (name), Movie (title), отношение DIRECTED. LLM генерирует:
MATCH (p:Person {name: 'Christopher Nolan'})-[:DIRECTED]->(m:Movie)
RETURN m.title
Результат: ["Inception", "Interstellar", "Tenet", ...] → LLM отвечает списком.
5. Проблемы и решения для KG
| Проблема | Описание | Решение |
|---|---|---|
| Сложность онтологии | Схема графа может быть большой (сотни типов узлов и отношений) | Предоставлять LLM только релевантную часть схемы (через ретривер по метаданным) |
| Неоднозначность сущностей | «Нолан» — может быть Кристофер Нолан или Джонатан Нолан | Использовать entity linking (сопоставление с URI), уточняющий вопрос |
| Производительность | Сложные графовые запросы могут выполняться долго | Индексировать узлы по имени, ограничивать глубину обхода, кэшировать частые запросы |
| Альтернатива — GraphRAG | Вместо генерации запросов — эмбеддинги графа и поиск по ним | Использовать графовые нейросети (GNN) для создания эмбеддингов подграфов, затем векторный поиск |
GraphRAG (например, Microsoft GraphRAG) — гибридный подход: граф разбивается на сообщества, для каждого строится текстовое описание, которое индексируется векторно. Это упрощает retrieval, но теряет точность формальных запросов.
6. Сравнение подходов: SQL vs Knowledge Graph
| Характеристика | SQL (реляционные БД) | Knowledge Graph |
|---|---|---|
| Модель данных | Таблицы, строки, колонки | Узлы, рёбра, свойства |
| Язык запросов | SQL (ANSI, диалекты) | SPARQL, Cypher, Gremlin |
| Типичные вопросы | Агрегации, фильтры, JOIN по ключам | Пути, связи, транзитивные зависимости |
| Сложность генерации | Средняя (схема фиксирована) | Высокая (онтология сложнее) |
| Производительность | Высокая (индексы, оптимизаторы) | Зависит от размера графа, глубины обхода |
| Пример использования | «Средний чек по магазинам за прошлый месяц» | «Какие лекарства взаимодействуют с аспирином?» |
7. Интеграция с RAG: как использовать результаты
Результаты SQL/KG запроса — это не готовый ответ, а структурированный контекст. LLM должна его интерпретировать и сформулировать ответ на естественном языке.
Пример для SQL:
Контекст (результат SQL):
| customer_name | total_orders |
|---------------|--------------|
| Иван | [[15. Какие embedding-модели вы использовали и почему\|15]] |
| Мария | [[22. Какие методы fine-tuning вы знаете и какой используете чаще всего\|22]] |
Вопрос: "Сколько заказов сделал Иван?"
Ответ: Иван сделал 15 заказов.
Для KG:
Контекст (пути графа):
- Кристофер Нолан -> режиссёр -> "Inception"
- Кристофер Нолан -> режиссёр -> "Interstellar"
Вопрос: "Какие фильмы снял Нолан?"
Ответ: Кристофер Нолан снял фильмы "Inception" и "Interstellar".
Форматирование критично: таблицы Markdown, списки, JSON — в зависимости от задачи.
8. Инструменты и фреймворки
- LangChain: SQLDatabaseChain,
SQLDatabaseAgent, GraphCypherQAChain — готовые цепочки для Text-to-SQL и Cypher. - LlamaIndex: SQLTableNodeMapping, KnowledgeGraphIndex — интеграция с SQL и Neo4j.
- Vanna.ai: специализированный Text-to-SQL с возможностью fine-tuning на собственных данных.
- Neo4j + LLM: плагин
neo4j-graphrag-python, интеграция с OpenAI. - SPARQLWrapper: для выполнения SPARQL-запросов из Python.
from langchain_community.utilities import SQLDatabase
from langchain.chains import create_sql_query_chain
from langchain_openai import ChatOpenAI
db = SQLDatabase.from_uri("sqlite:///chinook.db")
llm = ChatOpenAI(model="gpt-4", temperature=0)
chain = create_sql_query_chain(llm, db)
question = "Сколько треков в альбоме 'Let There Be Rock'?"
result = chain.invoke({"question": question})
print(result) # SQL-запрос
# Затем выполнить и получить ответ
9. Оценка качества retrieval для структурированных данных
Традиционные метрики (Hit Rate, MRR) здесь не работают, потому что результат — не набор документов, а точный ответ на запрос.
Метрики для Text-to-SQL:
- Execution Accuracy — доля запросов, для которых результат выполнения SQL совпадает с эталонным (золотой стандарт).
- Exact Set Match — совпадение множества строк (порядок не важен).
- Valid Efficiency Score — учитывает и корректность, и производительность.
Метрики для KG:
- F1 по узлам/рёбрам — насколько найденный подграф совпадает с эталонным.
- Path Accuracy — точность восстановления пути в графе.
Оценка требует размеченного датасета (NL-запрос → правильный SQL/SPARQL → ожидаемый результат). Популярные бенчмарки: Spider (SQL), LC-QuAD 2.0 (SPARQL).
Пет-проект для закрепления
Задача: Создать агента, который отвечает на вопросы по SQLite-базе данных (например, Chinook — музыкальный магазин) и по небольшому графу знаний (например, FilmKG — фильмы, актёры, режиссёры).
Инструменты: Python, LangChain, SQLite, Neo4j (или in-memory граф через NetworkX + SPARQLWrapper для имитации).
Шаги:
- Загрузить Chinook (SQLite) и создать граф FilmKG (можно в Neo4j Desktop или AuraDB).
- Написать функцию, которая по NL-запросу генерирует SQL через LangChain
create_sql_query_chain. - Реализовать выполнение SQL с обработкой ошибок (повторная генерация при неудаче).
- Для графа — аналогично через
GraphCypherQAChain. - Объединить в одного агента с маршрутизацией: если вопрос про таблицы → SQL, если про связи → KG.
- Протестировать на 10 вопросах разного типа.
Ожидаемый результат: Агент, который на естественном языке возвращает точные данные из обеих БД, например:
- «Сколько треков в жанре Rock?» → SQL → «125 треков».
- «Какие фильмы снял Стивен Спилберг?» → Cypher → «Список: "Список Шиндлера", "Парк Юрского периода"...».
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 376 | Проектирование агентных RAG-систем |
| 378 | Гибридный поиск (векторный + ключевой) |
| 379 | Маршрутизация запросов в RAG |
| 380 | Мультимодальный retrieval |
| 381 | Кэширование результатов retrieval |
| 382 | Оценка качества RAG-системы |
Навигация
- Предыдущий: 376
- Следующий: 378
- Индекс: 00. Индекс разборов