File size: 4,198 Bytes
8a1fc38
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Solver Agent (Google ADK)

Uses RAG context and LLM to solve the math problem.
"""

import logging
from typing import Dict, Any, List

from backend.src.services.llm_service import _get_llm
from backend.src.services.vector_service import build_pipeline
from backend.src.config import settings

try:
    from google_adk.agent import Agent
except ImportError:
    class Agent:
        def __init__(self, name, description, instructions, llm=None):
            self.name = name
            self.description = description
            self.instructions = instructions
            self.llm = llm

logger = logging.getLogger("math_assistant.agents.solver")

class SolverAgent(Agent):
    """Core mathematical engine."""
    
    def __init__(self):
        super().__init__(
            name="SolverAgent",
            description="Solves mathematical problems step-by-step using RAG context.",
            instructions="Solve the math problem accurately."
        )
        self.llm = _get_llm()
        self.vector_store = build_pipeline()
        
        from backend.src.agents.mcp_registry import get_mcp_tools
        self.tools = get_mcp_tools()
        
        try:
            from langchain.agents import create_tool_calling_agent, AgentExecutor
            from langchain_core.prompts import ChatPromptTemplate
            
            prompt = ChatPromptTemplate.from_messages([
                ("system", "You are an advanced mathematical solver. Provide a clear, step-by-step solution. You MUST use the provided tools for differentiation, integration, arithmetic, python code execution, etc. whenever a complex calculation is needed. Do not guess complex answers."),
                ("human", "Question: {query}\n\nRelevant Knowledge Base Context:\n{context}\n\nPrevious Chat Context:\n{history}\n\nSolution:")
            ])
            
            # If the LLM doesn't support bind_tools, this will fail or we can catch it
            if getattr(settings, "USE_MCP", True) and hasattr(self.llm, "bind_tools") and self.tools:
                agent = create_tool_calling_agent(self.llm, self.tools, prompt)
                self.executor = AgentExecutor(agent=agent, tools=self.tools, verbose=True, handle_parsing_errors=True)
            else:
                self.executor = None
        except ImportError:
            self.executor = None

    def solve(self, query: str, context: str, history: str) -> str:
        """Generate a solution based on query, RAG context, and history."""
        if getattr(self, 'executor', None):
            try:
                response = self.executor.invoke({
                    "query": query,
                    "context": context,
                    "history": history
                })
                return response.get("output", "")
            except Exception as e:
                logger.error(f"Solver AgentExecutor failed: {e}")
                return "I encountered an error while trying to solve this problem with tools."
        
        prompt = (
            f"You are a mathematical solver. Provide a clear, step-by-step solution.\n\n"
            f"Question: {query}\n\n"
            f"Relevant Knowledge Base Context:\n{context}\n\n"
            f"Previous Chat Context:\n{history}\n\n"
            f"Solution:"
        )
        
        try:
            if hasattr(self.llm, "invoke"):
                response = self.llm.invoke(prompt)
                return response.content
            else:
                return self.llm(prompt)
        except Exception as e:
            logger.error(f"Solver failed: {e}")
            return "I encountered an error while trying to solve this problem."

    def retrieve_context(self, query: str) -> str:
        """Retrieve RAG context for the query."""
        try:
            retriever = self.vector_store.as_retriever(search_kwargs={"k": 3})
            docs = retriever.invoke(query)
            if not docs:
                return "No relevant context found."
            return "\n\n".join([doc.page_content for doc in docs])
        except Exception as e:
            logger.warning(f"RAG retrieval failed in Solver: {e}")
            return "No relevant context found."