testtest123's picture
feat: upgrade RAG conversational intent classification to multi-lingual LLM
27d1bb9
Raw
History Blame Contribute Delete
4.78 kB
from .base import BaseRAGTechnique
from ..services.embed_service import get_embedding
from ..utils.json_utils import extract_json_block, repair_json
from typing import List, Dict, Any
import json
class AgenticRAG(BaseRAGTechnique):
async def retrieve(self, query: str, document_id: str, top_k: int, **kwargs) -> List[Dict[str, Any]]:
# This is the "agent loop"
await self.emit("AGENT_INIT", "#22C55E", "Qwen3 agent ready with 4 tools")
all_collected_chunks = []
conversation_history = []
system_prompt = f"""
You are an intelligent RAG agent. You have access to a document (ID: {document_id}).
Your goal is to answer the user query: "{query}"
Available tools:
1. search_docs(query: str, top_k: int) -> list of chunks
2. filter_search(filters: dict, query: str) -> list of chunks. filters can include "page" or "section".
3. get_page(page_num: int) -> text of that page
4. finish(answer: str) -> finish with final answer
Respond ONLY with a JSON object:
{{
"thought": "your reasoning",
"tool": "tool_name",
"args": {{ ... }}
}}
"""
for i in range(5): # Max 5 iterations
await self.emit("PLAN", "#8B5CF6", f"Agent iteration {i+1}: Thinking...")
agent_prompt = f"{system_prompt}\n\nHistory: {json.dumps(conversation_history)}\n\nAction:"
response_text = self.llm.generate(agent_prompt)
try:
action_data = repair_json(extract_json_block(response_text))
thought = action_data.get("thought", "")
tool = action_data.get("tool", "")
args = action_data.get("args", {})
await self.emit("PLAN", "#8B5CF6", f"Thought: {thought[:100]}...")
if tool == "finish":
self.final_agent_answer = args.get("answer", "")
break
# Execute Tool
await self.emit("TOOL", "#D97706", f"Tool call: {tool}({json.dumps(args)})")
observation = ""
if tool == "search_docs":
q = args.get("query", query)
tk = args.get("top_k", top_k)
q_vec = get_embedding(q)
results = await self.supabase.vector_search(q_vec, document_id, self.user_id, tk)
all_collected_chunks.extend(results)
observation = f"Found {len(results)} chunks."
elif tool == "filter_search":
f = args.get("filters", {})
q = args.get("query", query)
matching_ids = await self.supabase.filter_chunk_ids(document_id, self.user_id, f)
if matching_ids:
q_vec = get_embedding(q)
results = await self.supabase.vector_search(q_vec, document_id, self.user_id, top_k, filter_chunk_ids=matching_ids)
all_collected_chunks.extend(results)
observation = f"Filtered search found {len(results)} chunks."
else:
observation = "No chunks matched the filters."
elif tool == "get_page":
p = args.get("page_num")
results = await self.supabase.filter_chunk_ids(document_id, self.user_id, {"page": p})
if results:
chunks = await self.supabase.get_chunks_by_ids(results)
all_collected_chunks.extend(chunks)
observation = f"Retrieved page {p}."
else:
observation = f"Page {p} not found."
await self.emit("OBSERVE", "#22C55E", observation)
conversation_history.append({"action": action_data, "observation": observation})
except Exception as e:
logger.error(f"Agent error decoding JSON: {e}")
conversation_history.append({"error": f"Invalid JSON response from your side. Use the required JSON format. error: {str(e)}"})
await self.emit("FINAL", "#22C55E", "Answer generated after tool usage.")
return all_collected_chunks
async def generate(self, query: str, chunks: List[Dict[str, Any]]) -> str:
# If the agent finished with a final answer, use it.
if hasattr(self, "final_agent_answer") and self.final_agent_answer:
return self.final_agent_answer
await self.emit("GENERATE", "#7C3AED", "Qwen3 generating final summary...")
prompt = self.build_prompt(query, chunks)
return self.llm.generate(prompt)