Задумывались ли вы, кто на самом деле находится по ту сторону телефонной линии или чата? В современном мире за приятным голосом неизвестного абонента или ненавязчивым текстовым сообщением часто скрывается вовсе не человек, а искусственный интеллект. Этот робот обучен выполнять задачи маркетинга и клиентской поддержки. Но когда мы пишем негативный фидбек или выражаем свои пожелания, то надеемся если не на изменения, то хотя бы на эмоциональную реакцию. Но ИИ такой ответ — не по силам.
Всем привет, меня зовут Никита Сергиевский. Я — разработчик программ и приложений на базе больших языковых моделей (LLM) в компании Raft Digital Solutions. В своей первой статье расскажу, что такое Retrieval-Augmented Generation (RAG), как его сделать нативнее и с помощью каких фрейморков разрабатывать помимо нашумевшего «из каждого утюга» Langchain. Кстати, его мы тоже немного «потыкаем».
Огромное спасибо моему коллеге из Raft Кириллу Кухареву (@Kosmak) за помощь в написании технической части статьи.
Концепция RAG приобретает всё большее значение в бизнес-процессах и технологиях компаний, зачастую даже не связанных с IT. Особенно когда речь идёт о предоставлении контекстуально точной и актуальной информации. Представьте сценарий, в котором ваша компания ежедневно обрабатывает тысячи запросов от клиентов. Каждый, конечно, требует индивидуального подхода и точного ответа на поставленные вопросы. В таких случаях традиционные методы генерации текста могут не справиться с задачей на должном уровне. И здесь на сцену выходит RAG.
RAG — это подход, сочетающий механизмы извлечения данных и генерации текста. Он позволяет использовать существующие источники данных — такие, как база знаний или интернет. Этот метод не только улучшает генерацию текста языковой моделью, но и обогащает её актуальными данными, недоступными напрямую при традиционном использовании или обучении.
Основные преимущества:
-
Увеличение точности ответов. RAG снижает вероятность ошибок и галлюцинаций в предоставляемой информации благодаря использованию актуальных данных.
-
Экономия времени и ресурсов. Автоматизация с помощью RAG сокращает время на обработку запросов и снижает нагрузку на сотрудников, высвобождая ресурсы для решения более сложных задач.
-
Персонализация и индивидуальный подход. Возможность динамически извлекать и интегрировать данные обеспечивает высокую степень персонализации ответов, улучшая пользовательский опыт.
-
Масштабируемость. Технология легко адаптируется под рост объёмов данных и расширение бизнес-задач, поддерживая высокий уровень производительности.
Когда простого RAG недостаточно
Представьте ситуацию: вы просите систему «если на улице дождь, вызови мне такси». Классический RAG отреагирует так: предоставит информацию о том, как проверить погоду и воспользоваться приложением для вызова машины. Он на самом деле не воспринимает этот запрос как инструкцию к действию, а интерпретирует, как запрос на получение информации.
В бизнес-процессах часто возникают задачи, которые решаются в несколько этапов. Простого «вынь да положь» релевантной информации в красивой обёртке из базы знаний будет недостаточно. К тому же стандартные RAG-системы лишены возможности принимать динамические решения или выполнять действия по заданному контексту. Это ограничивает их применение в более сложных сценариях.
С такими задачами может справиться Агентный RAG. Использование агентов ИИ открывает возможности для создания более мощных, надёжных и универсальных приложений на базе LLM. Это достигается за счёт использования краткосрочной и долговременной памяти (история запросов), элементов планирования (рефлексия, самокритика, маршрутизация запросов и т.д.) и «тулзов» — функций, выполняющих определённые действия (калькулирование значений, обращение к API). Принцип работы Агентного RAG организован так:
-
Первый этап. Происходит идентификация задачи. LLM анализирует запрос пользователя и определяет, что требуется сделать.
-
Второй этап. Агент выполняет задачу пользователя. Это может быть запрос к базе данных, поиск веб-контента, вызов API или вычисления.
-
Третий этап. После выполнения задачи агент возвращает результат в LLM для дальнейших рассуждений или генерации ответа.
Как вы могли заметить, на изображении выше представлена одноагентная система, имеющая свои ограничения. Поэтому выгодно объединить несколько агентов в многоагентное приложение RAG для сложных сценариев. Например, у вас может быть один главный агент, координирующий поиск информации среди нескольких специализированных агентов-поисковиков. Один агент извлекает информацию из собственных внутренних источников данных. Другой агент специализируется на получении информации из личных аккаунтов, таких как электронная почта или чат. Третий агент извлекает публичную информацию из веб-поиска.
Однако, на этом развитие концепции RAG не останавливается. Одно из наиболее перспективных направлений — GraphRAG — подход, который объединяет мощь графовых баз данных с Retrieval-Augmented Generation.
GraphRAG использует графовые БД для хранения и обработки информации, а также построения более сложных связей между объектами. Наибольшее различие GraphRAG и обычного RAG в использовании графов. Это особенно полезно в ситуациях, когда данные обладают сложной структурой, например, при моделировании отношений между пользователями, событиями или продуктами.
Преимущества GraphRAG:
-
Позволяют моделировать контекст. Если пользователь запрашивает контекстно-зависимую информацию, то GraphRAG учитывает не только текущий запрос, но и связи, которые формирует информация из запроса пользователя.
-
Динамическое принятие решений. Например, при построении маршрутов.
-
Гибкость. Можно объединять данные из разных источников, включая базы знаний или CRM-системы.
На изображении приведена концепция Graph RAG — основанный на входных данных (документах) подход для обработки, структурирования, объединения в ответы на вопросы. На схеме изображено два процесса — индексирование (Indexing time) и получение ответа на основе подготовленных данных (Query time).
Процесс индексирования состоит из таких этапов:
-
Source Documents → Text Chunks
Из исходных документов извлекается текст и разбивается на небольшие смысловые части — чанки.
-
Text Chunks → Element Instances
Для каждого текстового чанка производится обобщение с учётом специфики домена. В результате создаются экземпляры элементов. Эти экземпляры могут представлять ключевые смысловые структуры внутри текстов, адаптированные для конкретной задачи (например, в финансовом или медицинском контексте).
-
Element Instances → Element Summaries
Выполняется дополнительное доменное резюмирование, чтобы получить краткие резюме для каждого элемента.
Процесс оценки:
-
Element Summaries → Graph Communities
Из резюме элементов затем строятся графы. С помощью алгоритмов обнаружения сообществ (Community Detection) анализируется схожесть между элементами. Графовые сообщества строятся на основе текстовой связи, общего смысла или темы, что группирует элементы с похожей информацией.
Процесс поиска информации:
-
Graph Communities → Community Summaries
При возникновении запроса применяется доменно-ориентированное резюмирование для формирования итогов из графов-сообществ. Это позволяет выделить компактные смыслы из набора связанной информации.
-
Community Summaries → Community Answers
На основании конкретного запроса от пользователя выполняется query-focused summarization или направленное резюмирование. Здесь учитывается содержание вопроса чтобы извлечь наиболее релевантные данные из графа.
-
Community Answers → Global Answer
На последнем шаге результаты различных сообществ агрегируются в глобальный ответ — единое решение на запрос пользователя в результате объединения релевантных ответов.
Звучит интересно, а что на практике
На практике у каждого разработчика или группы разработки всегда получается по-своему. Ведь, инструменты и предпочтения при решении комплексных задач различаются. В последние годы наиболее популярными фреймворками для разработки RAG стали LangChain
, Semantic-router
и Llama_index
.
Рассмотрим пример реализации простого RAG'а на LangChain, ищущего информацию для ответа на вопросы о новогодних традициях разных стран
import os
from langchain_chroma import Chroma
from yandex_chain import YandexEmbeddings
# Инициализируем модель для эмбеддинга
embeddings = YandexEmbeddings(
folder_id=os.getenv('folder_id'),
api_key=os.getenv('api_key')
)
# Прочитаем предварительно подготовленный файлик с традициями и обычаями разных стран
with open('attributes.txt',encoding='utf-8') as f:
attributes = ''.join(f.readlines())
normalized_attributes = [x for x in attributes.split('-----')]
# Складываем информацию по традициям каждой страны в векторную базу,
# в качестве векторной БД используем Chroma
Chroma.from_texts(normalized_attributes, embeddings, persist_directory='./chroma_db')
# После того, как данные сложили, мы можем их подгрузить
db = Chroma(embedding_function=embeddings, persist_directory='./chroma_db')
# Создаем задачу "Сгенерировать полноценный анализ по статье"
task_research = Task(
description=(
"Perform a thorough analysis of the published research paper. "
"Identify the key components and explain how they function."
),
expected_output="Produce a comprehensive analysis report of the research paper.",
agent=reasarcher,
output_file='researcher_analysis.md'
)
# Объявляем переменную q с запросом, инициализируем ретривер
# и задаем вопрос RAG.
# MMR-поиск (Maximal Marginal Relevance) позволяет исключить из выдачи слишком похожие фрагменты.
q = "Где можно встретить самый запоминающийся Новый Год?"
retriever = db.as_retriever(search_type="mmr", search_kwargs={"k": 5})
res = retriever.invoke(q)
print(res)
Чтобы получить человекоподобный ответ на вопрос, необходимо построить цепочку, которая вызывает retriever для получения релевантных фрагментов текста, отправляет фрагменты в контекст модели, и просит её ответить на исходный вопрос с учётом контекста.
import langchain.chains
import langchain.prompts
from yandex_chain import YandexLLM, YandexGPTModel
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
llm = YandexLLM(
folder_id=os.getenv('folder_id'),
api_key=os.getenv('api_key'),
model=YandexGPTModel.Pro
)
prompt = """
Проанализируй текст ниже и дай краткий ответ на вопрос, опираясь только на информацию из текста.
Не упоминай в ответе, что ты нашел информацию в тексте.
Текст:
-----
{context}
-----
Вопрос:
{question}
Ответ:
"""
prompt = langchain.prompts.PromptTemplate(
template=prompt, input_variables=["context", "question"]
)
def join_docs(docs):
return "nn".join(doc.page_content for doc in docs)
# Создаём цепочку
chain = (
{"context": retriever | join_docs, "question": RunnablePassthrough()}
| prompt
| llm
| StrOutputParser()
)
# Вызываем RAG с запросом
print(chain.invoke(q))
Посмотрим на ответы нашего RAG.
chain.invoke('Почему в некоторых странах Новый год отмечают не 31 декабря, а в другие дни?')
""В разных странах Новый год отмечают в разное время из-за особенностей традиций и культуры. Например, в Индии его встречают несколько раз в году: в марте наступает традиционное индийское начало года — Гуди-падва, а ещё есть фестиваль красок холи, который тоже связан с празднованием Нового года."""
chain.invoke("Как традиции встречи Нового года в России отличаются от традиций, описанных в Европе?")
"""В России Новый год отмечают с 31 декабря на 1 января. Люди собираются за обильным столом, традиционно подают «Оливье», «Селёдку под шубой» и шампанское. После боя курантов на Спасской башне Кремля люди загадывают желания и выходят на улицы запускать фейерверки. Центральными фигурами праздника являются Дед Мороз, который приходит с подарками, и ёлка, которую украшают игрушками и гирляндами."""
."""В Великобритании и Исландии в праздновании Нового года можно увидеть элементы, связанные с семейным единением и традициями: приготовление и совместное участие в создании праздничного блюда (пудинг), а также определённые ритуалы при его приготовлении для загадывания желаний, ожидание подарков и сладостей от сказочных персонажей (Йольские братья).."""
."""В Иране Новый год — Навруз — совпадает с днём весеннего равноденствия. В этот день люди украшают свои дома, готовят специальный стол «хафт-син» и дарят друг другу подарки, желая счастья в новом году.."""
."""Итальянцы выбрасывают из окон ненужный хлам, верят, что это принесёт им счастье в новом году, целуются всю ночь и надевают красное бельё — считается, что эти традиции могут обеспечить успех и процветание.."""
Таким образом, в отличие от европейских традиций, в России меньше внимания уделяется таким специфическим действиям, как приготовление ритуальных блюд или символичные наряды. Российские новогодние традиции скорее включают в себя обильное застолье и массовые гуляния после полуночи.
Но такой RAG не выделяет взаимосвязи между несколькими найденными ответами из базы знаний. Для определения взаимосвязей между несколькими смысловыми кусками текста, как уже говорилось ранее, используется GraphRAG. Дальше разберём пример.
Для начала определим промпт для выделения сущностей и связи между ними в тексте:
entity_extraction_prompt =
"""
# Цель
Тебе даётся текстовый документ. Задача: извлечь информацию в структурированном виде.
1. Выдели **сущности**, чтобы передать информацию и идеи текста.
2. Выдели **связи** между этими сущностями.
# Шаги
1. Извлечение сущностей:
- **Имя сущности** (entity_name): Название сущности (заглавными буквами).
- **Тип сущности** (entity_type): Общая категория сущности.
- **Описание сущности** (entity_description): Подробности о сущности (что она представляет).
Для каждого объекта выведи строку:
`(entity|<entity_name>|<entity_type>|<entity_description>)`
2. Извлечение связей:
Найди пары связанных сущностей и для каждой укажи:
- **Исходная сущность** (source_entity): Имя первой сущности.
- **Целевая сущность** (target_entity): Имя второй сущности.
- **Тип связи** (relationship_name): Короткое описание характера связи.
- **Описание связи** (relationship_description): Как именно связаны сущности.
Для каждой связи выведи строку:
`(relationship|<source_entity>|<target_entity>|<relationship_name>|<relationship_description>)`
"""
llm = YandexLLM(
folder_id=userdata.get('folder_id'),
api_key=userdata.get('api_key'),
model=YandexGPTModel.Pro
)
text = """
Шотландия
Шотландия, будучи частью Великобритании, тем не менее, всегда гордилась своей обособленностью от Объединенного Королевства и своими уникальными традициями.
Одна из них — поджигать деготь в бочках и катить их по улицам, что должно символизировать «сгорание старого года».
Шотландцы провожают старый год с главными атрибутами праздника — кострами, через которые прыгают, огнем и свечами.
Огонь является важным элементом очищающих ритуалов. Как только прозвонят звоны, извещающие о наступлении нового года, вступает в силу поверье о том, что первый вошедший в дом человек является предвестником счастья и благополучия принимающей семьи.
Самым лучшим вариантом считается темноволосый мужчина с традиционными подарками.
"""
result = llm.invoke(entity_extraction_prompt.format(text))
Получится примерно такой ответ:
(entity|ШОТЛАНДИЯ|РЕГИОН|часть Великобритании)
(entity|ВЕЛИКОБРИТАНИЯ|ГОСУДАРСТВО|объединенное королевство)
(relationship|ШОТЛАНДИЯ|ВЕЛИКОБРИТАНИЯ|ЧАСТЬ_ОТ|Шотландия является частью Великобритании)
(entity|ОБОСОБЛЕННОСТЬ|КОНЦЕПТ|уникальные традиции)
(entity|ТРАДИЦИИ|КОНЦЕПТ|особенности культуры)
(entity|ПОДЖИГАНИЕ_ДЁГТЯ|ДЕЙСТВИЕ|ритуал очищения)
(entity|КАТАНИЕ_БОЧЕК|ДЕЙСТВИЕ|элемент ритуала)
(entity|СГОРАНИЕ_СТАРОГО_ГОДА|СИМВОЛ|сжигание старого года)
(entity|КОСТРЫ|ПРЕДМЕТ|атрибут праздника)
(entity|ПРЫЖКИ_ЧЕРЕЗ_КОСТРЫ|ДЕЙСТВИЕ|атрибут празднования)
(entity|ОГОНЬ|СТИХИЯ|важный элемент очищающих ритуалов)
(entity|СВЕЧИ|ПРЕДМЕТ|элементы очищающего ритуала)
(entity|ЗВОНЫ|ЗВУК|извещают о наступлении нового года)
Теперь возьмём файл с традициями и обычаями разных стран на Новый Год и прогоним через модельку.
from tqdm.auto import tqdm
with open('attributes.txt',encoding='utf-8') as f:
attributes = ''.join(f.readlines())
with open('results/relations.txt','w',encoding='utf-8') as f:
for x in tqdm(prepared_attributes):
result = llm.invoke(entity_extraction_prompt.format(x))
f.write(result)
Чтобы построить граф отношений между сущностями, выполним следующий код:
import json
with open('graphs/entities.json','w',encoding='utf-8') as f:
json.dump(entities,f,ensure_ascii=False,indent=4)
with open('graphs/relations.json','w',encoding='utf-8') as f:
json.dump(relations,f,ensure_ascii=False,indent=4)
И, наконец, чтобы отобразить граф сущностей и взаимосвязей используем библиотеку networkx
и matplotlib
.
import networkx as nx
import matplotlib.pyplot as plt
G = nx.DiGraph()
exist_entities = set([r['source'] for r in relations] + [r['target'] for r in relations])
for e,v in entities.items():
if e in exist_entities:
G.add_node(e, label=e)
for r in relations:
G.add_edge(r['source'], r['target'], label=r['relation'], desc=r['desc'])
def plot_graph(G):
plt.figure(figsize=(20,20))
# Define node positions using a layout
pos = nx.spring_layout(G)
# Draw the nodes with labels
nx.draw_networkx_nodes(G, pos, node_size=700)
nx.draw_networkx_labels(G, pos, labels=nx.get_node_attributes(G, 'label'), font_size=12)
# Draw the edges with labels
nx.draw_networkx_edges(G, pos, edgelist=G.edges(), arrowstyle='-|>', arrowsize=20)
nx.draw_networkx_edge_labels(G, pos, edge_labels=nx.get_edge_attributes(G, 'label'))
# Display the graph
plt.show()
plot_graph(G)
Вот что в итоге получилось.
На схеме выше видим достаточно много связей. Кажется, что это усложнит поиск всех связей для каждой отдельной сущности. Но это, на самом деле, не проблема. Достаточно, реализовать функцию для построения связей к отдельному слову «традиция».
G = nx.DiGraph()
def populate_graph(G,e,level=None):
if e in G.nodes:
return
if e in entities.keys():
G.add_node(e, label=e)
if level is not None and level<=0:
return
new_ent = set(
[r['source'] for r in relations if r['target'] == e] +
[r['target'] for r in relations if r['source'] == e])
for ne in new_ent:
populate_graph(G,ne,None if level is None else level-1)
for r in relations:
if r['source'] == e:
G.add_edge(e, r['target'], label=r['relation'], desc=r['desc'])
if r['target'] == e:
G.add_edge(r['source'], e, label=r['relation'], desc=r['desc'])
populate_graph(G,'традиция',2)
plot_graph(G)
Теперь с уверенностью можно сказать, когда в России «происходит» Новый год и что обычно делают во время боя курантов.
Можно сделать вывод, что Langchain — это универсальный инструмент. Но кроме него сейчас развивается множество других фреймворков, способных составить конкуренцию в простоте, гибкости и функциональности. Давайте сравним три самых популярных.
Критерий |
LangChain |
Semantic Router |
Llama Index |
Основной фокус |
Универсальная |
Упрощение работы с разными языковыми моделями |
Для быстрого поиска и извлечения данных |
Применение |
Чаты, системы автоматической поддержки клиентов |
Приложения для эффективной обработки языка |
Поиск документов, генерация контента и т.п |
Скорость работы |
Средняя |
Быстрая обработка запросов благодаря оптимизированным алгоритмам маршрутизации |
Медленнее чем Langchain, но эффективней всего для поиска |
Подход к индексации данных |
Использует модульный подход с комплексными цепочками операций для индексации данных |
Ограниченные возможности индексации |
Специализируется на преобразовании данных в числовые эмбеддинги для сематичного значения, что делает поиск данных эффективней |
Поддержка различных форматов данных |
Широкий спектр форматов данных, включая текстовые документы, базы данных и знания графов |
Ограниченная поддержка форматов, в основном ориентирован на текстовые данные |
Множество форматов, включая неструктурированные текстовые документы,структурированные записи баз данных, знания графов |
Масштабируемость |
Высокая, особенно с крупными объемами данных в распределённых системах |
Средняя, не подходит для случаев с высоким количеством запросов |
Легко масштабируется для крупных и сложных баз знаний |
Уровень безопасности |
Имеет множество встроенных механизмов защиты, включая контроль доступа, контроль безопасности данных на этапе получения запроса и отправки результата и возможности для интеграции с дополнительными внешними инструментами безопасности |
Предлагает базовый уровень безопасности и скорее полагается на внешние решения |
Ориентирован на работу с данными и поиск, и его безопасность сильно зависит от внешней конфигурации хранилищ данных и применения кастомных политик безопасности |
Как мы видим, реализация RAG на этих библиотеках довольно проста. Но что, если попробовать их сравнить? LangChain предлагает высокую гибкость в создании цепочек обработки языка и поддерживает различные модели и ретриверы, что делает её отличным выбором для сложных задач, требующих настройки. С другой стороны, Semantic использует семантическое маршрутизирование для направления запросов к наиболее подходящим моделям или системам. Это помогает улучшить качество ответов, хоть и требует дополнительной настройки. А Llama index поддерживает множество форматов данных и полезен при очень большом объёме данных.
Перспективные фреймворки
Сейчас большая часть решений, конечно же, построена на основе Langchain, но есть и новые, ещё не набравшие популярность аналоги. Рассмотрим несколько из них.
CrewAi — недавно появившийся фреймворк, предназначенный для упрощения разработки и управления мультиагентными системами. У него простой интерфейс и инструменты для координации между агентами. Это облегчает создание сложных распределённых приложений.
Ключевая особенность: «думайте только о логике приложения, не о технической сложности коммуникации между агентами».
Преимущества:
-
Простая интеграция и масштабирование.
-
Подходит для быстрого написания прототипа
Недостатки:
-
Архитектура фреймворка построена так, что не до конца понятно как на самом деле LLM создаёт ответы.
-
Поскольку проект относительно молодой, подробной документации ещё нет.
Swarm — легковесный мультиагентный фреймворк от OpenAI. Он упрощает задачи с использованием нескольких агентов, работающих над одной целью. Swarm уже получил положительные отзывы разработчиков за гибкость и масштабируемость, и, как мне кажется, в скором времени станет популярен.
Ключевая особенность: модульная архитектура, обеспечивающая гибкость и масштабируемость.
Преимущества:
-
Высокая производительность даже при большом количестве агентов.
-
Возможность адаптировать к различным сценариям.
Минусы:
-
Нужно глубоко разбираться как работают агенты для дальнейшей оптимизации.
Letta — фреймворк, ориентированный на разработку интеллектуальных агентов с использованием современных технологий. Предоставляет инструменты для создания агентов, способных обучаться и адаптироваться к меняющимся условиями.
Ключевая особенность: много встроенных инструментов для автоматического обучения агентов.
Преимущества:
-
Простота интеграции алгоритмов машинного обучения.
-
Поддержка адаптивного поведения in-real-time.
Минусы:
-
Высокая ресурсоемкость.
-
Для сложных и специфических задач требует более глубоких знаний фреймворка.
Atomic agents — фреймворк для создания высокопроизводительных агентов, выполняющих сложные процессы в режиме реального времени. Предоставляет низкоуровневый контроль над агентами, что позволяет их гибко оптимизировать для конкретных задач.
Ключевая особенность: низкоуровневый контроль.
Преимущества:
-
Отлично подходит для задач, требующих максимальной производительности.
Минусы:
-
Сложность освоения для новичков.
-
Меньше встроенных инструментов.
Ну а теперь, давайте попробуем реализовать агентный RAG с фреймворком CrewAI.
# Загружаем pdf статью Attention is all you need
loader = PyPDFLoader("attention.pdf")
# Разделяем на чанки
text_splitter = RecursiveCharacterTextSplitter(chunk_size=512, chunk_overlap=50)
document = loader.load_and_split(text_splitter)
# Объявляем модель для эмбеддинга и название директории для векторной БД
embedding = OpenAIEmbeddings(openai_api_key=OPENAI_API_KEY)
persist_directory = "chroma_db"
# Создаем векторное хранилище Chroma из документов
vectorstore = Chroma.from_documents(
documents=document,
embedding=embedding,
persist_directory=persist_directory
)
vectorstore.persist()
template = """
You are an assistant for question-answering tasks.
Use the following pieces of retrieved context to answer the question.
If you don't know the answer, just say that you don't know.
Question: {question}
Context: {context}
Answer:
"""
# Определяем pipeline для RAG
retriever = vectorstore.as_retriever()
prompt = ChatPromptTemplate.from_template(template)
handler = StdOutCallbackHandler()
# Инициализируем модель gpt-3.5-turbo
llm35 = ChatOpenAI(
openai_api_key=OPENAI_API_KEY,
temperature=0.0,
model="gpt-3.5-turbo",
max_tokens=512
)
# Пользователь задает вопрос
# Retriever ищет релевантные куски текста в Chroma DB
# Найденные куски "запихиваются" в промпт (chain_type="stuff")
# LLM генерирует ответ на основе этих кусков текста
qa_d35 = RetrievalQA.from_chain_type(
llm=llm35,
chain_type="stuff",
callbacks=[handler],
retriever=retriever
)
qa_db4o = RetrievalQA.from_chain_type(
llm=llm4o,
chain_type="stuff",
callbacks=[handler],
retriever=retriever
)
# Создание кастомной тулзы
class MyCustomTool(BaseTool):
name: str = "Research Paper"
description: str = "Research Paper"
def _run(self, argument: str) -> str:
return qa_db4o.run("Can you analyze the research paper?")
tool_instance = MyCustomTool()
# Инициализация Агента-исследователя
reasarcher = Agent(
role="Computer Science Researcher",
goal='Understanding the published research paper and extract key insights',
backstory=(
"As a professor at a leading Computer Science department, your responsibility is to "
"thoroughly evaluate the latest scholarly articles. You aim to extract and present "
"critical insights to advance academic discussions and student understanding."),
verbose=True,
tools=[tool_instance],
allow_delegation=False,
llm=ChatOpenAI(
openai_api_key=OPENAI_API_KEY,
temperature=0.0,
model="gpt-3.5-turbo"
)
)
# Создание задачи для агента-исследователя
task_research = Task(
description=(
"Perform a thorough analysis of the published research paper. "
"Identify the key components and explain how they function."
),
expected_output="Produce a comprehensive analysis report of the research paper.",
agent=reasarcher,
output_file='researcher_analysis.md'
)
# Инициализация Агента-писателя
writer = Agent(
role="Computer Science Writer",
goal= "Produce insightful and engaging articles for the professional data science community",
backstory=(
"As a writer focusing on the data science field, your objective is to create "
"in-depth summary that provide valuable insights and foster discussion among seasoned professionals. "
"Draw on the expertise from research analyses and cutting-edge developments to craft content that resonates with the community."
),
verbose=True,
allow_delegation=False,
llm=ChatOpenAI(
openai_api_key=OPENAI_API_KEY,
temperature=0.0,
model="gpt-4o"
)
)
# Создание задачи для агента-писателя
task_writer = Task(
description="Identify the most important topics and key elements from the report created by the Computer Science Researcher.",
expected_output= "Provide a concise and comprehensive summary suitable for Computer Science community.",
agent=writer,
output_file='writer_summary.md'
)
# Инициализация экземпляра для работы нескольких агентов
Crew = Crew(
agents=[reasarcher, writer], # определение агентов
tasks=[task_research, task_writer], # определение задач
verbose=True, # подробный вывод результатов
)
result = Crew.kickoff()
print(result)
Посмотрим, что смогли создать агенты.
Agent: Computer Science Writer
Task: Identify the most important topics and key elements from the report created by the Computer Science Researcher.
Agent: Computer Science Writer
Final Answer: The research paper "Attention Is All You Need" introduces the Transformer model, a revolutionary approach in the field of natural language processing. By utilizing self-attention mechanisms, the Transformer model eliminates the need for recurrent neural networks (RNNs) and processes input data in parallel. The paper showcases the Transformer's exceptional performance on various tasks such as machine translation and English constituency parsing, surpassing previous models and setting new benchmarks in the field. Its capability to effectively handle long-range dependencies and scalability makes it a valuable asset for a wide range of NLP applications. Furthermore, the paper delves into the intricacies of English constituency parsing and highlights how the Transformer model's architecture excels in capturing intricate dependencies and producing structured outputs with high accuracy. Overall, the Transformer model represents a significant advancement in NLP, offering a versatile and powerful solution for complex language processing tasks.
Выводы
Таким образом, RAG стремительно завоёвывает признание как ключевая технология будущего. Популярности технология обязана своему умению сочетать искусство извлечения данных с мастерством генерации текста. Такой подход открывает двери к высокой точности, персонализации и масштабируемости даже в сложных бизнес-сценариях.
Однако стандартный RAG испытывает проблемы при решении многошаговых задач. Здесь на помощь приходят Агентные RAG системы, превращая ограничения в возможности с помощью планирования, памяти и динамических действий.
Мы в Raftуже сделали шаг в будущее, активно разрабатывая комплексные системы на основе различных архитектур RAG. Кроме того, зачастую мы сами придумываем ориентированную на требования заказчика архитектуру для построения надёжного RAG. Не стесняйтесь делиться своим опытом работы с RAG в комментариях. Буду рад услышать ваше мнение, критику и пожелания.
Автор: yepiwt