DSPy: Заміна крихкого промпт-інжинірингу компільованими конвеєрами LLM
Я постійно стикаюся з однією і тією ж проблемою, роздумуючи про фінансові ШІ-конвеєри: можна побудувати щось, що чудово працює на тестових прикладах, а потім спостерігати, як воно тихо розвалюється, коли постачальник змінює формат інвойсу або з'являється новий тип транзакції. Крихкість майже завжди полягає в промптах — написаних вручну рядках, які ніхто не хоче чіпати. DSPy, представлений Хаттабом та ін. зі Стенфорда та опублікований на ICLR 2024, пропонує принципово інший спосіб побудови конвеєрів LLM, який заслуговує на пильну увагу кожного, хто намагається автоматизувати бухгалтерську роботу.
Стаття
DSPy: Compiling Declarative Language Model Calls into Self-Improving Pipelines (Khattab, Singhvi, Maheshwari et al., ICLR 2024) переосмислює побудову конвеєрів LLM як задачу програмування, а не задачу промпт-інжинірингу. Основне спостереження полягає в тому, що сучасні LLM-додатки зазвичай будуються як набори жорстко закодованих рядків промптів — те, що автори називають "шаблонами промптів" — склеєних за допомогою логіки керування Python. Коли модель змінюється або змінюється розподіл завдань, комусь доводиться переписувати ці рядки вручну.
DSPy замінює шаблони промптів двома абстракціями: сигнатурами та модулями. Сигнатура — це типізована декларативна специфікація того, що має робити виклик мовної моделі (LM), записана компактно як question -> answer або з явними описами полів у класі Python. Модуль обгортає сигнатуру стратегією міркування — ChainOfThought, ReAct, ProgramOfThought, MultiChainComparison тощо. Вирішальним доповненням є компілятор (у статті він називається teleprompter), який бере програму DSPy, невеликий набір розмічених даних та метрику валідації, а потім автоматично генерує few-shot приклади, обирає найкращі з них і створює промпти, оптимізовані під цю метрику. Компілятору не потрібні мітки на кожному проміжному етапі — він може самостійно створювати приклади (bootstrap), запускаючи програму-"вчителя" на нерозмічених вхідних даних та фільтруючи результати, що призвели до правильних кінцевих відповідей.
Ключові ідеї
- Сигнатури відокремлюють намір від реалізації. Написання
question, context -> answerдостатньо для того, щоб DSPy знав, як побудувати, викликати та оптимізувати відповідний виклик LM. Розробник ніколи не пише рядок промпту власноруч. - Компіляція — це бутстрепінг на основі метрик. Оптимізатор
BootstrapFewShotзапускає програму на тренувальних даних, збирає траси "вхід-вихід", де конвеєр спрацював успішно, і вико ристовує їх як приклади — анотація проміжних кроків міркування людиною не потрібна. - Компілятор відкриває можливості малих моделей. На GSM8K (математичні текстові задачі) звичайна Llama2-13b отримує 9,4% при zero-shot промптингу. Після компіляції DSPy з модулями рефлексії та ансамблювання вона досягає 46,9%. T5-Large (770 млн параметрів), модель, яку більшість списала для складних міркувань, досягає 39,3% точного збігу відповідей на HotPotQA, використовуючи лише 200 розмічених прикладів.
- Експертні промпти не є лімітом. На GSM8K GPT-3.5 зі звичайним few-shot промптингом досягає 25,2%. Створений експертом ланцюжок міркувань (chain-of-thought) підвищує цей показник приблизно до 72–73%. Скомпільований DSPy конвеєр з рефлексією та ансамблем доводить його до 81,6% — без жодного написаного людиною промпту.
- Програми компонуються. Конвеєр для багатокрокових відповідей на питання (multi-hop retrieval QA) у DSPy займає близько 12 рядків коду на Python. Еквівалент у LangChain, як зазначають автори, містить 50 рядків, що перевищують 1000 символів написаного вручну контенту промптів.
- Три стадії компіляції. Оптимізатор п рацює як: генерація кандидатів (бутстрепінг трас), оптимізація параметрів (випадковий пошук або Optuna за гіперпараметрами) та оптимізація вищого порядку (ансамблі, динамічне керування потоком).
Що працює, а що — ні
Емпіричні результати реальні та суттєві. Перехід від 9,4% до 46,9% на GSM8K з Llama2-13b при використанні лише кількох розмічених тренувальних прикладів — це не інкрементальне покращення; це той тип розриву, який робить малі, дешеві моделі придатними для завдань, що раніше потребували GPT-4. Архітектура також справді елегантна: сигнатури легко читаються, модулі компонуються, а абстракція не здається "дірявою" для продемонстрованих завдань.
Однак обмеження існують, хоча в статті вони не обговорюються в окремому розділі. Найважливіше: компілятор настільки хорош, наскільки хороша ваша метрика. Якщо ваша метрика валідації неточна або не відповідає реальній якості виконання завдання — що надзвичайно ча сто трапляється на практиці — оптимізатор знайде розумні способи максимізувати її, водночас провалюючи те, що вас насправді цікавить. У такій структурованій галузі, як бухгалтерський облік, ви можете визначити метрику типу "журнальний запис збалансований", але збалансований запис все одно може мати абсолютно неправильні коди рахунків. Автори знають про цю проблему, але залишають її на розсуд розробника.
Друге обмеження: компіляція все ще потребує певних розмічених даних. У статті стверджується, що можна використовувати лише 10 прикладів з BootstrapFewShot, і що потрібні лише вхідні значення (а не проміжні мітки). Це правда в ідеальному випадку, але на практиці надійність бутстрепінгу падає, коли початкова програма не може вирішити жодного тренувального прикладу. Якщо ваш фінансовий ШІ-конвеєр має нульову базову точність — що часто буває при створенні чогось нового — компіляція може просто "буксувати" на місці.
Третє, більш тонке зауваження: DSPy оптимізує промпти та приклади, але не саму структуру програми. Якщо ви з’єднали модулі способом, який принципово не підходить для завдання, компілятор вам не допоможе. Проектування програми все ще залишається за розробником.
Чому це важливо для ШІ у фінансах
Проблема крихкості промптів, мабуть, є найбільшою практичною перешкодою для впровадження фінансових ШІ-агентів у роботу. Конвеєр, який класифікує транзакції, зіставляючи описи з кодами рахунків, буде деградувати щоразу, коли змінюється формат даних мерчанта, з'являється нова категорія витрат або оновлюється план рахунків. З DSPy ви визначаєте завдання абстрактно (transaction_description, chart_of_accounts -> account_code, confidence) і дозволяєте компілятору підібрати оптимальні приклади щоразу, коли розподіл даних змінюється.
Зокрема для Beancount я бачу конвеєр, структурований як три послідовні модулі DSPy: один витягує структуровані дані транзакцій із необроблених банківських виписок, другий шукає найбільш відповідний рахунок у чинному плані рахунків леджера, а третій перевіряє отриманий журнальний запис на відповідність правилам подвійного запису. Кожен модуль отримує власну сигнатуру; вся програма компілюється за метрикою, яка перевіряє як бухгалтерську правильність, так і відповідність формату. Проблема якості метрик тут постає найгостріше — потрібна метрика, яка виявляє неправильні коди рахунків, а не просто незбалансовані записи — але це вирішувана інженерна задача.
Глибший сенс: DSPy зміщує фокус роботи з "написання кращих промптів" на "написання кращих метрик та збір невеликих наборів розмічених даних". Це набагато стійкіша інженерна практика для промислової фінансової системи, яка має розвиватися разом зі змінами в законодавстві, структурі плану рахунків та форматах транзакцій.
Що почитати далі
- OPRO: Large Language Models as Optimizers (Yang et al., arXiv:2309.03409) — підхід Google DeepMind до оптимізації промптів через ітеративне вдосконалення, згенероване LM; корисна альтернатива підходу бутстрепінгу в DSPy.
- TextGrad: Automatic "Differentiation" via Text (Yuksekgonul et al., arXiv:2406.07496) — розглядає оптимізацію як зворотне поширення через текстовий зворотний зв'язок, а не бутстрепінг на основі метрик; показує сильні результати в програмуванні та наукових завданнях, де підхід DSPy слабший.
- DSPy Assertions: Computational Constraints for Self-Refining Language Model Pipelines (Singhvi et al., arXiv:2312.13382) — додає жорсткі та м'які обмеження до програм DSPy, дозволяючи конвеєрам самостійно виправлятися, коли вихідні дані порушують правила предметної області; безпосередньо стосується забезпечення дотримання бухгалтерських інваріантів.
