stackConsult commited on
Commit
f088210
·
verified ·
1 Parent(s): 93eb4a4

Add enhanced RAG-powered analytics agent with community insights, versioning hooks, and rollback support

Browse files

This enhanced analytics agent integrates patterns from community RAG agents (bziiit/AGENT_ANALYSE_RAG, fahmiaziz/rag-sql-agent) with:
- RAG pipeline integration for context-aware analytics
- Schema versioning hooks per SCHEMA_VERSIONING.md
- Rollback/checkpoint capabilities for safe operations
- Citation tracking and confidence scoring
- Audit trail for compliance
- Multi-source context retrieval

Files changed (1) hide show
  1. rag_analytics_agent.py +318 -0
rag_analytics_agent.py ADDED
@@ -0,0 +1,318 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Enhanced RAG-Powered Analytics Agent with Community Insights.
2
+
3
+ Integrates retrieval-augmented generation for context-aware analytics,
4
+ versioning hooks per SCHEMA_VERSIONING.md, and rollback capabilities.
5
+ Enhanced with patterns from bziiit/AGENT_ANALYSE_RAG and fahmiaziz/rag-sql-agent.
6
+ """
7
+
8
+ import os
9
+ import json
10
+ import logging
11
+ from datetime import datetime
12
+ from typing import Dict, List, Optional, Any, Tuple
13
+ from dataclasses import dataclass, asdict
14
+ import sys
15
+
16
+ # Import RAG pipeline for context retrieval
17
+ from smolagents.rag_pipeline import RAGPipeline, RetrievalConfig
18
+ from schema_registry import SchemaRegistry
19
+
20
+ logger = logging.getLogger(__name__)
21
+
22
+ @dataclass
23
+ class AnalyticsConfig:
24
+ """Configuration for RAG-powered analytics."""
25
+ rag_enabled: bool = True
26
+ top_k_docs: int = 5
27
+ similarity_threshold: float = 0.7
28
+ enable_versioning: bool = True
29
+ schema_version: str = "1.0.0"
30
+ rollback_enabled: bool = True
31
+ audit_trail: bool = True
32
+
33
+ @dataclass
34
+ class AnalyticsQuery:
35
+ """Structured analytics query with RAG context."""
36
+ query_id: str
37
+ query_text: str
38
+ context_docs: List[Dict[str, Any]]
39
+ filters: Dict[str, Any]
40
+ aggregations: List[str]
41
+ timestamp: str
42
+ schema_version: str
43
+
44
+ @dataclass
45
+ class AnalyticsResult:
46
+ """Enhanced analytics result with citations and provenance."""
47
+ query_id: str
48
+ data: Dict[str, Any]
49
+ citations: List[Dict[str, Any]]
50
+ confidence_score: float
51
+ schema_version: str
52
+ rollback_checkpoint: Optional[str]
53
+ timestamp: str
54
+
55
+ class RAGAnalyticsAgent:
56
+ """Enhanced Analytics Agent with RAG, versioning, and rollback."""
57
+
58
+ def __init__(
59
+ self,
60
+ config: Optional[AnalyticsConfig] = None,
61
+ rag_pipeline: Optional[RAGPipeline] = None,
62
+ schema_registry: Optional[SchemaRegistry] = None
63
+ ):
64
+ self.config = config or AnalyticsConfig()
65
+ self.rag_pipeline = rag_pipeline
66
+ self.schema_registry = schema_registry
67
+ self.checkpoints: Dict[str, Dict] = {}
68
+
69
+ logger.info(f"Initialized RAGAnalyticsAgent with config: {self.config}")
70
+
71
+ def create_checkpoint(self, checkpoint_id: str, state: Dict[str, Any]) -> None:
72
+ """Create rollback checkpoint per SCHEMA_VERSIONING.md."""
73
+ self.checkpoints[checkpoint_id] = {
74
+ "state": state,
75
+ "timestamp": datetime.utcnow().isoformat(),
76
+ "schema_version": self.config.schema_version
77
+ }
78
+ logger.info(f"Created checkpoint: {checkpoint_id}")
79
+
80
+ def rollback_to_checkpoint(self, checkpoint_id: str) -> Optional[Dict[str, Any]]:
81
+ """Rollback to a previous checkpoint."""
82
+ if checkpoint_id in self.checkpoints:
83
+ checkpoint = self.checkpoints[checkpoint_id]
84
+ logger.info(f"Rolling back to checkpoint: {checkpoint_id}")
85
+ return checkpoint["state"]
86
+ logger.warning(f"Checkpoint not found: {checkpoint_id}")
87
+ return None
88
+
89
+ def retrieve_context(
90
+ self,
91
+ query_text: str,
92
+ top_k: Optional[int] = None
93
+ ) -> List[Dict[str, Any]]:
94
+ """Retrieve relevant context using RAG pipeline."""
95
+ if not self.config.rag_enabled or not self.rag_pipeline:
96
+ return []
97
+
98
+ top_k = top_k or self.config.top_k_docs
99
+
100
+ try:
101
+ results = self.rag_pipeline.retrieve(
102
+ query=query_text,
103
+ top_k=top_k,
104
+ threshold=self.config.similarity_threshold
105
+ )
106
+
107
+ context_docs = [
108
+ {
109
+ "content": r.get("content", ""),
110
+ "source": r.get("metadata", {}).get("source", "unknown"),
111
+ "score": r.get("score", 0.0),
112
+ "metadata": r.get("metadata", {})
113
+ }
114
+ for r in results
115
+ ]
116
+
117
+ logger.info(f"Retrieved {len(context_docs)} context documents")
118
+ return context_docs
119
+
120
+ except Exception as e:
121
+ logger.error(f"Context retrieval failed: {e}")
122
+ return []
123
+
124
+ def validate_schema(
125
+ self,
126
+ data: Dict[str, Any],
127
+ schema_version: Optional[str] = None
128
+ ) -> Tuple[bool, List[str]]:
129
+ """Validate data against schema version."""
130
+ if not self.config.enable_versioning or not self.schema_registry:
131
+ return True, []
132
+
133
+ schema_version = schema_version or self.config.schema_version
134
+
135
+ try:
136
+ is_valid = self.schema_registry.validate(data, schema_version)
137
+ errors = [] if is_valid else ["Schema validation failed"]
138
+ return is_valid, errors
139
+ except Exception as e:
140
+ logger.error(f"Schema validation error: {e}")
141
+ return False, [str(e)]
142
+
143
+ def analyze(
144
+ self,
145
+ query_text: str,
146
+ data_source: Dict[str, Any],
147
+ filters: Optional[Dict[str, Any]] = None,
148
+ aggregations: Optional[List[str]] = None
149
+ ) -> AnalyticsResult:
150
+ """Perform RAG-enhanced analytics with versioning and rollback."""
151
+ query_id = f"analytics_{datetime.utcnow().timestamp()}"
152
+
153
+ # Create checkpoint before analysis
154
+ if self.config.rollback_enabled:
155
+ self.create_checkpoint(
156
+ f"{query_id}_pre",
157
+ {"data_source": data_source, "filters": filters}
158
+ )
159
+
160
+ # Retrieve context
161
+ context_docs = self.retrieve_context(query_text)
162
+
163
+ # Build query
164
+ query = AnalyticsQuery(
165
+ query_id=query_id,
166
+ query_text=query_text,
167
+ context_docs=context_docs,
168
+ filters=filters or {},
169
+ aggregations=aggregations or [],
170
+ timestamp=datetime.utcnow().isoformat(),
171
+ schema_version=self.config.schema_version
172
+ )
173
+
174
+ # Perform analysis (simplified - extend with actual analytics logic)
175
+ try:
176
+ analysis_data = self._execute_analysis(query, data_source)
177
+
178
+ # Validate result schema
179
+ is_valid, errors = self.validate_schema(analysis_data)
180
+ if not is_valid:
181
+ logger.error(f"Schema validation failed: {errors}")
182
+ # Attempt rollback
183
+ if self.config.rollback_enabled:
184
+ rollback_state = self.rollback_to_checkpoint(f"{query_id}_pre")
185
+ if rollback_state:
186
+ logger.info("Successfully rolled back to pre-analysis state")
187
+
188
+ # Build citations from context
189
+ citations = [
190
+ {
191
+ "source": doc["source"],
192
+ "relevance_score": doc["score"],
193
+ "excerpt": doc["content"][:200]
194
+ }
195
+ for doc in context_docs
196
+ ]
197
+
198
+ # Calculate confidence based on context quality
199
+ avg_score = sum(d["score"] for d in context_docs) / len(context_docs) if context_docs else 0.5
200
+
201
+ result = AnalyticsResult(
202
+ query_id=query_id,
203
+ data=analysis_data,
204
+ citations=citations,
205
+ confidence_score=avg_score,
206
+ schema_version=self.config.schema_version,
207
+ rollback_checkpoint=f"{query_id}_pre" if self.config.rollback_enabled else None,
208
+ timestamp=datetime.utcnow().isoformat()
209
+ )
210
+
211
+ # Audit trail
212
+ if self.config.audit_trail:
213
+ self._log_audit(query, result)
214
+
215
+ return result
216
+
217
+ except Exception as e:
218
+ logger.error(f"Analysis failed: {e}")
219
+ # Return error result with rollback info
220
+ return AnalyticsResult(
221
+ query_id=query_id,
222
+ data={"error": str(e)},
223
+ citations=[],
224
+ confidence_score=0.0,
225
+ schema_version=self.config.schema_version,
226
+ rollback_checkpoint=f"{query_id}_pre" if self.config.rollback_enabled else None,
227
+ timestamp=datetime.utcnow().isoformat()
228
+ )
229
+
230
+ def _execute_analysis(
231
+ self,
232
+ query: AnalyticsQuery,
233
+ data_source: Dict[str, Any]
234
+ ) -> Dict[str, Any]:
235
+ """Execute the actual analysis logic (extend as needed)."""
236
+ # Simplified analytics - enhance with real logic
237
+ results = {
238
+ "query_id": query.query_id,
239
+ "metrics": {},
240
+ "insights": [],
241
+ "context_applied": len(query.context_docs) > 0
242
+ }
243
+
244
+ # Apply filters
245
+ filtered_data = data_source
246
+ for key, value in query.filters.items():
247
+ if key in filtered_data:
248
+ filtered_data = {k: v for k, v in filtered_data.items() if v == value}
249
+
250
+ # Apply aggregations
251
+ for agg in query.aggregations:
252
+ if agg == "count":
253
+ results["metrics"]["count"] = len(filtered_data)
254
+ elif agg == "sum":
255
+ results["metrics"]["sum"] = sum(v for v in filtered_data.values() if isinstance(v, (int, float)))
256
+
257
+ # Extract insights from RAG context
258
+ if query.context_docs:
259
+ for doc in query.context_docs[:3]: # Top 3 docs
260
+ results["insights"].append({
261
+ "source": doc["source"],
262
+ "insight": doc["content"][:150]
263
+ })
264
+
265
+ return results
266
+
267
+ def _log_audit(
268
+ self,
269
+ query: AnalyticsQuery,
270
+ result: AnalyticsResult
271
+ ) -> None:
272
+ """Log audit trail for compliance."""
273
+ audit_entry = {
274
+ "timestamp": datetime.utcnow().isoformat(),
275
+ "query_id": query.query_id,
276
+ "query_text": query.query_text,
277
+ "schema_version": query.schema_version,
278
+ "confidence_score": result.confidence_score,
279
+ "citations_count": len(result.citations)
280
+ }
281
+ logger.info(f"Audit: {json.dumps(audit_entry)}")
282
+
283
+ def get_version_info(self) -> Dict[str, Any]:
284
+ """Get current version and rollback information."""
285
+ return {
286
+ "schema_version": self.config.schema_version,
287
+ "checkpoints": list(self.checkpoints.keys()),
288
+ "versioning_enabled": self.config.enable_versioning,
289
+ "rollback_enabled": self.config.rollback_enabled
290
+ }
291
+
292
+ # Example usage
293
+ if __name__ == "__main__":
294
+ logging.basicConfig(level=logging.INFO)
295
+
296
+ # Initialize agent
297
+ config = AnalyticsConfig(
298
+ rag_enabled=True,
299
+ top_k_docs=5,
300
+ enable_versioning=True,
301
+ rollback_enabled=True
302
+ )
303
+
304
+ agent = RAGAnalyticsAgent(config=config)
305
+
306
+ # Example query
307
+ result = agent.analyze(
308
+ query_text="What are the top engagement metrics for Q4?",
309
+ data_source={"engagement": 100, "reach": 500},
310
+ aggregations=["count", "sum"]
311
+ )
312
+
313
+ print(f"\nAnalysis Result:")
314
+ print(f"Query ID: {result.query_id}")
315
+ print(f"Confidence: {result.confidence_score}")
316
+ print(f"Citations: {len(result.citations)}")
317
+ print(f"Rollback checkpoint: {result.rollback_checkpoint}")
318
+ print(f"\nVersion Info: {json.dumps(agent.get_version_info(), indent=2)}")