Я читал документацию весь день и, похоже, не могу понять, как я могу создать VectorStoreIndex с помощью llama_index и использовать созданные внедрения в качестве дополнительной информации для приложения/чат-бота RAG, который может общаться с пользователем. Я хочу использовать llama_index, потому что у них есть несколько интересных способов реализовать более продвинутые методы поиска, такие как поиск из окна предложений и поиск с автоматическим объединением (честно говоря, я не исследовал, поддерживает ли Langchain также эти типы методов векторного поиска). Я хочу использовать LangChain из-за его функциональности для разработки более сложных шаблонов подсказок (аналогично я не исследовал, поддерживает ли это llama_index).
Моя цель — в конечном итоге оценить, как эти различные методы поиска работают в контексте приложения/чат-бота. Я знаю, как оценить их с помощью отдельного файла оценочных вопросов, но мне бы хотелось сделать такие вещи, как сравнение скорости и человечности ответов, использования токенов и т. д.
Код минимального воспроизводимого примера будет следующим:
1) LangChain ChatBot initiation
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain.memory import ChatMessageHistory
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""You are the world's greatest... \
Use this document base to help you provide the best support possible to everyone you engage with.
""",
),
MessagesPlaceholder(variable_name = "messages"),
]
)
chat = ChatOpenAI(model=llm_model, temperature=0.7)
chain = prompt | chat
chat_history = ChatMessageHistory()
while True:
user_input = input("You: ")
chat_history.add_user_message(user_input)
response = chain.invoke({"messages": chat_history.messages})
if user_input.lower() == 'exit':
break
print("AI:", response)
chat_history.add_ai_message(response)
from llama_index.core.node_parser import SentenceWindowNodeParser
from llama_index.core.indices.postprocessor import MetadataReplacementPostProcessor
from llama_index.core.postprocessor import LLMRerank
class SentenceWindowUtils:
def __init__(self, documents, llm, embed_model, sentence_window_size):
self.documents = documents
self.llm = llm
self.embed_model = embed_model
self.sentence_window_size = sentence_window_size
# self.save_dir = save_dir
self.node_parser = SentenceWindowNodeParser.from_defaults(
window_size=self.sentence_window_size,
window_metadata_key = "window",
original_text_metadata_key = "original_text",
)
self.sentence_context = ServiceContext.from_defaults(
llm=self.llm,
embed_model=self.embed_model,
node_parser=self.node_parser,
)
def build_sentence_window_index(self, save_dir):
if not os.path.exists(save_dir):
os.makedirs(save_dir)
sentence_index = VectorStoreIndex.from_documents(
self.documents, service_context=self.sentence_context
)
sentence_index.storage_context.persist(persist_dir=save_dir)
else:
sentence_index = load_index_from_storage(
StorageContext.from_defaults(persist_dir=save_dir),
service_context=self.sentence_context,
)
return sentence_index
def get_sentence_window_query_engine(self, sentence_index, similarity_top_k=6, rerank_top_n=3):
postproc = MetadataReplacementPostProcessor(target_metadata_key = "window")
rerank = LLMRerank(top_n=rerank_top_n, service_context=self.sentence_context)
sentence_window_engine = sentence_index.as_query_engine(
similarity_top_k=similarity_top_k, node_postprocessors=[postproc, rerank]
)
return sentence_window_engine
sentence_window = SentenceWindowUtils(documents=documents, llm = llm, embed_model=embed_model, sentence_window_size=1)
sentence_window_1 = sentence_window.build_sentence_window_index(save_dir='./indexes/sentence_window_index_1')
sentence_window_engine_1 = sentence_window.get_sentence_window_query_engine(sentence_window_1)
Оба блока кода будут работать независимо. Но цель состоит в том, чтобы при выполнении запроса, требующего извлечения данных из существующей базы документов, я мог использовать встроенный механизм предложения_window_engine. Я предполагаю, что мог бы получить соответствующую информацию на основе запроса, а затем передать эту информацию в последующее приглашение для чат-бота, но я хотел бы попытаться избежать включения данных документа в приглашение.
Какие-либо предложения?






Я так и не нашел точного способа получить информацию через llama_index, как я надеялся, но в основном я нашел обходной путь, сделав то, чего изначально хотел избежать, запросив мою базу документов и добавив ее в качестве контекстной информации в моего чат-бота как такового.
#### Conversation Prompt Chain #####
prompt = ChatPromptTemplate.from_messages(
[
(
"system",
"""You are the world's greatest...
You have access to an extensive document base of information.
Relevant Information to the user query is provided below. Use the information at your own discretion if it improves the quality of the response.
A summary of the previous conversation is also provided to contextualize you on previous conversation.
<<Relevant Information>>
{relevant_information}
<< Previous Conversation Summary>>
{previous_conversation}
<< Current Prompt >>
{user_input}
""",
),
MessagesPlaceholder(variable_name = "messages"),
]
)
chat = ChatOpenAI(model=llm_model, temperature=0.0)
chain = prompt | chat
### Application Start ###
while True:
# Some code....
if route['destination'] == "data querying":
formatted_response = query_and_format_sql(username, password, host, port, mydatabase, query_prompt, model = 'gpt-4', client_name = client_name, user_input=user_input)
print(formatted_response)
chat_history.add_ai_message(AIMessage(f'The previous query triggered a SQL agent response that was {formatted_response}'))
else:
# Search Document Base
RAG_Context = sentence_window_engine_1.query(user_input)
# Inject the retrieved information into the chatbot's context
context_with_relevant_info = {
"user_input": user_input,
"messages": chat_history.messages,
"previous_conversation": memory.load_memory_variables({}),
"relevant_information": RAG_Context # ==> Inject relevant information from llama_index here
}
response = chain.invoke(context_with_relevant_info)
Я еще не сталкивался с проблемой токена, но могу себе представить, что если мое приложение будет расти и масштабироваться, у него могут возникнуть проблемы при попытке ввести соответствующую информацию, историю сообщений и приглашение. Я ограничиваю свою память с помощью ConversationBufferMemoryHistory, и пока это работает нормально.