pluto90 commited on
Commit
195e631
Β·
verified Β·
1 Parent(s): cad117b

Upload 6 files

Browse files
app/graph/nodes/evaluator.py ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/graph/nodes/evaluator.py
2
+ from app.core.llm_engine import llm
3
+ from app.core.prompts.evaluator_prompt import evaluator_prompt
4
+ from langchain_core.output_parsers import StrOutputParser
5
+ import json
6
+
7
+ chain = evaluator_prompt | llm | StrOutputParser()
8
+
9
+
10
+ def evaluator_node(state):
11
+ query = state.get("query")
12
+ answer = state.get("final_answer")
13
+ context = state.get("context", "")
14
+
15
+ try:
16
+ response = chain.invoke({
17
+ "query": query,
18
+ "answer": answer,
19
+ "context": context
20
+ })
21
+
22
+ # πŸ”₯ clean response (important)
23
+ response = response.strip()
24
+
25
+ # sometimes model adds ```json
26
+ if response.startswith("```"):
27
+ response = response.replace("```json", "").replace("```", "").strip()
28
+
29
+ evaluation = json.loads(response)
30
+
31
+ except Exception as e:
32
+ print("EVALUATOR ERROR β†’", e)
33
+
34
+ evaluation = {
35
+ "relevance_score": 0.5,
36
+ "context_usage": 0.5,
37
+ "hallucination": True
38
+ }
39
+
40
+ return {
41
+ **state,
42
+ "evaluation": evaluation
43
+ }
app/graph/nodes/general_agent.py ADDED
@@ -0,0 +1,48 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from app.core.llm_engine import llm
2
+ from langchain_core.output_parsers import StrOutputParser
3
+ from app.core.prompts.general_prompt import general_prompt
4
+
5
+ # general_prompt= PromptTemplate(
6
+ # input_variables= ["query"],
7
+ # template= (
8
+ # "Answer clearly and concisely.\n"
9
+ # "Do NOT rely on any external document.\n"
10
+ # "Avoid long explanations.\n"
11
+ # "Use bullet points if helpful.\n"
12
+ # "Max 150 words.\n\n"
13
+ # "Question:\n{query}\n\n"
14
+ # "Answer:"
15
+ # )
16
+ # )
17
+
18
+ # def general_agent_node(state):
19
+ # query = state.get("query")
20
+
21
+ # prompt = f"""
22
+ # Answer the following question directly.
23
+
24
+ # Question: {query}
25
+
26
+ # Do NOT rely on any external document.
27
+ # Answer clearly and accurately.
28
+ # """
29
+
30
+ # response = llm.invoke(prompt)
31
+
32
+ # return {
33
+ # **state,
34
+ # "general_answer": response.content
35
+ # }
36
+
37
+
38
+ def general_agent_node(state):
39
+ query = state.get("query")
40
+
41
+ chain = general_prompt | llm | StrOutputParser()
42
+ response = chain.invoke({"query": query})
43
+
44
+ return {
45
+ **state,
46
+ "general_answer": response.strip()
47
+ }
48
+
app/graph/nodes/rag_agent.py ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # # app/graph/rag_agent.py
2
+ # from app.core.rag_service import get_rag_context
3
+
4
+ # def rag_agent_node(state):
5
+
6
+ # print("DEBUG β†’ state received:", state)
7
+
8
+ # query= state["query"]
9
+ # doc_id= state["doc_id"]
10
+ # print("DEBUG β†’ query:", query)
11
+ # print("DEBUG β†’ doc_id:", doc_id)
12
+
13
+ # context, sources= get_rag_context(query, doc_id)
14
+ # print("DEBUG β†’ context:", context[:200] if context else "EMPTY")
15
+
16
+ # return {
17
+ # **state,
18
+ # "context": context,
19
+ # "sources": sources
20
+ # }
21
+
22
+
23
+
24
+
25
+ def rag_agent_node(state):
26
+
27
+ print("DEBUG β†’ state received:", state)
28
+
29
+ # βœ… context already comes from router now
30
+ context = state.get("context")
31
+ sources = state.get("sources")
32
+
33
+ print("DEBUG β†’ context:", context[:200] if context else "EMPTY")
34
+
35
+ return {
36
+ **state,
37
+ "context": context,
38
+ "sources": sources
39
+ }
40
+
41
+
app/graph/nodes/rag_answer_node.py ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # # app/graph/rag_answer_node.py
2
+
3
+ # from langchain_core.prompts import PromptTemplate
4
+ # from app.core.llm_engine import run_llm
5
+ # from app.core.prompts.rag_prompt import rag_prompt
6
+ # # rag_prompt = PromptTemplate(
7
+ # # input_variables=["context", "query"],
8
+ # # template=(
9
+ # # "You are a document intelligence system.\n"
10
+ # # "Answer ONLY using the provided context.\n"
11
+ # # "If answer is not present, say: 'Not in document'.\n\n"
12
+
13
+ # # "Keep response concise:\n"
14
+ # # "- Short explanation\n"
15
+ # # "- Bullet points if useful\n"
16
+ # # "- Max 120 words\n\n"
17
+
18
+ # # "Avoid repeating the question.\n\n"
19
+
20
+ # # "Context:\n{context}\n\n"
21
+ # # "Question:\n{query}\n\n"
22
+ # # "Answer:"
23
+ # # )
24
+ # # )
25
+
26
+ # def rag_answer_node(state):
27
+ # response = run_llm(rag_prompt, {
28
+ # "context": state.get("context", ""),
29
+ # "query": state.get("query")
30
+ # })
31
+
32
+ # return {
33
+ # **state,
34
+ # "final_answer": response
35
+ # }
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+ from app.core.llm_engine import llm
49
+ from app.core.prompts.rag_prompt import rag_prompt
50
+ from langchain_core.output_parsers import StrOutputParser
51
+
52
+ chain = rag_prompt | llm | StrOutputParser()
53
+
54
+
55
+ def rag_answer_node(state):
56
+ response = chain.invoke({
57
+ "context": state.get("context", ""),
58
+ "query": state.get("query")
59
+ })
60
+
61
+ return {
62
+ **state,
63
+ "final_answer": response
64
+ }
app/graph/nodes/router.py ADDED
@@ -0,0 +1,52 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app/graph/nodes/router.py
2
+
3
+ from app.core.rag_service import get_rag_context
4
+
5
+
6
+ def router_node(state):
7
+ query = state.get("query")
8
+ doc_id = state.get("doc_id")
9
+
10
+ # πŸ”₯ Step 1: Try retrieving context
11
+ context, sources, scores = get_rag_context(query, doc_id)
12
+ print("ROUTER DEBUG β†’ scores:", scores)
13
+
14
+ # print("ROUTER DEBUG β†’ context:", context[:100] if context else "EMPTY")
15
+
16
+ # # πŸ”₯ Step 2: Decide route based on context presence
17
+ # if context and len(context.strip()) > 50:
18
+ # route = "rag"
19
+ # else:
20
+ # route = "general"
21
+
22
+ # print("ROUTER DECISION β†’", route)
23
+
24
+ # return {
25
+ # **state,
26
+ # "route": route,
27
+ # "context": context, # βœ… pass forward (important)
28
+ # "sources": sources
29
+ # }
30
+
31
+
32
+ # πŸ”₯ Step 1: get best score
33
+ max_score = max(scores) if scores else 0
34
+
35
+ # πŸ”₯ Step 2: threshold decision
36
+ THRESHOLD = 0.75 # πŸ‘ˆ tune this
37
+
38
+ if max_score >= THRESHOLD:
39
+ route = "rag"
40
+ else:
41
+ route = "general"
42
+ context = "" # ❗ important: clear bad context
43
+
44
+ print("ROUTER DECISION β†’", route, "| score:", max_score)
45
+
46
+ return {
47
+ **state,
48
+ "route": route,
49
+ "context": context,
50
+ "sources": sources,
51
+ "score": max_score
52
+ }
app/graph/nodes/synthesizer.py ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from app.core.llm_engine import llm
2
+ from app.core.prompts.rag_prompt import rag_prompt
3
+ from langchain_core.output_parsers import StrOutputParser
4
+
5
+ def synthesizer_node(state):
6
+ query= state["query"]
7
+ context= state.get("context", "")
8
+ history= state.get("histroy", "")
9
+
10
+ general_answer = state.get("general_answer")
11
+
12
+ # If general route, skip RAG context
13
+ if state.get("route") == "general":
14
+ return {
15
+ **state,
16
+ "final_answer": general_answer or "No answer generated."
17
+ }
18
+
19
+ full_context= f"""
20
+ Conversation History:
21
+ {history}
22
+
23
+ Retrieved Context:
24
+ {context}
25
+ """
26
+
27
+
28
+
29
+ chain = rag_prompt | llm | StrOutputParser()
30
+ answer = chain.invoke({
31
+ "context": full_context,
32
+ "query": query
33
+ })
34
+
35
+ return {
36
+ **state,
37
+ "final_answer": answer.strip()
38
+ }