Цепочка поиска langchain qa не может фильтроваться по конкретным документам
пытаюсь использовать RetrivalQA с Chromadb для создания бота вопросов и ответов по документам нашей компании. общая настройка, как показано ниже:
импортировать библиотеки
from langchain.vectorstores.chroma import Chroma # for storing and retrieving vectors
from langchain.embeddings.openai import OpenAIEmbeddings # for embedding text
from langchain.text_splitter import CharacterTextSplitter # for splitting text into tokens
from langchain import OpenAI # for using the OpenAI API
from langchain.chains import RetrievalQA # for question and answer retrieval
from langchain.document_loaders import DirectoryLoader # for loading documents from a directory
from langchain.llms import OpenAI
import magic
import os
import nltk
загрузка документов, разбиение на части, встраивание
loader = DirectoryLoader('dir',glob='**/*.txt')
documents = loader.load()
text_splitter = CharacterTextSplitter(chunk_size=2000, chunk_overlap = 100)
texts = text_splitter.split_documents(documents)
embeddings = OpenAIEmbeddings()
persist_directory = 'db'
docsearch = Chroma.from_documents(
texts,
embeddings,
persist_directory=persist_directory
затем начни цепочку и задай вопрос
llm = OpenAI(temperature=0.1, model_name='gpt-3.5-turbo', cache=False,verbose=True)
chain_type_kwargs = {"prompt": PROMPT_1}
qa = RetrievalQA.from_chain_type(llm=llm, chain_type="stuff", retriever=docsearch.as_retriever(search_kwargs = {'filter': {'source':'DB_Manual.txt'}}), chain_type_kwargs=chain_type_kwargs)
query = "what's our company's dress code?"
result = qa.run(query)
result
с несколькими документами в базе данных search_kwargs, похоже, не работает последовательно.
Я пытался спросить о дресс-коде, фильтруя руководство (которое не имеет ничего общего с дресс-кодом), ожидая, что оно даст мне не знаю, как ответ, но иногда оно все равно давало мне правильный ответ о дресс-коде.
Я чувствую, что это из-за метаданных, может быть, по умолчанию цветность не включает «источник» в качестве метаданных, и мне нужно загрузить документы с явно определенными метаданными «источника»? если да, то кто-нибудь знает, как это сделать через langchain?
4 ответа
Нижеприведенное работает для меня с версией Lanchain 0.0.223.
import os
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.llms import AzureOpenAI
from langchain.chains import ConversationalRetrievalChain
from langchain.document_loaders import DirectoryLoader
from langchain.vectorstores import Chroma
from dotenv import load_dotenv
load_dotenv('../../.env')
document_directory = '../../data'
embedding_function = OpenAIEmbeddings(
openai_api_key=os.getenv("OPENAI_API_KEY"),
deployment=os.getenv('EMBEDDING_DEPLOYMENT_NAME'),
model=os.getenv('EMBEDDING_MODEL'),
chunk_size=1)
loader = DirectoryLoader(document_directory)
documents = loader.load()
db = Chroma.from_documents(documents, embedding_function)
llm = AzureOpenAI(deployment_name=os.getenv('CHAT_DEPLOYMENT_NAME'),
model_name=os.getenv('CHAT_MODEL'),
temperature=0, openai_api_version='2023-05-15')
vec = db.as_retriever(search_kwargs={"filter": {"source":'..\\..\\data\\musk-article-1.txt'}})
qa = ConversationalRetrievalChain.from_llm(llm = llm,
retriever = vec,
return_source_documents = True)
response = qa({"question": "Who is William Rich?", "chat_history": []})
print(response['answer'])
У меня есть две статьи. В первой статье конкретно упоминается Уильям Рич, а во второй — нет.
Когда я запускаю это с помощью:
vec = db.as_retriever(search_kwargs={"filter": {"source":'..\\..\\data\\musk-article-1.txt'}})
Я получил:
William Rich is an Employee
Но когда я меняю исходный документ на:
vec = db.as_retriever(search_kwargs={"filter": {"source":'..\\..\\data\\musk-article-2.txt'}})
Я получил:
"William Rich is not mentioned in the context"
Это доказывает, что фильтрация источников работает, поскольку Уильям Рич не упоминается в Musk-article-2.txt.
Взгляните на эту проблему github для langchain, связанную с вашей проблемой.
Кажется, что это работает напрямую:
qa = ConversationalRetrievalChain.from_llm(
OpenAI(temperature=0),
VectorStoreRetriever(vectorstore=vectorstore, search_kwargs={"filter":{"tenant":"commerce-hub"}}),
callback_manager=manager,
verbose = True,
return_source_documents=True)
Не уверен, поможет ли это вам, но я столкнулся с аналогичной проблемой при использовании векторного хранилища mongodb.
Я использовал MongoDBAtlasVectorSearch в качестве средства извлечения и пытался фильтровать согласно документации следующим образом :
# Use a filter to only retrieve documents from a specific paper
docsearch.as_retriever(
search_kwargs={'filter': {'paper_title':'GPT-4 Technical Report'}}
)
Однако, когда я нашел этот пост на странице справки mongodb, они показали следующее (в этом примере им следовало использовать «defaultPath» вместо «path», но все остальное правильно):
search_kwargs={
'k': k * 10,
'pre_filter': {
'text': {
'path': 'project',
'query': 'heroes'
}
},
'post_filter_pipeline': [ { '$limit': k } ]
}
Если вы посмотрите, что сказал помогающий человек, он упомянул, что их реализация в mongodb была уникальной для них.
Все это означает, что Chroma, возможно, изменила свою документацию о том, как фильтровать метаданные применительно к Chroma и Langchain. Я бы посмотрел и посмотрел, как они это реализуют.
Надеюсь, поможет!
Здесь та же проблема.
Я распечатываю количество полученных документов и всегда получаю 0. Вот код, по которому вы также можете попробовать проверить, извлекается ли что-нибудь:
# Create a retriever
retriever = vectordb.as_retriever(search_kwargs={"k": 2})
docs = retriever.get_relevant_documents(query)
print(f'Number of retrieved docs = {len(docs)}')
Предупреждаю, что это касается стороны langchain, связанной с javascript/typescript , но, возможно, это поможет кому-то получить общее представление о том, что сработало для меня.
ПРИМЕЧАНИЕ . Я также использую Milvus в качестве векторного хранилища, поэтому возможно, что каждое из векторных хранилищ может иметь некоторую специфичную для векторного хранилища логику фильтрации.
Я был очень расстроен, пытаясь выяснить, что, черт возьми, может быть указано в качестве фильтра, поскольку я пытался выполнить очень простое логическое выражение.
Я покопался в векторном хранилище langchain для Milvus, расположенном в node_modules/langchain/dist/vectorstores/milvus.cjs , и обнаружил, что в этом методе фильтр представляет собой просто строку:async similaritySearchVectorWithScore(query, k, filter) {
Я закончил с этим. Первый аргумент – этоk
и второй — простой фильтр.
const retriever = await vectorStore.asRetriever(10, 'is_a_client == FALSE');
В качестве альтернативы я мог бы также указать их как объект конфигурации, например:
const retrieverOptions = {
k: 10,
filter: 'is_a_client == TRUE',
}
const retriever = await vectorStore.asRetriever(retrieverOptions);
Однако мне пришлось немного поиграться с приемлемыми выражениями, чтобы выяснить== TRUE
немного заглавными буквами. Правила логических выражений были перечислены в клиентской документации Milvus здесь. Там упоминалось, что фильтрация Python работает аналогичным образом.
В любом случае, я надеюсь, что это кому-то поможет. Я обнаружил, что, когда я сталкиваюсь с проблемами langchain, я отчаянно нуждаюсь в подсказке или примере, и часто у меня есть только один пост о переполнении стека на Python или Javascript, который мог бы помочь мне.