The Paradigm Shift: From Retrieval to Prediction
Most developers view Retrieval-Augmented Generation (RAG) as a tool for answering questions: "What is our refund policy?" or "Show me the transaction history." In high-frequency domains like QR Code Payments, RAG can be integrated into a Predictive Intelligence Workflow. Here, retrieval doesn't just fetch facts; it fetches contextual patterns, historical anomalies, and dynamic risk rules that feed into a predictive model. The LLM then acts not as a chatbot, but as a reasoning engine that synthesizes retrieved data to predict outcomes (e.g., fraud probability, merchant churn, settlement delay) before they happen.
The Core Difference
| Feature | Pure QA Workflow | Predictive Intelligence Workflow |
|---|
| Goal | Answer user queries | Predict future states/events |
| Retrieval Target | Static documents (PDFs, FAQs) | Dynamic vectors (historical patterns, risk scores, real-time rules) |
| Output | Text response | Structured prediction (Score, Probability, Action) |
| Latency Sensitivity | Moderate (seconds) | Critical (milliseconds) |
| State Management | Session-based | Transaction-based + Long-term memory |
Real-Time Unique Use Case: "Dynamic Fraud & Settlement Prediction for Merchant QR Codes"
Scenario
Merchant Profile: "Spice Garden," a mid-sized restaurant in Delhi using a static QR code for UPI payments.
Business Problem:
Fraud Risk: A sudden spike in small-value transactions from new users at 2 AM could indicate "testing" for carding attacks or money laundering.
Settlement Cash Flow: The merchant needs to know if tomorrow’s settlement will be delayed due to high-risk flags triggered by today’s unusual pattern.
Customer Churn: If legitimate customers face repeated failed scans due to network issues, they might switch competitors.
Traditional Approach: Rule-based engines flag transactions after they occur. They cannot predict settlement impact or churn risk based on unstructured context (e.g., local festival spikes, weather-related footfall changes).
RAG-Powered Predictive Solution: During each QR scan event, a multi-agent LangGraph system:
Retrieves Historical Patterns: Fetches similar transaction clusters from a vector DB (e.g., "Similar spikes occurred during Diwali 2025").
Retrieves Dynamic Risk Rules: Fetches real-time regulatory thresholds from a compliance knowledge base.
Predicts Outcomes: Uses an LLM to reason over retrieved patterns + real-time data to predict:
Fraud Probability Score (0-1)
Settlement Delay Risk (High/Medium/Low)
Customer Friction Score (Likelihood of drop-off)
Triggers Pre-emptive Actions: Auto-holds suspicious funds, sends proactive alerts to the merchant, or optimizes routing for faster settlement.
System Architecture
![438]()
Step-by-Step Implementation
Prerequisites
pip install langgraph langchain langchain-openai chromadb psycopg2-binary redis pydantic numpy pandas
Step 1: Define State Schema and Data Models
from typing import TypedDict, List, Optional, Dict, Anyfrom pydantic import BaseModel, Field
from datetime import datetime
import uuid
class QRScanEvent(BaseModel):
"""Represents a single QR scan transaction."""
event_id: str = Field(default_factory=lambda: str(uuid.uuid4()))
merchant_id: str
user_id: str
amount: float
timestamp: datetime
location_lat: Optional[float] = None
location_lon: Optional[float] = None
device_fingerprint: Optional[str] = None
class RetrievedContext(BaseModel):
"""Context retrieved from Vector DB and Rule Engine."""
similar_historical_patterns: List[Dict[str, Any]]
applicable_risk_rules: List[Dict[str, Any]]
merchant_profile_summary: str
recent_anomalies: List[str]
class PredictionResult(BaseModel):
"""Output of the predictive agent."""
fraud_probability: float = Field(ge=0.0, le=1.0)
settlement_delay_risk: str = Field(description="high, medium, low")
customer_friction_score: float = Field(ge=0.0, le=1.0)
recommended_action: str = Field(description="allow, hold, review, alert_merchant")
reasoning: str
class PaymentState(TypedDict):
"""State passed between agents in LangGraph workflow."""
event: QRScanEvent
retrieved_context: Optional[RetrievedContext]
prediction: Optional[PredictionResult]
action_taken: Optional[str]
conversation_history: List[Dict[str, str]] # For audit/debugging
error_message: Optional[str]
Step 2: Context Retriever Agent (RAG Core)
This agent retrieves historical patterns and dynamic rules relevant to the current transaction.
from langchain_chroma import Chroma
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
import psycopg2
import json
class ContextRetrieverAgent:
def __init__(self, vector_db_path: str = "./qr_payment_db"):
self.embeddings = OpenAIEmbeddings(model="text-embedding-3-small")
self.vector_db = Chroma(
persist_directory=vector_db_path,
embedding_function=self.embeddings,
collection_name="payment_patterns"
)
self._seed_data()
def _seed_data(self):
"""Seed with sample historical patterns and risk rules."""
if self.vector_db._collection.count() == 0:
docs = [
Document(
page_content="High frequency small transactions (< ₹100) from new users at night often indicate fraud testing.",
metadata={"type": "pattern", "risk_level": "high"}
),
Document(
page_content="Merchants with > 5% failure rate in last 24 hours face settlement delays.",
metadata={"type": "rule", "source": "internal_policy"}
),
Document(
page_content="Festival seasons see 3x normal volume; false positives increase if rules are static.",
metadata={"type": "pattern", "seasonal": True}
)
]
self.vector_db.add_documents(docs)
def retrieve_historical_patterns(self, event: QRScanEvent) -> List[Dict]:
"""Find similar historical transactions."""
query = f"merchant {event.merchant_id} amount {event.amount} time {event.timestamp.hour}"
results = self.vector_db.similarity_search(query, k=3)
return [{"content": doc.page_content, "metadata": doc.metadata} for doc in results]
def retrieve_risk_rules(self, merchant_id: str) -> List[Dict]:
"""Fetch applicable risk rules."""
# In production, query a rule engine or SQL DB
return [
{"rule_id": "R001", "description": "Flag transactions > ₹50,000 without KYC"},
{"rule_id": "R002", "description": "Hold funds if merchant failure rate > 5%"}
]
def get_merchant_profile(self, merchant_id: str) -> str:
"""Fetch merchant summary from SQL."""
# Simulated DB call
return f"Merchant {merchant_id}: Restaurant, Avg Daily Vol: ₹25,000, Risk Tier: Medium"
def run(self, state: PaymentState) -> PaymentState:
"""Execute retrieval logic."""
event = state['event']
patterns = self.retrieve_historical_patterns(event)
rules = self.retrieve_risk_rules(event.merchant_id)
profile = self.get_merchant_profile(event.merchant_id)
state['retrieved_context'] = RetrievedContext(
similar_historical_patterns=patterns,
applicable_risk_rules=rules,
merchant_profile_summary=profile,
recent_anomalies=[] # Populate from real-time anomaly detection service
)
return state
Step 3: Predictor Agent (LLM-Based Reasoning)
This agent uses the retrieved context to predict outcomes. It doesn’t just answer questions; it generates structured predictions.
from langchain_openai import ChatOpenAI
import json
class PredictorAgent:
def __init__(self):
self.llm = ChatOpenAI(model="gpt-4o", temperature=0.1) # Low temp for consistency
def predict_outcomes(self, state: PaymentState) -> PaymentState:
"""Generate predictions based on retrieved context."""
event = state['event']
context = state['retrieved_context']
prompt = f"""
You are a Financial Risk AI. Analyze the current QR payment event and predict risks.
Event Details:
- Amount: ₹{event.amount}
- Time: {event.timestamp.strftime('%H:%M')}
- Merchant: {context.merchant_profile_summary}
Retrieved Context:
- Historical Patterns: {json.dumps(context.similar_historical_patterns, indent=2)}
- Risk Rules: {json.dumps(context.applicable_risk_rules, indent=2)}
Tasks:
1. Estimate Fraud Probability (0-1). Consider time, amount, and patterns.
2. Assess Settlement Delay Risk (high/medium/low).
3. Calculate Customer Friction Score (0-1). High score means likely drop-off.
4. Recommend Action: 'allow', 'hold', 'review', or 'alert_merchant'.
5. Provide brief reasoning.
Return ONLY valid JSON:
{{
"fraud_probability": 0.1,
"settlement_delay_risk": "low",
"customer_friction_score": 0.2,
"recommended_action": "allow",
"reasoning": "Normal pattern for this merchant."
}}
"""
try:
response = self.llm.invoke(prompt)
prediction_data = json.loads(response.content)
state['prediction'] = PredictionResult(**prediction_data)
except Exception as e:
state['error_message'] = f"Prediction failed: {str(e)}"
return state
Step 4: Decision Orchestrator Agent
This agent executes the recommended action and updates state.
class DecisionOrchestratorAgent:
def run(self, state: PaymentState) -> PaymentState:
"""Execute the predicted action."""
if not state.get('prediction'):
state['action_taken'] = "error"
return state
action = state['prediction'].recommended_action
# Simulate action execution
if action == "hold":
state['action_taken'] = "funds_held_for_review"
elif action == "alert_merchant":
state['action_taken'] = "merchant_alert_sent"
else:
state['action_taken'] = "transaction_allowed"
# Log to conversation history for audit
state['conversation_history'].append({
"role": "system",
"content": f"Action: {state['action_taken']} | Reason: {state['prediction'].reasoning}"
})
return state
Step 5: Assemble the LangGraph Workflow
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
# Initialize agents
retriever = ContextRetrieverAgent()
predictor = PredictorAgent()
orchestrator = DecisionOrchestratorAgent()
# Define nodesdef retrieve_node(state: PaymentState) -> PaymentState:
return retriever.run(state)
def predict_node(state: PaymentState) -> PaymentState:
return predictor.predict_outcomes(state)
def orchestrate_node(state: PaymentState) -> PaymentState:
return orchestrator.run(state)
# Build graph
workflow = StateGraph(PaymentState)
workflow.add_node("retrieve", retrieve_node)
workflow.add_node("predict", predict_node)
workflow.add_node("orchestrate", orchestrate_node)
workflow.set_entry_point("retrieve")
workflow.add_edge("retrieve", "predict")
workflow.add_edge("predict", "orchestrate")
workflow.add_edge("orchestrate", END)
# Compile with memory
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
Step 6: Execute the Workflow
def process_qr_payment(event: QRScanEvent) -> Dict:
"""Main entry point for predictive processing."""
initial_state = PaymentState(
event=event,
retrieved_context=None,
prediction=None,
action_taken=None,
conversation_history=[],
error_message=None
)
thread_id = f"qr_{event.event_id}"
config = {"configurable": {"thread_id": thread_id}}
result = app.invoke(initial_state, config=config)
return {
"event_id": event.event_id,
"prediction": result['prediction'].dict() if result['prediction'] else None,
"action": result['action_taken']
}
# Example usageif __name__ == "__main__":
event = QRScanEvent(
merchant_id="MERCH_001",
user_id="USER_123",
amount=75.0,
timestamp=datetime.now(),
location_lat=28.6139,
location_lon=77.2090
)
result = process_qr_payment(event)
print(json.dumps(result, indent=2))
Sample Output
{"event_id": "evt_abc123","prediction": {
"fraud_probability": 0.12,
"settlement_delay_risk": "low",
"customer_friction_score": 0.05,
"recommended_action": "allow",
"reasoning": "Transaction amount is within normal range for this merchant. No historical anomalies detected."},"action": "transaction_allowed"}
Why This Is "Predictive Intelligence" and Not Just QA
Proactive vs. Reactive: The system predicts future settlement delays and fraud before the transaction completes, allowing pre-emptive holds.
Structured Output: The LLM outputs a PredictionResult object, not text. This can be directly consumed by downstream systems (payment gateways, dashboards).
Dynamic Context: Retrieval fetches real-time patterns (e.g., "similar spikes happened yesterday"), not static FAQs.
Actionable Insights: The output drives automated actions (hold, alert), not just user notifications.
Memory and State Management
Persistent State for Continuous Learning
Short-Term: LangGraph MemorySaver tracks the lifecycle of a single transaction.
Long-Term: Redis stores merchant-specific risk profiles updated after each prediction.
Feedback Loop: If a predicted "fraud" turns out to be legitimate, the system logs this to retrain the retrieval embeddings or fine-tune the LLM prompt.
def update_merchant_profile(merchant_id: str, prediction: PredictionResult):
"""Update long-term memory with new data."""
redis_client.hset(f"merchant:{merchant_id}", mapping={
"last_fraud_score": prediction.fraud_probability,
"last_action": prediction.recommended_action
})
Compliance and Security
Explainability: Every prediction includes a reasoning field for audit trails.
Data Privacy: PII (user_id, location) is hashed before storage in vector DB.
Guardrails: The DecisionOrchestrator ensures no action violates hard-coded regulatory limits (e.g., never hold funds > 24 hours without manual review).
Conclusion
Integrating RAG into a predictive workflow transforms QR payment processing from a simple pass/fail check into an intelligent, adaptive system that:
✅ Predicts Fraud before it impacts the merchant
✅ Optimizes Settlements by anticipating delays
✅ Reduces Friction by understanding contextual nuances
This approach leverages the reasoning power of LLMs combined with the precision of retrieval to create a competitive advantage in the fast-paced world of digital payments.