-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathrag.py
More file actions
149 lines (101 loc) · 4.13 KB
/
Copy pathrag.py
File metadata and controls
149 lines (101 loc) · 4.13 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
from langchain_community.vectorstores import FAISS
from langchain_ollama import OllamaLLM, OllamaEmbeddings
from langchain_core.runnables import RunnableLambda, RunnableParallel, RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplate
from config import OLLAMA_EMBED_MODEL, FAISS_INDEX_PATH
def load_vectorestore():
embeddings = OllamaEmbeddings(model=OLLAMA_EMBED_MODEL)
vectorestore = FAISS.load_local(FAISS_INDEX_PATH,
embeddings,
allow_dangerous_deserialization=True)
return vectorestore
def get_rag_chain(model_name = "llama3:latest"):
try:
llm = OllamaLLM(model=model_name, stream=True)
except:
llm = OllamaLLM(model=model_name, stream=False)
vectorstore = load_vectorestore()
retriever = vectorstore.as_retriever(
search_type="mmr",
search_kwargs={
"k": 4,
"fetch_k": 20,
"lambda_mult": 0.5
})
prompt = ChatPromptTemplate.from_template("""
You are an AI assistant answering questions using BOTH:
1. Retrieved document context (primary source)
2. Your own general knowledge (secondary source)
Your job is to:
- First check whether the answer can be found in the provided context.
- If the context contains the answer:
* Answer based on the context.
* You MAY add extra correct information from your own knowledge,
but clearly mark it as: "(Additional info, NOT from the documents)" before adding it.
- If the context does NOT contain the answer:
* Answer using your own knowledge.
* Clearly state, "This information was NOT found in the provided documents.", before your answer.
### STRICT RULES
- Do NOT hallucinate. If you do not know, say so.
- Your answer must be helpful. It should not be concise but also not overly verbose.
- NEVER invent document content.
- NEVER claim something is in the documents unless it truly appears there.
- Do NOT repeat the question.
- Do NOT repeat large passages from context.
### CONTEXT (retrieved from documents)
{context}
### QUESTION
{question}
### ANSWER
""")
extract_question = RunnableLambda(lambda x: x["question"])
extract_history = RunnableLambda(lambda x: x.get("history", ""))
rag_inputs = RunnableParallel(
question = extract_question,
history = extract_history,
docs = extract_question | retriever
)
def prepare_prompt(x):
cleaned_chunks = []
q_lower = x["question"].strip().lower()
for doc in x["docs"]:
text = doc.page_content.strip()
if len(text) < 20:
continue
if text.lower() == q_lower:
continue
cleaned_chunks.append(text)
context_text = "\n\n".join(cleaned_chunks) if cleaned_chunks else "No relevant context found."
return {
"question": x["question"],
"history": x["history"],
"context": context_text
}
prep_prompt = RunnableLambda(prepare_prompt)
answer_chain = prep_prompt | prompt | llm
rag_chain = RunnableParallel(
answer=answer_chain,
context=RunnableLambda(lambda x: x["docs"])
)
# combine inputs and final output
final_chain = rag_inputs | rag_chain
return final_chain
def ask(question: str, history: str = "", model_name="llama3:latest"):
chain = get_rag_chain(model_name)
result = chain.invoke({"question": question, "history": history})
return result
if __name__ == "__main__":
print("\nRAG Chatbot (CLI Mode)\n")
while True:
question = input("Ask a question (or type 'exit' or 'quit' to stop): ").strip()
if question.lower() in ['exit', 'quit']:
print("Goodbye!")
break
output = ask(question, history)
answer = output["answer"]
print("\n Answer:", answer)
print("\n Retireved Chunks:")
for doc in output["context"]:
print("-", doc.metadata.get("source", "Unknown"))
print(doc.page_content[0:200] + "...\n")
history += f"User: {question}\nAssistant: {answer}\n"