TL;DR
FINDER — метод который разделяет работу с числами на два запроса: первый извлекает только релевантные факты из длинного контекста, второй генерирует Python код используя эти факты. Вместо того чтобы скармливать модели весь финансовый отчет сразу, метод сначала фильтрует только нужные числа.
LLM часто путают числа когда видят много данных одновременно — берут цифры не из той строки, путают годы, пропускают важные значения. Это называется grounding errors ("ошибки привязки"). Эксперимент показал: GPT-4 делает больше ошибок когда обрабатывает полный финансовый отчет на 100+ строк, чем когда получает список из 5-7 конкретных фактов. Причина — модель теряется в большом контексте, не может точно определить какие именно числа нужны.
FINDER решает это через двухэтапный процесс: (1) Отдельная модель извлекает только релевантные факты — превращает отчет на 100 строк в список из 5-7 нужных значений (2) GPT-4 генерирует Python код используя эти чистые факты + автоматически подобранные примеры похожих задач. Код выполняется отдельно — получаем точный числовой ответ. Метод показал 75.32% точности на финансовых задачах против 69.38% у стандартного PoT.
Схема метода
ШАГ 1: Извлечение фактов
Вход: [длинный отчет] + [вопрос]
→ Выход: [короткий список релевантных чисел]
ШАГ 2: Генерация кода
Вход: [факты из Шага 1] + [вопрос] + [примеры]
→ Выход: [Python программа]
ШАГ 3: Выполнение
→ [численный ответ]
Два шага можно делать одним промптом (попросить модель сначала извлечь, потом сгенерировать) или двумя отдельными запросами (получить факты, затем передать их в новый запрос для генерации кода).
Пример применения
Задача: Анализируешь квартальный отчет Сбера на 15 страниц — нужно быстро посчитать рост прибыли и ROE чтобы решить стоит ли покупать акции. В отчете куча таблиц, сносок, пояснений — легко взять не те цифры.
Промпт:
Вот квартальный отчет Сбера:
[таблица: Чистая прибыль 2022: 350 млрд руб, 2023: 420 млрд руб]
[таблица: Капитал 2023: 5 трлн руб]
[куча других показателей: резервы, активы, кредиты...]
[текст про стратегию, риски, дивиденды...]
Задача разбита на 2 этапа:
ЭТАП 1 - Извлечение фактов:
Извлеки только цифры нужные для расчета:
1. Рост чистой прибыли (сравнение 2022 vs 2023)
2. ROE (рентабельность капитала)
Формат: "показатель: значение"
ЭТАП 2 - Код для расчета:
Используя факты из Этапа 1, напиши Python код.
Требования:
- Переменные с понятными названиями
- Комментарии к формулам
- Финальный ответ в переменную ans
Результат:
Модель выдаст два чистых блока. Сначала список фактов — только те числа которые реально нужны (чистая прибыль за оба года, капитал). Без лишних показателей про резервы или кредиты. Затем Python код с переменными и вычислениями. Код можно скопировать и выполнить в любом Python окружении — получишь точные проценты роста и ROE без риска что модель взяла не те строки из таблицы.
Почему это работает
LLM плохо извлекают числа из длинного контекста. Когда GPT-4 видит финансовый отчет на 100+ строк с десятками таблиц, он часто берет цифру из соседней строки (2022 вместо 2023), путает "выручку" с "прибылью", или пропускает важный показатель. Это не баг — это особенность как работает внимание в трансформерах. Модель пытается одновременно понять вопрос, найти факты И сделать вычисления — слишком много задач.
LLM отлично генерируют структурированный код когда видят конкретные числа и четкую задачу. Python код явно показывает логику: рост = (420 - 350) / 350 * 100 — легко проверить правильно ли. Без извлечения чисел из контекста — просто чистая математическая логика.
Двухэтапность использует сильную сторону и обходит слабую. Первый запрос фокусируется ТОЛЬКО на поиске фактов — никаких вычислений, только "найди нужные числа". Второй запрос фокусируется ТОЛЬКО на логике расчета — числа уже даны, не нужно искать. Эксперимент (Table 8) показал: GPT-4 с таргетированными фактами делает меньше ошибок чем GPT-4 с полным отчетом.
Рычаги управления:
- Формат извлечения — попроси JSON вместо списка если нужна структура:
{"прибыль_2022": 350, "прибыль_2023": 420} - Объединение шагов — для простых задач (<5 фактов) можно делать одним промптом: "Сначала извлеки факты, затем напиши код"
- Строгость кода — добавь "без округлений" или "с проверкой на ноль" если нужна точность
- Отдельные запросы — для сложных задач лучше делать два запроса — второй будет короче и четче
Шаблон промпта
Базовый вариант (один промпт):
Контекст: {финансовый_отчет_или_длинный_документ}
Вопрос: {вопрос_требующий_вычислений}
Задача в 2 этапа:
ЭТАП 1 - Извлечь факты:
Найди только числа релевантные для вопроса.
Формат: список "показатель: значение"
ЭТАП 2 - Написать код:
Используя факты из Этапа 1, напиши Python код для ответа.
Требования:
- Понятные названия переменных
- Комментарии к формулам
- Результат в переменную ans
Продвинутый вариант (два запроса):
Запрос 1 (извлечение):
Из этого документа: {документ}
Извлеки факты для вопроса: {вопрос}
Выведи только числа и их значения.
Формат: "показатель: значение"
---
Запрос 2 (код):
Факты: {факты_из_запроса_1}
Вопрос: {вопрос}
Напиши Python код используя эти факты.
Финальный ответ присвой в переменную ans.
Пояснение к плейсхолдерам:
{документ}— вставь весь текст: отчет, статью, таблицу{вопрос}— конкретный вопрос требующий вычислений{факты_из_запроса_1}— скопируй что модель извлекла на первом шаге
Второй вариант точнее для сложных задач — модель не держит в голове весь документ когда генерирует код.
Ограничения
⚠️ Многошаговые вычисления: Точность падает при сложных расчетах. Для задач с 1-2 шагами (рост = новое / старое) — 80% точности. Для >2 шагов (например "посчитай средний рост за 5 лет, потом сравни с инфляцией") — 52%. Модель теряет нить логики в длинных цепочках.
⚠️ Задачи с внешними константами: Если вопрос требует знаний не из документа (налоговые ставки, коэффициенты, формулы) — точность 54%. Модель не знает например что "ставка НДС 20%" или "формула ROE = прибыль / капитал" если это явно не указано.
⚠️ Смешанный контекст (таблицы + текст): Когда нужные числа разбросаны между таблицами и текстом — модель хуже извлекает. Точность для вопросов требующих и таблицы и текста: 68% против 81% для чисто табличных. Модель путается где искать — в структурированных данных или в прозе.
Как исследовали
Команда из Indian Institute of Technology взяла 1147 финансовых вопросов из датасета FinQA (годовые отчеты компаний) и 434 диалога из ConvFinQA (разговорные цепочки про финансы). Каждый вопрос требует извлечь числа из длинного документа (50-150 строк текста + таблицы) и сделать вычисления.
Сравнивали три подхода к извлечению фактов:
- FLAN-T5 (780 млн параметров) — instruction-tuned модель
- Mistral-7B — большая современная LLM
- APOLLO — текущий SOTA с scoring-based ретривером
Неожиданная находка: Mistral извлекает хуже чем в 9 раз меньший FLAN-T5, хотя Mistral мощнее. Причина — Mistral генерирует слишком много контекста: средний вывод 105 слов против 88 у FLAN-T5 (Table 3). Эти лишние 17 слов — не релевантные факты, а "объяснения" и "рассуждения" которые только мешают второму шагу. FLAN-T5 выдает четкий список чисел без воды.
Еще важнее: протестировали GPT-4 в трех режимах (Table 8):
- С полным отчетом сразу → делает grounding errors
- С фактами от APOLLO → лучше, но APOLLO иногда пропускает важное
- С фактами от FLAN-T5 → лучший результат
Ключевой инсайт: даже с правильными фактами, GPT-4 генерирует код с ошибками если в промпте слишком много "шума" (нерелевантных чисел). Чистота извлечения важнее полноты.
Динамический выбор примеров тоже дал прирост: вместо статичных 4 примеров "для всех задач", модель выбирала примеры похожие на конкретный вопрос (через кластеризацию тем: "рост выручки", "ROE", "амортизация"). Это добавило +3-4% точности против статичных примеров.
Оригинал из исследования
<question>
What is the amount of total Liabilities in 2019 and 2018?
<facts>
fact_1: total current liabilities is 20 in 2019
fact_2: total current liabilities is 15 in 2018
fact_3: long-term debt is 35 in 2019
fact_4: long-term debt is 30 in 2018
# Extract values from facts
current_2019 = 20
current_2018 = 15
longterm_2019 = 35
longterm_2018 = 30
# Calculate total liabilities
total_2019 = current_2019 + longterm_2019
total_2018 = current_2018 + longterm_2018
# Store answer
ans = (total_2019, total_2018)
Контекст: Исследователи тестировали формат где факты и код разделены в XML-блоки <facts> и <code>. Это помогло модели четко разграничить извлечение (что нашли) и логику (как посчитали). Нумерация фактов (fact_1, fact_2) дала модели явную структуру — легче ссылаться на конкретные числа в коде.
Ресурсы
Program of Thoughts for Financial Reasoning: Leveraging Dynamic In-Context Examples and Generative Retrieval
Subhendu Khatuya, Shashwat Naidu, Pawan Goyal, Niloy Ganguly
Indian Institute of Technology Kharagpur, 2024
