mcikalmerdeka's picture
Initial commit: extract langgraph agentic rag project into standalone repository
79d0909
Raw
History Blame Contribute Delete
2.8 kB
"""Conditional edge functions for the RAG graph."""
from src.chains import answer_grader, hallucination_grader, question_router, RouterQuery
from src.core import logger
from src.core.state import GraphState
from src.graph.constants import (
GENERATE,
WEB_SEARCH,
DECISION_USEFUL,
DECISION_NOT_USEFUL,
DECISION_NOT_SUPPORTED,
DECISION_WEBSEARCH,
DECISION_VECTORSTORE,
)
def route_question(state: GraphState) -> str:
"""
Route the initial question to vectorstore or web search.
Args:
state: Current graph state with question.
Returns:
Route decision: 'vectorstore' or 'websearch'.
"""
logger.debug("Routing question...")
question = state["question"]
source: RouterQuery = question_router.invoke({"question": question})
if source.datasource == "websearch":
logger.info("Route β†’ Web Search")
return DECISION_WEBSEARCH
else:
logger.info("Route β†’ Vectorstore")
return DECISION_VECTORSTORE
def decide_to_generate(state: GraphState) -> str:
"""
Decide whether to generate or perform web search based on document relevance.
Args:
state: Current graph state with web_search flag.
Returns:
Next node: WEB_SEARCH or GENERATE.
"""
logger.debug("Assessing graded documents...")
if state["web_search"]:
logger.info("Documents insufficient β†’ Web Search")
return WEB_SEARCH
else:
logger.info("Documents sufficient β†’ Generate")
return GENERATE
def grade_generation(state: GraphState) -> str:
"""
Grade the generation for hallucination and answer quality.
Args:
state: Current graph state with question, documents, and generation.
Returns:
Decision: 'useful', 'not_useful', or 'not_supported'.
"""
logger.debug("Checking for hallucinations...")
question = state["question"]
documents = state["documents"]
generation = state["generation"]
# Check if generation is grounded in documents
hallucination_score = hallucination_grader.invoke(
{"documents": documents, "generation": generation}
)
if hallucination_score.binary_score:
logger.debug("Generation grounded in documents")
# Check if generation addresses the question
answer_score = answer_grader.invoke(
{"question": question, "generation": generation}
)
if answer_score.binary_score:
logger.info("Generation βœ“ Useful")
return DECISION_USEFUL
else:
logger.warning("Generation does not address question β†’ Retry")
return DECISION_NOT_USEFUL
else:
logger.warning("Generation not grounded β†’ Web Search")
return DECISION_NOT_SUPPORTED