Rag-ag / src /agent.py
beastLucifer's picture
Upload 11 files
9806c71 verified
from typing import Annotated, List, TypedDict
from langchain_google_genai import ChatGoogleGenerativeAI
from langgraph.graph import StateGraph, START, END
from langgraph.prebuilt import ToolNode
from src.tools import tools
# The Local Knowledge Registry (Update this whenever you add new data types)
# Manual as of now
LOCAL_MANIFEST = {
"topics": ["HR Policies", "Project X Design Docs", "Q3 Financials", "Employee Handbook"],
"date_range": "Documents updated as of Dec 2024",
"domain": "Internal Corporate Knowledge"
}
SYSTEM_PROMPT = f"""
You are an expert Research Assistant. You have access to:
1. INTERNAL DATA: {LOCAL_MANIFEST['topics']}. (Use 'local_research_tool')
2. EXTERNAL DATA: The entire internet via duckduckgosearch. (Use 'web_search_tool')
GUIDELINES:
- Given the user's technical question and the fact that our internal documents are insufficient, generate a generic search query for the internet that does NOT include any proprietary names or internal details.
- If a query is about {LOCAL_MANIFEST['topics']}, try LOCAL first.
- If a query is TECHNICAL (e.g., PyTorch, Python APIs) or REAL-TIME, go to WEB immediately.
- If the query is ambiguous, try LOCAL first, then fallback to WEB if the results are empty or low confidence.
"""
class AgentState(TypedDict):
"""MNC Agent state with intent tracking and sufficiency grading."""
messages: Annotated[List, "Chat history"]
intent: str
is_sufficient: bool
# Brain: Gemini 2.0 Flash (high-speed agentic reasoning)
llm = ChatGoogleGenerativeAI(model="gemini-2.0-flash", temperature=0)
llm_with_tools = llm.bind_tools(tools)
def router(state: AgentState):
"""Classifies user intent to prioritize retrieval paths."""
query = state['messages'][-1].content
prompt = f"Categorize intent: TECHNICAL (API/Docs), INTERNAL (Proprietary), or REALTIME. Query: {query}"
response = llm.invoke(prompt)
intent = "TECHNICAL" if any(x in response.content.upper() for x in ["TECHNICAL", "REALTIME"]) else "INTERNAL"
return {"intent": intent}
def call_model(state: AgentState):
"""Invokes Gemini with tools based on intent and history."""
return {"messages": [llm_with_tools.invoke(state['messages'])]}
# Orchestration Graph
workflow = StateGraph(AgentState)
workflow.add_node("router", router)
workflow.add_node("llm", call_model)
workflow.add_node("tools", ToolNode(tools))
workflow.add_edge(START, "router")
workflow.add_edge("router", "llm")
# Self-Correction Loop
def should_continue(state: AgentState):
last_msg = state["messages"][-1]
return "tools" if last_msg.tool_calls else END
workflow.add_conditional_edges("llm", should_continue)
workflow.add_edge("tools", "llm")
app = workflow.compile()