reworked document adding and most of the project
This commit is contained in:
+34
-12
@@ -12,6 +12,23 @@ from langchain_ollama import ChatOllama
|
||||
from langchain_openai import ChatOpenAI
|
||||
from langchain_text_splitters import RecursiveCharacterTextSplitter
|
||||
|
||||
# Pipeline tuning: used when adding documents (rebuild index after changing).
|
||||
CHUNK_SIZE = 2000
|
||||
CHUNK_OVERLAP = 400
|
||||
|
||||
# Retrieval / query tuning
|
||||
RETRIEVAL_K = 5
|
||||
|
||||
# Appended to the embedding query for FAISS (does not affect the answer-generation prompt).
|
||||
QUERY_ADDITIONAL_INSTRUCTIONS = (
|
||||
"Do not return a list of references but prioritize meaningful text from abstracts, results and discussion sections."
|
||||
)
|
||||
|
||||
# Opening instructions for the final answer LLM call only. The rest (history, context, question)
|
||||
# is assembled in query_with_history.
|
||||
ANSWER_PROMPT = """You are an assistant for question-answering. Use the chat history (if any) and the retrieved context below to answer the current question.
|
||||
If you don't know the answer, say so. Keep the conversation coherent."""
|
||||
|
||||
|
||||
class LocalRAG:
|
||||
def __init__(
|
||||
@@ -19,7 +36,7 @@ class LocalRAG:
|
||||
vectorstore_path="./vectorstore",
|
||||
llm_provider="ollama",
|
||||
ollama_model="gpt-oss:20b",
|
||||
openai_model="gpt-5.2",
|
||||
openai_model="gpt-5-mini",
|
||||
ollama_base_url="http://localhost:11434",
|
||||
):
|
||||
"""Initialize local RAG system. llm_provider: 'ollama' or 'openai'."""
|
||||
@@ -32,11 +49,12 @@ class LocalRAG:
|
||||
model_name="sentence-transformers/all-MiniLM-L6-v2"
|
||||
)
|
||||
|
||||
# Text splitter
|
||||
# Text splitter (used when adding documents; tune CHUNK_SIZE / CHUNK_OVERLAP above)
|
||||
self.text_splitter = RecursiveCharacterTextSplitter(
|
||||
chunk_size=2000,
|
||||
chunk_overlap=400
|
||||
chunk_size=CHUNK_SIZE,
|
||||
chunk_overlap=CHUNK_OVERLAP,
|
||||
)
|
||||
print(f"Text splitter: chunk_size={CHUNK_SIZE}, chunk_overlap={CHUNK_OVERLAP}")
|
||||
|
||||
# LLM (Ollama or OpenAI)
|
||||
if llm_provider == "openai":
|
||||
@@ -186,15 +204,19 @@ class LocalRAG:
|
||||
for doc, score in docs_with_scores
|
||||
]
|
||||
|
||||
def query(self, question, k=8):
|
||||
def query(self, question, k=None):
|
||||
"""Query the RAG system (no conversation history). Returns dict with 'answer' and 'retrieved'."""
|
||||
if k is None:
|
||||
k = RETRIEVAL_K
|
||||
return self.query_with_history(question, chat_history=[], k=k)
|
||||
|
||||
def query_with_history(self, question, chat_history=None, k=8):
|
||||
def query_with_history(self, question, chat_history=None, k=None):
|
||||
"""Query the RAG with conversation history: rephrase question using history for retrieval,
|
||||
then answer with full conversation + retrieved context in the prompt.
|
||||
Returns dict with 'answer' and 'retrieved' (list of chunks with content, source, page).
|
||||
"""
|
||||
if k is None:
|
||||
k = RETRIEVAL_K
|
||||
if self.vectorstore is None:
|
||||
return {
|
||||
"answer": "Error: No documents loaded. Please add documents first.",
|
||||
@@ -203,9 +225,6 @@ class LocalRAG:
|
||||
|
||||
history_str = self._format_history(chat_history)
|
||||
search_query = question
|
||||
rag_query_instruction = (
|
||||
"Do not return a list of references but prioritize meaningful text from abstracts, results and discussion sections."
|
||||
)
|
||||
|
||||
print(f"[RAG] User question: {question!r}")
|
||||
|
||||
@@ -224,7 +243,7 @@ Standalone question:"""
|
||||
search_query = (rephrase_response.content if hasattr(rephrase_response, "content") else str(rephrase_response)).strip() or question
|
||||
print(f"[RAG] Standalone search query (rephrased): {search_query!r}")
|
||||
|
||||
retrieval_query = f"{search_query}\n\n{rag_query_instruction}"
|
||||
retrieval_query = f"{search_query}\n\n{QUERY_ADDITIONAL_INSTRUCTIONS}"
|
||||
print(f"[RAG] Search query: {search_query!r}")
|
||||
print(f"[RAG] Retrieval query sent to vector store: {retrieval_query!r}")
|
||||
|
||||
@@ -239,8 +258,9 @@ Standalone question:"""
|
||||
|
||||
# 3) Answer using conversation history + retrieved context
|
||||
history_block = f"Chat history:\n{history_str}\n\n" if history_str else ""
|
||||
answer_prompt = f"""You are an assistant for question-answering. Use the chat history (if any) and the retrieved context below to answer the current question.
|
||||
If you don't know the answer, say so. Keep the conversation coherent.
|
||||
answer_prompt = (
|
||||
ANSWER_PROMPT
|
||||
+ f"""
|
||||
|
||||
{history_block}Relevant context from documents:
|
||||
|
||||
@@ -249,6 +269,8 @@ Standalone question:"""
|
||||
Current question: {question}
|
||||
|
||||
Answer:"""
|
||||
)
|
||||
print(f"[RAG] Composed answer prompt:\n{answer_prompt}")
|
||||
response = self.llm.invoke(answer_prompt)
|
||||
answer = response.content if hasattr(response, "content") else str(response)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user