Введение

В первой части говорили про использование поиска и генерации ответа с помощью языковых моделей. В этой части рассмотрим память и агентов.

Данные и окружение

Будем использовать модели от OpenAI. Для opensource моделей примерно похожий механизм.

Устанавливаем и подключаем библиотеки

library(reticulate)
library(data.table)
library(magrittr)
library(stringr)

py_install(c('torch', 
             'torchvision', 
             "torchaudio", 
             'langchain', 
             'docx2txt', 
             'faiss-cpu', 
             'openai==0.28.1', 
             'tiktoken',
             "google-api-python-client>=2.100.0"), pip = TRUE)


langchain <- import('langchain')

Константы

Токен для гугла дальше описываю как получить.

OPENAI_API_KEY <- '<YOUR OPENAI TOKEN>'
GOOGLE_API_KEY <- "<YOUR GOOGLE TOKEN>"
CUSTOM_SEARCH_ENGINE_ID <- "<YOUR GOOGLE SEARCH ID>"
MODEL_NAME_GPT <- "gpt-4"
TEMPERATURE <- 0.5
MAX_TOKENS <- 100L

Память

Типы памяти:

  • ConversationBufferMemory - самый простой тип памяти. В history записываются все предыдущие сообщения, что является не эффективным.

  • ConversationSummaryMemory - суммаризирует историю перед подачей в history. В данном случае модель вызывается дважды (для ответа и для суммаризации).

  • ConversationSummaryBufferMemory - при указанном значении окна в токенах, сохраняет истории, а то что больше, суммаризирует.

  • ConversationBufferWindowMemory - сохраняет последние k диалогов.

  • ConversationKGMemory - использует граф знаний для сохранения памяти.

  • ConversationEntityMemory - сохраняет в history информацию об определенном объекте.

ConversationBufferMemory

llm <- langchain$llms$OpenAI(temperature = TEMPERATURE, 
                             openai_api_key = OPENAI_API_KEY, 
                             max_tokens = MAX_TOKENS)
  
memory_buffer <- langchain$chains$conversation$memory$ConversationBufferMemory()
chain_buffer <- langchain$chains$ConversationChain(llm = llm, memory = memory_buffer)

chain_buffer("Знаешь кто такой конь?") 
### $input
### [1] "Знаешь кто такой конь?"
### 
### $history
### [1] ""
### 
### $response
### [1] " Да, я знаю о коне. Это животное, которое используется в качестве домашнего животного и для с"

chain_buffer("Опиши его")
### $input
### [1] "Опиши его"
### 
### $history
### [1] "Human: Знаешь кто такой конь?\nAI:  Да, я знаю о коне. Это животное, которое используется в качестве домашнего животного и для с"
### 
### $response
### [1] " Кони обычно являются высокими и мощными животными с длинной шеей, длинными ногами и плотным т"


# Для систем с использованием внутренних данных
# chain_buffer <- langchain$chains$ConversationalRetrievalChain$from_llm(llm = llm,
#                                                                        memory = memory_buffer, 
#                                                                        retriever = db_gpt$as_retriever())
# chat_history <- list()
# query <- "<Запрос 1>"
# res1 <- chain_buffer$run(list(question = query, chat_history = chat_history))
# res1
# chat_history <- c(chat_history, tuple(query, res1))
# 
# query <- "<Запрос 2>"
# res2 <- chain_buffer$run(list(question = query, chat_history = chat_history))
# res2
# chat_history <- c(chat_history, tuple(query, res2))

ConversationSummaryMemory

Суммаризирует память.

memory_summary <- langchain$chains$conversation$memory$ConversationSummaryMemory(llm = llm)
chain_summary <- langchain$chains$ConversationChain(llm = llm, memory = memory_summary)

chain_summary("Знаешь кто такой конь?") 
### $input
### [1] "Знаешь кто такой конь?"
### 
### $history
### [1] ""
### 
### $response
### [1] " Да, я знаю о коне. Конь - это домашнее животное из семейства лошадей. Они используются для"

chain_summary("Опиши его")
### $input
### [1] "Опиши его"
### 
### $history
### [1] "\nThe human asks what the AI thinks of artificial intelligence. The AI thinks artificial intelligence is a force for good because it will help humans reach their full potential. The human then asks who a horse is and the AI responds that it is a domesticated animal from the horse family and is used for transportation and recreation."
### 
### $response
### [1] " A horse is a four-legged mammal with a long snout, long mane, and a short tail. It has hooves and is typically a brown or black color. It is usually around 1.5 to 1.8 meters tall and can weigh up to 900 kilograms. Horses are intelligent creatures and have been domesticated for thousands of years. They are used for transportation, recreation, and even as a source of food."

Память

chain_summary$memory$chat_memory
### ChatMessageHistory(messages=[HumanMessage(content='Знаешь кто такой конь?'), AIMessage(content=' Да, я знаю о коне. Конь - это домашнее животное из семейства лошадей. Они используются для'), HumanMessage(content='Опиши его'), AIMessage(content=' A horse is a four-legged mammal with a long snout, long mane, and a short tail. It has hooves and is typically a brown or black color. It is usually around 1.5 to 1.8 meters tall and can weigh up to 900 kilograms. Horses are intelligent creatures and have been domesticated for thousands of years. They are used for transportation, recreation, and even as a source of food.')])

Агент

Агент - это связующее завено между языковой моделью (LLM) и инструментом (Tool). Например, можно сделать так, чтобы языковая модель отвечала из информации гугла (обладала новыми знаниями).

Для этого создадим API ключ гугла (гугл облако -> APIs & services -> Credentials -> Create credentials -> API key). Далее перейти в Custom search API -> Enable. Настроить, дав название и активировав поиск по всему интернету, затем взять Идентификатор поисковой системы.

# Обёртка для поиска
search_engine <- langchain$utilities$GoogleSearchAPIWrapper(google_api_key = GOOGLE_API_KEY, google_cse_id = CUSTOM_SEARCH_ENGINE_ID)

# Создаём инструмент. Имя нужно указать как Intermediate Answer, по-другому ломается.
tool <- langchain$tools$Tool(name = "Intermediate Answer", func = search_engine$run, description = "Google answers")

# Гугл агент
agent_google <- langchain$agents$initialize_agent(tools = c(tool), 
                                                  llm = llm, 
                                                  agent = "self-ask-with-search", # Другие варианты: zero-shot-react-description, react-docstore, conversational-react-description
                                                  verbose = TRUE, 
                                                  max_iterations = 5)


# Запуск агента
agent_google$run("Кто такой Гемуда?")


### [1m> Entering new AgentExecutor chain...[0m
### [32;1m[1;3m Yes.
### Follow up: Что такое Гемуда?[0m
### Intermediate answer: [36;1m[1;3mГемуда, как велел Карашауай, начал скакать и прыгать по морю и по его дну туда-сюда. Когда море почернело, помутнело настолько, что под водой ничего не стало ... ... Гемуда-Секирген-таш «Камень-Через-Который-Перепрыгнул-Гемуда» и т.д.), что подтверждает тесную связь содержания богатырского эпоса и материальной культуры ... Доскакали до громадной горы,. [Гемуда] грудью [ее] ударил,. Громадную гору на две части расколол. Голубые озера — следы его копыт,. Разведение и популяризация племенных лошадей Карачаевской породы/Къ Карачаево-Черкесская Республика · ❌ПРОДАН❌ Жеребец-производитель в ПРОДАЖЕ Гемуда 2017г ... May 18, 2010 ... В мирное время Гемуда живет в подземной конюшне, питаясь рудой или железными опилками. Но самое главное - Гемуда владеет человеческой речью и ... Гемуда может принимать то облик захудалой клячи, то вид богатырского коня. Однажды он предстает в истинном виде - с крыльями орла и с рыбьим хвостом, т. е. Mar 13, 2023 ... Нарт ат – конь нарта,(Гемуда); Юч аякъ ат – крылатый конь (трёхногий в нартском эпосе, аналог современного самолета – три шасси). Жылкъы ... Sep 25, 2016 ... Так же на сколько Нарты были верны своим скакунам, и скакуны Нартам можно понять из клятвы Карашуайа и Гемуды при первой их встрече: (Гемуда): Dec 10, 2015 ... А в сказании «Карашауай и Гемуда» даже подчеркивается, что у Гемуды около ушей были жабры и он, очутившись под водой, «къулакъ орталары бла, ... Jul 6, 2021 ... легендарный конь Гемуда, рожденный на вершине. Эльбруса. Он мог скакать так, что грудью рассекал горы. Так появились Черекское и. Чегемское ...[0m
### [32;1m[1;3mSo the final answer is: Гемуда - легендарный конь, рожденный на вершине Эльбруса, который мог скакать так, что[0m
### 
### [1m> Finished chain.[0m
### [1] "Гемуда - легендарный конь, рожденный на вершине Эльбруса, который мог скакать так, что"

Заключение

Данные начальные решения представляют собой основу для разработки более сложных и эффективных систем поиска и RAG. Они могут быть доработаны и адаптированы под конкретные потребности и условия работы с помощью других методов langchain. Можно расширить функциональность самой системы RAG, добавив новые возможности и инструменты для анализа и классификации информации. Другим возможным направлением для расширения может быть рассмотрение различных сценариев применения этих систем.

Комментарии (0)