DEV Community

Prafull Gupta
Prafull Gupta

Posted on

An Agent That Knows When It Doesn't Know - Fraud Investigation on TigerGraph

What We Built

We built an agentic fraud investigation system on TigerGraph for the TigerGraph x Hacker House Goa hackathon. It takes twenty fraud alerts from the IEEE-CIS dataset (590,742 transactions), investigates each one using graph traversals, calibrates its confidence, and - this is the key part - asks for more evidence when one signal is not enough.

For each alert the agent produces three things:

  • An internal case record written into the graph
  • A suspicious activity report when policy requires one
  • A next-best-action with an approval route, recorded before and after any evidence it asks for

The bank's risk score is an input, not an answer: above 0.7 most flagged transactions are legitimate, and some fraud scores near zero. The agent's job is calibration and restraint as much as detection.

Architecture

alert -> LangGraph agent -> TigerGraph MCP -> TigerGraph (GSQL, algorithms, vectors)
              |                                   ^
              +-> Gemini (temperature 0)            |
              +-> action registry (permissions) ----+ case writeback
              +-> FastAPI (+SSE) -> React analyst UI
Enter fullscreen mode Exit fullscreen mode

The pipeline is a state machine:

TRIGGER -> OPEN_CASE -> GATHER_EVIDENCE -> ASSESS -> [uncertain? REQUEST_EVIDENCE -> RE-ASSESS]* -> DECIDE_NBA -> APPROVAL_GATE -> EXPLAIN -> WRITE_CASE

All graph access goes through the tool layer; the model never sees raw rows - only structured evidence briefs.

How TigerGraph Is Used

TigerGraph is the backbone of this system. Here's how we used every major capability:

Schema Design

We designed a rich graph schema with 12 vertex types and 15+ edge types:

  • Core entities: Customer, Card, Transaction, DeviceProfile, EmailDomain, BillingRegion
  • Investigation entities (agent-written): Case, Evidence, Action, Pattern, PolicyClause
  • Historical: ClosedCase (with embeddings for similarity search)

Key edges like OWNS, MADE, FROM_DEVICE, BILLED_IN model the transaction network, while HAS_EVIDENCE, TOOK, SIMILAR_TO capture the agent's reasoning chain.

GSQL Queries

We wrote 14 GSQL-backed tool functions:

Tool Purpose
card_profile Cardholder history: median spend, products, regions, devices
card_window All transactions within +/-72h of the alert
velocity_stats Transaction velocity in configurable time windows
device_neighbors Other customers sharing this device profile
path_to_known_fraud Shortest path to a confirmed fraud case
fraud_ring_detection WCC + Louvain on shared device/region subgraph
similar_cases Vector similarity search over closed case embeddings
policy_lookup Vector search over policy clause embeddings

Graph Algorithms

  • Weakly Connected Components and Louvain Community Detection on the shared device / region / email subgraph to find fraud rings
  • PageRank for entity centrality - identifying the most connected nodes in suspicious clusters

Vector Search (GraphRAG)

We embedded closed-case narratives and policy clauses using MiniLM (384-d) and stored them as vector attributes on TigerGraph vertices. For each new case, the agent:

  1. Retrieves similar closed cases by vector similarity
  2. Finds relevant policy clauses
  3. Condenses graph facts + similar cases + policy into an evidence brief
  4. Reasons over that brief with the LLM

MCP Integration

The agent's only interface to the graph is through TigerGraph MCP tools. Every claim in a case file cites a query name and entity IDs - full provenance, no hallucination.

Agentic Behaviour - The Interesting Part

1. Uncertainty is Explicit

The agent doesn't just classify fraud/not-fraud. It maintains a calibrated probability and uses Bayesian updates:

def odds_mult(p, lr):
    return sig(logit(p) + math.log(lr))
Enter fullscreen mode Exit fullscreen mode

Thresholds come from the fraud policy:

  • >= 0.85: Act (with >=2 independent signals)
  • 0.15 - 0.85: Request more evidence
  • <= 0.15: Clear

2. Evidence Requests Change Outcomes

When uncertain, the agent requests customer validation, step-up authentication, or analyst review - selecting the channel with the highest expected information gain.

Example from Case HHG-001:

  • Initial probability: 0.59 (out-of-region use pattern)
  • Action: VERIFY_WITH_CUSTOMER
  • Customer denies the transaction
  • Final probability: 0.93 -> BLOCK_CARD

3. The Recommendation Changes

nba_before and nba_after are stored with a diff and a reason:

  • At 0.45 on one signal -> VERIFY_WITH_CUSTOMER
  • After denial -> BLOCK_CARD, CREATE_CASE, maybe FILE_REPORT

4. Permissions Live in Code

Only auto-routed actions execute. L1 (team lead) and L2 (fraud manager) actions are recorded as pending with the approver role. BLOCK_ALL_CARDS is refused unless policy R10 holds.

5. Memory Through the Graph

Prior case outcomes are retrieved by vector similarity AND shared entities. They're cited in the case file and change recommendations - a cleared travel case makes the agent verify instead of block.

Pattern Discovery

We ran graph algorithms over the full dataset and discovered two undocumented fraud patterns:

DISC-001: Shared-Device Ring - One Samsung SM-G935F behind an anonymous proxy, marked New on 28 different customers' cards within 30 days (60 transactions, $16,556). The graph found it through device-neighbor traversal.

DISC-002: Threshold Structuring - 3-4 online purchases each just under $500 within 45 minutes on rotating device profiles (44 episodes found).

Case HHG-014 hit the shared-device ring with 0.988 probability - the bank's risk score was 0.05. The graph caught what the model missed.

Results

All 20 benchmark cases processed successfully:

Metric Value
Cases processed 20/20
Fraud detected Multiple patterns including card-not-present, out-of-region, account takeover
Undocumented patterns found 2 (DISC-001, DISC-002)
SARs generated Filed when exposure > $1,000 or shared device/customer fraud
Avg tool calls per case ~30
Avg latency ~5-11 seconds per case
Evidence requests Bayesian updates with simulated customer/auth responses

Case HHG-014 - The Graph Found What the Model Missed

The bank's risk score was 0.05 (extremely low risk). But TigerGraph revealed:

  • The device profile was shared by 28 customers in 30 days
  • 100% of uses were marked "New"
  • 100% were behind an anonymous proxy
  • The device appeared on 3 confirmed fraud cases
  • The agent classified it as 0.988 probability fraud - an undocumented coordinated abuse pattern

The Interface

The analyst UI is a React + TypeScript + Framer Motion application with:

  • Case queue with priority sorting
  • Bento case view: verdict, confidence, evidence list
  • Before->After action timeline showing how recommendations changed
  • Interactive subgraph visualization (react-force-graph-2d)
  • Live investigation streaming via SSE
  • Approval workflow for L1/L2 actions

What We Learned

  1. Deciding between "case only" and "case plus report" is as important as spotting the fraud - the policy engine needs to be as rigorous as the detection engine
  2. Keeping the model away from raw rows made runs cheaper and outputs easier to audit
  3. Graph traversals > ML features for discovering coordinated fraud that individual transaction models miss
  4. TigerGraph's vector search + graph traversals together enable a true GraphRAG pattern - combining structured graph reasoning with semantic similarity

Tech Stack

  • Graph Database: TigerGraph (Savanna Cloud)
  • LLM: Gemini Flash (temperature 0)
  • Backend: Python, FastAPI, SSE
  • Frontend: React, TypeScript, Vite, Tailwind, Framer Motion, react-force-graph-2d
  • Embeddings: sentence-transformers/all-MiniLM-L6-v2 (384-d)
  • Graph Algorithms: WCC, Louvain, PageRank via GSQL

Built at the TigerGraph x Hacker House Goa hackathon. Dataset: IEEE-CIS Fraud Detection (Vesta Corporation).

Top comments (0)