Skip to content

Commit 7ad5691

Browse files
committed
Enhance AIFAQ RAG System with Multi-Agent Architecture
- Implemented a multi-agent framework to optimize the RAG pipeline. - Developed agents for query understanding, document retrieval, response generation, and evaluation. - Integrated a new backend API endpoint and modified frontend components for multi-agent system support. - Improved RAG pipeline with dynamic query refinement, context-aware retrieval, and coherent response generation. - Enhanced response quality, accuracy, and relevance through evaluation system, with 25-30% improvement in factual accuracy. - Comprehensive testing demonstrated improved contextual understanding, completeness, and coherence. Contributed by RAWx18 as part of the LFX Mentorship Program. Signed-off-by: RAWx18 <[email protected]>
1 parent e39d1a5 commit 7ad5691

File tree

112 files changed

+27884
-659
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+27884
-659
lines changed

.gitignore

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Ignore files for PNPM, NPM and YARN
2+
pnpm-lock.yaml
3+
package-lock.json
4+
yarn.lock
5+
6+
# copy of .gitignore
7+
# dependencies
8+
/node_modules
9+
/.pnp
10+
.pnp.js
11+
.yarn/install-state.gz
12+
13+
# testing
14+
/coverage
15+
16+
# next.js
17+
/.next/
18+
/out/
19+
20+
# production
21+
/build
22+
23+
# misc
24+
.DS_Store
25+
*.pem
26+
27+
# debug
28+
npm-debug.log*
29+
yarn-debug.log*
30+
yarn-error.log*
31+
32+
# local env files
33+
.env*.local
34+
35+
# vercel
36+
.vercel
37+
38+
# typescript
39+
*.tsbuildinfo
40+
next-env.d.ts
41+
42+
# Python
43+
.venv/
44+
__pycache__/
45+
*.py[cod]
46+
*.pyo
47+
*.pyd
48+
*.egg-info/
49+
.eggs/
50+
*.pytest_cache/

src/core/agents/README.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# filepath: /home/raw/Documents/workspace/lfx/aifaq/src/core/agents/README.md
2+
# Multi-Agent RAG Architecture for AIFAQ
3+
4+
This module implements a multi-agent framework for Retrieval Augmented Generation (RAG) in the AIFAQ system. The architecture divides responsibilities among specialized agents to improve the overall quality of responses.
5+
6+
## Agent Roles
7+
8+
1. **Query Understanding Agent**: Analyzes user queries to identify intent, context requirements, and keywords
9+
2. **Retrieval Agent**: Manages document retrieval and relevance scoring
10+
3. **Context Integration Agent**: Combines retrieved documents with conversation history
11+
4. **Response Generation Agent**: Creates the final response using the prepared context
12+
5. **Evaluation Agent**: Assesses response quality and provides feedback for improvement
13+
14+
## Implementation
15+
16+
The multi-agent system uses a coordinator to manage agent interactions and ensure a smooth workflow from query to response.
17+
18+
## Usage
19+
20+
The multi-agent system integrates with the existing RAG pipeline, providing enhanced capabilities without disrupting the current user experience.

src/core/agents/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
from .base_agent import BaseAgent
2+
from .agent_coordinator import AgentCoordinator
3+
from .query_agent import QueryUnderstandingAgent
4+
from .retrieval_agent import RetrievalAgent
5+
from .context_agent import ContextIntegrationAgent
6+
from .response_agent import ResponseGenerationAgent
7+
from .evaluation_agent import EvaluationAgent

src/core/agents/agent_coordinator.py

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
from typing import Dict, List, Any, Optional
2+
from .base_agent import BaseAgent
3+
from .logger import get_agent_logger
4+
import time
5+
6+
7+
class AgentCoordinator:
8+
"""
9+
Coordinates the activities of multiple agents in the RAG pipeline.
10+
11+
The coordinator manages the flow of information between agents and ensures
12+
that each agent's output is properly passed to the next agent in the pipeline.
13+
"""
14+
15+
def __init__(self, agents: List[BaseAgent]):
16+
"""
17+
Initialize the coordinator with a list of agents.
18+
19+
Args:
20+
agents: A list of BaseAgent instances that will participate in the pipeline.
21+
"""
22+
self.agents = agents
23+
self.agent_map = {agent.name: agent for agent in agents}
24+
self.logger = get_agent_logger("coordinator")
25+
26+
async def run_pipeline(self, initial_input: Dict[str, Any]) -> Dict[str, Any]:
27+
"""
28+
Run the complete multi-agent pipeline.
29+
30+
Args:
31+
initial_input: The initial input data for the pipeline, typically including the user query.
32+
33+
Returns:
34+
The final result after all agents have processed the data.
35+
"""
36+
self.logger.info("Starting multi-agent pipeline")
37+
start_time = time.time()
38+
39+
current_data = initial_input
40+
processing_history = []
41+
42+
try:
43+
for agent in self.agents:
44+
self.logger.info(f"Running agent: {agent.name}")
45+
agent_start_time = time.time()
46+
47+
# Use the new execute_with_logging method
48+
agent_result = await agent.execute_with_logging(current_data)
49+
50+
agent_duration = time.time() - agent_start_time
51+
52+
processing_history.append({
53+
"agent": agent.name,
54+
"duration": agent_duration,
55+
"error": agent_result.get("error", None)
56+
})
57+
58+
# If there was an error, log it but continue with what we have
59+
if "error" in agent_result:
60+
self.logger.error(f"Error in agent {agent.name}: {agent_result['error']}")
61+
62+
# Merge the agent result with the current data
63+
current_data = {**current_data, **agent_result}
64+
65+
# Add the processing history to the result for debugging and evaluation
66+
current_data["processing_history"] = processing_history
67+
68+
total_duration = time.time() - start_time
69+
self.logger.info(f"Multi-agent pipeline completed in {total_duration:.2f}s")
70+
71+
return current_data
72+
73+
except Exception as e:
74+
self.logger.error(f"Error in pipeline execution: {str(e)}", exc_info=True)
75+
return {
76+
"error": f"Pipeline error: {str(e)}",
77+
"processing_history": processing_history
78+
}
79+
80+
async def get_agent(self, name: str) -> Optional[BaseAgent]:
81+
"""Get an agent by name."""
82+
return self.agent_map.get(name)
83+
return self.agent_map.get(name)

src/core/agents/base_agent.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from abc import ABC, abstractmethod
2+
from typing import Any, Dict, List, Optional
3+
import time
4+
import logging
5+
from .logger import get_agent_logger
6+
7+
8+
class BaseAgent(ABC):
9+
"""
10+
Base class for all agents in the multi-agent RAG system.
11+
12+
Each agent has a specific responsibility in the RAG pipeline and implements
13+
the process method to perform its task.
14+
"""
15+
16+
def __init__(self, name: str):
17+
self.name = name
18+
self.logger = get_agent_logger(name)
19+
20+
@abstractmethod
21+
async def process(self, input_data: Dict[str, Any]) -> Dict[str, Any]:
22+
"""
23+
Process the input data and return the results.
24+
25+
Args:
26+
input_data: A dictionary containing the input data for the agent.
27+
28+
Returns:
29+
A dictionary containing the results of the agent's processing.
30+
"""
31+
# This will be implemented by each specific agent
32+
pass
33+
34+
async def execute_with_logging(self, input_data: Dict[str, Any]) -> Dict[str, Any]:
35+
"""
36+
Wrapper around the process method that adds logging and timing.
37+
38+
Args:
39+
input_data: Input data for the agent
40+
41+
Returns:
42+
Result from the agent's process method
43+
"""
44+
self.logger.info(f"Starting processing in {self.name}")
45+
start_time = time.time()
46+
47+
try:
48+
# Log key input data without sensitive information
49+
safe_input = {k: v for k, v in input_data.items()
50+
if k not in ["model", "tokenizer", "vectordb"]}
51+
self.logger.debug(f"Input data: {safe_input}")
52+
53+
# Call the actual processing method
54+
result = await self.process(input_data)
55+
56+
# Calculate processing time
57+
processing_time = time.time() - start_time
58+
59+
# Log results without very large content
60+
safe_result = {k: (v if not isinstance(v, (str, list)) or (isinstance(v, str) and len(v) < 500)
61+
else f"[{type(v).__name__}: length={len(v)}]")
62+
for k, v in result.items()}
63+
64+
self.logger.info(f"Completed processing in {self.name} (took {processing_time:.2f}s)")
65+
self.logger.debug(f"Result: {safe_result}")
66+
67+
# Add processing time to the result
68+
result["processing_time"] = processing_time
69+
70+
return result
71+
except Exception as e:
72+
self.logger.error(f"Error in {self.name}: {str(e)}", exc_info=True)
73+
# Return minimal result with error information
74+
return {
75+
"error": str(e),
76+
"agent": self.name,
77+
"processing_time": time.time() - start_time
78+
}
79+
80+
def __str__(self) -> str:
81+
return f"{self.__class__.__name__}(name={self.name})"

0 commit comments

Comments
 (0)