3,583 papers
arXiv:2511.18405 74 23 нояб. 2025 г. FREE

Talk2Data: принципы роутинга и контекстной привязки для работы с данными

КЛЮЧЕВАЯ СУТЬ
Работаешь с данными через LLM — знакомая боль: модель то выдумывает колонки которых нет, то генерирует 20 строк кода вместо простого ответа "какие колонки в таблице?". Проблема в том что модель не понимает когда нужен код (вычисления), а когда достаточно слов. Talk2Data решает эту путаницу через явный роутинг — перед каждым ответом модель классифицирует запрос по примерам: "построй график" → код, "что означает колонка" → текст. Ключевая фишка: передаёшь схему данных явно (названия колонок, типы, примеры значений) — модель привязывается к реальной структуре, галлюцинации о несуществующих полях исчезают.
Адаптировать под запрос

TL;DR

Talk2Data — система-исследование, которая показывает как структурировать диалог с LLM при работе с табличными данными. Ключевой принцип: перед каждым ответом модель решает — генерировать код для анализа или дать текстовое объяснение. Эта развилка решений реализована через специальный промпт с примерами ("построй распределение" → код; "что означает колонка" → текст). В промпт передаётся структура данных — названия колонок, типы, примеры значений, диапазоны чисел.

Проблема: когда работаешь с данными через LLM, модель часто либо пытается объяснить словами то, что требует вычислений ("средний возраст примерно 30-35" вместо точного числа), либо наоборот — генерирует код там, где достаточно короткого ответа ("какие колонки в таблице?" → 20 строк Python вместо списка). Ещё одна боль: модель может ссылаться на колонки, которых нет в твоих данных, потому что не видит реальную схему таблицы.

Решение — явный роутинг на уровне промпта: сначала классифицируй запрос (нужен код или объяснение?), потом действуй. Плюс передавай схему данных в каждом запросе: "в таблице 8 колонок: age (числа 18-65), gender (Male/Female), score (0-100)...". Модель делает выбор осознанно и привязывается к реальным данным, а не к галлюцинациям.

🔬

Схема метода

КОНТЕКСТ (один раз при загрузке данных):
→ Извлеки схему: названия колонок, типы, примеры значений, диапазоны
→ Сохрани как metadata для всех запросов

КАЖДЫЙ ЗАПРОС:
ШАГ 1: Роутинг
→ Промпт с примерами: "нужен код или текст для этого запроса?"
→ Вывод: {"action": "code_generation"} или {"action": "chat_response"}

ШАГ 2а (если код):
→ Сгенерируй Python с привязкой к metadata
→ Выполни в безопасной среде
→ Верни результат (график/таблица/число)

ШАГ 2б (если текст):
→ Дай краткое объяснение на основе metadata и истории
→ Можешь предложить "хочешь, я посчитаю?"

ШАГ 3: Обнови историю диалога для следующего запроса

Все шаги выполняются в одном диалоге, но каждый запрос проходит через роутинг заново.

🚀

Пример применения

Задача: Ты ведёшь онлайн-магазин на Ozon, выгрузил CSV с заказами за квартал (цена, регион, категория, дата, статус). Хочешь быстро понять паттерны: где продаётся лучше, какие категории, есть ли сезонность. Но не хочешь каждый раз писать "построй график" или "посчитай среднее" — хочешь просто спрашивать, а модель сама понимает что нужно.

Промпт (первый запрос — инициализация):

У меня CSV с данными о заказах:
- order_id (уникальный номер)
- price (рубли, от 290 до 45000)
- region (Москва, МО, СПб, Екатеринбург, Казань, Новосибирск)
- category (Электроника, Одежда, Дом и сад, Спорт, Красота)
- date (2024-01-01 до 2024-03-31)
- status (Доставлен, Отменён, Возврат)
Всего 3847 строк.

Дальше я буду задавать вопросы. Для каждого:
1. Реши: нужен код (для графиков/вычислений) или текстовое объяснение (для вопросов о данных)?
2. Если код — напиши Python для pandas/matplotlib, используя df с этими колонками
3. Если объяснение — дай короткий ответ и предложи, если нужно посчитать

Примеры решений:
- "покажи распределение цен" → код (histogram)
- "что означает статус 'Возврат'?" → текст
- "средний чек по регионам" → код (groupby + bar chart)
- "какие категории есть?" → текст (список из metadata)

Первый вопрос: какой средний чек в Москве?

Результат:

Модель классифицирует запрос как code_generation (нужно вычисление), генерирует код:

df[df['region'] == 'Москва']['price'].mean()

Вернёт точное число, например: "4856 рублей — средний чек в Москве".

Следующие запросы в диалоге: - "а в СПб?" → модель помнит контекст, заменит фильтр на 'СПб' - "покажи топ-3 категории по выручке" → сгруппирует, посчитает сумму, выдаст bar chart - "что такое статус 'Отменён'?" → текстовое объяснение без вычислений

🧠

Почему это работает

Слабость LLM: Модель не знает когда нужен код, а когда — слова. Попросишь "средний чек" — может выдать приблизительную оценку вместо точного числа. Попросишь "что означает колонка" — может написать 20 строк кода для простого ответа. Ещё хуже: модель может придумать колонки, которых нет в твоих данных (галлюцинация), потому что не видит реальную схему.

Сильная сторона LLM: Модель отлично классифицирует тип задачи по примерам (few-shot learning) и хорошо работает с явными контрактами — "если X, то делай Y". Также хорошо привязывается к конкретным данным, если их показать явно.

Как метод использует это: Вместо одного универсального промпта делаем два специализированных — один для роутинга, другой для действия. В роутинге показываем примеры: "визуализация/вычисления → код", "вопрос о структуре/объяснение → текст". Это убирает двусмысленность. Плюс передаём схему данных явно в начале — модель видит реальные названия колонок, типы, примеры значений, и не может придумать несуществующие поля. Результат: точные вычисления там где нужно, короткие ответы там где достаточно, никаких галлюцинаций о структуре данных.

Рычаги управления:

  • Примеры в роутинге — добавь свои типы задач ("сравнение двух метрик" → код; "расшифруй аббревиатуру" → текст), чтобы модель училась на твоих паттернах
  • Детальность metadata — для больших таблиц передавай только топ-5 значений по каждой категории и диапазоны, чтобы не раздувать промпт
  • История диалога — ограничь последними 3-5 обменами для длинных сессий, иначе контекст раздуется и модель начнёт путаться
  • Условие выбора кода — можешь сместить баланс: "если сомневаешься — выбирай текст и предлагай код" (безопаснее) или "если сомневаешься — сразу генерируй код" (быстрее для опытных)
📋

Шаблон промпта

У меня {формат} с данными о {тема}:

СХЕМА:
{для_каждой_колонки}
- {название} ({тип}: {диапазон_или_примеры_значений})

Всего {число} строк.

Дальше я буду задавать вопросы. Для каждого:
1. Реши: нужен КОД (для графиков/вычислений/группировок) или ТЕКСТОВОЕ ОБЪЯСНЕНИЕ (для вопросов о структуре/смысле данных)?
2. Если код — напиши Python для pandas/matplotlib, используя переменную df с этими колонками. Без комментариев, только исполняемый код.
3. Если объяснение — дай краткий ответ (1-2 предложения) и предложи, если есть смысл посчитать точно.

Примеры решений:
- "распределение {числовая_колонка}" → КОД (histogram)
- "что означает {категория_или_термин}?" → ТЕКСТ (объяснение)
- "среднее/сумма по группам" → КОД (groupby + chart/число)
- "какие значения в {колонка}?" → ТЕКСТ (список из схемы выше)
- "топ-N по {метрика}" → КОД (sort + head + chart/таблица)
- "есть ли связь между X и Y?" → ТЕКСТ ("давай построим scatter plot") или сразу КОД

Первый вопрос: {твой_запрос}

Заполнение плейсхолдеров: - {формат} — "CSV файл", "таблица Excel", "Google Sheets" - {тема} — "заказах интернет-магазина", "рекламных кампаниях", "транзакциях" - {название} — реальные имена колонок из твоих данных - {тип}: {диапазон_или_примеры} — для чисел: "рубли, от 100 до 50000", для категорий: "Москва, СПб, Новосибирск, Казань" (топ-5 значений) - {число} — количество строк - {твой_запрос} — твой первый вопрос к данным

🚀 Быстрый старт — вставь в ChatGPT (с Code Interpreter) или Claude:

Вот шаблон для работы с моими данными через роутинг (код/объяснение). 
Адаптируй под мою задачу: [опиши свою таблицу и тип данных].
Попроси меня прислать первые 5 строк, если нужно увидеть структуру.

[вставить шаблон выше]

Модель спросит какие колонки в таблице, какие типы данных, примеры значений — потому что без схемы роутинг не сработает правильно (модель может галлюцинировать несуществующие поля). После этого она возьмёт паттерн роутинга и будет применять для каждого твоего запроса, сама решая когда генерировать код, а когда объяснять словами.

⚠️

Ограничения

⚠️ Зависимость от качества метаданных: Если передашь неполную или неточную схему (забыл указать колонку, перепутал тип), модель будет генерировать неправильный код или галлюцинировать. Роутинг работает только при точном описании структуры данных.

⚠️ Роутинг не абсолютен: Маленькие модели (1.5-3B параметров) часто ошибаются в классификации — выбирают "объяснение" там где нужен код, или наоборот. Исследование показало: модели 7B+ ошибаются в 1-2% случаев, модели 1.5B — в 35% случаев. Для продакшн-использования нужны модели от 7B параметров (GPT-4, Claude Sonnet, Gemini Pro).

⚠️ Не для сложных многошаговых вычислений: Метод работает для стандартной аналитики (группировки, графики, фильтры, топы). Для сложных многоступенчатых пайплайнов (множественные джойны, ресемплинг временных рядов, custom агрегации) одного запроса может не хватить — придётся разбивать на шаги вручную или переключаться на чистое программирование.

⚠️ Требует загрузки данных: В обычном чате без Code Interpreter модель не может выполнить код — будет только симулировать вычисления (приблизительные ответы). Для работы метода нужен ChatGPT Plus/Enterprise с Code Interpreter, Claude с artifacts, или свой Python environment.

🔍

Как исследовали

Команда из ИТМО собрала прототип полноценной системы с голосовым вводом (Whisper ASR), генерацией кода (Qwen2.5-Coder), безопасным выполнением Python в sandbox и озвучкой ответов (Coqui TTS). Но исследовательский фокус был на принципе роутинга: как точно модель классифицирует тип запроса и насколько правильный код генерирует.

Проверили на 48 задачах (26 визуализаций, 13 аналитических запросов, 9 объяснений) для трёх публичных датасетов: товары Otto Group (27 МБ, 94 колонки), рейсы США 2008 года (673 МБ, 7 млн строк), успеваемость студентов (70 КБ, 8 колонок). Протестировали пять размеров модели Qwen от 1.5B до 32B параметров.

Результаты показали резкий скачок точности от размера модели: 1.5B справилась с 62.5% задач (но 17 из 48 запросов неправильно классифицировала — выбирала объяснение вместо кода), 3B — 87.5%, а 7B достигла 95.8% с всего одной ошибкой роутинга. Интересно, что 32B-параметровая модель не превзошла 7B (та же точность 95.8%), а 14B показала максимум — 97.9%, но с минимальным приростом за троекратное увеличение размера.

Ключевой инсайт: маленькие модели консервативны — боятся генерировать код и предпочитают объяснять словами ("давайте я расскажу как это посчитать" вместо самого вычисления). Средние модели агрессивны — пытаются написать код даже там, где достаточно списка категорий. Модели от 7B параметров находят баланс: точно различают "когда код, когда текст" и при этом генерируют правильный Python в 95% случаев.

Замерили скорость генерации кода: 7B модель выдаёт ответ за 1.15-1.64 секунды (чистое время модели, без учёта распознавания речи и выполнения кода). Это укладывается в требования интерактивного диалога. Latency растёт линейно с размером модели, но точность — нет, поэтому 7B оказалась sweet spot для продакшн-применения.

Дизайн показал, что разделение на два промпта (роутинг + действие) работает лучше чем один универсальный: модель меньше путается, ошибки легко отследить (видно на каком этапе сломалось — классификация или генерация), а код получается чище (без лишних комментариев и принтов).

📄

Оригинал из исследования

Decision prompt (роутинг) — определяет нужен код или текст:

You are a conversational agent analyzing the dataset "{dataset_name}".

**Dataset Schema:**
{schema_description}

**Conversation History:**
{history}

**User Request:** "{user_query}"

**Task:** Determine if the request requires:
- "code_generation" (computation, visualization, aggregation), OR
- "chat_response" (explanation, clarification, metadata question).

**Return JSON only:**
{
  "action": "code_generation" or "chat_response",
  "reason": "brief explanation"
}

**Examples:**
User: "Plot age distribution" → {"action": "code_generation", "reason": "requires histogram"}
User: "What columns exist?" → {"action": "chat_response", "reason": "metadata query"}
User: "Find max sales by region" → {"action": "code_generation", "reason": "groupby + aggregation"}

Code generation prompt (если выбран код):

You are a Python code generator for tabular analysis.

**Dataset:** df (pandas DataFrame)
**Schema:** {schema}

**Task:** Generate concise Python code to answer: "{user_query}"

**Rules:**
- Use pandas, matplotlib, seaborn, plotly as needed
- Reference only columns that exist in schema
- Output must be an expression (figure object or dataframe), NOT print statements
- No comments, no explanations—just executable code

**Example:**
Query: "Scatter plot of price vs quantity"
Code:
```python
import matplotlib.pyplot as plt
plt.scatter(df['price'], df['quantity'])
plt.xlabel('Price')
plt.ylabel('Quantity')
plt.title('Price vs Quantity')

**Chat response prompt** (если выбран текст):

You are a conversational assistant for data analysis.

Dataset Schema: {schema} Conversation History: {history}

User Question: "{user_query}"

Task: Provide a brief, speakable answer (1-2 sentences). Reference the schema if needed. If computation is required, suggest switching to code.

Style: Clear, concise, no formatting (for TTS compatibility).


**Контекст:** Эти три промпта используются в оркестрации: сначала decision prompt классифицирует запрос, затем либо code generation prompt создаёт Python, либо chat response prompt формирует текстовое объяснение. Все промпты получают одинаковую схему данных (metadata) и историю диалога для консистентности.

## Адаптации и экстраполяции

💡 **Адаптация для SQL-баз вместо CSV:**

Тот же принцип роутинга, но вместо генерации Python → генерируй SQL. Передай схему таблиц (названия таблиц, колонки, типы, связи через foreign keys) и меняй промпт генерации кода:

Вместо "используй df (pandas)" напиши: "используй таблицы: {список_таблиц}. Напиши SQL запрос для PostgreSQL."

Примеры решений: - "средний чек по городам" → SELECT city, AVG(price) FROM orders GROUP BY city - "топ-10 клиентов" → SELECT customer_id, SUM(total) FROM orders GROUP BY customer_id ORDER BY SUM(total) DESC LIMIT 10


Роутинг остаётся тем же ("нужен запрос или объяснение?"), но действие — SQL вместо Python. Полезно если работаешь с Postgres/MySQL и не хочешь каждый раз выгружать CSV для анализа.

🔧 **Техника: bias роутинга → контроль риска и скорости**

В decision prompt можешь **сместить порог** в сторону безопасности или скорости:

**Для консервативного режима** (меньше кода, больше объяснений):

If uncertain, prefer "chat_response" and offer to compute if user confirms.

Эффект: модель будет чаще спрашивать "хочешь я посчитаю?" вместо того чтобы сразу генерировать код. Полезно когда данные большие, выполнение дорогое или ты хочешь контролировать каждый шаг.

**Для агрессивного режима** (больше кода, быстрее результаты):

If the question implies any computation, aggregation, or comparison—choose "code_generation" immediately.

Эффект: модель будет генерировать код даже для пограничных случаев. Полезно когда ты уверен в данных и хочешь максимум автоматизации.

🔧 **Техника: многоуровневая схема → работа с большими таблицами**

Для таблиц с **50+ колонками** передавать всю схему в каждый промпт дорого. Используй **иерархическую схему**:

СХЕМА (краткая): - 15 колонок с метриками: revenue, cost, profit, ... (числа) - 8 колонок с категориями: region, product_type, channel, ... (текст) - 5 временных: order_date, delivery_date, ... (даты) - остальные 22 колонки: технические ID и метаданные

Полная схема: {ссылка_или_детали_по_запросу}

Если пользователь спрашивает про конкретную колонку — уточни полное описание. ```

Эффект: промпт компактный, но модель знает что есть детали и может попросить, если нужно. Роутинг работает быстрее, контекст не раздувается.

🔗

Ресурсы

Talk2Data: A Multimodal Conversational Agent for Tabular Data Analysis — Mohammad Nour Al Awad, Sergey Ivanov, Olga Tikhonova, Ivan Khodnenko (ITMO University, Saint Petersburg, Russia)

Упомянутые модели и инструменты: - OpenAI Whisper (ASR) — github.com/openai/whisper - Qwen2.5-Coder (code generation) — huggingface.co/Qwen - Coqui TTS (text-to-speech) — github.com/coqui-ai/TTS - LangGraph (orchestration framework) — langchain-ai.github.io/langgraph

Датасеты для бенчмарка: - Otto Group Product Classification — Kaggle - US Flights 2008 — публичный датасет авиаперевозок - Student Performance Dataset — UCI Machine Learning Repository


📋 Дайджест исследования

Ключевая суть

Работаешь с данными через LLM — знакомая боль: модель то выдумывает колонки которых нет, то генерирует 20 строк кода вместо простого ответа "какие колонки в таблице?". Проблема в том что модель не понимает когда нужен код (вычисления), а когда достаточно слов. Talk2Data решает эту путаницу через явный роутинг — перед каждым ответом модель классифицирует запрос по примерам: "построй график" → код, "что означает колонка" → текст. Ключевая фишка: передаёшь схему данных явно (названия колонок, типы, примеры значений) — модель привязывается к реальной структуре, галлюцинации о несуществующих полях исчезают.

Принцип работы

Не один универсальный промпт, а два специализированных этапа. Сначала модель классифицирует запрос через few-shot примеры: "средний чек по регионам" → code_generation, "какие категории есть?" → chat_response. Роутинг убирает двусмысленность — модель не угадывает, а решает по паттерну. Второй этап — действие: если код, генерируешь Python с привязкой к схеме данных (df['region'], df['price']); если текст, даёшь краткий ответ из metadata. Схема данных передаётся в каждом запросе как контекст — модель видит реальные названия колонок и не может придумать несуществующие.

Почему работает

LLM катастрофически плохо понимает когда нужен код, а когда слова без явных инструкций. Попросишь "средний чек" — может выдать приблизительную оценку "примерно 4000-5000" вместо точного вычисления. Или наоборот: "какие колонки?" — напишет 20 строк кода для простого списка. Ещё хуже: модель может сослаться на колонку 'customer_id' которой нет в твоих данных (галлюцинация), потому что не видит реальную структуру таблицы. Роутинг через примеры использует сильную сторону LLM — few-shot классификацию. Модель отлично распознаёт тип задачи когда видит паттерн: "визуализация/группировка → код", "вопрос о смысле → текст". Передача схемы данных явно закрывает галлюцинации — модель привязывается к конкретным названиям и типам, не выдумывает. Исследование показало: модели 7B+ ошибаются в роутинге только в 1-2% случаев когда есть примеры, против 35% у мелких моделей без примеров.

Когда применять

Аналитика табличных данных через диалог → конкретно для работы с CSV/Excel/Google Sheets через ChatGPT Code Interpreter или Claude, когда хочешь просто спрашивать, а не писать код каждый раз. Особенно полезно когда задаёшь серию разных вопросов к одним данным: то график, то вычисление, то объяснение термина — модель сама переключается между режимами. НЕ подходит для сложных многошаговых пайплайнов (множественные джойны, кастомные агрегации) — там придётся разбивать на шаги вручную или писать код самому.

Мини-рецепт

1. Извлеки схему данных: Для каждой колонки — название, тип (числа/текст/дата), примеры значений или диапазон. Для больших таблиц бери топ-5 значений по категориям, чтобы не раздувать промпт.

2. Напиши промпт с роутингом: Покажи схему данных, дай примеры классификации (какие запросы → код, какие → текст). Шаблон: "построй график" → КОД, "что означает термин?" → ТЕКСТ, "средний чек по группам" → КОД, "какие колонки есть?" → ТЕКСТ.

3. Запускай через ChatGPT с Code Interpreter или Claude: Модель будет проходить роутинг для каждого твоего запроса — сама решать генерировать код или отвечать текстом. История диалога сохраняется, можно задавать уточнения ("а в Москве?").

4. Ограничивай историю для длинных сессий: Если диалог идёт 10+ обменов, оставляй только последние 3-5 в контексте — иначе модель начнёт путаться в длинной истории.

Примеры

[ПЛОХО] : Вот мои данные о заказах. Какой средний чек? — модель не видит схему, может выдумать колонки или дать приблизительную оценку вместо точного числа.
[ХОРОШО] : У меня CSV с заказами: price (рубли, 290-45000), region (Москва, СПб, Екб), category (Электроника, Одежда, Дом), date (2024-01-01 до 2024-03-31), status (Доставлен, Отменён). Всего 3847 строк. Для каждого вопроса реши: нужен КОД (графики/вычисления) или ТЕКСТ (объяснение)? Примеры: "распределение цен" → КОД (histogram), "что означает статус?" → ТЕКСТ, "средний чек по регионам" → КОД (groupby), "какие категории?" → ТЕКСТ. Вопрос: средний чек в Москве? — модель видит схему, классифицирует запрос как code_generation, генерит df[df['region']=='Москва']['price'].mean(), вернёт точное число 4856 рублей.
Источник: A Multimodal Conversational Agent for Tabular Data Analysis
ArXiv ID: 2511.18405 | Сгенерировано: 2026-01-12 18:06

Концепты не выделены.

📖 Простыми словами

Суть системы в том, что она превращает нейронку из болтливого гуманитария в строгого аналитика, который сначала думает, а потом делает. Главная проблема обычных чат-ботов — они пытаются угадать ответ, глядя на таблицу, и постоянно врут. Здесь же архитектура заставляет LLM работать как диспетчера: она не выдает цифры из головы, а решает, нужно ли написать кусок кода на Python для расчета или можно просто ответить словами. Это разделение ответственности между «мозгом» (планирование) и «руками» (выполнение кода в песочнице) дает точность 95.8%, потому что код не умеет галлюцинировать — он либо работает, либо нет.

Это как если бы у тебя был стажер-аналитик, который сидит в соседней комнате. Ты не видишь его монитор, но можешь крикнуть: "А покажи-ка мне продажи по регионам!". Стажер не пытается угадать их по памяти, он открывает Excel, строит график и просовывает тебе под дверь листок с картинкой. Если ты спросишь: "А что значит колонка X?", он просто ответит голосом, не отвлекаясь на расчеты. Формально он делает кучу действий, но для тебя это выглядит как обычный разговор с умным человеком, который помнит всё, что вы обсуждали пять минут назад.

Что реально круто работает: централизованная маршрутизация (модель по ключевым словам и контексту четко понимает, когда пора кодить, а когда — болтать), заземление в схеме данных (нейронке перед глазами всегда тыкают списком реальных колонок, чтобы она не выдумывала свои) и память диалога. Если ты сначала попросил график, а потом сказал: "Сделай его красным", система не тупит, а понимает, что "его" — это тот самый график из предыдущего шага. Это превращает монолог в живой цикл анализа, где каждое следующее действие опирается на предыдущее.

Тестировали всё это на авиарейсах и студентах, но принцип универсален. Эту схему можно натянуть на любые таблицы: от складских остатков до банковских транзакций. Главное, что это не закрытая черная коробка, а открытая архитектура, которую можно развернуть на своем железе. По сути, эпоха ручного написания SQL-запросов и Python-скриптов для простых отчетов заканчивается, уступая место голосовому управлению данными.

Короче: хватит мучить менеджеров обучением Python — проще дать им инструмент, который сам переводит голос в код. Главный риск тут — барьер входа, потому что для нормальной работы (модель на 7B параметров) нужна мощная видеокарта с 16 ГБ видеопамяти и прямые руки для настройки «песочницы». Но если один раз настроить этот конвейер, ты получишь аналитика, который не спит, не ошибается в расчетах и отвечает за полторы секунды. Кто внедрит такое первым, перестанет тонуть в рутинных отчетах.

Сгенерировано: 21.12.2025 16:59 | ArXiv Data Collector

Работа с исследованием

Адаптируйте исследование под ваши задачи или создайте готовый промпт на основе техник из исследования.

0 / 2000
~0.5-2 N-токенов ~10-30с
~0.3-1 N-токенов ~5-15с