{"slug": "the-agent-that-knows-when-to-stop-agentic-fraud-investigation-on-tigergraph", "title": "The Agent That Knows When to Stop: Agentic Fraud Investigation on TigerGraph", "summary": "A developer built SentinelGraph, an AI agent that runs end-to-end fraud alert investigations on TigerGraph, combining graph queries, a deterministic evidence layer, a policy engine, and an LLM that only probes open questions and writes narratives. Tested on 20 benchmark alerts (10 legitimate, 9 fraud, 1 uncertain, 6 SARs), the agent reproduced identical decisions on every re-run and reached a 0.914 memory-model AUC versus the bank's 0.866 score, surfacing a 28-card fraud ring.", "body_md": "*Task #4 · TigerGraph problem statement · Hacker House Goa 2026*\n\nA risk score pings. Is it fraud, a holiday, or a new phone?\n\nWe built **SentinelGraph**, an AI agent that works the alert like a sharp analyst: it digs through the graph, admits what it doesn't know, asks for the one piece of evidence that would settle it, and recommends the next move with the right person signing off.\n\n**590,742** transactions in the graph · **5,565** closed cases as memory · **16** GSQL queries via MCP · **0.914** memory-model AUC (bank score: 0.866) · **28** cards in the biggest ring we found\n\n🔗 **Code:** [https://github.com/nirmaljosephukken/HH_GOA_Task_4](https://github.com/nirmaljosephukken/HH_GOA_Task_4) \n\nFraud teams are never short of alerts. They're short of time to turn each one into a call they can defend. For every ping an analyst pulls the card history, checks the device, hunts for other victims, rereads the policy, decides whether to phone the customer, and writes it all up. Usually after the money has moved.\n\nSentinelGraph runs that loop end to end:\n\nWe ran it on the 20 benchmark alerts: **10 legitimate, 9 fraud, 1 uncertain, 6 SARs**. Re-running all 20 gives the same decisions every time.\n\nThe dataset is the IEEE-CIS card data with the fraud label taken away. In its place: a bank risk score, 5,565 closed investigations (July to October), a fraud policy, five documented patterns, and 20 alerts from November and December. Three findings shaped everything:\n\n`Client` vertex: a latent cardholder built from card + billing region + account-open day. In closed cases, 85% of a fraud client's transactions are fraud.`card6` values reproduces every card ID in the closed cases and the case pack.\nEvery layer has one job. Graph queries find facts. A deterministic evidence layer weighs them. A policy engine picks the actions. The LLM probes open questions and writes the story, and it never sets a probability or an action.\n\n```\nTrigger (score / customer / analyst)\n   │\n   ▼\nCase orchestrator ── state machine + audit trail ──────────────┐\n   │  MCP: tigergraph__run_installed_query   GraphRAG: vectorSearch\n   ▼                                                            │\nTigerGraph Savanna (FraudGraph)                                 │\n   │                                                            │\n   ▼                                                            │\nEvidence layer ── detectors → likelihood ratios by family       │\n   ▼                                                            │\nUncertainty engine ── log-odds fusion, confidence, open questions\n   ▼                                                            │\nPolicy engine ── R1–R10, case vs report, stop rule, routes, guardrails\n   │                       │                                    │\n   ▼                       ▼                                    │\nask for evidence     next best action (auto runs, L1/L2 wait)   │\n(verify / step-up)         │                                    │\n   └──► re-assess          ▼                                    │\n                     FraudCase + CaseEvents written back ◄──────┘\n\nLLM (Gemini): bounded extra tool calls + narrative/SAR writer, output validated\n```\n\nOne alert, six moves:\n\n**One graph, three layers:**\n\n`Customer–Card–Client–Txn`, with `Txn` linked to `DeviceProfile`, `EmailDomain` (purchaser and recipient) and `BillingRegion`, plus a `NEXT_TXN` chain per card.`ClosedCase` vertices linked to their transactions, cards, connected cards and pattern. Every `FraudCase` the agent opens is stored too, with edges to the transactions, cards, devices and closed cases it used, and a `CaseEvent` chain as its audit trail.`PolicyChunk` vertices, one per policy rule, plus fraud typologies, a FinCEN/FATF/FFIEC digest and lessons mined from closed cases.\n`ClosedCase`, `FraudCase` and `PolicyChunk` carry TigerGraph's **native 256-dimension vector attribute**, so memory lookups are a `vectorSearch()` inside an installed query, right next to the graph hops.\n\n**Sixteen installed GSQL queries**, each exposed to the agent as a tool. Highlights:\n\n`peer_txns`: two hops, flagged transaction → its device or email → purchases on `card_profile`: a behavioural baseline in one pass with `MapAccum` s over products, regions, devices and emails.`ring_components`: `tg_wcc`) over the client↔device co-usage graph. It isolates the 28-card ring as one component.`device_ring_scan` and `amount_band_scan`: sweep the whole exam period, so the agent raises alerts nobody reported (`monitor.py`).` prior_cases` and `device_cases`: memory by adjacency. Which closed cases touched this device?\n**TigerGraph MCP.** The agent launches the official [`tigergraph-mcp`](https://github.com/tigergraph/tigergraph-mcp) server over stdio, discovers its tools, and calls `tigergraph__run_installed_query` for every read, vector searches included. Argument names come from the tool schema at runtime. If MCP is unavailable it falls back to RESTPP, and every call in the trace records which transport served it.\n\n**Loading.** Streamed parallel RESTPP upserts loaded 590k transactions and about 3M edges into Savanna in under two minutes.\n\n**Explicit uncertainty.** Every detector returns a claim, the query it came from, the entity IDs it rests on, a likelihood ratio and a family. The case records the prior, the posterior, each family's contribution, which families argue each way, and the open questions (\"device ownership not established\", \"evidence conflicts\").\n\n**A calibrated prior learned from case memory.** The closed cases cover about 3.4% of July to October transactions, close to the true fraud rate, so we trained a gradient-boosted model on them. Trained on July to September and tested on October: **AUC 0.914 vs 0.866 for the bank's score, with nearly double the average precision.**\n\n**Knowing when to stop.** Policy section 6, as code: stop at ≥ 0.85 or ≤ 0.15 with two independent families agreeing. Otherwise the agent picks the evidence request that best resolves the case: step-up authentication for an online score alert, customer verification for a dispute, R7 verification for a disputed charge that matches the customer's own recurring pattern. Replies aren't provided in this round, so a simulator assumes the reply the evidence supports, records the assumption and its basis, and the agent re-assesses. The next best action is recorded **before** and **after** the evidence, with what changed.\n\n**Policy as code, with permissions.** R1–R10, the case-vs-report rule, exposure-based routing, action ordering, and a guard that refuses breaches (blocking on a single weak signal, `BLOCK_ALL_CARDS` without two compromised cards, blocking a recurring dispute). Only `auto` actions execute. L1 and L2 actions wait in the console's approval queue, and every approval is written to the case's audit trail in TigerGraph.\n\n**Memory that changes the answer.**\n\n**The LLM where language is the product.** Gemini gets a bounded budget of extra tool calls to probe open questions, then writes the summary, pattern description and SAR narrative. Any text that cites an ID not present in the evidence is rejected. Its notes carry zero weight in the probability, which is why decisions are reproducible.\n\n| Case | Outcome | P(fraud) | Pattern | Exposure | Linked cards | SAR | Evidence asked | Final next best action | \n|---|---|---|---|---|---|---|---|---|\n| HHG-001 | legitimate | 0.01 | none | $0.00 | 0 | no | none | `ALLOW_TRANSACTION` →`GENERATE_REPORT` →`CLOSE_NO_FRAUD` | \n| HHG-002 | legitimate | 0.01 | none | $0.00 | 0 | no | step up auth | `ALLOW_TRANSACTION` →`CREATE_CASE` →`CLOSE_NO_FRAUD` | \n| HHG-003 | uncertain | 0.63 | out of region use | $49.00 | 0 | no | customer validation | `BLOCK_CARD` →`CREATE_CASE` →`ESCALATE_TO_ANALYST` | \n| HHG-004 | fraud | 0.73 | card not present new device | $128.33 | 0 | no | customer validation | `BLOCK_CARD` →`CREATE_CASE` | \n| HHG-005 | legitimate | 0.01 | none | $0.00 | 0 | no | step up auth | `ALLOW_TRANSACTION` →`CREATE_CASE` →`CLOSE_NO_FRAUD` | \n| HHG-006 | fraud | 0.99 | undocumented | $1,906.07 | 11 | yes | none | `BLOCK_CARD` →`CREATE_CASE` →`FILE_REPORT` →`MONITOR_CONNECTED_CARDS` →`ESCALATE_TO_ANALYST` | \n| HHG-007 | legitimate | 0.01 | none | $0.00 | 0 | no | none | `ALLOW_TRANSACTION` →`GENERATE_REPORT` →`CLOSE_NO_FRAUD` | \n| HHG-008 | fraud | 0.99 | card not present fraud | $166.97 | 1 | yes | none | `BLOCK_CARD` →`CREATE_CASE` →`FILE_REPORT` →`MONITOR_CONNECTED_CARDS` | \n| HHG-009 | fraud | 0.98 | card not present fraud | $30.02 | 0 | no | none | `BLOCK_CARD` →`CREATE_CASE` | \n| HHG-010 | legitimate | 0.01 | none | $0.00 | 0 | no | step up auth | `ALLOW_TRANSACTION` →`CREATE_CASE` →`CLOSE_NO_FRAUD` | \n| HHG-011 | fraud | 0.95 | card not present new device | $131.30 | 5 | yes | none | `BLOCK_CARD` →`CREATE_CASE` →`FILE_REPORT` →`MONITOR_CONNECTED_CARDS` | \n| HHG-012 | legitimate | 0.01 | none | $0.00 | 0 | no | none | `ALLOW_TRANSACTION` →`GENERATE_REPORT` →`CLOSE_NO_FRAUD` | \n| HHG-013 | legitimate | 0.01 | none | $0.00 | 0 | no | step up auth | `ALLOW_TRANSACTION` →`CREATE_CASE` →`CLOSE_NO_FRAUD` | \n| HHG-014 | fraud | 0.89 | undocumented | $439.61 | 27 | yes | none | `BLOCK_CARD` →`CREATE_CASE` →`FILE_REPORT` →`MONITOR_CONNECTED_CARDS` →`ESCALATE_TO_ANALYST` | \n| HHG-015 | legitimate | 0.01 | none | $0.00 | 0 | no | step up auth | `ALLOW_TRANSACTION` →`CREATE_CASE` →`CLOSE_NO_FRAUD` | \n| HHG-016 | fraud | 0.99 | card not present new device | $59.67 | 3 | yes | none | `BLOCK_CARD` →`CREATE_CASE` →`FILE_REPORT` →`MONITOR_CONNECTED_CARDS` | \n| HHG-017 | legitimate | 0.03 | none | $0.00 | 0 | no | none | `ALLOW_TRANSACTION` →`GENERATE_REPORT` →`CLOSE_NO_FRAUD` | \n| HHG-018 | legitimate | 0.02 | none | $0.00 | 0 | no | customer validation | `CREATE_CASE` →`WARN_CUSTOMER` →`CLOSE_NO_FRAUD` | \n| HHG-019 | fraud | 0.99 | card not present new device | $99.92 | 4 | yes | none | `BLOCK_CARD` →`CREATE_CASE` →`FILE_REPORT` →`MONITOR_CONNECTED_CARDS` | \n| HHG-020 | legitimate | 0.01 | none | $0.00 | 0 | no | step up auth | `ALLOW_TRANSACTION` →`CREATE_CASE` →`CLOSE_NO_FRAUD` | \n\n**Stack:** TigerGraph Savanna · GSQL · TigerGraph MCP · native vector search · Python · Gemini · Streamlit\n\nBuilt for Hacker House Goa 2026 with @TigerGraphDB. Code, the 20 answer files and full investigation traces: [https://github.com/nirmaljosephukken/HH_GOA_Task_4](https://github.com/nirmaljosephukken/HH_GOA_Task_4)", "url": "https://wpnews.pro/news/the-agent-that-knows-when-to-stop-agentic-fraud-investigation-on-tigergraph", "canonical_source": "https://dev.to/nekku/the-agent-that-knows-when-to-stop-agentic-fraud-investigation-on-tigergraph-5d18", "published_at": "2026-09-24 09:22:08+00:00", "updated_at": "2026-09-24 09:30:36.522230+00:00", "lang": "en", "topics": ["ai-agents", "artificial-intelligence", "large-language-models", "ai-tools", "mlops"], "entities": ["SentinelGraph", "TigerGraph", "TigerGraph Savanna", "Gemini", "IEEE-CIS", "Hacker House Goa", "MCP", "FinCEN"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/the-agent-that-knows-when-to-stop-agentic-fraud-investigation-on-tigergraph", "markdown": "https://wpnews.pro/news/the-agent-that-knows-when-to-stop-agentic-fraud-investigation-on-tigergraph.md", "text": "https://wpnews.pro/news/the-agent-that-knows-when-to-stop-agentic-fraud-investigation-on-tigergraph.txt", "jsonld": "https://wpnews.pro/news/the-agent-that-knows-when-to-stop-agentic-fraud-investigation-on-tigergraph.jsonld"}}