В 2024 году недостатка в приложениях на основе LLM не будет. Крупные технологические компании, такие как Microsoft и Google, продвигают все более мощные версии своих флагманских моделей ChatGPT и Gemini, а специализированные игроки, такие как Anthropic, продвигают конкурирующие предложения с дополнительными интеграциями. В мире прикладного LLM компании и даже правительства экспериментируют с чат-приложениями для различных контекстов.
Несмотря на огромную предпринимательскую энергию, вложенную в LLM, большинство громких приложений по-прежнему ограничены ориентацией на чат-интерфейсы, которые принимают и возвращают удобочитаемый текст. Это понятно: в конце концов, одним из наиболее интересных достижений LLM является способность понимать и генерировать человеческий язык, что позволяет создавать диалоговый пользовательский интерфейс. Однако интерфейсы чата упускают из виду еще один очень важный вариант использования LLM — обработку текста как промежуточный этап в более крупном конвейере данных.
Сегодня мы рассмотрим этот вариант использования и увидим, как LLM могут быть полезны как часть конвейера данных, а не только как генератор естественного языка.
Чтобы использовать LLM как часть конвейера данных, нам нужно изменить формат вывода LLM — вместо того, чтобы генерировать абзацы для чтения людьми, модель должна генерировать что-то, что могут прочитать компьютеры. Обычно это означает структурированный вывод в формате данных, например JSON, или инструкции на языке программирования, таком как Python или SQL. Эти форматы вывода гораздо менее щадящие, чем естественный язык, поскольку отсутствие кавычки или скобки может привести к сбою всего конвейера. Поэтому нам придется полагаться на специализированные методы и функции, разработанные для поддержки этого варианта использования. Эти функции в совокупности называются вызовом функций, поскольку выходные данные имеют тенденцию вызывать функции или использоваться при вызовах функций.
Однако прежде чем мы углубимся в эти методы, давайте сначала немного подробнее рассмотрим, почему вообще были разработаны функции вызова функций.
Подключение к внешним сервисам
Оригинальный и наиболее простой вариант использования вызова функций — подключение к внешним службам. Когда OpenAI первоначально выпустила GPT-4, она также обновила API функцией, которая позволяла пользователю предоставлять модели набор функций в стиле Python, которые модель могла вызывать для достижения своих целей. Например, модели можно сказать, что она может вызывать внешнюю функцию для расчета цены сложной ценной бумаги. Используя эту информацию, модель сможет написать код, который рассчитывает стоимость портфеля, состоящего из этих ценных бумаг, без необходимости обладать специальными знаниями о ценообразовании ценных бумаг.
Вызов функций в стиле Python — это лишь верхушка айсберга. Как только важность вызова функций была доказана на рынке, OpenAI и другие поставщики LLM начали поддерживать другие форматы вывода, такие как JSON или SQL. Важным было то, что эти модели выдавали машиночитаемые выходные данные, которые могли быть надежно прочитаны другими процессами.
Внимательные читатели могут заметить, что в предыдущих статьях мы делали нечто подобное, используя LLM для генерации обучающих данных , SQL или JSON . В этих статьях мы достигли этого с помощью быстрого проектирования и проверки вывода, но теперь, когда вызов функций является широко поддерживаемой функцией, мы можем сделать это проще, полагаясь на эти функции уровня модели.
Объединение LLM
Вызов функций создал новые возможности для приложений с несколькими LLM, и вскоре разработчики начали экспериментировать с объединением LLM в цепочки для создания сложных систем. Некоторые из этих систем стали известны как агенты , которые могли самостоятельно искать в сети, собирать новые данные и вызывать другой LLM с новой информацией. Эти конвейеры обладают удивительной степенью автономии и способны решать сложные проблемы с очень небольшими затратами, хотя все еще существуют ограничения, такие как стоимость API и поведенческие гарантии, которые не позволяют агентам получить широкое распространение.
Использование LLM в качестве входной и промежуточной обработки
Другой вариант использования LLM с вызовом функций — обработка входных и промежуточных данных. LLM можно использовать для анализа неструктурированных входных данных в структурированные данные, которые можно использовать для последующей обработки. Хотя многие из этих задач, как правило, передаются «традиционным» технологиям НЛП, гибкий характер моделей на основе преобразователей означает, что специально обученная модель может выполнять эти задачи намного лучше, чем другие технологии НЛП. В результате многие разработчики пытаются использовать эти специализированные модели в своих конвейерах данных.
Теперь, когда мы знакомы с теорией вызова функций, давайте посмотрим на приложение, которое мы будем создавать сегодня.
В предыдущей статье я создал простое приложение RAG для ответа на вопросы на естественном языке о популярном информационном бюллетене CB Insights. В сегодняшней статье мы создадим аналогичное приложение для ответов на вопросы, но вместо того, чтобы полагаться на встроенный поиск и GPT3.5, мы будем использовать распознавание объектов в качестве основного метода индексации. Кроме того, мы будем использовать DRAGON в качестве механизма суммирования, чтобы мы могли запускать все приложение на нашем ноутбуке без необходимости использования облачных сервисов.
Зачем использовать распознавание объектов?
Прежде чем углубиться в реализацию, давайте сначала рассмотрим преимущества использования NER в качестве технологии поиска вместо встроенного поиска. Хотя в производстве мы хотим использовать каждый метод в соответствии с требованиями конкретной ситуации, NER предлагает несколько преимуществ по сравнению с системой, основанной на встроенном поиске.
Возможность отладки. Поскольку распознавание объектов — это легко проверяемая задача, весь конвейер гораздо легче отлаживать. Легко проверить, правильно ли модель идентифицирует все объекты, а также легко построить и улучшить алгоритм сопоставления на основе этих объектов. Для сравнения, гораздо сложнее проверить, что алгоритм встраивания правильно определяет сходства и различия в отрывках.
Гибкость: разделяя распознавание и фильтрацию, мы делаем конвейер намного более гибким, чем алгоритм поиска на основе внедрения. Мы можем добавлять дополнительные метаданные, изменять алгоритмы поиска в зависимости от типа объекта и даже использовать алгоритмы встраивания поверх результатов поиска на основе NER. Это позволяет разрабатывать гораздо более мощные функции на основе сочетания технологий.
Например, конвейер на основе NER может использовать поиск на основе сущностей для сужения набора документов, а затем использовать алгоритм внедрения для дальнейшего сужения пространства поиска. Это делает поиск намного быстрее и эффективнее.
Способность идентификации: благодаря возможному уровню ручного управления конвейеры NER гораздо лучше подходят для определенных задач поиска и извлечения. Поиск по внедрению основан на близости отрывков в обучающих данных, что позволяет вычислить вероятность того, что два документа происходят из одного и того же более крупного документа. В некоторых случаях это может привести к тому, что при встроенном поиске будут пропущены важные документы.
Теперь, когда мы понимаем преимущества использования NER в конвейере RAG, давайте более подробно рассмотрим конкретные технологии, которые мы используем в нашем приложении.
Распознавание объектов LLM
Распознавание сущностей — это «традиционная» технология НЛП для извлечения структурированных данных из неструктурированных языковых данных. Извлеченные данные затем можно использовать в последующей обработке или в качестве метаданных для анализируемого отрывка.
Исторически это достигалось с помощью небольших, специально созданных алгоритмов машинного обучения, которые сначала маркируют части речи, а затем второй проход определяет, являются ли идентифицированные имена собственные именованными объектами.
С помощью LLM, вызывающих функции, мы можем выполнить ту же задачу, но с несколькими дополнительными преимуществами.
Поскольку архитектура преобразователя способна лучше понимать языковую структуру, чем более мелкие модели НЛП, производительность, вероятно, будет более надежной, например, в случаях, когда отрывок отформатирован неправильно.
Поскольку LLM обновляются с использованием самых последних данных обучения, система распознавания объектов, вероятно, останется более актуальной, чем другие модели распознавания объектов с открытым исходным кодом.
Для внедрения дополнительных данных и дополнительных инструкций можно использовать методы быстрого проектирования, что обеспечивает более гибкое поведение даже в готовых моделях.
DRAGON Мы рассказывали о Dragon в предыдущей статье, где подчеркивали его впечатляющую производительность при обобщении данных на естественном языке. Мы будем использовать Dragon для выполнения заключительного этапа анализа, на котором мы суммируем все статьи, относящиеся к выбранным объектам.
SLIM SLIM — это новое семейство миниатюрных локально запускаемых моделей от LLMWare (не секрет, что я фанат их работы по миниатюризации), которые специализируются на вызове функций. Эти модели были специально настроены для генерации выходных данных, которые могут быть интерпретированы машинами, что позволяет пользователям воспользоваться преимуществами последних разработок в архитектуре вызова функций без необходимости полагаться на внешние API.
Сегодня мы будем использовать модель SLIMs-NER, которая будет выполнять распознавание именованных объектов в статьях информационного бюллетеня. Помимо NER, существуют также модели SLIM для анализа настроений, генерации SQL и многошаговых агентов.
Теперь мы разобрались в технологии, давайте реализовывать приложение!
Начнем с загрузки статей CB Insights. Давайте импортируем зависимости:
import requests from bs4 import BeautifulSoup import os import pandas as pd import json import re
А теперь код для скачивания архива рассылки:
res = requests.get('https://www.cbinsights.com/newsletter/') soup = BeautifulSoup(res.text) article_links = [[i.text, i['href']] for i in soup.find_all('a') if 'campaign-archive' in i['href'] ] article_soups = [BeautifulSoup(requests.get(link).text) for title, link in article_links]
Теперь, когда мы скачали архив новостной рассылки, давайте обработаем его в формат JSON.
result_json = {} for soup_meta, soup_art in zip(article_links, article_soups): article_tables = [] cur_article = [] for table in soup_art.find_all('table'): if table.attrs.get('mc:variant') == 'Section_Divider': article_tables.append(get_deduped_article_tables(cur_article)) cur_article = [] else: cur_article.append(table.text) article_tables.append(get_deduped_article_tables(cur_article)) result_json[soup_meta[0]] = article_tables articles_with_meta = [] for name, tables in result_json.items(): print(name, pd.to_datetime(tables[0][1].strip())) articles_with_meta.append({ 'name': name, 'date': pd.to_datetime(tables[0][1].strip()).strftime('%Y-%m-%d'), 'tables': tables }) df = pd.DataFrame(articles_with_meta)
Теперь мы находимся в том же месте, где были в предыдущей статье. Однако вместо того, чтобы сразу перейти к построению RAG путем создания вложений, мы выполним этап распознавания объектов.
Во-первых, давайте импортируем зависимости для запуска SLIM, нового набора моделей от LLMWare, который позволяет нам выполнять распознавание объектов локально на нашей машине:
from llmware.agents import LLMfx from llmware.parsers import WikiParser from collections import defaultdict # define a function for identifying all the named entities def run_ner(text): agent = LLMfx() agent.load_work(text) agent.load_tool("ner") named_entities = agent.ner() ner_dict= named_entities["llm_response"] return ner_dict
Теперь мы можем запустить распознавание именованного объекта для всех статей:
date_entities = defaultdict(dict) for _, row in df.iterrows(): for idx, t in enumerate(row['tables'][1:]): if 'Start Your Free Trial' in t: t = t[:t.index('Start Your Free Trial')] date_entities[row['date']][idx] = run_ner('\n'.join(t))
Завершение работы конвейера NER может занять несколько минут, но это все, что вам нужно для распознавания объектов с помощью современного миниатюрного LLM.
Вы можете проверить словарь date_entities, распечатав несколько тестовых элементов. Например, код:
date_entities[list(date_entities.keys())[0]]
Должен выдать результат ниже:
{0: {'people': ['Yahoo!'], 'place': [], 'company': ['Databricks', 'MosaicML'], 'misc': []}, 1: {'people': [], 'place': ['New York'], 'company': ['CB Insights'], 'misc': []}}
Здесь показаны все различные объекты, обнаруженные моделью SLIM.
Теперь, когда сущности обнаружены, давайте построим рабочий процесс вопросов и ответов, который продемонстрирует мощь этого метода. В нашем примере мы будем использовать тестовый вопрос: Какую роль OpenAI играет в стратегии Microsoft в области искусственного интеллекта?
Начнем с импорта необходимых пакетов для запуска DRAGON:
from llmware.prompts import Prompt query = "What role does OpenAI play in Microsoft's AI strategy?" model_name = "llmware/dragon-llama-7b-gguf" prompter = Prompt().load_model(model_name)
Теперь мы можем создать функцию, которая отвечает на вопрос, используя распознавание объектов. Чтобы использовать наши данные NER, нам нужно реализовать следующий рабочий процесс:
Вот как выглядит рабочий процесс в виде кода:
def answer_question_with_ner(query): ner_results = run_ner(query) # run NER on the user query search_entities = [] for ent_type, ent_list in ner_results.items(): search_entities.extend(ent_list) # create a list of entities to search for search_entities = list(set(search_entities)) # now perform a lookup for articles that mention the identified entities, using set arithmetic. articles = set(entity_to_place_map[search_entities[0]]) for se in search_entities: articles &= set(entity_to_place_map[se]) # now process the corpus into a prompt and feed it to the question-answering LLM. article_content = [] for article in articles: article_content.extend(df[df['date'] == article[0]].iloc[0]['tables'][article[1]+1]) response = prompter.prompt_main(query, context='\n'.join(article_content), prompt_name="default_with_context", temperature=0.3) return response # return the response.
Запустите функцию с запросом из первого блока кода, и вы должны увидеть следующий результат:
Microsoft has poured billions of dollars into ChatGPT developer OpenAI. However, it's also placed a number of bets on other GenAI startups across computing, mapping, and gaming.
В разделе «доказательства» объекта ответа вы также можете увидеть, что действительно были получены две статьи из архива CB Insights, в которых упоминаются Microsoft и OpenAI, и что ответ LLM основан непосредственно на доказательствах.
Обратите внимание: поскольку мы выполняем явное распознавание объектов, процесс поиска чрезвычайно прозрачен и легко отлаживается. Если когда-либо возникнет вопрос, почему модель извлекла эти конкретные фрагменты информации из корпуса, достаточно простого оператора печати, чтобы увидеть, что модель выбрала статью, потому что в запросе упоминаются «Microsoft» и «OpenAI», а два извлеченных раздела информационного бюллетеня — единственные разделы, в которых упоминаются оба объекта.
Кроме того, по сравнению с векторным поиском на основе встраивания, метод поиска NER дает гораздо более точные ответы. В ходе моих тестов выбранные статьи входили в десятку наиболее релевантных статей по рейтингу алгоритма ada OpenAI, но не были определены как наиболее близкие к рассматриваемому вопросу. Следовательно, возможно, что приложение, использующее встроенный поиск, вообще не ответило на вопрос правильно, а отсутствие возможностей отладки только усугубит путаницу.
И благодаря этому мы создали приложение для ответов на вопросы, используя поиск NER, улучшая при этом качество конвейера!
Сегодня мы создали приложение, используя вызов функций — новую интересную функцию LLM. Миниатюрные, локально запускаемые модели вызова функций — это революционная разработка, которая открывает новый класс приложений ИИ, и мы видим только первую итерацию этих технологий. Будет интересно посмотреть, какие приложения разработчики создадут с помощью этих технологий в ближайшие месяцы.
Если у вас есть идея в области искусственного интеллекта, которую вы хотите реализовать, или просто хотите поговорить о технологиях, не стесняйтесь обращаться к Github или LinkedIn .
Если вы хотите узнать больше о LLMWare, компании, разрабатывающей SLIM и DRAGON, вы можете найти их на HugginFace или Github .