Patterns for Building LLM-based Systems & Products
Юджин Ян (Eugene Yan) разбирает семь ключевых паттернов для интеграции LLM в системы и продукты, расположенных по осям «улучшение качества vs. снижение стоимости/риска» и «ближе к данным vs. ближе к пользователю». Это: Evals (оценки) для измерения качества, RAG для добавления свежих внешних знаний, fine-tuning для специализации на задачах, кэширование для снижения задержки и стоимости, guardrails для контроля качества вывода, защитный UX (Defensive UX) для аккуратной обработки ошибок и сбор обратной связи пользователей для построения «маховика данных». Автор подробно разбирает метрики (BLEU, ROUGE, BERTScore, MoverScore) и их слабую корреляцию с человеческими оценками, чувствительность бенчмарков вроде MMLU к реализации, а также растущий тренд использования сильной LLM (например, GPT-4) как оценщика — G-Eval показал корреляцию по Спирмену 0,514 с людьми. По разделу RAG прослеживается история от DPR, RAG, FiD и RETRO до практических советов по гибридному поиску и эмбеддингам. По fine-tuning рассматриваются PEFT-техники (prompt/prefix tuning, adapters, LoRA, QLoRA), а также UX-гайдлайны Microsoft, Google и Apple.
Patterns for Building LLM-based Systems & Products
Паттерны для построения систем и продуктов на основе LLM
[ llm engineering production 🔥 ] · 66 мин чтения
Discussions on HackerNews, Twitter, and LinkedIn
Обсуждения на HackerNews, Twitter и LinkedIn
“There is a large class of problems that are easy to imagine and build demos for, but extremely hard to make products out of. For example, self-driving: It’s easy to demo a car self-driving around a block, but making it into a product takes a decade.” - Karpathy
«Есть большой класс задач, которые легко вообразить и для которых легко собрать демо, но из которых крайне трудно сделать продукт. Например, беспилотные автомобили: легко показать демо, где машина сама проезжает вокруг квартала, но превратить это в продукт занимает десятилетие». — Karpathy
This write-up is about practical patterns for integrating large language models (LLMs) into systems & products. We’ll build on academic research, industry resources, and practitioner know-how, and distill them into key ideas and practices.
Эта статья — о практических паттернах интеграции больших языковых моделей (LLM) в системы и продукты. Мы будем опираться на академические исследования, отраслевые ресурсы и практический опыт специалистов, дистиллируя их в ключевые идеи и практики.
There are seven key patterns. They’re also organized along the spectrum of improving performance vs. reducing cost/risk, and closer to the data vs. closer to the user.
Существует семь ключевых паттернов. Они также выстроены вдоль спектра «улучшение качества vs. снижение стоимости/риска» и «ближе к данным vs. ближе к пользователю».
Evals: чтобы измерять качество RAG: чтобы добавлять свежие внешние знания Fine-tuning: чтобы лучше справляться с конкретными задачами Кэширование: чтобы снижать задержку и стоимость Guardrails: чтобы обеспечивать качество вывода Защитный UX: чтобы предвосхищать и аккуратно обрабатывать ошибки Сбор обратной связи пользователей: чтобы строить маховик данных
(Also see this addendum on how to match these LLM patterns to potential problems.)
(См. также это дополнение о том, как сопоставить эти паттерны LLM с потенциальными проблемами.)
LLM patterns: From data to user, from defensive to offensive (see connections between patterns)
Паттерны LLM: от данных к пользователю, от обороны к атаке (см. связи между паттернами)
Evals: To measure performance
Evals: чтобы измерять качество
Evaluations are a set of measurements used to assess a model’s performance on a task. They include benchmark data and metrics. From a HackerNews comment:
Оценки (evals) — это набор измерений, используемых для оценки качества работы модели на задаче. Они включают эталонные данные и метрики. Из комментария на HackerNews:
How important evals are to the team is a major differentiator between folks rushing out hot garbage and those seriously building products in the space.
То, насколько важны оценки для команды, — главное отличие тех, кто выпускает откровенный мусор второпях, от тех, кто всерьёз строит продукты в этой области.
Why evals?
Зачем нужны evals?
Evals enable us to measure how well our system or product is doing and detect any regressions. (A system or product can be made up of multiple components such as LLMs, prompt templates, retrieved context, and parameters like temperature.) A representative set of evals takes us a step towards measuring system changes at scale. Without evals, we would be flying blind, or would have to visually inspect LLM outputs with each change.
Оценки позволяют измерять, насколько хорошо работает наша система или продукт, и выявлять любые регрессии. (Система или продукт могут состоять из нескольких компонентов, таких как LLM, шаблоны промптов, извлечённый контекст и параметры вроде температуры.) Репрезентативный набор оценок приближает нас к измерению изменений в системе в масштабе. Без оценок мы бы летели вслепую или были бы вынуждены визуально проверять вывод LLM при каждом изменении.
More about evals
Подробнее об оценках
There are many benchmarks in the field of language modeling. Some notable ones are:
В области языкового моделирования есть множество бенчмарков. Некоторые из заметных:
MMLU: набор из 57 задач, охватывающих элементарную математику, историю США, информатику, право и многое другое. Чтобы показывать хороший результат, модели должны обладать обширными знаниями о мире и способностью решать задачи. EleutherAI Eval: единый фреймворк для тестирования моделей в режимах zero/few-shot на 200 задачах. Включает большое число оценок, в том числе BigBench, MMLU и др. HELM: вместо конкретных задач и метрик HELM предлагает комплексную оценку LLM по множеству областей. Метрики включают точность, калибровку, устойчивость, справедливость, предвзятость, токсичность и др. Задачи включают вопрос-ответ, информационный поиск, суммаризацию, классификацию текста и др. AlpacaEval: автоматизированный фреймворк оценки, измеряющий, как часто сильная LLM (например, GPT-4) предпочитает вывод одной модели выводу референсной модели. Метрики включают win rate, предвзятость, задержку, цену, дисперсию и др. Подтверждено, что он хорошо согласуется с 20 тыс. человеческих аннотаций.
We can group metrics into two categories: context-dependent or context-free.
Метрики можно разделить на две категории: контекстно-зависимые и контекстно-независимые.
Контекстно-зависимые: учитывают контекст. Они часто предлагаются под конкретную задачу; переиспользование их для других задач потребует определённой адаптации. Контекстно-независимые: не привязаны к контексту при оценке сгенерированного вывода; они лишь сравнивают вывод с предоставленными эталонными ответами. Поскольку они не зависят от задачи, их проще применять к широкому спектру задач.
To get a better sense of these metrics (and their potential shortfalls), we’ll explore a few of the commonly used metrics such as BLEU, ROUGE, BERTScore, and MoverScore.
Чтобы лучше понять эти метрики (и их возможные недостатки), рассмотрим несколько часто используемых метрик, таких как BLEU, ROUGE, BERTScore и MoverScore.
BLEU (Bilingual Evaluation Understudy) is a precision-based metric: It counts the number of n-grams in the generated output that also show up in the reference, and then divides it by the total number of words in the output. It’s predominantly used in machine translation and remains a popular metric due to its cost-effectiveness.
BLEU (Bilingual Evaluation Understudy) — это метрика, основанная на точности (precision): она подсчитывает число n-грамм в сгенерированном выводе, которые также встречаются в эталоне, и делит его на общее число слов в выводе. Она преимущественно используется в машинном переводе и остаётся популярной благодаря своей экономичности.
First, precision for various values of \(n\) is computed:
Сначала вычисляется precision для различных значений \(n\):
\(Count_{clip}(\text{n-gram})\) is clipped by the maximum number of times an n-gram appears in any corresponding reference sentence.
\(Count_{clip}(\text{n-gram})\) обрезается по максимальному числу раз, которое n-грамма встречается в любом соответствующем эталонном предложении.
Once we’ve computed precision at various \(n\), a final BLEU-N score is computed as the geometric mean of all the \(precision_n\) scores.
После того как мы вычислили precision при различных \(n\), итоговый показатель BLEU-N вычисляется как среднее геометрическое всех значений \(precision_n\).
However, since precision relies solely on n-grams and doesn’t consider the length of the generated output, an output containing just one unigram of a common word (like a stop word) would achieve perfect precision. This can be misleading and encourage outputs that contain fewer words to increase BLEU scores. To counter this, a brevity penalty is added to penalize excessively short sentences.
Однако, поскольку precision опирается исключительно на n-граммы и не учитывает длину сгенерированного вывода, вывод, содержащий лишь одну униграмму распространённого слова (например, стоп-слова), получил бы идеальный precision. Это может вводить в заблуждение и поощрять вывод с меньшим числом слов ради повышения BLEU. Чтобы противодействовать этому, добавляется штраф за краткость (brevity penalty), наказывающий чрезмерно короткие предложения.
Thus, the final formula is:
Таким образом, итоговая формула:
ROUGE (Recall-Oriented Understudy for Gisting Evaluation): In contrast to BLEU, ROUGE is recall-oriented. It counts the number of words in the reference that also occur in the output. It’s typically used to assess automatic summarization tasks.
ROUGE (Recall-Oriented Understudy for Gisting Evaluation): в отличие от BLEU, ROUGE ориентирована на полноту (recall). Она подсчитывает число слов в эталоне, которые также встречаются в выводе. Обычно её используют для оценки задач автоматической суммаризации.
There are several ROUGE variants. ROUGE-N is most similar to BLEU in that it also counts the number of matching n-grams between the output and the reference.
Существует несколько вариантов ROUGE. ROUGE-N наиболее похожа на BLEU, поскольку также подсчитывает число совпадающих n-грамм между выводом и эталоном.
Other variants include:
Другие варианты включают:
ROUGE-L: измеряет наибольшую общую подпоследовательность (LCS) между выводом и эталоном. Она учитывает структурное сходство на уровне предложения и фокусируется на самой длинной серии совместно встречающихся последовательных n-грамм. ROUGE-S: измеряет skip-биграммы между выводом и эталоном. Skip-биграммы — это пары слов, сохраняющие свой порядок в предложении независимо от слов, которые могут оказаться между ними.
BERTScore is an embedding-based metric that uses cosine similarity to compare each token or n-gram in the generated output with the reference sentence. There are three components to BERTScore:
BERTScore — это метрика на основе эмбеддингов, которая использует косинусное сходство для сравнения каждого токена или n-граммы сгенерированного вывода с эталонным предложением. У BERTScore три компонента:
Recall: среднее косинусное сходство между каждым токеном эталона и наиболее близким к нему токеном в сгенерированном выводе. Precision: среднее косинусное сходство между каждым токеном сгенерированного вывода и ближайшим к нему токеном в эталоне. F1: гармоническое среднее recall и precision.
BERTScore is useful because it can account for synonyms and paraphrasing. Simpler metrics like BLEU and ROUGE can’t do this due to their reliance on exact matches. BERTScore has been shown to have better correlation for tasks such as image captioning and machine translation.
BERTScore полезна тем, что может учитывать синонимы и перефразирование. Более простые метрики вроде BLEU и ROUGE не способны на это из-за опоры на точные совпадения. Показано, что BERTScore лучше коррелирует с человеческими оценками в таких задачах, как описание изображений и машинный перевод.
MoverScore also uses contextualized embeddings to compute the distance between tokens in the generated output and reference. But unlike BERTScore, which is based on one-to-one matching (or “hard alignment”) of tokens, MoverScore allows for many-to-one matching (or “soft alignment”).
MoverScore также использует контекстуализированные эмбеддинги для вычисления расстояния между токенами в сгенерированном выводе и эталоне. Но в отличие от BERTScore, основанной на сопоставлении токенов один-к-одному (или «жёстком выравнивании»), MoverScore допускает сопоставление многие-к-одному (или «мягкое выравнивание»).
MoverScore enables the mapping of semantically related words in one sequence to their counterparts in another sequence. It does this by solving a constrained optimization problem that finds the minimum effort to transform one text into another. The idea is to measure the distance that words would have to move to convert one sequence to another.
MoverScore позволяет сопоставлять семантически связанные слова в одной последовательности с их аналогами в другой. Она делает это, решая задачу оптимизации с ограничениями, которая находит минимальные усилия для преобразования одного текста в другой. Идея в том, чтобы измерить расстояние, на которое словам пришлось бы переместиться, чтобы преобразовать одну последовательность в другую.
However, there are several pitfalls to using these conventional benchmarks and metrics.
Однако у использования этих традиционных бенчмарков и метрик есть несколько подводных камней.
First, there’s poor correlation between these metrics and human judgments. BLEU, ROUGE, and others have had negative correlation with how humans evaluate fluency. They also showed moderate to less correlation with human adequacy scores. In particular, BLEU and ROUGE have low correlation with tasks that require creativity and diversity.
Во-первых, наблюдается слабая корреляция между этими метриками и человеческими суждениями. BLEU, ROUGE и другие демонстрировали отрицательную корреляцию с тем, как люди оценивают беглость. Они также показывали умеренную или слабую корреляцию с человеческими оценками адекватности. В частности, BLEU и ROUGE имеют низкую корреляцию с задачами, требующими креативности и разнообразия.
Second, these metrics often have poor adaptability to a wider variety of tasks. Adopting a metric proposed for one task to another is not always prudent. For example, exact match metrics such as BLEU and ROUGE are a poor fit for tasks like abstractive summarization or dialogue. Since they’re based on n-gram overlap between output and reference, they don’t make sense for a dialogue task where a wide variety of responses are possible. An output can have zero n-gram overlap with the reference but yet be a good response.
Во-вторых, эти метрики часто плохо адаптируются к более широкому спектру задач. Применять метрику, предложенную для одной задачи, к другой не всегда разумно. Например, метрики точного совпадения вроде BLEU и ROUGE плохо подходят для задач вроде абстрактивной суммаризации или диалога. Поскольку они основаны на перекрытии n-грамм между выводом и эталоном, они не имеют смысла для диалоговой задачи, где возможен широкий спектр ответов. Вывод может иметь нулевое перекрытие n-грамм с эталоном и при этом быть хорошим ответом.
Third, these metrics have poor reproducibility. Even for the same metric, high variance is reported across different studies, possibly due to variations in human judgment collection or metric parameter settings. Another study of ROUGE scores across 2,000 studies found that scores were hard to reproduce, difficult to compare, and often incorrect because evals were often conducted with untested, incorrect ROUGE implementations.
В-третьих, эти метрики обладают плохой воспроизводимостью. Даже для одной и той же метрики в разных исследованиях сообщается о высокой дисперсии, возможно, из-за различий в сборе человеческих суждений или в настройках параметров метрики. Другое исследование показателей ROUGE по 2000 работам обнаружило, что результаты трудно воспроизвести, сложно сравнивать и часто они некорректны, потому что оценки нередко проводились с непротестированными, неправильными реализациями ROUGE.
Dimensions of model evaluations with ROUGE (source)
Измерения моделей с помощью ROUGE по различным параметрам (источник)
And even with recent benchmarks such as MMLU, the same model can get significantly different scores based on the eval implementation. Huggingface compared the original MMLU implementation with the HELM and EleutherAI implementations and found that the same example could have different prompts across various providers.
И даже с недавними бенчмарками вроде MMLU одна и та же модель может получить существенно разные результаты в зависимости от реализации оценки. Huggingface сравнил оригинальную реализацию MMLU с реализациями HELM и EleutherAI и обнаружил, что один и тот же пример может иметь разные промпты у разных провайдеров.
Different prompts for the same question across MMLU implementations (source)
Разные промпты для одного и того же вопроса в разных реализациях MMLU (источник)
Furthermore, the evaluation approach differed across all three benchmarks:
Более того, подход к оценке различался во всех трёх бенчмарках:
Оригинальный MMLU: сравнивает предсказанные вероятности только по вариантам ответа (A, B, C, D). HELM: использует вероятности следующего токена от модели и выбирает токен с наибольшей вероятностью, даже если он не является одним из вариантов. EleutherAI: вычисляет вероятность полной последовательности ответа (т. е. буквы, за которой следует текст ответа) для каждого варианта. Затем выбирает ответ с наибольшей вероятностью.
Different eval for the same question across MMLU implementations (source)
Разные способы оценки одного и того же вопроса в разных реализациях MMLU (источник)
As a result, even for the same eval, both absolute scores and model ranking can fluctuate widely depending on eval implementation. This means that model metrics aren’t truly comparable—even for the same eval—unless the eval’s implementation is identical down to minute details like prompts and tokenization. Similarly, the author of QLoRA found MMLU overly sensitive and concluded: “do not work with/report or trust MMLU scores”.
В результате даже для одной и той же оценки как абсолютные результаты, так и ранжирование моделей могут сильно колебаться в зависимости от реализации. Это означает, что метрики моделей по-настоящему несопоставимы — даже для одной и той же оценки — если реализация оценки не идентична вплоть до мельчайших деталей вроде промптов и токенизации. Аналогично, автор QLoRA обнаружил, что MMLU чрезмерно чувствителен, и заключил: «не работайте с показателями MMLU, не сообщайте их и не доверяйте им».
Beyond conventional evals such as those mentioned above, an emerging trend is to use a strong LLM as a reference-free metric to evaluate generations from other LLMs. This means we may not need human judgments or gold references for evaluation.
Помимо традиционных оценок, упомянутых выше, зарождается тренд использовать сильную LLM как безэталонную метрику для оценки генераций других LLM. Это означает, что нам, возможно, не понадобятся человеческие суждения или эталонные ответы для оценки.
G-Eval is a framework that applies LLMs with Chain-of-Though (CoT) and a form-filling paradigm to evaluate LLM outputs. First, they provide a task introduction and evaluation criteria to an LLM and ask it to generate a CoT of evaluation steps. Then, to evaluate coherence in news summarization, they concatenate the prompt, CoT, news article, and summary and ask the LLM to output a score between 1 to 5. Finally, they use the probabilities of the output tokens from the LLM to normalize the score and take their weighted summation as the final result.
G-Eval — это фреймворк, применяющий LLM с цепочкой рассуждений (Chain-of-Thought, CoT) и парадигмой заполнения формы для оценки вывода LLM. Сначала авторы дают LLM введение в задачу и критерии оценки и просят сгенерировать CoT из шагов оценки. Затем, чтобы оценить связность в суммаризации новостей, они соединяют промпт, CoT, новостную статью и краткое содержание и просят LLM выдать оценку от 1 до 5. Наконец, они используют вероятности выходных токенов LLM, чтобы нормализовать оценку, и берут их взвешенную сумму как итоговый результат.
They found that GPT-4 as an evaluator had a high Spearman correlation with human judgments (0.514), outperforming all previous methods. It also outperformed traditional metrics on aspects such as coherence, consistency, fluency, and relevance. On topical chat, it did better than traditional metrics such as ROUGE-L, BLEU-4, and BERTScore across several criteria such as naturalness, coherence, engagingness, and groundedness.
Они обнаружили, что GPT-4 в роли оценщика имел высокую корреляцию по Спирмену с человеческими суждениями (0,514), превзойдя все предыдущие методы. Он также превзошёл традиционные метрики по таким аспектам, как связность, согласованность, беглость и релевантность. На задаче topical chat он показал себя лучше традиционных метрик, таких как ROUGE-L, BLEU-4 и BERTScore, по нескольким критериям: естественность, связность, увлекательность и обоснованность.
The Vicuna paper adopted a similar approach. They start by defining eight categories (writing, roleplay, extraction, reasoning, math, coding, STEM, and humanities/social science) before developing 10 questions for each category. Next, they generated answers from five chatbots: LLaMA, Alpaca, ChatGPT, Bard, and Vicuna. Finally, they asked GPT-4 to rate the quality of the answers based on helpfulness, relevance, accuracy, and detail.
В статье про Vicuna применили похожий подход. Авторы начинают с определения восьми категорий (письмо, ролевая игра, извлечение, рассуждение, математика, программирование, STEM и гуманитарные/социальные науки), а затем разрабатывают по 10 вопросов для каждой категории. Далее они сгенерировали ответы от пяти чат-ботов: LLaMA, Alpaca, ChatGPT, Bard и Vicuna. Наконец, они попросили GPT-4 оценить качество ответов по полезности, релевантности, точности и детальности.
Overall, they found that GPT-4 not only provided consistent scores but could also give detailed explanations for those scores. Under the single answer grading paradigm, GPT-4 had higher agreement with humans (85%) than the humans had amongst themselves (81%). This suggests that GPT-4’s judgment aligns closely with the human evaluators.
В целом они обнаружили, что GPT-4 не только давал согласованные оценки, но и мог приводить подробные объяснения этих оценок. В рамках парадигмы оценки одиночного ответа GPT-4 показал большее согласие с людьми (85%), чем люди между собой (81%). Это говорит о том, что суждения GPT-4 тесно согласуются с человеческими оценщиками.
QLoRA also used an LLM to evaluate another LLM’s output. They asked GPT-4 to rate the performance of various models against gpt-3.5-turbo on the Vicuna benchmark. Given the responses from gpt-3.5-turbo and another model, GPT-4 was prompted to score both out of 10 and explain its ratings. They also measured performance via direct comparisons between models, simplifying the task to a three-class rating scheme that included ties.
QLoRA также использовала одну LLM для оценки вывода другой LLM. Авторы попросили GPT-4 оценить качество различных моделей в сравнении с gpt-3.5-turbo на бенчмарке Vicuna. Получив ответы от gpt-3.5-turbo и другой модели, GPT-4 предлагалось выставить обоим оценку по 10-балльной шкале и объяснить свои оценки. Они также измеряли качество через прямые сравнения между моделями, упрощая задачу до трёхклассовой схемы оценки, включавшей ничьи.
To validate the automated evaluation, they collected human judgments on the Vicuna benchmark. Using Mechanical Turk, they enlisted two annotators for comparisons to gpt-3.5-turbo, and three annotators for pairwise comparisons. They found that human and GPT-4 ranking of models were largely in agreement, with a Spearman rank correlation of 0.55 at the model level. This provides an additional data point suggesting that LLM-based automated evals could be a cost-effective and reasonable alternative to human evals.
Чтобы валидировать автоматизированную оценку, они собрали человеческие суждения на бенчмарке Vicuna. С помощью Mechanical Turk они привлекли двух аннотаторов для сравнений с gpt-3.5-turbo и трёх аннотаторов для попарных сравнений. Они обнаружили, что ранжирование моделей людьми и GPT-4 во многом совпадало, с ранговой корреляцией Спирмена 0,55 на уровне моделей. Это даёт ещё один аргумент в пользу того, что автоматизированные оценки на основе LLM могут быть экономичной и разумной альтернативой человеческим оценкам.
How to apply evals?
Как применять evals?
Building solid evals should be the starting point for any LLM-based system or product (as well as conventional machine learning systems).
Построение надёжных оценок должно быть отправной точкой для любой системы или продукта на основе LLM (как и для традиционных систем машинного обучения).
Unfortunately, classical metrics such as BLEU and ROUGE don’t make sense for more complex tasks such as abstractive summarization or dialogue. Furthermore, we’ve seen that benchmarks like MMLU (and metrics like ROUGE) are sensitive to how they’re implemented and measured. And to be candid, unless your LLM system is studying for a school exam, using MMLU as an eval doesn’t quite make sense.
К сожалению, классические метрики вроде BLEU и ROUGE не имеют смысла для более сложных задач, таких как абстрактивная суммаризация или диалог. Кроме того, мы убедились, что бенчмарки вроде MMLU (и метрики вроде ROUGE) чувствительны к тому, как они реализованы и измерены. И, откровенно говоря, если ваша система на LLM не готовится к школьному экзамену, использовать MMLU в качестве оценки не вполне разумно.
Thus, instead of using off-the-shelf benchmarks, we can start by collecting a set of task-specific evals (i.e., prompt, context, expected outputs as references). These evals will then guide prompt engineering, model selection, fine-tuning, and so on. And as we update our systems, we can run these evals to quickly measure improvements or regressions. Think of it as Eval Driven Development (EDD).
Поэтому вместо готовых бенчмарков мы можем начать со сбора набора оценок под конкретную задачу (т. е. промпт, контекст, ожидаемый вывод в качестве эталонов). Затем эти оценки будут направлять prompt engineering, выбор модели, fine-tuning и так далее. И по мере обновления систем мы можем прогонять эти оценки, чтобы быстро измерять улучшения или регрессии. Считайте это разработкой через оценки (Eval Driven Development, EDD).
In addition to the evaluation dataset, we also need useful metrics. They help us distill performance changes into a single number that’s comparable across eval runs. And if we can simplify the problem, we can choose metrics that are easier to compute and interpret.
Помимо набора данных для оценки, нам также нужны полезные метрики. Они помогают свести изменения качества к одному числу, сопоставимому между прогонами оценок. И если мы можем упростить задачу, мы можем выбрать метрики, которые проще вычислять и интерпретировать.
The simplest task is probably classification: If we’re using an LLM for classification-like tasks (e.g., toxicity detection, document categorization) or extractive QA without dialogue, we can rely on standard classification metrics such as recall, precision, PRAUC, etc. If our task has no correct answer but we have references (e.g., machine translation, extractive summarization), we can rely on reference metrics based on matching (BLEU, ROUGE) or semantic similarity (BERTScore, MoverScore).
Простейшая задача — это, вероятно, классификация: если мы используем LLM для задач классификационного типа (например, обнаружение токсичности, категоризация документов) или экстрактивного вопрос-ответа без диалога, мы можем опираться на стандартные классификационные метрики, такие как recall, precision, PRAUC и др. Если у задачи нет единственно верного ответа, но есть эталоны (например, машинный перевод, экстрактивная суммаризация), мы можем опираться на эталонные метрики, основанные на совпадении (BLEU, ROUGE) или семантическом сходстве (BERTScore, MoverScore).
However, these metrics may not work for more open-ended tasks such as abstractive summarization, dialogue, and others. But collecting human judgments can be slow and expensive. Thus, we may opt to lean on automated evaluations via a strong LLM.
Однако эти метрики могут не работать для более открытых задач, таких как абстрактивная суммаризация, диалог и других. Но сбор человеческих суждений может быть медленным и дорогим. Поэтому мы можем сделать выбор в пользу автоматизированных оценок с помощью сильной LLM.
Relative to human judgments which are typically noisy (due to differing biases among annotators), LLM judgments tend to be less noisy (as the bias is more systematic) but more biased. Nonetheless, since we’re aware of these biases, we can mitigate them accordingly:
По сравнению с человеческими суждениями, которые обычно зашумлены (из-за различающихся предвзятостей аннотаторов), суждения LLM, как правило, менее зашумлены (поскольку их предвзятость более систематична), но более предвзяты. Тем не менее, поскольку мы осознаём эти предвзятости, мы можем соответствующим образом их смягчать:
Предвзятость к позиции: LLM склонны отдавать предпочтение ответу на первой позиции. Чтобы смягчить это, мы можем оценивать одну и ту же пару ответов дважды, меняя их порядок местами. Если один и тот же ответ предпочтён в обоих порядках, мы засчитываем это как победу; иначе — ничья. Предвзятость к многословию: LLM склонны предпочитать более длинные, многословные ответы более лаконичным, даже если последние яснее и качественнее. Возможное решение — следить, чтобы сравниваемые ответы были схожи по длине. Предвзятость к самоусилению: у LLM есть лёгкий уклон в пользу собственных ответов. GPT-4 предпочитает себя с win rate на 10% выше, тогда как Claude-v1 предпочитает себя с win rate на 25% выше. Чтобы противодействовать этому, не используйте одну и ту же LLM для задач оценки.
Another tip: Rather than asking an LLM for a direct evaluation (via giving a score), try giving it a reference and asking for a comparison. This helps with reducing noise.
Ещё один совет: вместо того чтобы просить LLM о прямой оценке (через выставление балла), попробуйте дать ей эталон и попросить о сравнении. Это помогает снизить шум.
Finally, sometimes the best eval is human eval aka vibe check. (Not to be confused with the poorly named code evaluation benchmark HumanEval.) As mentioned in the Latent Space podcast with MosaicML (34th minute):
Наконец, иногда лучшая оценка — это человеческая оценка, она же vibe check (проверка по ощущениям). (Не путать с неудачно названным бенчмарком оценки кода HumanEval.) Как было сказано в подкасте Latent Space с MosaicML (34-я минута):
The vibe-based eval cannot be underrated. … One of our evals was just having a bunch of prompts and watching the answers as the models trained and see if they change. Honestly, I don’t really believe that any of these eval metrics capture what we care about. One of our prompts was “suggest games for a 3-year-old and a 7-year-old to play” and that was a lot more valuable to see how the answer changed during the course of training. — Jonathan Frankle
Оценку по ощущениям нельзя недооценивать. … Одной из наших оценок было просто иметь набор промптов и наблюдать за ответами по мере обучения моделей, чтобы видеть, меняются ли они. Честно говоря, я не очень верю, что какие-либо из этих метрик оценки улавливают то, что нам важно. Один из наших промптов был «предложи игры, в которые могут поиграть трёхлетний и семилетний ребёнок», и было гораздо ценнее наблюдать, как менялся ответ в ходе обучения. — Jonathan Frankle
Also see this deep dive into evals for abstractive summarization. It covers reference, context, and preference-based metrics, and also discusses hallucination detection.
См. также этот глубокий разбор оценок для абстрактивной суммаризации. Он охватывает метрики на основе эталона, контекста и предпочтений, а также обсуждает обнаружение галлюцинаций.
Retrieval-Augmented Generation: To add knowledge
Retrieval-Augmented Generation: чтобы добавлять знания
Retrieval-Augmented Generation (RAG) fetches relevant data from outside the foundation model and enhances the input with this data, providing richer context to improve output.
Retrieval-Augmented Generation (RAG) извлекает релевантные данные извне базовой модели и дополняет ими вход, предоставляя более богатый контекст для улучшения вывода.
Why RAG?
Зачем нужен RAG?
RAG helps reduce hallucination by grounding the model on the retrieved context, thus increasing factuality. In addition, it’s cheaper to keep retrieval indices up-to-date than to continuously pre-train an LLM. This cost efficiency makes it easier to provide LLMs with access to recent data via RAG. Finally, if we need to update or remove data such as biased or toxic documents, it’s more straightforward to update the retrieval index (compared to fine-tuning or prompting an LLM not to generate toxic outputs).
RAG помогает снизить галлюцинации, заземляя модель на извлечённый контекст и тем самым повышая фактологичность. Кроме того, поддерживать актуальность индексов поиска дешевле, чем непрерывно дообучать LLM. Эта экономичность упрощает предоставление LLM доступа к свежим данным через RAG. Наконец, если нам нужно обновить или удалить данные, например предвзятые или токсичные документы, обновить индекс поиска проще (по сравнению с fine-tuning или промптингом LLM, чтобы она не генерировала токсичный вывод).
In short, RAG applies mature and simpler ideas from the field of information retrieval to support LLM generation. In a recent Sequoia survey, 88% of respondents believe that retrieval will be a key component of their stack.
Короче говоря, RAG применяет зрелые и более простые идеи из области информационного поиска для поддержки генерации LLM. В недавнем опросе Sequoia 88% респондентов считают, что поиск (retrieval) станет ключевым компонентом их стека.
More about RAG
Подробнее о RAG
Before diving into RAG, it helps to have a basic understanding of text embeddings. (Feel free to skip this section if you’re familiar with the subject.)
Прежде чем погружаться в RAG, полезно иметь базовое понимание текстовых эмбеддингов. (Смело пропускайте этот раздел, если вы знакомы с темой.)
A text embedding is a compressed, abstract representation of text data where text of arbitrary length can be represented as a fixed-size vector of numbers. It’s usually learned from a corpus of text such as Wikipedia. Think of them as a universal encoding for text, where similar items are close to each other while dissimilar items are farther apart.
Текстовый эмбеддинг — это сжатое, абстрактное представление текстовых данных, где текст произвольной длины может быть представлен как вектор чисел фиксированного размера. Обычно он выучивается из корпуса текста, например Википедии. Считайте их универсальной кодировкой текста, где похожие объекты расположены близко друг к другу, а непохожие — дальше друг от друга.
A good embedding is one that does well on a downstream task, such as retrieving similar items. Huggingface’s Massive Text Embedding Benchmark (MTEB) scores various models on diverse tasks such as classification, clustering, retrieval, summarization, etc.
Хороший эмбеддинг — это тот, который хорошо справляется с целевой задачей, например с извлечением похожих объектов. Massive Text Embedding Benchmark (MTEB) от Huggingface оценивает различные модели на разнообразных задачах, таких как классификация, кластеризация, поиск, суммаризация и др.
Quick note: While we mainly discuss text embeddings here, embeddings can take many modalities. For example, CLIP is multimodal and embeds images and text in the same space, allowing us to find images most similar to an input text. We can also embed products based on user behavior (e.g., clicks, purchases) or graph relationships.
Небольшая ремарка: хотя здесь мы в основном обсуждаем текстовые эмбеддинги, эмбеддинги могут охватывать множество модальностей. Например, CLIP мультимодален и встраивает изображения и текст в одно пространство, позволяя находить изображения, наиболее похожие на входной текст. Мы также можем встраивать товары на основе поведения пользователей (например, кликов, покупок) или графовых связей.
RAG has its roots in open-domain Q&A. An early Meta paper showed that retrieving relevant documents via TF-IDF and providing them as context to a language model (BERT) improved performance on an open-domain QA task. They converted each task into a cloze statement and queried the language model for the missing token.
RAG берёт начало в открытом вопрос-ответе (open-domain Q&A). Ранняя статья Meta показала, что извлечение релевантных документов через TF-IDF и предоставление их в качестве контекста языковой модели (BERT) улучшало качество на задаче открытого вопрос-ответа. Они преобразовывали каждую задачу в cloze-утверждение и запрашивали у языковой модели пропущенный токен.
Following that, Dense Passage Retrieval (DPR) showed that using dense embeddings (instead of a sparse vector space such as TF-IDF) for document retrieval can outperform strong baselines like Lucene BM25 (65.2% vs. 42.9% for top-5 accuracy.) They also showed that higher retrieval precision translates to higher end-to-end QA accuracy, highlighting the importance of upstream retrieval.
Вслед за этим Dense Passage Retrieval (DPR) показал, что использование плотных эмбеддингов (вместо разреженного векторного пространства вроде TF-IDF) для извлечения документов может превзойти сильные базлайны, такие как Lucene BM25 (65,2% против 42,9% для top-5 accuracy). Они также показали, что более высокая точность извлечения транслируется в более высокую точность вопрос-ответа от начала до конца, что подчёркивает важность качественного извлечения на входе.
To learn the DPR embedding, they fine-tuned two independent BERT-based encoders on existing question-answer pairs. The passage encoder (\(E_p\)) embeds text passages into vectors while the query encoder (\(E_q\)) embeds questions into vectors. The query embedding is then used to retrieve \(k\) passages that are most similar to the question.
Чтобы выучить эмбеддинг DPR, они дообучили два независимых энкодера на основе BERT на существующих парах вопрос-ответ. Энкодер пассажей (\(E_p\)) встраивает текстовые фрагменты в векторы, а энкодер запросов (\(E_q\)) встраивает вопросы в векторы. Затем эмбеддинг запроса используется для извлечения \(k\) пассажей, наиболее похожих на вопрос.
They trained the encoders so that the dot-product similarity makes a good ranking function, and optimized the loss function as the negative log-likelihood of the positive passage. The DPR embeddings are optimized for maximum inner product between the question and relevant passage vectors. The goal is to learn a vector space such that pairs of questions and their relevant passages are close together.
Они обучали энкодеры так, чтобы скалярное произведение служило хорошей функцией ранжирования, и оптимизировали функцию потерь как отрицательное логарифмическое правдоподобие правильного пассажа. Эмбеддинги DPR оптимизированы под максимальное внутреннее произведение между векторами вопроса и релевантного пассажа. Цель — выучить такое векторное пространство, где пары вопросов и их релевантных пассажей расположены близко друг к другу.
For inference, they embed all passages (via \(E_p\)) and index them in FAISS offline. Then, given a question at query time, they compute the question embedding (via \(E_q\)), retrieve the top \(k\) passages via approximate nearest neighbors, and provide it to the language model (BERT) that outputs the answer to the question.
Для инференса они встраивают все пассажи (через \(E_p\)) и индексируют их в FAISS офлайн. Затем, получив вопрос во время запроса, они вычисляют эмбеддинг вопроса (через \(E_q\)), извлекают топ-\(k\) пассажей через приближённый поиск ближайших соседей и передают их языковой модели (BERT), которая выдаёт ответ на вопрос.
Retrieval Augmented Generation (RAG), from which this pattern gets its name, highlighted the downsides of pre-trained LLMs. These include not being able to expand or revise memory, not providing insights into generated output, and hallucinations.
Retrieval Augmented Generation (RAG), от которой этот паттерн и получил название, обозначила недостатки предобученных LLM. К ним относятся невозможность расширять или пересматривать память, отсутствие объяснений сгенерированного вывода и галлюцинации.
To address these downsides, they introduced RAG (aka semi-parametric models). Dense vector retrieval serves as the non-parametric component while a pre-trained LLM acts as the parametric component. They reused the DPR encoders to initialize the retriever and build the document index. For the LLM, they used BART, a 400M parameter seq2seq model.
Чтобы устранить эти недостатки, авторы представили RAG (он же полупараметрические модели). Извлечение по плотным векторам выступает непараметрическим компонентом, а предобученная LLM — параметрическим компонентом. Они переиспользовали энкодеры DPR для инициализации ретривера и построения индекса документов. В качестве LLM они использовали BART, модель seq2seq с 400 млн параметров.
During inference, they concatenate the input with the retrieved document. Then, the LLM generates \(\text{token}_i\) based on the original input, the retrieved document, and the previous \(i-1\) tokens. For generation, they proposed two approaches that vary in how the retrieved passages are used to generate output.
Во время инференса они соединяют вход с извлечённым документом. Затем LLM генерирует \(\text{token}_i\) на основе исходного входа, извлечённого документа и предыдущих \(i-1\) токенов. Для генерации они предложили два подхода, различающихся тем, как извлечённые пассажи используются для порождения вывода.
In the first approach, RAG-Sequence, the model uses the same document to generate the complete sequence. Thus, for \(k\) retrieved documents, the generator produces an output for each document. Then, the probability of each output sequence is marginalized (sum the probability of each output sequence in \(k\) and weigh it by the probability of each document being retrieved). Finally, the output sequence with the highest probability is selected.
В первом подходе, RAG-Sequence, модель использует один и тот же документ для генерации всей последовательности. Таким образом, для \(k\) извлечённых документов генератор порождает по выводу для каждого документа. Затем вероятность каждой выходной последовательности маргинализируется (суммируется вероятность каждой выходной последовательности по \(k\) и взвешивается по вероятности извлечения каждого документа). Наконец, выбирается выходная последовательность с наибольшей вероятностью.
On the other hand, RAG-Token can generate each token based on a different document. Given \(k\) retrieved documents, the generator produces a distribution for the next output token for each document before marginalizing (aggregating all the individual token distributions.). The process is then repeated for the next token. This means that, for each token generation, it can retrieve a different set of \(k\) relevant documents based on the original input and previously generated tokens. Thus, documents can have different retrieval probabilities and contribute differently to the next generated token.
С другой стороны, RAG-Token может генерировать каждый токен на основе разного документа. Получив \(k\) извлечённых документов, генератор порождает распределение для следующего выходного токена для каждого документа, прежде чем маргинализировать (агрегировать все отдельные распределения токенов). Затем процесс повторяется для следующего токена. Это означает, что при генерации каждого токена он может извлекать разный набор из \(k\) релевантных документов на основе исходного входа и ранее сгенерированных токенов. Таким образом, документы могут иметь разные вероятности извлечения и вносить разный вклад в следующий сгенерированный токен.
Fusion-in-Decoder (FiD) also uses retrieval with generative models for open-domain QA. It supports two methods for retrieval, BM25 (Lucene with default parameters) and DPR. FiD is named for how it performs fusion on the retrieved documents in the decoder only.
Fusion-in-Decoder (FiD) также использует извлечение вместе с генеративными моделями для открытого вопрос-ответа. Он поддерживает два метода извлечения — BM25 (Lucene с параметрами по умолчанию) и DPR. FiD назван так из-за того, как он выполняет слияние (fusion) извлечённых документов только в декодере.
For each retrieved passage, the title and passage are concatenated with the question. These pairs are processed independently in the encoder. They also add special tokens such as question:, title:, and context: before their corresponding sections. The decoder attends over the concatenation of these retrieved passages.
Для каждого извлечённого пассажа заголовок и пассаж соединяются с вопросом. Эти пары обрабатываются в энкодере независимо. Они также добавляют специальные токены, такие как question:, title: и context:, перед соответствующими секциями. Декодер применяет внимание к конкатенации этих извлечённых пассажей.
Because it processes passages independently in the encoder, it can scale to a large number of passages as it only needs to do self-attention over one context at a time. Thus, compute grows linearly (instead of quadratically) with the number of retrieved passages, making it more scalable than alternatives such as RAG-Token. Then, during decoding, the decoder processes the encoded passages jointly, allowing it to better aggregate context across multiple retrieved passages.
Поскольку он обрабатывает пассажи в энкодере независимо, он может масштабироваться на большое число пассажей, так как ему нужно выполнять self-attention лишь по одному контексту за раз. Таким образом, вычисления растут линейно (а не квадратично) с числом извлечённых пассажей, что делает его более масштабируемым, чем альтернативы вроде RAG-Token. Затем, во время декодирования, декодер обрабатывает закодированные пассажи совместно, что позволяет ему лучше агрегировать контекст по нескольким извлечённым пассажам.
Retrieval-Enhanced Transformer (RETRO) adopts a similar pattern where it combines a frozen BERT retriever, a differentiable encoder, and chunked cross-attention to generate output. What’s different is that RETRO does retrieval throughout the entire pre-training stage, and not just during inference. Furthermore, they fetch relevant documents based on chunks of the input. This allows for finer-grained, repeated retrieval during generation instead of only retrieving once per query.
Retrieval-Enhanced Transformer (RETRO) применяет схожий паттерн, объединяя замороженный ретривер BERT, дифференцируемый энкодер и поблочное перекрёстное внимание (chunked cross-attention) для порождения вывода. Отличие в том, что RETRO выполняет извлечение на всём этапе предобучения, а не только во время инференса. Кроме того, релевантные документы извлекаются на основе блоков входа. Это позволяет вести более тонкозернистое, повторяющееся извлечение во время генерации, а не извлекать лишь один раз на запрос.
For each input chunk (\(C_u\)), the \(k\) retrieved chunks \(RET(C_u)\) are fed into an encoder. The output is the encoded neighbors \(E^{j}_{u}\) where \(E^{j}_{u} = \text{Encoder}(\text{RET}(C_{u})^{j}, H_{u}) \in \mathbb{R}^{r \times d_{0}}\). Here, each chunk encoding is conditioned on \(H_u\) (the intermediate activations) and the activations of chunk \(C_u\) through cross-attention layers. In short, the encoding of the retrieved chunks depends on the attended activation of the input chunk. \(E^{j}_{u}\) is then used to condition the generation of the next chunk.
Для каждого входного блока (\(C_u\)) \(k\) извлечённых блоков \(RET(C_u)\) подаются в энкодер. Выходом являются закодированные соседи \(E^{j}_{u}\), где \(E^{j}_{u} = \text{Encoder}(\text{RET}(C_{u})^{j}, H_{u}) \in \mathbb{R}^{r \times d_{0}}\). Здесь кодирование каждого блока обусловлено \(H_u\) (промежуточными активациями) и активациями блока \(C_u\) через слои перекрёстного внимания. Короче говоря, кодирование извлечённых блоков зависит от активаций входного блока, к которым применено внимание. Затем \(E^{j}_{u}\) используется для обуславливания генерации следующего блока.
During retrieval, RETRO splits the input sequence into chunks of 64 tokens. Then, it finds text similar to the previous chunk to provide context to the current chunk. The retrieval index consists of two contiguous chunks of tokens, \(N\) and \(F\). The former is the neighbor chunk (64 tokens) which is used to compute the key while the latter is the continuation chunk (64 tokens) in the original document.
Во время извлечения RETRO разбивает входную последовательность на блоки по 64 токена. Затем он находит текст, похожий на предыдущий блок, чтобы предоставить контекст для текущего блока. Индекс извлечения состоит из двух смежных блоков токенов, \(N\) и \(F\). Первый — это блок-сосед (64 токена), который используется для вычисления ключа, а второй — блок-продолжение (64 токена) в исходном документе.
Retrieval is based on approximate \(k\)-nearest neighbors via \(L_2\) distance (euclidean) on BERT embeddings. (Interesting departure from the usual cosine or dot product similarity.) The retrieval index, built on SCaNN, can query a 2T token database in 10ms.
Извлечение основано на приближённом поиске \(k\) ближайших соседей по расстоянию \(L_2\) (евклидову) на эмбеддингах BERT. (Любопытное отступление от обычного косинусного сходства или скалярного произведения.) Индекс извлечения, построенный на SCaNN, может выполнять запрос к базе из 2 трлн токенов за 10 мс.
They also demonstrated how to RETRO-fit existing baseline models. By freezing the pre-trained weights and only training the chunked cross-attention and neighbor encoder parameters (< 10% of weights for a 7B model), they can enhance transformers with retrieval while only requiring 6M training sequences (3% of pre-training sequences). RETRO-fitted models were able to surpass the performance of baseline models and achieve performance close to that of RETRO trained from scratch.
Они также продемонстрировали, как RETRO-фитить существующие базовые модели. Заморозив предобученные веса и обучая только параметры поблочного перекрёстного внимания и энкодера соседей (< 10% весов для модели на 7B), они могут дополнить трансформеры извлечением, требуя при этом всего 6 млн обучающих последовательностей (3% от последовательностей предобучения). RETRO-фитнутые модели смогли превзойти качество базовых моделей и достичь качества, близкого к RETRO, обученной с нуля.
Performance from RETRO-fitting a pre-trained model (source)
Качество от RETRO-фитинга предобученной модели (источник)
Internet-augmented LMs proposes using a humble “off-the-shelf” search engine to augment LLMs. First, they retrieve a set of relevant documents via Google Search. Since these retrieved documents tend to be long (average length 2,056 words), they chunk them into paragraphs of six sentences each. Finally, they embed the question and paragraphs via TF-IDF and applied cosine similarity to rank the most relevant paragraphs for each query.
LLM, дополненные интернетом предлагают использовать скромную «готовую» поисковую систему для дополнения LLM. Сначала они извлекают набор релевантных документов через Google Search. Поскольку эти извлечённые документы обычно длинные (средняя длина 2056 слов), их разбивают на абзацы по шесть предложений каждый. Наконец, они встраивают вопрос и абзацы через TF-IDF и применяют косинусное сходство для ранжирования наиболее релевантных абзацев под каждый запрос.
The retrieved paragraphs are used to condition the LLM via few-shot prompting. They adopt the conventional \(k\)-shot prompting (\(k=15\)) from closed-book QA (only providing question-answer pairs) and extend it with an evidence paragraph, such that each context is an evidence, question, and answer triplet.
Извлечённые абзацы используются для обуславливания LLM через few-shot-промптинг. Они применяют традиционный \(k\)-shot-промптинг (\(k=15\)) из вопрос-ответа с закрытой книгой (где предоставляются только пары вопрос-ответ) и расширяют его абзацем-свидетельством, так что каждый контекст представляет собой тройку «свидетельство, вопрос, ответ».
For the generator, they used Gopher, a 280B parameter model trained on 300B tokens. For each question, they generated four candidate answers based on each of the 50 retrieved paragraphs. Finally, they select the best answer by estimating the answer probability via several methods including direct inference, RAG, noisy channel inference, and Product-of-Experts (PoE). PoE consistently performed the best.
В качестве генератора они использовали Gopher — модель на 280B параметров, обученную на 300B токенов. Для каждого вопроса они генерировали по четыре кандидата-ответа на основе каждого из 50 извлечённых абзацев. Наконец, они выбирают лучший ответ, оценивая вероятность ответа несколькими методами, включая прямой инференс, RAG, инференс по зашумлённому каналу (noisy channel) и Product-of-Experts (PoE). PoE стабильно показывал наилучший результат.
RAG has also been applied to non-QA tasks such as code generation. While CodeT5+ can be used as a standalone generator, when combined with RAG, it significantly outperforms similar models in code generation.
RAG также применялся к не-QA-задачам, таким как генерация кода. Хотя CodeT5+ можно использовать как самостоятельный генератор, в сочетании с RAG он значительно превосходит аналогичные модели в генерации кода.
To assess the impact of RAG on code generation, they evaluate the model in three settings:
Чтобы оценить влияние RAG на генерацию кода, они тестируют модель в трёх режимах:
На основе извлечения: берётся top-1 фрагмент кода в качестве предсказания. Только генерация: код выдаётся только декодером. С дополнением извлечением: top-1 фрагмент кода добавляется ко входу энкодера перед генерацией кода декодером.
As a qualitative example, they showed that retrieved code provides crucial context (e.g., use urllib3 for an HTTP request) and guides the generative process towards more correct predictions. In contrast, the generative-only approach returns incorrect output that only captures the concepts of “download” and “compress”.
В качестве качественного примера они показали, что извлечённый код предоставляет важный контекст (например, использовать urllib3 для HTTP-запроса) и направляет процесс генерации к более правильным предсказаниям. В противоположность этому подход только с генерацией возвращает некорректный вывод, который улавливает лишь понятия «скачать» и «сжать».
What if we don’t have relevance judgments for query-passage pairs? Without them, we would not be able to train the bi-encoders that embed the queries and documents in the same embedding space where relevance is represented by the inner product. Hypothetical document embeddings (HyDE) suggests a solution.
А что, если у нас нет суждений о релевантности для пар запрос-пассаж? Без них мы не смогли бы обучить би-энкодеры, которые встраивают запросы и документы в одно эмбеддинг-пространство, где релевантность представлена внутренним произведением. Гипотетические эмбеддинги документов (HyDE) предлагают решение.
Given a query, HyDE first prompts an LLM, such as InstructGPT, to generate a hypothetical document. Then, an unsupervised encoder, such as Contriver, encodes the document into an embedding vector. Finally, the inner product is computed between the hypothetical document and the corpus, and the most similar real documents are retrieved.
Получив запрос, HyDE сначала промптит LLM, например InstructGPT, сгенерировать гипотетический документ. Затем неконтролируемый (unsupervised) энкодер, например Contriver, кодирует документ в эмбеддинг-вектор. Наконец, вычисляется внутреннее произведение между гипотетическим документом и корпусом, и извлекаются наиболее похожие реальные документы.
The expectation is that the encoder’s dense bottleneck serves as a lossy compressor and the extraneous, non-factual details are excluded via the embedding. This reframes the relevance modeling problem from a representation learning task to a generation task.
Ожидание состоит в том, что плотное «бутылочное горлышко» энкодера работает как сжатие с потерями, и лишние, нефактологические детали исключаются через эмбеддинг. Это переформулирует задачу моделирования релевантности из задачи обучения представлениям в задачу генерации.
How to apply RAG
Как применять RAG
From experience with Obsidian-Copilot, I’ve found that hybrid retrieval (traditional search index + embedding-based search) works better than either alone. There, I complemented classical retrieval (BM25 via OpenSearch) with semantic search (e5-small-v2).
Из опыта работы с Obsidian-Copilot я обнаружил, что гибридный поиск (традиционный поисковый индекс + поиск на основе эмбеддингов) работает лучше, чем каждый из них по отдельности. Там я дополнил классический поиск (BM25 через OpenSearch) семантическим поиском (e5-small-v2).
Why not embedding-based search only? While it’s great in many instances, there are situations where it falls short, such as:
Почему не только поиск на основе эмбеддингов? Хотя во многих случаях он отлично работает, есть ситуации, где он не справляется, например:
gpt-3.5-turbo, titan-xlarge-v1.01)Поиск имени человека или названия объекта (например, Eugene, Kaptir 2.0) Поиск аббревиатуры или фразы (например, RAG, RLHF) Поиск идентификатора (например, gpt-3.5-turbo, titan-xlarge-v1.01)
But keyword search has its limitations too. It only models simple word frequencies and doesn’t capture semantic or correlation information. Thus, it doesn’t deal well with synonyms or hypernyms (i.e., words that represent a generalization). This is where combining it with semantic search is complementary.
Но и у поиска по ключевым словам есть свои ограничения. Он моделирует лишь простые частоты слов и не улавливает семантическую или корреляционную информацию. Поэтому он плохо справляется с синонимами или гиперонимами (т. е. словами, представляющими обобщение). Именно здесь сочетание с семантическим поиском оказывается взаимодополняющим.
In addition, with a conventional search index, we can use metadata to refine results. For example, we can use date filters to prioritize newer documents or narrow our search to a specific time period. And if the search is related to e-commerce, filters on average rating or categories are helpful. Finally, having metadata is handy for downstream ranking, such as prioritizing documents that are cited more, or boosting products by their sales volume.
Кроме того, с традиционным поисковым индексом мы можем использовать метаданные для уточнения результатов. Например, мы можем использовать фильтры по дате, чтобы отдавать приоритет более новым документам, или сузить поиск до определённого периода. А если поиск связан с e-commerce, полезны фильтры по среднему рейтингу или категориям. Наконец, наличие метаданных удобно для последующего ранжирования, например для приоритизации чаще цитируемых документов или поднятия товаров по объёму продаж.
With regard to embeddings, the seemingly popular approach is to use text-embedding-ada-002. Its benefits include ease of use via an API and not having to maintain our own embedding infra or self-host embedding models. Nonetheless, personal experience and anecdotes from others suggest there are better alternatives for retrieval.
Что касается эмбеддингов, кажущийся популярным подход — использовать text-embedding-ada-002. Его преимущества — простота использования через API и отсутствие необходимости поддерживать собственную инфраструктуру эмбеддингов или самостоятельно хостить модели эмбеддингов. Тем не менее личный опыт и свидетельства других указывают, что для извлечения есть варианты получше.
The OG embedding approaches include Word2vec and fastText. FastText is an open-source, lightweight library that enables users to leverage pre-trained embeddings or train new embedding models. It comes with pre-trained embeddings for 157 languages and is extremely fast, even without a GPU. It’s my go-to for early-stage proof of concepts.
Классические подходы к эмбеддингам включают Word2vec и fastText. FastText — это open-source, лёгкая библиотека, позволяющая пользователям задействовать предобученные эмбеддинги или обучать новые модели эмбеддингов. Она поставляется с предобученными эмбеддингами для 157 языков и крайне быстра, даже без GPU. Это мой выбор для ранних proof of concept.
Another good baseline is sentence-transformers. It makes it simple to compute embeddings for sentences, paragraphs, and even images. It’s based on workhorse transformers such as BERT and RoBERTa and is available in more than 100 languages.
Ещё один хороший базлайн — sentence-transformers. Он упрощает вычисление эмбеддингов для предложений, абзацев и даже изображений. Он основан на проверенных трансформерах вроде BERT и RoBERTa и доступен более чем на 100 языках.
More recently, instructor models have shown SOTA performance. During training, these models prepend the task description to the text. Then, when embedding new text, we simply have to describe the task to get task-specific embeddings. (Not that different from instruction tuning for embedding models IMHO.)
Совсем недавно instructor-модели показали SOTA-качество. Во время обучения эти модели предваряют текст описанием задачи. Затем, встраивая новый текст, нам достаточно описать задачу, чтобы получить эмбеддинги под конкретную задачу. (По моему мнению, не так уж отличается от instruction tuning для моделей эмбеддингов.)
An example is the E5 family of models. For open QA and information retrieval, we simply prepend documents in the index with passage:, and prepend queries with query:. If the task is symmetric (e.g., semantic similarity, paraphrase retrieval) or if we want to use embeddings as features (e.g., classification, clustering), we just use the query: prefix.
Пример — семейство моделей E5. Для открытого вопрос-ответа и информационного поиска мы просто предваряем документы в индексе префиксом passage:, а запросы — префиксом query:. Если задача симметрична (например, семантическое сходство, поиск перефразирований) или если мы хотим использовать эмбеддинги как признаки (например, для классификации, кластеризации), мы используем просто префикс query:.
The Instructor model takes it a step further, allowing users to customize the prepended prompt: “Represent the domain task_type for the task_objective:” For example, “Represent the Wikipedia document for retrieval:”. (The domain and task objective are optional). This brings the concept of prompt tuning into the field of text embedding.
Модель Instructor идёт ещё дальше, позволяя пользователям настраивать предваряющий промпт: «Represent the domain task_type for the task_objective:» Например, «Represent the Wikipedia document for retrieval:». (Домен и цель задачи опциональны.) Это привносит концепцию prompt tuning в область текстовых эмбеддингов.
Finally, as of Aug 1st, the top embedding model on the MTEB Leaderboard is the GTE family of models by Alibaba DAMO Academy. The top performing model’s size is half of the next best model e5-large-v2 (0.67GB vs 1.34GB). In 2nd position is gte-base with a model size of only 0.22GB and embedding dimension of 768. (H/T Nirant.)
Наконец, по состоянию на 1 августа топовой моделью эмбеддингов в MTEB Leaderboard является семейство моделей GTE от Alibaba DAMO Academy. Размер лучшей по качеству модели вдвое меньше, чем у следующей за ней e5-large-v2 (0,67 ГБ против 1,34 ГБ). На втором месте — gte-base с размером модели всего 0,22 ГБ и размерностью эмбеддинга 768. (Спасибо Nirant.)
To retrieve documents with low latency at scale, we use approximate nearest neighbors (ANN). It optimizes for retrieval speed and returns the approximate (instead of exact) top \(k\) most similar neighbors, trading off a little accuracy loss for a large speed up.
Чтобы извлекать документы с низкой задержкой в масштабе, мы используем приближённый поиск ближайших соседей (ANN). Он оптимизирует скорость извлечения и возвращает приближённые (а не точные) топ-\(k\) наиболее похожих соседей, разменивая небольшую потерю точности на значительный прирост скорости.
ANN embedding indices are data structures that let us do ANN searches efficiently. At a high level, they build partitions over the embedding space so we can quickly zoom in on the specific space where the query vector is. Some popular techniques include:
ANN-индексы эмбеддингов — это структуры данных, позволяющие эффективно выполнять ANN-поиск. На высоком уровне они строят разбиения эмбеддинг-пространства, чтобы мы могли быстро фокусироваться на конкретной области, где находится вектор запроса. К популярным техникам относятся:
Locality Sensitive Hashing (LSH): основная идея — создавать хеш-функции так, чтобы похожие объекты с большой вероятностью попадали в одну и ту же хеш-корзину. Проверяя только релевантные корзины, мы можем эффективно выполнять ANN-запросы. Facebook AI Similarity Search (FAISS): использует сочетание квантования и индексации для эффективного извлечения, поддерживает как CPU, так и GPU и может работать с миллиардами векторов благодаря эффективному использованию памяти. Hierarchical Navigable Small Worlds (HNSW): вдохновлённый «шестью рукопожатиями», он строит иерархическую графовую структуру, воплощающую феномен тесного мира. Здесь большинство узлов достижимы из любого другого узла за минимальное число переходов. Эта структура позволяет HNSW начинать запросы с более широких, грубых приближений и постепенно сужать поиск на нижних уровнях. Scalable Nearest Neighbors (ScaNN): работает в два этапа. Сначала грубое квантование сокращает пространство поиска. Затем выполняется тонкозернистый поиск внутри сокращённого набора. Лучший компромисс recall/latency, который я видел.
When evaluating an ANN index, some factors to consider include:
При оценке ANN-индекса стоит учесть некоторые факторы:
Recall: насколько он хорош по сравнению с точным поиском ближайших соседей? Задержка/пропускная способность: сколько запросов в секунду он может обработать? Объём памяти: сколько RAM требуется для обслуживания индекса? Простота добавления новых элементов: можно ли добавлять новые элементы без переиндексации всех документов (LSH) или индекс нужно перестраивать (ScaNN)?
No single framework is better than all others in every aspect. Thus, start by defining your functional and non-functional requirements before benchmarking. Personally, I’ve found ScaNN to be outstanding in the recall-latency trade-off (see benchmark graph here).
Ни один фреймворк не превосходит все остальные во всех аспектах. Поэтому начните с определения своих функциональных и нефункциональных требований, прежде чем проводить бенчмаркинг. Лично я нашёл, что ScaNN выдаётся по компромиссу recall-latency (см. график бенчмарка здесь).
Fine-tuning: To get better at specific tasks
Fine-tuning: чтобы лучше справляться с конкретными задачами
Fine-tuning is the process of taking a pre-trained model (that has already been trained with a vast amount of data) and further refining it on a specific task. The intent is to harness the knowledge that the model has already acquired during its pre-training and apply it to a specific task, usually involving a smaller, task-specific, dataset.
Fine-tuning — это процесс взятия предобученной модели (которая уже обучена на огромном объёме данных) и её дальнейшей доработки под конкретную задачу. Цель — задействовать знания, которые модель уже приобрела во время предобучения, и применить их к конкретной задаче, обычно с использованием меньшего, специфичного для задачи набора данных.
The term “fine-tuning” is used loosely and can refer to several concepts such as:
Термин «fine-tuning» используется довольно вольно и может относиться к нескольким понятиям, таким как:
Продолженное предобучение (continued pre-training): на данных конкретной области применяется тот же режим предобучения (предсказание следующего токена, masked language modeling) к базовой модели. Instruction fine-tuning: предобученная (базовая) модель дообучается на примерах пар «инструкция-вывод», чтобы следовать инструкциям, отвечать на вопросы, быть вайфу и т. д. Single-task fine-tuning: предобученная модель оттачивается под узкую и конкретную задачу, такую как обнаружение токсичности или суммаризация, подобно BERT и T5. Обучение с подкреплением на основе обратной связи человека (RLHF): сочетает instruction fine-tuning с обучением с подкреплением. Оно требует сбора человеческих предпочтений (например, попарных сравнений), которые затем используются для обучения модели вознаграждения. Модель вознаграждения затем используется для дальнейшего дообучения инструктированной LLM с помощью RL-техник, таких как proximal policy optimization (PPO).
We’ll mainly focus on single-task and instruction fine-tuning here.
Здесь мы сосредоточимся в основном на single-task fine-tuning и instruction fine-tuning.
Why fine-tuning?
Зачем нужен fine-tuning?
Fine-tuning an open LLM is becoming an increasingly viable alternative to using a 3rd-party, cloud-based LLM for several reasons.
Fine-tuning открытой LLM становится всё более жизнеспособной альтернативой использованию сторонней облачной LLM по нескольким причинам.
Performance & control: Fine-tuning can improve the performance of an off-the-shelf base model, and may even surpass a 3rd-party LLM. It also provides greater control over LLM behavior, resulting in a more robust system or product. Overall, fine-tuning enables us to build products that are differentiated from simply using 3rd-party or open LLMs.
Качество и контроль: fine-tuning может улучшить качество готовой базовой модели и даже превзойти стороннюю LLM. Он также обеспечивает больший контроль над поведением LLM, что приводит к более надёжной системе или продукту. В целом fine-tuning позволяет строить продукты, отличающиеся от простого использования сторонних или открытых LLM.
Modularization: Single-task fine-tuning lets us to use an army of smaller models that each specialize on their own tasks. Via this setup, a system can be modularized into individual models for tasks like content moderation, extraction, summarization, etc. Also, given that each model only has to focus on a narrow set of tasks, we can get around the alignment tax, where fine-tuning a model on one task reduces performance on other tasks.
Модуляризация: single-task fine-tuning позволяет нам использовать целую армию меньших моделей, каждая из которых специализируется на своей задаче. При такой схеме систему можно модуляризировать на отдельные модели для задач вроде модерации контента, извлечения, суммаризации и т. д. Кроме того, поскольку каждой модели нужно сосредоточиться лишь на узком наборе задач, мы можем обойти «налог на выравнивание» (alignment tax), при котором дообучение модели на одной задаче снижает качество на других задачах.
Reduced dependencies: By fine-tuning and hosting our own models, we can reduce legal concerns about proprietary data (e.g., PII, internal documents and code) being exposed to external APIs. It also gets around constraints that come with 3rd-party LLMs such as rate-limiting, high costs, or overly restrictive safety filters. By fine-tuning and hosting our own LLMs, we can ensure data doesn’t leave our network, and can scale throughput as needed.
Снижение зависимостей: дообучая и хостя собственные модели, мы можем снизить юридические опасения по поводу попадания проприетарных данных (например, PII, внутренних документов и кода) во внешние API. Это также обходит ограничения, сопутствующие сторонним LLM, такие как rate-limiting, высокая стоимость или чрезмерно строгие фильтры безопасности. Дообучая и хостя собственные LLM, мы можем гарантировать, что данные не покидают нашу сеть, и масштабировать пропускную способность по мере необходимости.
More about fine-tuning
Подробнее о fine-tuning
Why do we need to fine-tune a base model? At the risk of oversimplifying, base models are primarily optimized to predict the next word based on the corpus they’re trained on. Hence, they aren’t naturally adept at following instructions or answering questions. When posed a question, they tend to respond with more questions. Thus, we perform instruction fine-tuning so they learn to respond appropriately.
Зачем вообще дообучать базовую модель? Рискуя чрезмерно упростить: базовые модели в основном оптимизированы под предсказание следующего слова на корпусе, на котором они обучены. Поэтому они от природы не очень хорошо следуют инструкциям или отвечают на вопросы. Когда им задают вопрос, они склонны отвечать новыми вопросами. Поэтому мы выполняем instruction fine-tuning, чтобы они научились реагировать должным образом.
However, fine-tuning isn’t without its challenges. First, we need a significant volume of demonstration data. For instance, in the InstructGPT paper, they used 13k instruction-output samples for supervised fine-tuning, 33k output comparisons for reward modeling, and 31k prompts without human labels as input for RLHF.
Однако fine-tuning не лишён сложностей. Во-первых, нам нужен значительный объём демонстрационных данных. Например, в статье про InstructGPT использовали 13 тыс. образцов «инструкция-вывод» для supervised fine-tuning, 33 тыс. сравнений выводов для моделирования вознаграждения и 31 тыс. промптов без человеческих меток в качестве входа для RLHF.
Furthermore, fine-tuning comes with an alignment tax—the process can lead to lower performance on certain critical tasks. (There’s no free lunch after all.) The same InstructGPT paper found that RLHF led to performance regressions (relative to the GPT-3 base model) on public NLP tasks like SQuAD, HellaSwag, and WMT 2015 French to English. (A workaround is to have several smaller, specialized models that excel at narrow tasks.)
Кроме того, fine-tuning сопровождается налогом на выравнивание — этот процесс может приводить к снижению качества на некоторых критически важных задачах. (Бесплатного сыра, в конце концов, не бывает.) Та же статья про InstructGPT обнаружила, что RLHF приводил к регрессиям качества (относительно базовой модели GPT-3) на публичных NLP-задачах вроде SQuAD, HellaSwag и WMT 2015 (перевод с французского на английский). (Обходной путь — иметь несколько меньших, специализированных моделей, отлично справляющихся с узкими задачами.)
Fine-tuning is similar to the concept of transfer learning. As defined in Wikipedia: “Transfer learning is a technique in machine learning in which knowledge learned from a task is re-used to boost performance on a related task.” Several years ago, transfer learning made it easy for me to apply ResNet models trained on ImageNet to classify fashion products and build image search.
Fine-tuning схож с понятием transfer learning. Как определено в Википедии: «Transfer learning — это техника в машинном обучении, при которой знания, полученные на одной задаче, переиспользуются для повышения качества на связанной задаче». Несколько лет назад transfer learning позволил мне легко применить модели ResNet, обученные на ImageNet, чтобы классифицировать модные товары и построить поиск по изображениям.
ULMFit is one of the earlier papers to apply transfer learning to text. They established the protocol of self-supervised pre-training (on unlabeled data) followed by fine-tuning (on labeled data). They used AWS-LSTM, an LSTM variant with dropout at various gates.
ULMFit — одна из ранних статей, применивших transfer learning к тексту. Они утвердили протокол самоконтролируемого предобучения (на неразмеченных данных) с последующим fine-tuning (на размеченных данных). Они использовали AWS-LSTM — вариант LSTM с дропаутом на различных гейтах.
During pre-training (next word prediction), the model is trained on wikitext-103 which contains 28.6 Wikipedia articles and 103M words. Then, during target task fine-tuning, the LM is fine-tuned with data from the domain of the specific task. Finally, during classifier fine-tuning, the model is augmented with two additional linear blocks and fine-tuned on the target classification tasks which includes sentiment analysis, question classification, and topic classification.
Во время предобучения (предсказание следующего слова) модель обучается на wikitext-103, который содержит 28,6 статей Википедии и 103 млн слов. Затем, во время fine-tuning под целевую задачу, языковая модель дообучается на данных из области конкретной задачи. Наконец, во время fine-tuning классификатора модель дополняется двумя дополнительными линейными блоками и дообучается под целевые задачи классификации, включающие анализ тональности, классификацию вопросов и классификацию тем.
Since then, the pre-training followed by fine-tuning paradigm has driven much progress in language modeling. Bidirectional Encoder Representations from Transformers (BERT; encoder only) was pre-trained on masked language modeling and next sentence prediction on English Wikipedia and BooksCorpus. It was then fine-tuned on task-specific inputs and labels for single-sentence classification, sentence pair classification, single-sentence tagging, and question & answering.
С тех пор парадигма «предобучение, затем fine-tuning» обеспечила значительный прогресс в языковом моделировании. Bidirectional Encoder Representations from Transformers (BERT; только энкодер) был предобучен на masked language modeling и предсказании следующего предложения на английской Википедии и BooksCorpus. Затем он был дообучен на специфичных для задачи входах и метках для классификации одиночных предложений, классификации пар предложений, разметки одиночных предложений и вопрос-ответа.
Generative Pre-trained Transformers (GPT; decoder only) was first pre-trained on BooksCorpus via next token prediction. This was followed by single-task fine-tuning for tasks such as text classification, textual entailment, similarity, and Q&A. Interestingly, they found that including language modeling as an auxiliary objective helped the model generalize and converge faster during training.
Generative Pre-trained Transformers (GPT; только декодер) был сначала предобучен на BooksCorpus через предсказание следующего токена. За этим следовал single-task fine-tuning для задач вроде классификации текста, текстового следования (entailment), сходства и вопрос-ответа. Интересно, что они обнаружили: включение языкового моделирования как вспомогательной цели помогало модели лучше обобщать и быстрее сходиться во время обучения.
Text-to-text Transfer Transformer (T5; encoder-decoder) was pre-trained on the Colossal Clean Crawled Corpus (C4), a cleaned version of the Common Crawl from April 2019. It employed the same denoising objective as BERT, namely masked language modeling. It was then fine-tuned on tasks such as text classification, abstractive summarization, Q&A, and machine translation.
Text-to-text Transfer Transformer (T5; энкодер-декодер) был предобучен на Colossal Clean Crawled Corpus (C4) — очищенной версии Common Crawl от апреля 2019 года. Он использовал ту же denoising-цель, что и BERT, а именно masked language modeling. Затем он был дообучен на задачах вроде классификации текста, абстрактивной суммаризации, вопрос-ответа и машинного перевода.
But unlike ULMFIt, BERT, and GPT which used different classifier heads for downstream tasks, T5 represented downstream tasks as text-to-text only. For example, a translation task would have input text starting with Translation English to German:, while a summarization task might start with Summarize: or TL;DR:. The prefix essentially became a hyperparameter (first instance of prompt engineering?) This design choice allowed them to use a single fine-tuned model across a variety of downstream tasks.
Но в отличие от ULMFiT, BERT и GPT, которые использовали разные классификационные «головы» для целевых задач, T5 представлял целевые задачи исключительно в формате text-to-text. Например, задача перевода имела бы входной текст, начинающийся с Translation English to German:, тогда как задача суммаризации могла бы начинаться с Summarize: или TL;DR:. Префикс по сути стал гиперпараметром (первый случай prompt engineering?). Это решение позволило им использовать одну дообученную модель для целого ряда целевых задач.
InstructGPT expanded this idea of single-task fine-tuning to instruction fine-tuning. The base model was GPT-3, pre-trained on internet data including Common Crawl, WebText, Books, and Wikipedia. It then applied supervised fine-tuning on demonstrations of desired behavior (instruction and output). Next, it trained a reward model on the dataset of comparisons. Finally, it optimized the instructed model against the reward model via PPO, with this last stage focusing more on alignment than specific task performance.
InstructGPT расширил эту идею single-task fine-tuning до instruction fine-tuning. Базовой моделью был GPT-3, предобученный на интернет-данных, включая Common Crawl, WebText, книги и Википедию. Затем был применён supervised fine-tuning на демонстрациях желаемого поведения (инструкция и вывод). Далее обучалась модель вознаграждения на наборе сравнений. Наконец, инструктированная модель оптимизировалась относительно модели вознаграждения через PPO, причём этот последний этап был сосредоточен скорее на выравнивании, чем на качестве конкретной задачи.
Overview of fine-tuning steps in InstructGPT (source)
Обзор этапов fine-tuning в InstructGPT (источник)
Next, let’s move from fine-tuned models to fine-tuning techniques.
Далее перейдём от дообученных моделей к техникам fine-tuning.
Soft prompt tuning prepends a trainable tensor to the model’s input embeddings, essentially creating a soft prompt. Unlike discrete text prompts, soft prompts can be learned via backpropagation, meaning they can be fine-tuned to incorporate signals from any number of labeled examples.
Soft prompt tuning предваряет входные эмбеддинги модели обучаемым тензором, по сути создавая «мягкий промпт». В отличие от дискретных текстовых промптов, мягкие промпты можно обучать через обратное распространение, то есть их можно дообучать, вбирая сигналы из любого числа размеченных примеров.
Next, there’s prefix tuning. Instead of adding a soft prompt to the model input, it prepends trainable parameters to the hidden states of all transformer blocks. During fine-tuning, the LM’s original parameters are kept frozen while the prefix parameters are updated.
Далее есть prefix tuning. Вместо добавления мягкого промпта ко входу модели он предваряет обучаемыми параметрами скрытые состояния всех блоков трансформера. Во время fine-tuning исходные параметры языковой модели остаются замороженными, а параметры префикса обновляются.
The paper showed that this achieved performance comparable to full fine-tuning despite requiring updates on just 0.1% of parameters. Moreover, in settings with limited data and involved extrapolation to new topics, it outperformed full fine-tuning. One hypothesis is that training fewer parameters helped reduce overfitting on smaller target datasets.
Статья показала, что это достигает качества, сопоставимого с полным fine-tuning, несмотря на необходимость обновлять лишь 0,1% параметров. Более того, в условиях ограниченных данных и при экстраполяции на новые темы он превосходил полный fine-tuning. Одна из гипотез в том, что обучение меньшего числа параметров помогало снизить переобучение на меньших целевых наборах данных.
There’s also the adapter technique. This method adds fully connected network layers twice to each transformer block, after the attention layer and after the feed-forward network layer. On GLUE, it’s able to achieve within 0.4% of the performance of full fine-tuning by just adding 3.6% parameters per task.
Есть также техника adapter. Этот метод дважды добавляет слои полносвязной сети к каждому блоку трансформера — после слоя внимания и после слоя feed-forward сети. На GLUE он способен достичь качества в пределах 0,4% от полного fine-tuning, добавляя всего 3,6% параметров на задачу.
Low-Rank Adaptation (LoRA) is a technique where adapters are designed to be the product of two low-rank matrices. It was inspired by Aghajanyan et al. which showed that, when adapting to a specific task, pre-trained language models have a low intrinsic dimension and can still learn efficiently despite a random projection into a smaller subspace. Thus, LoRA hypothesized that weight updates during adaption also have low intrinsic rank.
Low-Rank Adaptation (LoRA) — это техника, в которой адаптеры спроектированы как произведение двух матриц низкого ранга. Она была вдохновлена работой Aghajanyan et al., которая показала, что при адаптации к конкретной задаче предобученные языковые модели имеют низкую внутреннюю размерность и всё ещё могут эффективно учиться, несмотря на случайную проекцию в меньшее подпространство. Поэтому LoRA выдвинула гипотезу, что обновления весов во время адаптации также имеют низкий внутренний ранг.
Similar to prefix tuning, they found that LoRA outperformed several baselines including full fine-tuning. Again, the hypothesis is that LoRA, thanks to its reduced rank, provides implicit regularization. In contrast, full fine-tuning, which updates all weights, could be prone to overfitting.
Подобно prefix tuning, авторы обнаружили, что LoRA превосходила несколько базлайнов, включая полный fine-tuning. И снова гипотеза в том, что LoRA, благодаря своему сниженному рангу, обеспечивает неявную регуляризацию. В противоположность этому полный fine-tuning, обновляющий все веса, может быть склонен к переобучению.
QLoRA builds on the idea of LoRA. But instead of using the full 16-bit model during fine-tuning, it applies a 4-bit quantized model. It introduced several innovations such as 4-bit NormalFloat (to quantize models), double quantization (for additional memory savings), and paged optimizers (that prevent OOM errors by transferring data to CPU RAM when the GPU runs out of memory).
QLoRA развивает идею LoRA. Но вместо использования полной 16-битной модели во время fine-tuning он применяет 4-битную квантованную модель. Он представил несколько нововведений, таких как 4-bit NormalFloat (для квантования моделей), двойное квантование (для дополнительной экономии памяти) и paged optimizers (которые предотвращают ошибки OOM, перенося данные в CPU RAM, когда у GPU заканчивается память).
As a result, QLoRA reduces the average memory requirements for fine-tuning a 65B model from > 780GB memory to a more manageable 48B without degrading runtime or predictive performance compared to a 16-bit fully fine-tuned baseline.
В результате QLoRA снижает средние требования к памяти для fine-tuning модели на 65B с > 780 ГБ памяти до более управляемых 48 ГБ, не ухудшая время выполнения или предсказательное качество по сравнению с 16-битным полностью дообученным базлайном.
(Fun fact: During a meetup with Tim Dettmers, an author of QLoRA, he quipped that double quantization was “a bit of a silly idea but works perfectly.” Hey, if it works, it works.)
(Забавный факт: на встрече с Tim Dettmers, одним из авторов QLoRA, он пошутил, что двойное квантование было «немного глупой идеей, но работает идеально». Что ж, если работает — значит работает.)
How to apply fine-tuning?
Как применять fine-tuning?
The first step is to collect demonstration data/labels. These could be for straightforward tasks such as document classification, entity extraction, or summarization, or they could be more complex such as Q&A or dialogue. Some ways to collect this data include:
Первый шаг — собрать демонстрационные данные/метки. Они могут быть для простых задач вроде классификации документов, извлечения сущностей или суммаризации, либо более сложных, таких как вопрос-ответ или диалог. Способы сбора этих данных включают:
Через экспертов или краудсорсинговых разметчиков: хотя это дорого и медленно, обычно это приводит к более качественным данным при наличии хороших инструкций. Через обратную связь пользователей: это может быть так же просто, как просить пользователей выбрать атрибуты, описывающие товар, оценивать ответы LLM лайком или дизлайком (например, ChatGPT) или логировать, какие изображения пользователи выбирают для скачивания (например, Midjourney). Запрос к более крупным открытым моделям с разрешительными лицензиями: с помощью prompt engineering мы можем суметь извлечь разумные демонстрационные данные из более крупной модели (Falcon 40B Instruct), которые можно использовать для дообучения меньшей модели. Переиспользование open-source данных: если вашу задачу можно сформулировать как задачу natural language inference (NLI), мы могли бы дообучить модель выполнять NLI с использованием данных MNLI. Затем мы можем продолжить дообучение модели на внутренних данных, чтобы классифицировать входы как следование (entailment), нейтральность или противоречие.
Note: Some LLM terms prevent users from using their output to develop other models.
Примечание: некоторые условия использования LLM запрещают пользователям применять их вывод для разработки других моделей.
Условия использования OpenAI (Раздел 2c, iii): Вы не можете использовать вывод Сервисов для разработки моделей, конкурирующих с OpenAI. Лицензионное соглашение сообщества LLaMA 2 (Раздел 1b-v): Вы не будете использовать материалы Llama или любой вывод или результаты материалов Llama для улучшения любой другой большой языковой модели (за исключением Llama 2 или производных от неё работ).
The next step is to define evaluation metrics. We’ve discussed this in a previous section.
Следующий шаг — определить метрики оценки. Мы обсуждали это в предыдущем разделе.
Then, select a pre-trained model. There are several open LLMs with permissive licenses to choose from. Excluding Llama 2 (since it isn’t fully commercial use), Falcon-40B is known to be the best-performing model. Nonetheless, I’ve found it unwieldy to fine-tune and serve in production given how heavy it is.
Затем выберите предобученную модель. Есть несколько открытых LLM с разрешительными лицензиями на выбор. Если исключить Llama 2 (поскольку она не полностью свободна для коммерческого использования), Falcon-40B известна как лучшая по качеству модель. Тем не менее я нашёл её неудобной для дообучения и обслуживания в продакшене, учитывая, насколько она тяжёлая.
Instead, I’m inclined to use smaller models like the Falcon-7B. And if we can simplify and frame the task more narrowly, BERT (340M params), RoBERTA (355M params), and BART (406M params) are solid picks for classification and natural language inference tasks. Beyond that, Flan-T5 (770M and 3B variants) is a reliable baseline for translation, abstractive summarization, headline generation, etc.
Вместо этого я склонен использовать меньшие модели вроде Falcon-7B. А если мы можем упростить и сформулировать задачу более узко, то BERT (340M параметров), RoBERTA (355M параметров) и BART (406M параметров) — солидный выбор для задач классификации и natural language inference. Помимо этого, Flan-T5 (варианты на 770M и 3B) — надёжный базлайн для перевода, абстрактивной суммаризации, генерации заголовков и т. д.
We may also need to update the model architecture, such as when the pre-trained model’s architecture doesn’t align with the task. For example, we might need to update the classification heads on BERT or T5 to match our task. Tip: If the task is a simple binary classification task, NLI models can work out of the box. Entailment is mapped to positive, contradiction is mapped to negative, while the neural label can indicate uncertainty.
Нам также может понадобиться обновить архитектуру модели, например когда архитектура предобученной модели не соответствует задаче. К примеру, нам может потребоваться обновить классификационные «головы» на BERT или T5, чтобы они соответствовали нашей задаче. Совет: если задача — простая бинарная классификация, NLI-модели могут работать «из коробки». Следование (entailment) сопоставляется с положительным классом, противоречие — с отрицательным, а нейтральная метка может указывать на неопределённость.
Then, pick a fine-tuning approach. LoRA and QLoRA are good places to start. But if your fine-tuning is more intensive, such as continued pre-training on new domain knowledge, you may find full fine-tuning necessary.
Затем выберите подход к fine-tuning. LoRA и QLoRA — хорошие отправные точки. Но если ваш fine-tuning более интенсивный, например продолженное предобучение на новых знаниях предметной области, вам может потребоваться полный fine-tuning.
Finally, basic hyperparameter tuning. Generally, most papers focus on learning rate, batch size, and number of epochs (see LoRA, QLoRA). And if we’re using LoRA, we might want to tune the rank parameter (though the QLoRA paper found that different rank and alpha led to similar results). Other hyperparameters include input sequence length, loss type (contrastive loss vs. token match), and data ratios (like the mix of pre-training or demonstration data, or the ratio of positive to negative examples, among others).
Наконец, базовая настройка гиперпараметров. Как правило, большинство статей фокусируются на скорости обучения, размере батча и числе эпох (см. LoRA, QLoRA). А если мы используем LoRA, нам, возможно, захочется настроить параметр ранга (хотя статья про QLoRA обнаружила, что разные ранг и alpha приводят к схожим результатам). К другим гиперпараметрам относятся длина входной последовательности, тип функции потерь (контрастная потеря vs. совпадение токенов) и пропорции данных (например, смесь данных предобучения и демонстрационных данных или соотношение положительных и отрицательных примеров и др.).
Caching: To reduce latency and cost
Кэширование: чтобы снижать задержку и стоимость
Caching is a technique to store data that has been previously retrieved or computed. This way, future requests for the same data can be served faster. In the space of serving LLM generations, the popularized approach is to cache the LLM response keyed on the embedding of the input request. Then, for each new request, if a semantically similar request is received, we can serve the cached response.
Кэширование — это техника хранения данных, которые ранее были извлечены или вычислены. Так будущие запросы на те же данные могут обслуживаться быстрее. В области обслуживания генераций LLM популяризованный подход — кэшировать ответ LLM по ключу, которым служит эмбеддинг входного запроса. Затем для каждого нового запроса, если получен семантически похожий запрос, мы можем выдать закэшированный ответ.
For some practitioners, this sounds like “a disaster waiting to happen.” I’m inclined to agree. Thus, I think the key to adopting this pattern is figuring out how to cache safely, instead of solely depending on semantic similarity.
Для некоторых практиков это звучит как «катастрофа, которая только и ждёт случиться». Я склонен согласиться. Поэтому я думаю, что ключ к внедрению этого паттерна — выяснить, как кэшировать безопасно, а не полагаться исключительно на семантическое сходство.
Why caching?
Зачем нужно кэширование?
Caching can significantly reduce latency for responses that have been served before. In addition, by eliminating the need to compute a response for the same input again and again, we can reduce the number of LLM requests and thus save cost. Also, there are certain use cases that do not support latency on the order of seconds. Thus, pre-computing and caching may be the only way to serve those use cases.
Кэширование может значительно снизить задержку для ответов, которые уже обслуживались ранее. Кроме того, устраняя необходимость снова и снова вычислять ответ на один и тот же вход, мы можем сократить число запросов к LLM и тем самым сэкономить. Также есть определённые сценарии использования, которые не допускают задержку порядка секунд. Поэтому предвычисление и кэширование могут быть единственным способом обслуживать такие сценарии.
More about caching
Подробнее о кэшировании
A cache is a high-speed storage layer that stores a subset of data that’s accessed more frequently. This lets us serve these requests faster via the cache instead of the data’s primary storage (e.g., search index, relational database). Overall, caching enables efficient reuse of previously fetched or computed data. (More about caching and best practices.)
Кэш — это высокоскоростной слой хранения, который хранит подмножество данных, обращения к которым происходят чаще. Это позволяет нам обслуживать такие запросы быстрее через кэш, а не через основное хранилище данных (например, поисковый индекс, реляционную базу данных). В целом кэширование обеспечивает эффективное переиспользование ранее извлечённых или вычисленных данных. (Подробнее о кэшировании и лучших практиках.)
When a new request is received:
Когда поступает новый запрос:
text-embedding-ada-002, FastText, Sentence Transformers, and more.Генератор эмбеддингов: встраивает запрос с помощью различных моделей, таких как text-embedding-ada-002 от OpenAI, FastText, Sentence Transformers и др. Оценщик сходства: вычисляет сходство запроса через векторное хранилище, а затем выдаёт метрику расстояния. Векторное хранилище может быть локальным (FAISS, Hnswlib) или облачным. Оно также может вычислять сходство с помощью модели. Хранилище кэша: если запрос похож, закэшированный ответ извлекается и выдаётся. LLM: если запрос недостаточно похож, он передаётся LLM, которая затем генерирует результат. Наконец, ответ выдаётся и кэшируется для будущего использования.
Redis also shared a similar example, mentioning that some teams go as far as precomputing all the queries they anticipate receiving. Then, they set a similarity threshold on which queries are similar enough to warrant a cached response.
Redis также поделился похожим примером, упомянув, что некоторые команды доходят до того, что предвычисляют все запросы, которые они ожидают получить. Затем они задают порог сходства, определяющий, какие запросы достаточно похожи, чтобы оправдать закэшированный ответ.
How to apply caching?
Как применять кэширование?
We should start with having a good understanding of user request patterns. This allows us to design the cache thoughtfully so it can be applied reliably.
Нам следует начать с хорошего понимания паттернов запросов пользователей. Это позволяет нам продуманно спроектировать кэш, чтобы его можно было применять надёжно.
First, let’s consider a non-LLM example. Imagine we’re caching product prices for an e-commerce site. During checkout, is it safe to display the (possibly outdated) cached price? Probably not, since the price the customer sees during checkout should be the same as the final amount they’re charged. Caching isn’t appropriate here as we need to ensure consistency for the customer.
Сначала рассмотрим не-LLM пример. Представьте, что мы кэшируем цены товаров для e-commerce-сайта. Во время оформления заказа безопасно ли показывать (возможно, устаревшую) закэшированную цену? Вероятно, нет, поскольку цена, которую покупатель видит при оформлении, должна совпадать с итоговой суммой, которую с него спишут. Кэширование здесь неуместно, так как нам нужно обеспечить согласованность для покупателя.
Now, bringing it back to LLM responses. Imagine we get a request for a summary of “Mission Impossible 2” that’s semantically similar enough to “Mission Impossible 3”. If we’re looking up cache based on semantic similarity, we could serve the wrong response.
Теперь вернёмся к ответам LLM. Представьте, что мы получаем запрос на краткое содержание «Миссия невыполнима 2», которое семантически достаточно похоже на «Миссия невыполнима 3». Если мы ищем по кэшу на основе семантического сходства, мы можем выдать неверный ответ.
We also need to consider if caching is effective for the usage pattern. One way to quantify this is via the cache hit rate (percentage of requests served directly from the cache). If the usage pattern is uniformly random, the cache would need frequent updates. Thus, the effort to keep the cache up-to-date could negate any benefit a cache has to offer. On the other hand, if the usage follows a power law where a small proportion of unique requests account for the majority of traffic (e.g., search queries, product views), then caching could be an effective strategy.
Нам также нужно учесть, эффективно ли кэширование для данного паттерна использования. Один из способов это количественно оценить — через коэффициент попаданий в кэш (процент запросов, обслуженных напрямую из кэша). Если паттерн использования равномерно случаен, кэш потребовал бы частых обновлений. Тогда усилия на поддержание актуальности кэша могли бы свести на нет любую его выгоду. С другой стороны, если использование следует степенному закону, при котором небольшая доля уникальных запросов составляет большинство трафика (например, поисковые запросы, просмотры товаров), то кэширование может быть эффективной стратегией.
Beyond semantic similarity, we could also explore caching based on:
Помимо семантического сходства, мы могли бы также рассмотреть кэширование на основе:
ID объектов: применимо, когда мы предвычисляем краткие выжимки отзывов о товарах или генерируем краткое содержание для целой кинотрилогии. Пар ID объектов: например, когда мы генерируем сравнения двух фильмов. Хотя это выглядит как \(O(N^2)\), на практике небольшое число комбинаций обеспечивает основную долю трафика, например сравнение популярных фильмов одной серии или жанра. Ограниченного входа: например, переменные вроде жанра фильма, режиссёра или ведущего актёра. К примеру, если пользователь ищет фильмы конкретного режиссёра, мы могли бы выполнить структурированный запрос и прогнать его через LLM, чтобы изящнее оформить ответ. Другой пример — генерация кода на основе выбора из выпадающих списков: если код проверен и работает, мы можем закэшировать его для надёжного переиспользования.
Also, caching doesn’t only have to occur on-the-fly. As Redis shared, we can pre-compute LLM generations offline or asynchronously before serving them. By serving from a cache, we shift the latency from generation (typically seconds) to cache lookup (milliseconds). Pre-computing in batch can also help reduce cost relative to serving in real-time.
Кроме того, кэширование не обязательно должно происходить «на лету». Как поделился Redis, мы можем предвычислять генерации LLM офлайн или асинхронно, прежде чем их выдавать. Обслуживая из кэша, мы смещаем задержку с генерации (обычно секунды) на поиск в кэше (миллисекунды). Предвычисление пакетами также может помочь снизить стоимость по сравнению с обслуживанием в реальном времени.
While the approaches listed here may not be as flexible as semantically caching on natural language inputs, I think it provides a good balance between efficiency and reliability.
Хотя перечисленные здесь подходы могут быть не такими гибкими, как семантическое кэширование на естественно-языковых входах, я думаю, что они дают хороший баланс между эффективностью и надёжностью.
Guardrails: To ensure output quality
Guardrails: чтобы обеспечивать качество вывода
In the context of LLMs, guardrails validate the output of LLMs, ensuring that the output doesn’t just sound good but is also syntactically correct, factual, and free from harmful content. It also includes guarding against adversarial input.
В контексте LLM guardrails (ограждения) валидируют вывод LLM, обеспечивая, что вывод не просто хорошо звучит, но и синтаксически корректен, фактологичен и свободен от вредоносного контента. Это также включает защиту от состязательного (adversarial) ввода.
Why guardrails?
Зачем нужны guardrails?
First, they help ensure that model outputs are reliable and consistent enough to use in production. For example, we may require output to be in a specific JSON schema so that it’s machine-readable, or we need code generated to be executable. Guardrails can help with such syntactic validation.
Во-первых, они помогают обеспечить, чтобы выводы модели были достаточно надёжными и согласованными для использования в продакшене. Например, нам может требоваться вывод в определённой JSON-схеме, чтобы он был машиночитаемым, или нам нужно, чтобы сгенерированный код был исполняемым. Guardrails могут помочь с такой синтаксической валидацией.
Second, they provide an additional layer of safety and maintain quality control over an LLM’s output. For example, to verify if the content generated is appropriate for serving, we may want to check that the output isn’t harmful, verify it for factual accuracy, or ensure coherence with the context provided.
Во-вторых, они обеспечивают дополнительный слой безопасности и поддерживают контроль качества над выводом LLM. Например, чтобы проверить, уместен ли сгенерированный контент для выдачи, мы можем захотеть убедиться, что вывод не вреден, проверить его на фактическую точность или обеспечить согласованность с предоставленным контекстом.
More about guardrails
Подробнее о guardrails
One approach is to control the model’s responses via prompts. For example, Anthropic shared about prompts designed to guide the model toward generating responses that are helpful, harmless, and honest (HHH). They found that Python fine-tuning with the HHH prompt led to better performance compared to fine-tuning with RLHF.
Один из подходов — управлять ответами модели через промпты. Например, Anthropic поделилась о промптах, спроектированных для направления модели к генерации ответов, которые полезны, безвредны и честны (helpful, harmless, and honest — HHH). Они обнаружили, что fine-tuning на Python с HHH-промптом привёл к лучшему качеству по сравнению с fine-tuning с RLHF.
A more common approach is to validate the output. An example is the Guardrails package. It allows users to add structural, type, and quality requirements on LLM outputs via Pydantic-style validation. And if the check fails, it can trigger corrective action such as filtering on the offending output or regenerating another response.
Более распространённый подход — валидировать вывод. Пример — пакет Guardrails. Он позволяет пользователям добавлять требования к структуре, типу и качеству вывода LLM через валидацию в стиле Pydantic. И если проверка не проходит, он может запустить корректирующее действие, например отфильтровать проблемный вывод или сгенерировать другой ответ.
Most of the validation logic is in validators.py. It’s interesting to see how they’re implemented. Broadly speaking, its validators fall into the following categories:
Большая часть логики валидации находится в validators.py. Интересно посмотреть, как они реализованы. В широком смысле его валидаторы делятся на следующие категории:
Валидация одиночного выходного значения: включает проверку того, что вывод (i) является одним из заранее заданных вариантов, (ii) имеет длину в определённом диапазоне, (iii) если числовой, попадает в ожидаемый диапазон, и (iv) является полным предложением. Синтаксические проверки: включают проверку того, что сгенерированные URL валидны и доступны, а код на Python и SQL не содержит ошибок. Семантические проверки: проверяют, что вывод согласован с эталонным документом или что экстрактивная выжимка близко соответствует исходному документу. Эти проверки можно выполнять через косинусное сходство или техники нечёткого сопоставления. Проверки безопасности: обеспечивают, что сгенерированный вывод свободен от неуместной лексики или что качество переведённого текста высоко.
Nvidia’s NeMo-Guardrails follows a similar principle but is designed to guide LLM-based conversational systems. Rather than focusing on syntactic guardrails, it emphasizes semantic ones. This includes ensuring that the assistant steers clear of politically charged topics, provides factually correct information, and can detect jailbreaking attempts.
NeMo-Guardrails от Nvidia следует схожему принципу, но спроектирован для направления диалоговых систем на основе LLM. Вместо фокуса на синтаксических ограждениях он делает упор на семантические. Это включает обеспечение того, чтобы ассистент держался подальше от политически заряженных тем, предоставлял фактологически корректную информацию и мог обнаруживать попытки джейлбрейка.
Thus, NeMo’s approach is somewhat different: Instead of using more deterministic checks like verifying if a value exists in a list or inspecting code for syntax errors, NeMo leans heavily on using another LLM to validate outputs (inspired by SelfCheckGPT).
Таким образом, подход NeMo несколько иной: вместо использования более детерминированных проверок, таких как проверка наличия значения в списке или инспекция кода на синтаксические ошибки, NeMo сильно опирается на использование другой LLM для валидации выводов (вдохновлено SelfCheckGPT).
In their example for fact-checking and preventing hallucination, they ask the LLM itself to check whether the most recent output is consistent with the given context. To fact-check, the LLM is queried if the response is true based on the documents retrieved from the knowledge base. To prevent hallucinations, since there isn’t a knowledge base available, they get the LLM to generate multiple alternative completions which serve as the context. The underlying assumption is that if the LLM produces multiple completions that disagree with one another, the original completion is likely a hallucination.
В их примере для проверки фактов и предотвращения галлюцинаций они просят саму LLM проверить, согласован ли самый последний вывод с данным контекстом. Чтобы проверить факты, у LLM спрашивают, истинен ли ответ на основе документов, извлечённых из базы знаний. Чтобы предотвратить галлюцинации, поскольку база знаний недоступна, они заставляют LLM сгенерировать несколько альтернативных завершений, которые служат контекстом. Базовое предположение в том, что если LLM выдаёт несколько завершений, которые противоречат друг другу, то исходное завершение, вероятно, является галлюцинацией.
The moderation example follows a similar approach: The response is screened for harmful and unethical content via an LLM. Given the nuance of ethics and harmful content, heuristics and conventional machine learning techniques fall short. Thus, an LLM is required for a deeper understanding of the intent and structure of dialogue.
Пример модерации следует похожему подходу: ответ проверяется на вредоносный и неэтичный контент с помощью LLM. Учитывая нюансы этики и вредоносного контента, эвристики и традиционные техники машинного обучения здесь не дотягивают. Поэтому LLM необходима для более глубокого понимания намерения и структуры диалога.
Apart from using guardrails to verify the output of LLMs, we can also directly steer the output to adhere to a specific grammar. An example of this is Microsoft’s Guidance. Unlike Guardrails which imposes JSON schema via a prompt, Guidance enforces the schema by injecting tokens that make up the structure.
Помимо использования guardrails для проверки вывода LLM, мы также можем напрямую направлять вывод к соответствию определённой грамматике. Пример этого — Guidance от Microsoft. В отличие от Guardrails, которая навязывает JSON-схему через промпт, Guidance обеспечивает соблюдение схемы, внедряя токены, составляющие структуру.
We can think of Guidance as a domain-specific language for LLM interactions and output. It draws inspiration from Handlebars, a popular templating language used in web applications that empowers users to perform variable interpolation and logical control.
Можно думать о Guidance как о предметно-ориентированном языке (DSL) для взаимодействий с LLM и их вывода. Он черпает вдохновение из Handlebars — популярного шаблонизатора, используемого в веб-приложениях, который позволяет пользователям выполнять интерполяцию переменных и логическое управление.
However, Guidance sets itself apart from regular templating languages by executing linearly. This means it maintains the order of tokens generated. Thus, by inserting tokens that are part of the structure—instead of relying on the LLM to generate them correctly—Guidance can dictate the specific output format. In their examples, they show how to generate JSON that’s always valid, generate complex output formats with multiple keys, ensure that LLMs play the right roles, and have agents interact with each other.
Однако Guidance отличается от обычных шаблонизаторов тем, что выполняется линейно. Это значит, что он сохраняет порядок генерируемых токенов. Поэтому, вставляя токены, являющиеся частью структуры, — вместо того чтобы полагаться на корректную генерацию их самой LLM, — Guidance может диктовать конкретный формат вывода. В своих примерах они показывают, как генерировать всегда валидный JSON, генерировать сложные форматы вывода с несколькими ключами, обеспечивать, чтобы LLM играли правильные роли, и заставлять агентов взаимодействовать друг с другом.
They also introduced a concept called token healing, a useful feature that helps avoid subtle bugs that occur due to tokenization. In simple terms, it rewinds the generation by one token before the end of the prompt and then restricts the first generated token to have a prefix matching the last token in the prompt. This eliminates the need to fret about token boundaries when crafting prompts.
Они также представили концепцию под названием token healing — полезную функцию, помогающую избегать тонких багов, возникающих из-за токенизации. Простыми словами, она откатывает генерацию на один токен назад до конца промпта, а затем ограничивает первый сгенерированный токен так, чтобы он имел префикс, совпадающий с последним токеном промпта. Это избавляет от необходимости беспокоиться о границах токенов при составлении промптов.
How to apply guardrails?
Как применять guardrails?
Though the concept of guardrails for LLMs in industry is still nascent, there are a handful of immediately useful and practical strategies we can consider.
Хотя концепция guardrails для LLM в индустрии всё ещё в зачаточном состоянии, есть несколько сразу полезных и практичных стратегий, которые мы можем рассмотреть.
Structural guidance: Apply guidance whenever possible. It provides direct control over outputs and offers a more precise method to ensure that output conforms to a specific structure or format.
Структурное направление (structural guidance): применяйте guidance везде, где это возможно. Оно даёт прямой контроль над выводом и предлагает более точный метод обеспечить соответствие вывода определённой структуре или формату.
Syntactic guardrails: These include checking if categorical output is within a set of acceptable choices, or if numeric output is within an expected range. Also, if we generate SQL, these can verify its free from syntax errors and also ensure that all columns in the query match the schema. Ditto for generating code (e.g., Python, JavaScript).
Синтаксические guardrails: включают проверку того, что категориальный вывод входит в набор допустимых вариантов, или что числовой вывод попадает в ожидаемый диапазон. Также, если мы генерируем SQL, они могут проверить, что он свободен от синтаксических ошибок, а также убедиться, что все столбцы в запросе соответствуют схеме. То же касается генерации кода (например, Python, JavaScript).
Content safety guardrails: These verify that the output has no harmful or inappropriate content. It can be as simple as checking against the List of Dirty, Naughty, Obscene, and Otherwise Bad Words or using profanity detection models. (It’s common to run moderation classifiers on output.) More complex and nuanced output can rely on an LLM evaluator.
Guardrails безопасности контента: проверяют, что вывод не содержит вредоносного или неуместного контента. Это может быть так же просто, как сверка со Списком грязных, непристойных, нецензурных и иных плохих слов или использование моделей обнаружения ненормативной лексики. (Запуск классификаторов модерации на выводе — обычное дело.) Более сложный и нюансированный вывод может опираться на LLM-оценщик.
Semantic/factuality guardrails: These confirm that the output is semantically relevant to the input. Say we’re generating a two-sentence summary of a movie based on its synopsis. We can validate if the produced summary is semantically similar to the output, or have (another) LLM ascertain if the summary accurately represents the provided synopsis.
Семантические/фактологические guardrails: подтверждают, что вывод семантически релевантен входу. Скажем, мы генерируем краткое содержание фильма из двух предложений на основе его синопсиса. Мы можем проверить, семантически ли похоже полученное содержание на вывод, или поручить (другой) LLM установить, точно ли содержание отражает предоставленный синопсис.
Input guardrails: These limit the types of input the model will respond to, helping to mitigate the risk of the model responding to inappropriate or adversarial prompts which would lead to generating harmful content. For example, you’ll get an error if you ask Midjourney to generate NSFW content. This can be as straightforward as comparing against a list of strings or using a moderation classifier.
Guardrails ввода: ограничивают типы ввода, на которые модель будет отвечать, помогая снизить риск того, что модель ответит на неуместные или состязательные промпты, ведущие к генерации вредоносного контента. Например, вы получите ошибку, если попросите Midjourney сгенерировать NSFW-контент. Это может быть так же прямолинейно, как сравнение со списком строк или использование классификатора модерации.
An example of an input guardrail on Midjourney
Пример guardrail на вводе в Midjourney
Defensive UX: To anticipate & handle errors gracefully
Защитный UX: чтобы предвосхищать и аккуратно обрабатывать ошибки
Defensive UX is a design strategy that acknowledges that bad things, such as inaccuracies or hallucinations, can happen during user interactions with machine learning or LLM-based products. Thus, the intent is to anticipate and manage these in advance, primarily by guiding user behavior, averting misuse, and handling errors gracefully.
Защитный UX (Defensive UX) — это стратегия проектирования, признающая, что во время взаимодействия пользователей с продуктами на основе машинного обучения или LLM могут происходить нежелательные вещи, такие как неточности или галлюцинации. Поэтому цель — предвосхищать и управлять ими заранее, прежде всего направляя поведение пользователя, предотвращая неправильное использование и аккуратно обрабатывая ошибки.
Why defensive UX?
Зачем нужен защитный UX?
Machine learning and LLMs aren’t perfect—they can produce inaccurate output. Also, they respond differently to the same input over time, such as search engines displaying varying results due to personalization, or LLMs generating diverse output on more creative, higher temperature, settings. This can violate the principle of consistency which advocates for a consistent UI and predictable behaviors.
Машинное обучение и LLM несовершенны — они могут выдавать неточный вывод. Кроме того, они по-разному реагируют на один и тот же вход с течением времени, например когда поисковые системы показывают разные результаты из-за персонализации, или когда LLM генерируют разнообразный вывод при более творческих настройках с высокой температурой. Это может нарушать принцип согласованности, который выступает за согласованный UI и предсказуемое поведение.
Defensive UX can help mitigate the above by providing:
Защитный UX может помочь смягчить вышеперечисленное, обеспечивая:
Повышенную доступность: помогая пользователям понять, как работают ML/LLM-функции и каковы их ограничения, защитный UX делает их более доступными и удобными. Повышенное доверие: когда пользователи видят, что функция способна аккуратно справляться со сложными сценариями и не выдаёт вредоносный вывод, они с большей вероятностью будут ей доверять. Лучший UX: проектируя систему и UX так, чтобы справляться с неоднозначными ситуациями и ошибками, защитный UX прокладывает путь к более гладкому и приятному пользовательскому опыту.
More about defensive UX
Подробнее о защитном UX
To learn more about defensive UX, we can look at Human-AI guidelines from Microsoft, Google, and Apple.
Чтобы узнать больше о защитном UX, можно обратиться к гайдлайнам по взаимодействию человека и ИИ от Microsoft, Google и Apple.
Microsoft’s Guidelines for Human-AI Interaction is based on a survey of 168 potential guidelines. These were collected from internal and external industry sources, academic literature, and public articles. After combining guidelines that were similar, filtering guidelines that were too vague or too specific or not AI-specific, and a round of heuristic evaluation, they narrowed it down to 18 guidelines.
Guidelines for Human-AI Interaction от Microsoft основаны на обзоре 168 потенциальных рекомендаций. Они были собраны из внутренних и внешних отраслевых источников, академической литературы и публичных статей. После объединения схожих рекомендаций, отсева слишком расплывчатых, слишком конкретных или не специфичных для ИИ, а также раунда эвристической оценки они сузили их до 18 рекомендаций.
Guidelines for Human-AI interaction across the user journey (source)
Рекомендации по взаимодействию человека и ИИ на протяжении пользовательского пути (источник)
These guidelines follow a certain style: Each one is a succinct action rule of 3 - 10 words, beginning with a verb. Each rule is accompanied by a one-liner that addresses potential ambiguities. They are organized based on their likely application during user interaction:
Эти рекомендации следуют определённому стилю: каждая из них — это сжатое правило-действие из 3–10 слов, начинающееся с глагола. Каждое правило сопровождается однострочным пояснением, устраняющим возможные неоднозначности. Они организованы по их вероятному применению в ходе взаимодействия с пользователем:
В начале: проясните, что система может делать (G1), проясните, насколько хорошо система может делать то, что она умеет (G2). Во время взаимодействия: соотносите подачу сервисов с контекстом (G3), смягчайте социальные предвзятости (G6). Когда ошибка: поддерживайте удобное отклонение (G8), поддерживайте удобное исправление (G9). Со временем: учитесь на поведении пользователя (G13), предоставляйте глобальные элементы управления (G17).
Google’s People + AI Guidebook is rooted in data and insights drawn from Google’s product team and academic research. In contrast to Microsoft’s guidelines which are organized around the user, Google organizes its guidelines into concepts that a developer needs to keep in mind.
People + AI Guidebook от Google укоренён в данных и выводах, полученных от продуктовой команды Google и академических исследований. В отличие от рекомендаций Microsoft, организованных вокруг пользователя, Google организует свои рекомендации вокруг концепций, которые разработчику нужно держать в уме.
There are 23 patterns grouped around common questions that come up during the product development process, including:
Есть 23 паттерна, сгруппированных вокруг распространённых вопросов, возникающих в процессе разработки продукта, включая:
Как мне начать с человекоцентричного ИИ: определить, добавляет ли ИИ ценность, рано вложиться в хорошие практики работы с данными (например, оценки). Как мне онбордить пользователей в новые ИИ-функции: сделать исследование безопасным, опереться на знакомое, автоматизировать поэтапно. Как мне помочь пользователям выстроить доверие к моему продукту: задать правильные ожидания, быть прозрачным, автоматизировать сильнее, когда риск низок.
Apple’s Human Interface Guidelines for Machine Learning differs from the bottom-up approach of academic literature and user studies. Instead, its primary source is practitioner knowledge and experience. Thus, it doesn’t include many references or data points, but instead focuses on Apple’s longstanding design principles. This results in a unique perspective that distinguishes it from the other two guidelines.
Human Interface Guidelines for Machine Learning от Apple отличается от восходящего подхода академической литературы и пользовательских исследований. Вместо этого её первичный источник — знания и опыт практиков. Поэтому она не включает много ссылок или данных, а вместо этого фокусируется на давних принципах дизайна Apple. Это даёт уникальную перспективу, отличающую её от двух других гайдлайнов.
The document focuses on how Apple’s design principles can be applied to ML-infused products, emphasizing aspects of UI rather than model functionality. It starts by asking developers to consider the role of ML in their app and work backwards from the user experience. This includes questions such as whether ML is:
Документ фокусируется на том, как принципы дизайна Apple могут быть применены к продуктам, насыщенным ML, делая упор на аспекты UI, а не на функциональность модели. Он начинается с просьбы к разработчикам обдумать роль ML в их приложении и работать в обратную сторону от пользовательского опыта. Это включает вопросы вроде того, является ли ML:
Критичным или дополняющим: например, Face ID не может работать без ML, но клавиатура всё ещё может работать без QuickType. Проактивным или реактивным: Siri Suggestions проактивны, тогда как автокоррекция реактивна. Динамическим или статическим: рекомендации динамичны, тогда как распознавание объектов в Photos улучшается только с каждым релизом iOS.
It then delves into several patterns, split into inputs and outputs of a system. Inputs focus on explicit feedback, implicit feedback, calibration, and corrections. This section guides the design for how AI products request and process user data and interactions. Outputs focus on mistakes, multiple options, confidence, attribution, and limitations. The intent is to ensure the model’s output is presented in a comprehensible and useful manner.
Затем он углубляется в несколько паттернов, разделённых на входы и выходы системы. Входы фокусируются на явной обратной связи, неявной обратной связи, калибровке и исправлениях. Этот раздел направляет проектирование того, как ИИ-продукты запрашивают и обрабатывают данные и взаимодействия пользователей. Выходы фокусируются на ошибках, множественных вариантах, уверенности, атрибуции и ограничениях. Цель — обеспечить, чтобы вывод модели был представлен понятным и полезным образом.
The differences between the three guidelines are insightful. Google has more emphasis on considerations for training data and model development, likely due to its engineering-driven culture. Microsoft has more focus on mental models, likely an artifact of the HCI academic study. Lastly, Apple’s approach centers around providing a seamless UX, a focus likely influenced by its cultural values and principles.
Различия между тремя гайдлайнами поучительны. Google делает больший упор на соображения о тренировочных данных и разработке модели, вероятно, из-за своей инженерно-ориентированной культуры. Microsoft больше фокусируется на ментальных моделях, что, вероятно, является артефактом академического исследования в области HCI. Наконец, подход Apple сосредоточен вокруг обеспечения бесшовного UX, и этот фокус, вероятно, обусловлен её культурными ценностями и принципами.
How to apply defensive UX?
Как применять защитный UX?
Here are some patterns based on the guidelines above. (Disclaimer: I’m not a designer.)
Вот несколько паттернов, основанных на приведённых выше гайдлайнах. (Дисклеймер: я не дизайнер.)
Set the right expectations. This principle is consistent across all three guidelines:
Задавайте правильные ожидания. Этот принцип единообразен во всех трёх гайдлайнах:
Microsoft: проясните, насколько хорошо система может делать то, что она умеет (помогите пользователю понять, как часто ИИ-система может ошибаться). Google: задавайте правильные ожидания (будьте прозрачны с пользователями о том, что ваш ИИ-продукт может и не может делать). Apple: помогите людям сформировать реалистичные ожидания (опишите ограничение в маркетинговых материалах или в контексте самой функции).
This can be as simple as adding a brief disclaimer above AI-generated results, like those of Bard, or highlighting our app’s limitations on its landing page, like how ChatGPT does it.
Это может быть так же просто, как добавить краткий дисклеймер над результатами, сгенерированными ИИ, как у Bard, или выделить ограничения нашего приложения на его лендинге, как это делает ChatGPT.
Example of a disclaimer on Google Bard results (Note: nrows is not a valid argument.)
Пример дисклеймера на результатах Google Bard (Примечание: nrows не является допустимым аргументом.)
By being transparent about our product’s capabilities and limitations, we help users calibrate their expectations about its functionality and output. While this may cause users to trust it less in the short run, it helps foster trust in the long run—users are less likely to overestimate our product and subsequently face disappointment.
Будучи прозрачными о возможностях и ограничениях нашего продукта, мы помогаем пользователям откалибровать ожидания относительно его функциональности и вывода. Хотя в краткосрочной перспективе это может заставить пользователей доверять ему меньше, в долгосрочной перспективе это помогает укрепить доверие — пользователи менее склонны переоценивать наш продукт и впоследствии сталкиваться с разочарованием.
Enable efficient dismissal. This is explicitly mentioned as Microsoft’s Guideline 8: Support efficient dismissal (make it easy to dismiss or ignore undesired AI system services).
Обеспечьте удобное отклонение. Это явно упомянуто в Рекомендации 8 от Microsoft: поддерживайте удобное отклонение (сделайте лёгким отклонение или игнорирование нежелательных сервисов ИИ-системы).
For example, if a user is navigating our site and a chatbot pops up asking if they need help, it should be easy for the user to dismiss the chatbot. This ensures the chatbot doesn’t get in the way, especially on devices with smaller screens. Similarly, GitHub Copilot allows users to conveniently ignore its code suggestions by simply continuing to type. While this may reduce usage of the AI feature in the short term, it prevents it from becoming a nuisance and potentially reducing customer satisfaction in the long term.
Например, если пользователь перемещается по нашему сайту и всплывает чат-бот, спрашивающий, нужна ли помощь, пользователю должно быть легко отклонить чат-бот. Это гарантирует, что чат-бот не помешает, особенно на устройствах с меньшими экранами. Аналогично, GitHub Copilot позволяет пользователям удобно игнорировать предложения кода, просто продолжая печатать. Хотя в краткосрочной перспективе это может снизить использование ИИ-функции, это предотвращает её превращение в раздражитель и потенциальное снижение удовлетворённости клиентов в долгосрочной перспективе.
Provide attribution. This is listed in all three guidelines:
Предоставляйте атрибуцию. Это указано во всех трёх гайдлайнах:
Microsoft: проясните, почему система сделала то, что сделала (дайте пользователю возможность получить объяснение, почему ИИ-система повела себя так, как повела). Google: добавляйте контекст из человеческих источников (помогите пользователям оценить ваши рекомендации с учётом сведений из сторонних источников). Apple: рассмотрите использование атрибуции, чтобы помочь людям различать результаты.
Citations are becoming an increasingly common design element. Take BingChat for example. When we make a query, it includes citations, usually from reputable sources, in its responses. This not only shows where the information came from, but also allows users to assess the quality of the sources. Similarly, imagine we’re using an LLM to explain why a user might like a product. Alongside the LLM-generated explanation, we could include a quote from an actual review or mention the product rating.
Цитаты становятся всё более распространённым элементом дизайна. Возьмём, к примеру, BingChat. Когда мы делаем запрос, он включает в свои ответы цитаты, обычно из авторитетных источников. Это не только показывает, откуда взялась информация, но и позволяет пользователям оценить качество источников. Аналогично, представьте, что мы используем LLM, чтобы объяснить, почему пользователю может понравиться товар. Наряду с объяснением, сгенерированным LLM, мы могли бы включить цитату из реального отзыва или упомянуть рейтинг товара.
Context from experts and the community also enhances user trust. For example, if a user is seeking recommendations for a hiking trail, mentioning that a suggested trail comes highly recommended by the relevant community can go a long way. It not only adds value to the recommendation but also helps users calibrate trust through the human connection.
Контекст от экспертов и сообщества также повышает доверие пользователей. Например, если пользователь ищет рекомендации по пешему маршруту, упоминание, что предложенный маршрут настоятельно рекомендован соответствующим сообществом, может многое значить. Это не только добавляет ценность рекомендации, но и помогает пользователям откалибровать доверие через человеческую связь.
Example of attribution via social proof (source)
Пример атрибуции через социальное доказательство (источник)
Finally, Apple’s guidelines include popular attributions such as “Because you’ve read non-fiction”, “New books by authors you’ve read”. These descriptors not only personalize the experience but also provide context, enhancing user understanding and trust.
Наконец, гайдлайны Apple включают популярные атрибуции вроде «Потому что вы читали нон-фикшн», «Новые книги авторов, которых вы читали». Эти описания не только персонализируют опыт, но и предоставляют контекст, усиливая понимание и доверие пользователя.
Anchor on familiarity. When introducing users to a new AI product or feature, it helps to guide them with familiar UX patterns and features. This makes it easier for users to focus on the main task and start to earn customer trust in our new product. Resist the temptation to showcase new and “magical” features via exotic UI elements.
Опирайтесь на знакомое. Знакомя пользователей с новым ИИ-продуктом или функцией, полезно направлять их с помощью знакомых UX-паттернов и элементов. Это облегчает пользователям сосредоточение на основной задаче и помогает начать завоёвывать доверие к нашему новому продукту. Сопротивляйтесь искушению демонстрировать новые и «магические» функции через экзотические элементы UI.
Along a similar vein, chat-based features are becoming more common due to ChatGPT’s growing popularity. For example, chat with your docs, chat to query your data, chat to buy groceries. However, I question whether chat is the right UX for most user experiences—it just takes too much effort relative to the familiar UX of clicking on text and images.
В схожем ключе функции на основе чата становятся всё более распространёнными из-за растущей популярности ChatGPT. Например, чат с вашими документами, чат для запросов к данным, чат для покупки продуктов. Однако я сомневаюсь, что чат — правильный UX для большинства пользовательских опытов — он требует слишком много усилий по сравнению со знакомым UX кликов по тексту и изображениям.
Furthermore, increasing user effort leads to higher expectations that are harder to meet. Netflix shared that users have higher expectations for recommendations that result from explicit actions such as search. In general, the more effort a user puts in (e.g., chat, search), the higher the expectations they have. Contrast this with lower-effort interactions such as scrolling over recommendations slates or clicking on a product.
Более того, увеличение усилий пользователя ведёт к более высоким ожиданиям, которые труднее оправдать. Netflix поделился, что у пользователей более высокие ожидания к рекомендациям, возникающим в результате явных действий, таких как поиск. В целом, чем больше усилий пользователь вкладывает (например, чат, поиск), тем выше его ожидания. Сравните это с менее затратными взаимодействиями, такими как прокрутка по подборкам рекомендаций или клик по товару.
Thus, while chat offers more flexibility, it also demands more user effort. Moreover, using a chat box is less intuitive as it lacks signifiers on how users can adjust the output. Overall, I think that sticking with a familiar and constrained UI makes it easier for users to navigate our product; chat should only be considered as a secondary or tertiary option.
Таким образом, хотя чат предлагает больше гибкости, он также требует больше усилий от пользователя. Более того, использование окна чата менее интуитивно, поскольку в нём недостаёт указателей (signifiers) на то, как пользователи могут корректировать вывод. В целом я думаю, что придерживаться знакомого и ограниченного UI проще для навигации пользователей по нашему продукту; чат стоит рассматривать лишь как вторичный или третичный вариант.
Collect user feedback: To build our data flywheel
Сбор обратной связи пользователей: чтобы строить маховик данных
Gathering user feedback allows us to learn their preferences. Specific to LLM products, user feedback contributes to building evals, fine-tuning, and guardrails. If we think about it, data—such as corpus for pre-training, expert-crafted demonstrations, human preferences for reward modeling—is one of the few moats for LLM products. Thus, we want to be deliberately thinking about collecting user feedback when designing our UX.
Сбор обратной связи пользователей позволяет нам узнавать их предпочтения. Применительно к продуктам на LLM обратная связь пользователей способствует построению оценок, fine-tuning и guardrails. Если задуматься, данные — такие как корпус для предобучения, демонстрации, созданные экспертами, человеческие предпочтения для моделирования вознаграждения — это один из немногих «рвов» (moats) для LLM-продуктов. Поэтому мы хотим осознанно думать о сборе обратной связи пользователей, проектируя наш UX.
Feedback can be explicit or implicit. Explicit feedback is information users provide in response to a request by our product; implicit feedback is information we learn from user interactions without needing users to deliberately provide feedback.
Обратная связь может быть явной или неявной. Явная обратная связь — это информация, которую пользователи предоставляют в ответ на запрос нашего продукта; неявная обратная связь — это информация, которую мы узнаём из взаимодействий пользователей, не требуя от них намеренно предоставлять обратную связь.
Why collect user feedback
Зачем собирать обратную связь пользователей
User feedback helps our models improve. By learning what users like, dislike, or complain about, we can improve our models to better meet their needs. It also allows us to adapt to individual preferences. Recommendation systems are a prime example. As users interact with items, we learn what they like and dislike and better cater to their tastes over time.
Обратная связь пользователей помогает нашим моделям улучшаться. Узнавая, что пользователям нравится, не нравится или на что они жалуются, мы можем улучшать наши модели, чтобы лучше удовлетворять их потребности. Это также позволяет нам адаптироваться к индивидуальным предпочтениям. Рекомендательные системы — яркий пример. По мере того как пользователи взаимодействуют с объектами, мы узнаём, что им нравится и не нравится, и со временем лучше угождаем их вкусам.
In addition, the feedback loop helps us evaluate our system’s overall performance. While evals can help us measure model/system performance, user feedback offers a concrete measure of user satisfaction and product effectiveness.
Кроме того, цикл обратной связи помогает нам оценивать общее качество нашей системы. Хотя оценки могут помочь нам измерить качество модели/системы, обратная связь пользователей предлагает конкретную меру удовлетворённости пользователей и эффективности продукта.
How to collect user feedback
Как собирать обратную связь пользователей
Make it easy for users to provide feedback. This is echoed across all three guidelines:
Сделайте так, чтобы пользователям было легко предоставлять обратную связь. Это перекликается во всех трёх гайдлайнах:
Microsoft: поощряйте детализированную обратную связь (дайте пользователю возможность предоставлять обратную связь, указывающую на его предпочтения, в ходе обычного взаимодействия с ИИ-системой). Google: позвольте пользователям давать обратную связь (дайте пользователям возможность обучения в реальном времени, обратной связи и исправления ошибок). Apple: предоставляйте действенную информацию, которую ваше приложение может использовать для улучшения контента и опыта, который оно представляет людям.
ChatGPT is one such example. Users can indicate thumbs up/down on responses, or choose to regenerate a response if it’s really bad or unhelpful. This is useful feedback on human preferences which can then be used to fine-tune LLMs.
ChatGPT — один из таких примеров. Пользователи могут ставить лайк/дизлайк на ответы или выбрать перегенерацию ответа, если он совсем плох или бесполезен. Это полезная обратная связь о человеческих предпочтениях, которую затем можно использовать для дообучения LLM.
Midjourney is another good example. After images are generated, users can generate a new set of images (negative feedback), tweak an image by asking for a variation (positive feedback), or upscale and download the image (strong positive feedback). This enables Midjourney to gather rich comparison data on the outputs generated.
Midjourney — ещё один хороший пример. После генерации изображений пользователи могут сгенерировать новый набор изображений (отрицательная обратная связь), подправить изображение, запросив вариацию (положительная обратная связь), или повысить разрешение и скачать изображение (сильная положительная обратная связь). Это позволяет Midjourney собирать богатые данные сравнений по сгенерированным выводам.
Example of collecting user feedback as part of the UX
Пример сбора обратной связи пользователей как части UX
Consider implicit feedback too. Implicit feedback is information that arises as users interact with our product. Unlike the specific responses we get from explicit feedback, implicit feedback can provide a wide range of data on user behavior and preferences.
Учитывайте и неявную обратную связь. Неявная обратная связь — это информация, которая возникает по мере взаимодействия пользователей с нашим продуктом. В отличие от конкретных ответов, которые мы получаем из явной обратной связи, неявная обратная связь может предоставить широкий спектр данных о поведении и предпочтениях пользователей.
Copilot-like assistants are a prime example. Users indicate whether a suggestion was helpful by either wholly accepting it (strong positive feedback), accepting and making minor tweaks (positive feedback), or ignoring it (neutral/negative feedback). Alternatively, they may update the comment that led to the generated code, suggesting that the initial code generation didn’t meet their needs.
Ассистенты в стиле Copilot — яркий пример. Пользователи указывают, было ли предложение полезным, либо полностью принимая его (сильная положительная обратная связь), либо принимая и внося мелкие правки (положительная обратная связь), либо игнорируя его (нейтральная/отрицательная обратная связь). В качестве альтернативы они могут обновить комментарий, приведший к сгенерированному коду, что говорит о том, что исходная генерация кода не отвечала их потребностям.
Chatbots, such as ChatGPT and BingChat, are another example. How has daily usage changed over time? If the product is sticky, it suggests that users like it. Also, how long is the average conversation? This can be tricky to interpret: Is a longer conversation better because the conversation was engaging and fruitful? Or is it worse because it took the user longer to get what they needed?
Чат-боты, такие как ChatGPT и BingChat, — ещё один пример. Как менялось ежедневное использование со временем? Если продукт «залипчив» (sticky), это говорит о том, что пользователям он нравится. Также: какова средняя длина разговора? Это может быть непросто интерпретировать: разговор длиннее, потому что он был увлекательным и плодотворным? Или хуже, потому что пользователю потребовалось больше времени, чтобы получить нужное?
Other patterns common in machine learning
Другие паттерны, распространённые в машинном обучении
Apart from the seven patterns above, there are other patterns in machine learning that are also relevant to LLM systems and products. They include:
Помимо семи паттернов выше, есть и другие паттерны в машинном обучении, которые также релевантны для систем и продуктов на LLM. К ним относятся:
Маховик данных (data flywheel): непрерывный сбор данных улучшает модель и ведёт к лучшему пользовательскому опыту. Это, в свою очередь, способствует росту использования, которое даёт больше данных для дальнейшей оценки и дообучения моделей, создавая благотворный цикл. Каскад (cascade): вместо того чтобы поручать LLM одну сложную задачу, мы можем упростить её и разбить так, чтобы ей приходилось обрабатывать лишь задачи, в которых она преуспевает, такие как рассуждение или красноречивое изложение. RAG — пример этого. Вместо того чтобы полагаться на LLM в извлечении и ранжировании объектов на основе её внутренних знаний, мы можем дополнить LLM внешними знаниями и сосредоточиться на применении способностей LLM к рассуждению. Мониторинг (monitoring): помогает продемонстрировать ценность, добавляемую ИИ-системой, или её отсутствие. Кто-то поделился историей о запуске решения для клиентской поддержки на основе LLM в продакшене на две недели, прежде чем его отключили — A/B-тест показал, что потери были в 12 раз больше при использовании LLM в качестве замены их команды поддержки!
(Read more about design patterns for machine learning code and systems.)
(Подробнее о паттернах проектирования для кода машинного обучения и систем.)
Also, here’s what others said:
Также вот что сказали другие:
Separation of concerns/task decomposition- having distinct prompts for distinct subtasks and chaining them together helps w attention and reliability (hurts latency). We were having trouble specifying a rigid output structure AND variable response content so we split up the tasks — Erick Enriquez
Разделение ответственности / декомпозиция задач — иметь отдельные промпты для отдельных подзадач и связывать их вместе помогает со вниманием и надёжностью (но вредит задержке). У нас были трудности с одновременным заданием жёсткой структуры вывода И переменного содержания ответа, поэтому мы разделили задачи. — Erick Enriquez
A few others that will be needed: role based access control: who can access what; security: if I’m using a DB with an LLM, how do I ensure that I have the right security guards — Krishna
Несколько других вещей, которые понадобятся: ролевой контроль доступа (role based access control): кто к чему может получить доступ; безопасность: если я использую БД с LLM, как мне обеспечить нужные меры безопасности. — Krishna
Consistent output format: setting outputs to a standardized format such as JSON; Tool augmentation: offload tasks to more specialised, proven, reliable models — Paul Tune
Согласованный формат вывода: приведение выводов к стандартизированному формату вроде JSON; дополнение инструментами (tool augmentation): передача задач более специализированным, проверенным, надёжным моделям. — Paul Tune
Security: mitigate cache poisoning, input validation, mitigate prompt injection, training data provenance, output with non-vulnerable code, mitigate malicious input aimed at influencing requests used by tools (AI Agent), mitigate denial of service (stress test llm), to name a few :) — Anderson Darario
Безопасность: смягчение отравления кэша, валидация ввода, смягчение prompt injection, происхождение тренировочных данных, вывод неуязвимого кода, смягчение вредоносного ввода, нацеленного на влияние на запросы, используемые инструментами (ИИ-агент), смягчение отказа в обслуживании (стресс-тестирование llm), и это лишь некоторые из них :) — Anderson Darario
Another ux/ui related: incentivize users to provide feedback on generated answers (implicit or explicit). Implicit could be sth like copilot’s ghost text style, if accepted with TAB, meaning positive feedback etc. — Wen Yang
Ещё кое-что, связанное с ux/ui: стимулируйте пользователей давать обратную связь по сгенерированным ответам (неявную или явную). Неявная может быть чем-то вроде стиля «призрачного текста» (ghost text) у copilot: если принято по TAB — это означает положительную обратную связь и т. д. — Wen Yang
Great list. I would add consistency checks like self-consistency sampling, chaining and decomposition of tasks, and the emsembling of multiple model outputs. Applying each of these almost daily. Dan White
Отличный список. Я бы добавил проверки согласованности вроде self-consistency sampling, цепочки и декомпозиции задач, а также ансамблирование выводов нескольких моделей. Применяю каждое из этого почти ежедневно. Dan White
Guardrails is super relevant for building analytics tools where llm is a translator from natural to programming language — m_voitko
Guardrails сверхрелевантны для построения аналитических инструментов, где llm выступает переводчиком с естественного языка на язык программирования. — m_voitko
Conclusion
Заключение
This is the longest post I’ve written by far. If you’re still with me, thank you! I hope you found reading about these patterns helpful, and that the 2x2 below makes sense.
Это самый длинный пост, который я когда-либо писал. Если вы всё ещё со мной — спасибо! Надеюсь, чтение об этих паттернах было полезным и что приведённая ниже схема 2x2 имеет смысл.
LLM patterns across the axis of data to user, and defensive to offensive.
Паттерны LLM по осям «от данных к пользователю» и «от обороны к атаке».
We’re still so early on the journey towards building LLM-based systems and products. Are there any other key patterns or resources? What have you found useful or not useful? I’d love to hear your experience. Please reach out!
Мы всё ещё в самом начале пути к построению систем и продуктов на основе LLM. Есть ли какие-то другие ключевые паттерны или ресурсы? Что вы нашли полезным или бесполезным? Я бы с удовольствием услышал о вашем опыте. Пожалуйста, свяжитесь со мной!
References
Источники
Hendrycks, Dan, et al. “Measuring massive multitask language understanding.” arXiv preprint arXiv:2009.03300 (2020).
Hendrycks, Dan, et al. «Measuring massive multitask language understanding.» arXiv preprint arXiv:2009.03300 (2020).
Gao, Leo, et al. “A Framework for Few-Shot Language Model Evaluation.” v0.0.1, Zenodo, (2021), doi:10.5281/zenodo.5371628.
Gao, Leo, et al. «A Framework for Few-Shot Language Model Evaluation.» v0.0.1, Zenodo, (2021), doi:10.5281/zenodo.5371628.
Liang, Percy, et al. “Holistic evaluation of language models.” arXiv preprint arXiv:2211.09110 (2022).
Liang, Percy, et al. «Holistic evaluation of language models.» arXiv preprint arXiv:2211.09110 (2022).
Dubois, Yann, et al. “AlpacaFarm: A Simulation Framework for Methods That Learn from Human Feedback.” (2023)
Dubois, Yann, et al. «AlpacaFarm: A Simulation Framework for Methods That Learn from Human Feedback.» (2023)
Papineni, Kishore, et al. “Bleu: a method for automatic evaluation of machine translation.” Proceedings of the 40th annual meeting of the Association for Computational Linguistics. 2002.
Papineni, Kishore, et al. «Bleu: a method for automatic evaluation of machine translation.» Proceedings of the 40th annual meeting of the Association for Computational Linguistics. 2002.
Lin, Chin-Yew. “Rouge: A package for automatic evaluation of summaries.” Text summarization branches out. 2004.
Lin, Chin-Yew. «Rouge: A package for automatic evaluation of summaries.» Text summarization branches out. 2004.
Zhang, Tianyi, et al. “Bertscore: Evaluating text generation with bert.” arXiv preprint arXiv:1904.09675 (2019).
Zhang, Tianyi, et al. «Bertscore: Evaluating text generation with bert.» arXiv preprint arXiv:1904.09675 (2019).
Zhao, Wei, et al. “MoverScore: Text generation evaluating with contextualized embeddings and earth mover distance.” arXiv preprint arXiv:1909.02622 (2019).
Zhao, Wei, et al. «MoverScore: Text generation evaluating with contextualized embeddings and earth mover distance.» arXiv preprint arXiv:1909.02622 (2019).
Sai, Ananya B., Akash Kumar Mohankumar, and Mitesh M. Khapra. “A survey of evaluation metrics used for NLG systems.” ACM Computing Surveys (CSUR) 55.2 (2022): 1-39.
Sai, Ananya B., Akash Kumar Mohankumar, and Mitesh M. Khapra. «A survey of evaluation metrics used for NLG systems.» ACM Computing Surveys (CSUR) 55.2 (2022): 1-39.
Grusky, Max. “Rogue Scores.” Proceedings of the 61st Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers). 2023.
Grusky, Max. «Rogue Scores.» Proceedings of the 61st Annual Meeting of the Association for Computational Linguistics (Volume 1: Long Papers). 2023.
Liu, Yang, et al. “Gpteval: Nlg evaluation using gpt-4 with better human alignment.” arXiv preprint arXiv:2303.16634 (2023).
Liu, Yang, et al. «Gpteval: Nlg evaluation using gpt-4 with better human alignment.» arXiv preprint arXiv:2303.16634 (2023).
Fourrier, Clémentine, et al. “What’s going on with the Open LLM Leaderboard?” (2023).
Fourrier, Clémentine, et al. «What’s going on with the Open LLM Leaderboard?» (2023).
Zheng, Lianmin, et al. “Judging LLM-as-a-judge with MT-Bench and Chatbot Arena.” arXiv preprint arXiv:2306.05685 (2023).
Zheng, Lianmin, et al. «Judging LLM-as-a-judge with MT-Bench and Chatbot Arena.» arXiv preprint arXiv:2306.05685 (2023).
Dettmers, Tim, et al. “Qlora: Efficient finetuning of quantized llms.” arXiv preprint arXiv:2305.14314 (2023).
Dettmers, Tim, et al. «Qlora: Efficient finetuning of quantized llms.» arXiv preprint arXiv:2305.14314 (2023).
Swyx et al. MPT-7B and The Beginning of Context=Infinity (2023).
Swyx et al. MPT-7B and The Beginning of Context=Infinity (2023).
Fradin, Michelle, Reeder, Lauren “The New Language Model Stack” (2023).
Fradin, Michelle, Reeder, Lauren «The New Language Model Stack» (2023).
Radford, Alec, et al. “Learning transferable visual models from natural language supervision.” International conference on machine learning. PMLR, 2021.
Radford, Alec, et al. «Learning transferable visual models from natural language supervision.» International conference on machine learning. PMLR, 2021.
Yan, Ziyou. “Search: Query Matching via Lexical, Graph, and Embedding Methods.” eugeneyan.com, (2021).
Yan, Ziyou. «Search: Query Matching via Lexical, Graph, and Embedding Methods.» eugeneyan.com, (2021).
Petroni, Fabio, et al. “How context affects language models’ factual predictions.” arXiv preprint arXiv:2005.04611 (2020).
Petroni, Fabio, et al. «How context affects language models’ factual predictions.» arXiv preprint arXiv:2005.04611 (2020).
Karpukhin, Vladimir, et al. “Dense passage retrieval for open-domain question answering.” arXiv preprint arXiv:2004.04906 (2020).
Karpukhin, Vladimir, et al. «Dense passage retrieval for open-domain question answering.» arXiv preprint arXiv:2004.04906 (2020).
Lewis, Patrick, et al. “Retrieval-augmented generation for knowledge-intensive nlp tasks.” Advances in Neural Information Processing Systems 33 (2020): 9459-9474.
Lewis, Patrick, et al. «Retrieval-augmented generation for knowledge-intensive nlp tasks.» Advances in Neural Information Processing Systems 33 (2020): 9459-9474.
Izacard, Gautier, and Edouard Grave. “Leveraging passage retrieval with generative models for open domain question answering.” arXiv preprint arXiv:2007.01282 (2020).
Izacard, Gautier, and Edouard Grave. «Leveraging passage retrieval with generative models for open domain question answering.» arXiv preprint arXiv:2007.01282 (2020).
Borgeaud, Sebastian, et al. “Improving language models by retrieving from trillions of tokens.” International conference on machine learning. PMLR, (2022).
Borgeaud, Sebastian, et al. «Improving language models by retrieving from trillions of tokens.» International conference on machine learning. PMLR, (2022).
Lazaridou, Angeliki, et al. “Internet-augmented language models through few-shot prompting for open-domain question answering.” arXiv preprint arXiv:2203.05115 (2022).
Lazaridou, Angeliki, et al. «Internet-augmented language models through few-shot prompting for open-domain question answering.» arXiv preprint arXiv:2203.05115 (2022).
Wang, Yue, et al. “Codet5+: Open code large language models for code understanding and generation.” arXiv preprint arXiv:2305.07922 (2023).
Wang, Yue, et al. «Codet5+: Open code large language models for code understanding and generation.» arXiv preprint arXiv:2305.07922 (2023).
Gao, Luyu, et al. “Precise zero-shot dense retrieval without relevance labels.” arXiv preprint arXiv:2212.10496 (2022).
Gao, Luyu, et al. «Precise zero-shot dense retrieval without relevance labels.» arXiv preprint arXiv:2212.10496 (2022).
Yan, Ziyou. “Obsidian-Copilot: An Assistant for Writing & Reflecting.” eugeneyan.com, (2023).
Yan, Ziyou. «Obsidian-Copilot: An Assistant for Writing & Reflecting.» eugeneyan.com, (2023).
Bojanowski, Piotr, et al. “Enriching word vectors with subword information.” Transactions of the association for computational linguistics 5 (2017): 135-146.
Bojanowski, Piotr, et al. «Enriching word vectors with subword information.» Transactions of the association for computational linguistics 5 (2017): 135-146.
Reimers, Nils, and Iryna Gurevych. “Making Monolingual Sentence Embeddings Multilingual Using Knowledge Distillation.” Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing, Association for Computational Linguistics, (2020).
Reimers, Nils, and Iryna Gurevych. «Making Monolingual Sentence Embeddings Multilingual Using Knowledge Distillation.» Proceedings of the 2020 Conference on Empirical Methods in Natural Language Processing, Association for Computational Linguistics, (2020).
Wang, Liang, et al. “Text embeddings by weakly-supervised contrastive pre-training.” arXiv preprint arXiv:2212.03533 (2022).
Wang, Liang, et al. «Text embeddings by weakly-supervised contrastive pre-training.» arXiv preprint arXiv:2212.03533 (2022).
Su, Hongjin, et al. “One embedder, any task: Instruction-finetuned text embeddings.” arXiv preprint arXiv:2212.09741 (2022).
Su, Hongjin, et al. «One embedder, any task: Instruction-finetuned text embeddings.» arXiv preprint arXiv:2212.09741 (2022).
Johnson, Jeff, et al. “Billion-Scale Similarity Search with GPUs.” IEEE Transactions on Big Data, vol. 7, no. 3, IEEE, 2019, pp. 535–47.
Johnson, Jeff, et al. «Billion-Scale Similarity Search with GPUs.» IEEE Transactions on Big Data, vol. 7, no. 3, IEEE, 2019, pp. 535–47.
Malkov, Yu A., and Dmitry A. Yashunin. “Efficient and Robust Approximate Nearest Neighbor Search Using Hierarchical Navigable Small World Graphs.” IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 42, no. 4, IEEE, 2018, pp. 824–36.
Malkov, Yu A., and Dmitry A. Yashunin. «Efficient and Robust Approximate Nearest Neighbor Search Using Hierarchical Navigable Small World Graphs.» IEEE Transactions on Pattern Analysis and Machine Intelligence, vol. 42, no. 4, IEEE, 2018, pp. 824–36.
Guo, Ruiqi, et al. “Accelerating Large-Scale Inference with Anisotropic Vector Quantization.” International Conference on Machine Learning, (2020)
Guo, Ruiqi, et al. «Accelerating Large-Scale Inference with Anisotropic Vector Quantization.» International Conference on Machine Learning, (2020)
Ouyang, Long, et al. “Training language models to follow instructions with human feedback.” Advances in Neural Information Processing Systems 35 (2022): 27730-27744.
Ouyang, Long, et al. «Training language models to follow instructions with human feedback.» Advances in Neural Information Processing Systems 35 (2022): 27730-27744.
Howard, Jeremy, and Sebastian Ruder. “Universal language model fine-tuning for text classification.” arXiv preprint arXiv:1801.06146 (2018).
Howard, Jeremy, and Sebastian Ruder. «Universal language model fine-tuning for text classification.» arXiv preprint arXiv:1801.06146 (2018).
Devlin, Jacob, et al. “Bert: Pre-training of deep bidirectional transformers for language understanding.” arXiv preprint arXiv:1810.04805 (2018).
Devlin, Jacob, et al. «Bert: Pre-training of deep bidirectional transformers for language understanding.» arXiv preprint arXiv:1810.04805 (2018).
Radford, Alec, et al. “Improving language understanding with unsupervised learning.” (2018).
Radford, Alec, et al. «Improving language understanding with unsupervised learning.» (2018).
Raffel, Colin, et al. “Exploring the limits of transfer learning with a unified text-to-text transformer.” The Journal of Machine Learning Research 21.1 (2020): 5485-5551.
Raffel, Colin, et al. «Exploring the limits of transfer learning with a unified text-to-text transformer.» The Journal of Machine Learning Research 21.1 (2020): 5485-5551.
Lester, Brian, Rami Al-Rfou, and Noah Constant. “The power of scale for parameter-efficient prompt tuning.” arXiv preprint arXiv:2104.08691 (2021).
Lester, Brian, Rami Al-Rfou, and Noah Constant. «The power of scale for parameter-efficient prompt tuning.» arXiv preprint arXiv:2104.08691 (2021).
Li, Xiang Lisa, and Percy Liang. “Prefix-tuning: Optimizing continuous prompts for generation.” arXiv preprint arXiv:2101.00190 (2021).
Li, Xiang Lisa, and Percy Liang. «Prefix-tuning: Optimizing continuous prompts for generation.» arXiv preprint arXiv:2101.00190 (2021).
Houlsby, Neil, et al. “Parameter-efficient transfer learning for NLP.” International Conference on Machine Learning. PMLR, 2019.
Houlsby, Neil, et al. «Parameter-efficient transfer learning for NLP.» International Conference on Machine Learning. PMLR, 2019.
Hu, Edward J., et al. “Lora: Low-rank adaptation of large language models.” arXiv preprint arXiv:2106.09685 (2021).
Hu, Edward J., et al. «Lora: Low-rank adaptation of large language models.» arXiv preprint arXiv:2106.09685 (2021).
Dettmers, Tim, et al. “Qlora: Efficient finetuning of quantized llms.” arXiv preprint arXiv:2305.14314 (2023).
Dettmers, Tim, et al. «Qlora: Efficient finetuning of quantized llms.» arXiv preprint arXiv:2305.14314 (2023).
Williams, Adina, et al. “A Broad-Coverage Challenge Corpus for Sentence Understanding through Inference.” Proceedings of the 2018 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, Volume 1 (Long Papers), Association for Computational Linguistics, (2018).
Williams, Adina, et al. «A Broad-Coverage Challenge Corpus for Sentence Understanding through Inference.» Proceedings of the 2018 Conference of the North American Chapter of the Association for Computational Linguistics: Human Language Technologies, Volume 1 (Long Papers), Association for Computational Linguistics, (2018).
Bai, Yuntao, et al. “Training a helpful and harmless assistant with reinforcement learning from human feedback.” arXiv preprint arXiv:2204.05862 (2022).
Bai, Yuntao, et al. «Training a helpful and harmless assistant with reinforcement learning from human feedback.» arXiv preprint arXiv:2204.05862 (2022).
Guardrails (2023)
Guardrails (2023)
NeMo-Guardrails (2023)
NeMo-Guardrails (2023)
Manakul, Potsawee, Adian Liusie, and Mark JF Gales. “Selfcheckgpt: Zero-resource black-box hallucination detection for generative large language models.” arXiv preprint arXiv:2303.08896 (2023).
Manakul, Potsawee, Adian Liusie, and Mark JF Gales. «Selfcheckgpt: Zero-resource black-box hallucination detection for generative large language models.» arXiv preprint arXiv:2303.08896 (2023).
Amershi, Saleema, et al. “Guidelines for human-AI interaction.” Proceedings of the 2019 chi conference on human factors in computing systems. 2019.
Amershi, Saleema, et al. «Guidelines for human-AI interaction.» Proceedings of the 2019 chi conference on human factors in computing systems. 2019.
People + AI Guidebook (2023).
People + AI Guidebook (2023).
Schendel, Zachary A., Faraz Farzin, and Siddhi Sundar. “A Human Perspective on Algorithmic Similarity.” Proceedings of the 14th ACM Conference on Recommender Systems. 2020.
Schendel, Zachary A., Faraz Farzin, and Siddhi Sundar. «A Human Perspective on Algorithmic Similarity.» Proceedings of the 14th ACM Conference on Recommender Systems. 2020.
If you found this useful, please cite this write-up as:
Если вы нашли это полезным, пожалуйста, цитируйте эту статью так:
Yan, Ziyou. (Jul 2023). Patterns for Building LLM-based Systems & Products. eugeneyan.com. https://eugeneyan.com/writing/llm-patterns/.
Yan, Ziyou. (Jul 2023). Patterns for Building LLM-based Systems & Products. eugeneyan.com. https://eugeneyan.com/writing/llm-patterns/.
or
или
@article{yan2023llm-patterns,
title = {Patterns for Building LLM-based Systems & Products},
author = {Yan, Ziyou},
journal = {eugeneyan.com},
year = {2023},
month = {Jul},
url = {https://eugeneyan.com/writing/llm-patterns/}
}
@article{yan2023llm-patterns, title = {Patterns for Building LLM-based Systems & Products}, author = {Yan, Ziyou}, journal = {eugeneyan.com}, year = {2023}, month = {Jul}, url = {https://eugeneyan.com/writing/llm-patterns/} }
Join 11,800+ readers getting updates on machine learning, RecSys, LLMs, and engineering.
Присоединяйтесь к 11 800+ читателей, получающих обновления о машинном обучении, RecSys, LLM и инженерии.