Experimenting with LLMs to Research, Reflect, and Plan
Eugene Yan описывает эксперименты с LLM, в ходе которых он собрал в Discord набор инструментов-команд: /summarize и /eli5 для краткого пересказа URL, /sql и /sql-agent для запросов к базе, /search для поиска в интернете, а также /board (советы от Paul Graham, Marc Andreessen, Will Larson, Charity Majors, Naval Ravikant) и /ask-ey по его собственным текстам. Стек: gpt-3.5-turbo и gpt-4, LangChain, text-embedding-ada-002, BeautifulSoup, Pinecone, Railway и обёртка interactions для Discord. Автор сталкивается с проблемами поиска по эмбеддингам: субоптимальная настройка ANN, плохой перенос готовых эмбеддингов на новый домен, неправильное разбиение документов на чанки по 1500 токенов и недостаточность одного только семантического поиска. В качестве решений он предлагает тюнинг ANN, дообучение через triplet loss, разбиение по секциям и параграфам и гибрид BM25 с семантическим поиском (следующая итерация использует OpenSearch + E5). Он видит большой потенциал в LLM-усиленном поиске и Q&A по корпоративным и личным базам знаний (упоминая Glean и Rewind), а также в помощи при написании документов. Цитируя Сэма Альтмана, Eugene подчёркивает: LLM — это движок рассуждения, а не база фактов, и ключ к успеху — подать им правильный контекст в нужный момент.
Эксперименты с LLM для исследований, рефлексии и планирования
[ llm deeplearning learning 🛠 🔥 ] · 14 мин чтения
Несколько последних выходных я возился с большими языковыми моделями (LLM) и собирал из них вместе с инструментами и интерфейсами простого ассистента. По ходу дела я заметил проблемы с поиском и придумал несколько идей, как их решить.
Было очень увлекательно, и после этого опыта я уверен, что у LLM огромный потенциал для расширения наших возможностей в работе, особенно в том, как мы исследуем, рефлексируем и планируем.
Вот код для быстрого старта. Он сыроват и сильно опирается на абстракции LangChain. Может пригодиться как ориентир, но не как обучающий материал.
Инструменты для суммаризации, запросов и советов
Мой первый проект был вдохновлён постом Simon о том, что ChatGPT не умеет читать содержимое URL. Я попробовал помочь ему это сделать с помощью /summarize и /eli5. Первая команда умеет /summarize сжимать содержимое URL в маркированный список, а вторая читает его и объясняет так, будто мне пять лет (eli5). Они помогают мне бегло оценить контент и решить, стоит ли читать его полностью (тред в твиттере).
Краткое содержание в виде списка для «ChatGPT Is a Blurry JPEG of the Web»
Объяснение пятилетнему ребёнку «ChatGPT Is a Blurry JPEG of the Web»
Далее я попробовал собрать агентов с доступом к инструментам вроде SQL и поиска. /sql принимает вопросы на естественном языке, пишет и запускает SQL-запросы и возвращает результат. /sql-agent делает то же самое, но в виде zero-shot-агента. Хотя /sql-agent работал не так надёжно, как хотелось бы (см. Приложение), наблюдать, как он мучается и в итоге справляется, было умилительно и мотивирующе (тред в твиттере).
Запрос к небольшой базе данных через /sql
Запрос к небольшой базе данных через /sql-agent (забавно наблюдать, как он думает, наблюдает и действует)
Я также собрал /search — агента, который умеет обращаться к API поисковых провайдеров (например, Google Search). Так LLM может находить свежие данные, на которых её не обучали, и возвращать точные и актуальные ответы. (Это было ещё до плагинов ChatGPT, в которых эта функциональность теперь есть из коробки. Но даже так собрать всё с нуля было интересно.)
Использование /search для поиска свежей информации для LLM
Совсем недавно я собрал /board — совет экспертов. В его основе — материалы неформальных менторов и плодовитых авторов: Paul Graham, Marc Andreessen, Will Larson, Charity Majors и Naval Ravikant. /board даёт советы по таким темам, как технологии, лидерство и стартапы. В ответе указаны URL-источники для дальнейшего чтения, которые можно прогнать через /summarize и /eli5 (тред в твиттере).
Спрашиваю у /board совета по техническому лидерству и личному успеху
Ещё я сделал /ask-ey — он похож на /board, но работает на моих собственных текстах. Поскольку я лучше знаком со своей работой, мне легче замечать проблемы — например, когда не используется ожидаемый источник (проблема recall) или используются нерелевантные источники (проблема ранжирования).
Синтез по постам про recsys и механизмы на моём сайте через /ask-ey
Комбинируем LLM, базы данных, поисковые API и Discord
Чтобы извлекать содержимое из URL, я воспользовался старыми добрыми requests и BeautifulSoup. Для LLM я использовал gpt-3.5-turbo и gpt-4 от OpenAI, преимущественно первую — она экономичнее. LangChain упростил работу с LLM-цепочками, агентами и инструментами. Для поиска я задействовал кастомный поиск Google через обёртку google-api-python-client. Для эмбеддингов документов и запросов — text-embedding-ada-002 от OpenAI.
Сервер приложения был развёрнут на Railway. Для хранения, обслуживания и поиска ближайших соседей по эмбеддингам я использовал Pinecone. Наконец, всё это интегрировано с Discord через обёртку interactions.
Слабые места поиска и как их исправить
Экспериментируя с /board и /ask-ey, я заметил, что они иногда не извлекают и не используют ожидаемые источники.
Например, когда я спросил у /board «Как мне выбрать между ролью менеджера и IC?», он не использовал в качестве источника ни один из текстов Charity о маятнике менеджер—инженер pendulum или о management. Однако, переформулировав вопрос как «Как мне выбрать между ролью менеджера и инженера?», я получил нужный результат.
При первом вопросе ожидаемые источники о паре менеджер—инженер не используются; при втором — используются
Аналогично, когда я через /ask-ey спросил «Какие бандиты используются в recommendation systems?», он не нашёл мой основной материал про бандитов. Но переформулировка вопроса на «Как используются бандиты в recommendation systems?» решила проблему.
При первом вопросе ожидаемые источники о бандитах не используются; при втором — используются
Но, посмотрев найденные источники, я с разочарованием заметил, что только верхний результат пришёл из ожидаемого URL, и даже это был нерелевантный кусок контента. (Текст с каждого URL разбивается на чанки по 1500 токенов.) Я ожидал, что поиск по эмбеддингам подтянет больше чанков из статьи про бандитов. Это говорит о том, что есть над чем поработать в подготовке данных перед эмбеддингом, и подчёркивает важность data prep.
Только верхний результат — это нужный источник, но в нём нет полезного контента
Частично это связано с плохим recall. Вот несколько гипотез, почему так происходит:
ANN-индексы могут быть настроены неоптимально Готовые эмбеддинги могут плохо переноситься между доменами Документы могут быть неудачно разбиты на чанки Одного только поиска по эмбеддингам может быть недостаточно
ANN-индексы могут быть настроены неоптимально
Большинство (если не все) систем поиска по эмбеддингам используют приближённый поиск ближайших соседей (ANN). Если использовать точный поиск, мы получим идеальный recall, равный 1.0, но с большей задержкой (порядка секунд). ANN же даёт достаточно хороший recall (~0.95) при задержках в миллисекунды. Я ранее сравнивал несколько open-source ANN, и большинство показывали ~0.95 recall при пропускной способности от сотен до тысяч запросов в секунду.
Сравнение ANN по recall и задержке при разных параметрах индекса; правый верхний угол — лучше.
Если проблема в неоптимально настроенном ANN-индексе, мы можем подкрутить параметры индекса, чтобы получить нужный компромисс между recall и задержкой. Однако это требует больше усилий по сравнению с plug-and-play-индексом как сервисом. Я также не уверен, что облачные векторные базы данных дают возможность тюнить ANN. В итоге recall может быть всего около 50%.
Готовые эмбеддинги могут плохо переноситься между доменами
Готовые эмбеддинги могут оказаться слишком общими и плохо переноситься на другие домены. По примерам из этого форума OpenAI видно, как у явно разных текстов оказывается неожиданно высокая косинусная близость. (Хотя примеры выше выглядят общими, суть в том, что нужно внимательно относиться к применению эмбеддингов в своём домене.)
Возможное решение: если у нас есть положительные и отрицательные примеры, мы можем дообучить модель эмбеддингов через triplet loss. Так мы добьёмся того, что расстояние между якорем и положительным примером будет меньше (с запасом), чем расстояние между якорем и отрицательным примером. Это особенно полезно при эмбеддинге приватных данных, в которых содержатся выражения, не встречавшиеся фундаментальным моделям.
Подготовка таких триплетов (якорь, положительный, отрицательный) — основная часть работы. Один из способов — собирать явную обратную связь, возвращая в ответах источники и прося пользователей ставить им лайк/дизлайк. Также доступна неявная обратная связь — например, в e-commerce можно считать отрицательными те результаты, которые пользователи игнорируют; или в поиске мы можем показывать источники в результатах (à la Bing Chat) и смотреть, кликают ли по ним.
Документы могут быть неудачно разбиты на чанки
В-третьих, если мы используем LangChain, скорее всего мы по умолчанию применяем его text splitter и режем контент на документы по 1000–2000 токенов каждый. Такие большие документы возможны, потому что современные модели эмбеддингов поддерживают длинные входные тексты, но проблемы возникают, когда вход перегружен несколькими концепциями.
Представьте, что мы эмбеддим документ на 3000 слов, в котором пять высокоуровневых концепций и дюжина более низкоуровневых. Эмбеддинг всего документа может заставить модель разместить его в латентном пространстве сразу всех концепций, что затрудняет поиск по любой отдельной из них. Даже если мы разобьём документ на несколько чанков по 1500 токенов, эмбеддинг каждого чанка может оказаться мутной смесью нескольких концепций.
Более эффективный подход — разбивать документы по разделам или абзацам. В конце концов, именно так организован большинство текстов: каждая секция или глава раскрывает высокоуровневую концепцию, а абзацы содержат более низкоуровневые. Это должно повысить качество эмбеддингов и улучшить поиск по ним. К счастью, большинство текстов организовано по разделам и главам, а абзацы разделены /n/n.
Подозреваю, что здесь можно получить большой выигрыш, хотя это скорее искусство, чем наука. Это также требует больше ручной работы — скрапинг и подготовка данных для моего хранилища документов заняли столько же усилий, сколько и сборка инструментов, если не больше. См. также пример от OpenAI о том, как они чистили, разбивали на чанки и эмбеддили статьи Википедии.
Одного только поиска по эмбеддингам может быть недостаточно
Наконец, опора лишь на эмбеддинги документов и запросов может быть недостаточной. Поиск по эмбеддингам отлично справляется с семантикой, но проигрывает там, где важно точное совпадение по терминам. Поскольку эмбеддинги представляют документы как плотные векторы, они могут не передать важность отдельных слов, что приводит к низкому recall. А если поисковый запрос точный и короткий, поиск по эмбеддингам может либо не давать большой пользы, либо работать даже хуже. Кроме того, простое эмбеддинг всего запроса может быть слишком грубым решением и сделать результаты чувствительными к формулировке вопроса.
Одно из решений — ансамбль семантического поиска и поиска по ключевым словам. BM25 — надёжная базовая модель, если ожидается совпадение хотя бы по одному ключевому слову. Тем не менее на коротких запросах, где нет совпадения по ключевым словам с релевантными документами, BM25 справляется хуже — здесь усреднённые эмбеддинги ключевых слов могут показать себя лучше. Комбинируя сильные стороны поиска по ключевым словам и семантического поиска, мы можем улучшить recall для разных типов запросов.
Парсинг запросов тоже помогает — он выявляет и расширяет (например, синонимы) ключевые слова, чтобы вопросы интерпретировались единообразно вне зависимости от мелких различий в формулировках. Исправление опечаток и автодополнение тоже могут вести пользователя к лучшим результатам. (Простой хак — пусть LLM разбирает запрос перед поиском.)
Также можно ранжировать найденные документы перед тем, как добавлять их в контекст LLM. В примере с запросом про бандитов выше верхний результат не несёт никакой полезной информации. Решение — ранжировать документы по сигналам, зависящим и не зависящим от запроса. Первые рассчитываются через BM25 и семантический поиск, вторые — через пользовательскую обратную связь, популярность, свежесть, PageRank и т. д. Эвристики вроде длины документа тоже могут помочь.
Обновление: следующая итерация использует гибрид OpenSearch и эмбеддингов E5.
Исследования, рефлексия и планирование с помощью LLM
Хотя инструменты выше собирались на коленке за пару выходных, они намекают на потенциал LLM-усиленных рабочих процессов. Вот несколько идей в смежном пространстве возможностей.
Корпоративный/персональный поиск и Q&A
Представьте, что вы работаете в организации, где внутренние документы, транскрипты встреч, код и другие ресурсы хранятся как поисковые документы. Из соображений конфиденциальности и безопасности вам доступны только те документы, на которые у вас есть права. Чтобы ориентироваться в этой огромной базе знаний, можно задавать простые вопросы вроде:
Какие были основные причины тикетов высокой важности в прошлом месяце? Каковы наши главные победы и самые ценные уроки за прошлый квартал? Какие недавние «Think Big»-идеи или PRFAQ написала команда?
Тогда вместо ссылок на документы, которые пришлось бы читать, почему бы не дать LLM /summarize или /eli5 эту информацию? Он также мог бы синтезировать через /board и находить общие закономерности, вскрывая корневые причины внешне не связанных инцидентов или находя синергии (или дублирование) в предстоящих проектах. Чтобы дополнить результаты, он мог бы делать /sql или /sql-agent к базам, или /search по свежим данным в интернете.
Рассмотрим другой сценарий — личная база знаний. За годы я накопил библиотеку книг, статей и разрозненных заметок. К сожалению, моя память со временем слабеет, и я забываю большую часть деталей в течение недели. Чтобы с этим справиться, я могу применить аналогичные приёмы к личной базе знаний и спрашивать /ask-ey:
В каких статьях обсуждается применение бандитов в recommendation systems? Какой совет я дал бы тому, кто приходит в новую команду? Какие основные темы были в моей жизни в последние несколько лет?
На каждый из этих вопросов я вложил усилия в исследование, перегонку и публикацию ответов в виде постоянных заметок. И сам процесс был бесценен для прояснения мыслей и обучения через письмо. Тем не менее, я думаю, что инструменты выше могут довести нас примерно до 50% результата с гораздо меньшими усилиями. Похоже, продукты вроде Glean (для корпораций) и Rewind (для личного использования) делают именно это.
Исследования, планирование и написание
Вернёмся к сценарию с внутренними документами и транскриптами встреч. Допустим, вы — лидер в своей организации и вам нужно написать важный документ. Это может быть шестинедельный план по борьбе с tech debt или более амбициозная трёхлетняя дорожная карта. Как облегчить написание такого документа?
Чтобы написать документ по техдолгу, сначала нужно понять, какие из проблем самые острые. Мы можем начать с того, что попросим /board собрать детали по уже известным проблемам. /board поможет нам найти и синтезировать релевантные тикеты, транскрипты war room-встреч и многое другое через /sql и внутренний /search. Затем мы можем расширить запросы, чтобы найти неосознанные проблемы, а потом погрузиться глубже там, где нужно.
Имея три главные проблемы, мы можем начать с введения, в котором изложим цель документа (то есть Why — он же prompt). Затем, по мере того как мы создаём заголовки секций для каждой проблемы, копилот на основе document retrieval + LLM помогает нам их наполнять, предоставляя данные (/sql), ссылки на релевантные источники (/search) и даже предлагая решения (/board). У Bing Chat это уже есть в каком-то виде. Также я верю, что в этом и состоит видение Office 365 Copilot.
Как основной автор мы по-прежнему должны включать своё суждение, чтобы проверять релевантность источников и расставлять приоритеты. Также нам придётся оценивать предложенные решения и решать, нельзя ли подкрутить одно из них так, чтобы оно закрыло сразу несколько проблем, снизив трудозатраты и дублирование. Тем не менее, пока мы остаёмся ответственными за документ, копилот помогает собрать и подготовить данные, существенно снижая нагрузку.
LLM: не база знаний, а движок рассуждений
«Правильный способ думать о моделях, которые мы создаём, — это reasoning engine, а не fact database. Они могут работать и как fact database, но в этом нет ничего особенного. Мы хотим, чтобы они умели именно рассуждать, а не запоминать.» — Sam Altman
Мы увидели, что LLM умеют пользоваться инструментами, суммировать информацию и синтезировать закономерности. Обучение на всём интернете каким-то образом дало им способности к рассуждению. (Возможно, это связано с обучением на данных GitHub и StackOverflow, ведь код — это логика?) Тем не менее, умея рассуждать, они часто ограничены отсутствием глубоких или приватных знаний — таких, что хранятся в корпоративных или личных базах знаний.
Думаю, ключевой вызов — и одновременно решение — в том, чтобы давать им нужную информацию в нужный момент. Хорошо организованное хранилище документов помогает. А используя гибрид keyword search и семантического поиска, мы можем точно извлекать контекст, нужный LLM, — это и объясняет, почему традиционные поисковые индексы интегрируют векторный поиск, почему векторные базы данных добавляют keyword search и почему некоторые приложения идут по гибридному пути (Vespa.ai, FB search).
• • •
Трудно предсказать, насколько эффективными и широко распространёнными станут LLM. Я уже задавался вопросом, окажут ли LLM такое же влияние, как компьютеры, мобильные телефоны или интернет. Но чем больше я экспериментирую с ними, тем больше склоняюсь к мысли, что их потенциал может быть даже больше, чем у всех этих технологий вместе взятых.
А даже если я ошибаюсь, мне как минимум всё ещё весело заставлять LLM объяснять заголовки в стиле Dr. Seuss или придумывать причудливые цитаты на моей Raspberry Pi Pico.
Пока одни используют LLM, чтобы переворачивать индустрии и больше,Другие пишут плагины ChatGPT, расширяя границы без меры.А я — вот, с Raspberry Pi в руке,С помощью LLM объясняю заголовки в стиле Dr. Seuss. pic.twitter.com/0MJn6HC2cw— Eugene Yan (@eugeneyan) 10 апреля 2023
Приложение
Вот пример того, как /sql-agent мучился и в итоге догадался, что надо проверить схему базы. Хотя он наконец выполнил правильный запрос и получил результат, у него закончились итерации до того, как он смог ответить 🥲 (Назад к началу)
/sql-agent мучается, пытаясь правильно составить запрос
Если этот материал оказался полезным, цитируйте его так:
Yan, Ziyou. (Apr 2023). Experimenting with LLMs to Research, Reflect, and Plan. eugeneyan.com. https://eugeneyan.com/writing/llm-experiments/.
или
@article{yan2023llmapps, title = {Experimenting with LLMs to Research, Reflect, and Plan}, author = {Yan, Ziyou}, journal = {eugeneyan.com}, year = {2023}, month = {Apr}, url = {https://eugeneyan.com/writing/llm-experiments/} }
Присоединяйтесь к 11 800+ читателей, получающих обновления о machine learning, RecSys, LLM и инженерии.