最新资讯
dev.to 如何在专用 GPU 服务器上用 OpenAI 兼容 API 部署 LLM dev.to 审计 153 份 Claude Code 与 Codex 会话记录:User-Agent 与 URL 中的邮箱泄露 dev.to 你的 Agent Harness 应具备的 17 项能力 dev.to 离线 AI 记忆中 0.8 余弦阈值为何失效 dev.to Kimi K3.1 Pro 开放权重:自托管 2.8T 模型前的开发者清单 dev.to 如何通过工具调用引导模型以提升 Harness 质量 dev.to AI Agent 审计轨迹不等于对话记录 dev.to 精简 MCP server 工具数量:更少工具、更小影响面,双重收益 dev.to 为什么 git checkout 无法撤销 AI 编码 agent 的改动? wechat AI短剧门槛降降降!实测即梦短剧工作室:剧本分镜预演一条龙,伙伴计划长期护航 dev.to 让模型改写文档前,先量化事实保真度 dev.to 回放 153 个 Claude Code 与 Codex 会话,审计 Agent 的生产影响范围
多元动态
登录 注册
智能体 dev.to · @jitin raju

图收集、规则决策、模型解释:在 TigerGraph 上构建 Agent 化欺诈调查器

原文 我的收藏

Tidewatch 是 TigerGraph × Hacker House Goa 2026 欺诈调查挑战赛的参赛方案。任务提供 590,742 笔卡交易、含十条规则的欺诈策略、5,565 个已结案调查和 20 个待处理告警,要求 Agent 调查每个告警、决定下一步、判断何时需要更多证据并给出可解释结论。文章介绍其以 TigerGraph 为核心的设计与运行数据,并提到工具曾两次发现自身判断错误。

AI推荐理由 Tidewatch 项目文章给出较具体的任务背景(590,742 笔卡交易、10 条欺诈策略、5,565 个已结案调查、20 个待处理告警)和“图收集、规则决策、模型解释”的分工设计,并提到工具两次发现自身错误,信息密度高于同批同类文章;但仍是黑客松项目自述,缺少独立验证与完整评测数据。

64

正文

Tidewatch: our build for the TigerGraph × Hacker House Goa 2026 Agentic Fraud Investigation challenge. A fraud alert is a question with an expensive wrong answer in both directions. If you block a real customer's card, you've failed them. If you wave through a stolen card, you've failed the bank. The challenge handed us 590,742 card transactions, a fraud policy with ten rules, 5,565 closed investigations and 20 open alerts. It asked for an agent that investigates each alert, decides what to do next, knows when to ask for more evidence, and explains itself well enough for an analyst, and eventually a regulator, to act on it. This post covers what we built, how TigerGraph sits at the centre of it, and the numbers. It also covers the two times our own tools caught us being wrong. 1. What we built Tidewatch works a fraud alert the way a careful analyst would: Investigate. It pulls the evidence out of a transaction graph on TigerGraph Savanna: the flagged transaction, the card's own history, the device it ran on, whether that device is shared with other customers' cards, card-testing bursts, recurring charges, and the customer's past cases along with the closest prior cases across the whole book. Assess. It scores that evidence with a transparent log-odds rubric, so every point of probability can be traced to a named signal. Decide whether to ask. It prices every question it could put to the customer or an analyst by how far the answer could move the recommended action, minus the cost of asking. It asks only when that net value is positive. Act within policy. It recommends actions from the policy's vocabulary. Each action carries the approval route the policy assigns it: auto, L1 or L2. Remember. It writes the finished case back into the graph as a FraudCase vertex, then reads it back before the answer file is allowed to say it was written. On top of that sit an analyst console and a Claude copilot. The console replays every investigation step by step, shows the case's neighbourhood in the graph, and runs an autonomous monitor over the book. The copilot explains and challenges the decision, but never makes it. The design choice everything else follows from: no language model sits in the decision loop. Every verdict, probability, action and route comes from graph queries, the rubric and the policy engine. Every answer file can be reproduced to the byte and audited line by line. The model does the thing a deterministic engine can't: it talks to the human. 2. Architecture The investigation runs in seven stages: open, investigate, assess, gather more evidence, take action, explain, update memory. Each stage is metered: graph queries, model calls, tokens, dollars, wall time. Each step also goes into a millisecond-stamped trace, which the console replays. There are two interchangeable graph backends behind one interface: TigerGraph (GSQL over REST++) and a parquet backend for offline runs and backtests. A contract test suite runs the same queries against both and fails if they disagree. It caught six divergences during the build, and one would have crashed at runtime: the two backends returned card-testing episodes in different shapes. 3. How we used TigerGraph The schema We modelled the domain the way the investigation traverses it. The vertex types are Customer, PaymentCard, Transaction, DeviceProfile, BillingRegion, EmailDomain, ClosedCase, FraudCase and PolicyChunk. The edges follow the questions an investigator asks: OWNS and USED_IN: whose card, and which transactions. NEXT_TXN: the card's timeline, as a linked list, so burst and velocity questions are walks rather than sorts. ON_DEVICE: which device profile ran the transaction, carrying device_state and proxy_kind as edge attributes. SHARES_DEVICE: card-to-card links through a common device, the backbone of ring detection. ABOUT, CASE_CARD, TRIGGERED_BY, SIMILAR_TO: our own cases, attached to the entities they're about so the next investigation can find them. The dataset has no card identifier, so we first reconstructed cards from the six card fields per customer, giving 14,893 cards across 13,553 customers. Loading the full book All 590,742 transactions went in, along with 575,849 NEXT_TXN edges, 144,432 ON_DEVICE edges and 128,852 SHARES_DEVICE edges. Every count matched the source exactly. The first attempt, a single 14 MB POST, hit a 504 gateway timeout, so the loader now sends 50,000-row chunks. The full load takes about eleven minutes. Queries in the loop Each investigation makes 10 or 11 graph calls: up to nine reads (card-present transactions skip the device lookup), then a write and a read-back. Question the agent asks GSQL query What exactly happened? get_transaction, get_customer Is this normal for this card? card_baseline (percentile of the amount in the card's own history, new region, new product, 1h/24h velocity) What device, and is it new or proxied? device_for_transaction Is the device shared with other customers' cards inside the window? shares_device_edges Was the card tested first (R5)? card_testing_window Is this a subscription the cardholder forgot (R7)? same_amount_priors Has this customer been investigated before? prior_cases_for_customer What did similar past cases conclude? similar_closed_cases Did our write land? read_case The ranking of similar cases deliberately runs outside the query. The channel, pattern and exposure filters are relaxable: a loosely filtered set of five is better evidence than a perfectly filtered set of one. When the query applied them itself, the graph backend returned zero similar cases where the parquet backend returned three. The one filter that is never relaxed, the as-of cut, stays in GSQL, because a case closed after the one being replayed would hand the agent its own answer. Case memory Every finished case becomes a FraudCase vertex with edges to its customer, card, triggering transactions and the prior cases it drew on. written_to_graph in an answer file is never a constant. It's set only after read_case finds the vertex. All 20 graded cases are in the graph. Making it fast on Savanna The first TigerGraph run took about 12 seconds per case. Three changes brought it to about 3 seconds, with identical answers: Concurrent waves. Seven of the nine reads depend only on the alert, so they go out together. The other two need the channel and amount from the first wave. One write, not eight. The case vertex and all its edges now go in a single upsertData call: 1.6 s → 0.23 s. An immutable pool fetched once. The closed-case history never changes, so it's read once per process and cut by date locally: 1.4–1.9 s per case → 9 ms. On the in-memory parquet backend, the same investigation takes a median of 40 ms. 4. How the agent reasons The rubric. Probability starts from a prior of 0.30 and moves in log-odds, one named contribution per signal. Signals are grouped into families: amount behaviour, geography, device, shared origin, customer response, and so on. One family on its own can't push a case out of the 0.15–0.85 band, however strong it looks. The bank's own risk score is deliberately capped just below the materiality floor, so it's a reason to look but never an independent signal. The policy says the same thing: "a score is a reason to look, never a verdict". Asking for evidence. Before asking anything, the agent prices every option: step-up authentication (friction 0.05), a call to validate with the customer (0.12), or a request to an analyst (0.20). For each one it simulates the likely answers, re-runs the rubric and the policy on each, and measures how far the recommended action would move. It asks only when expected movement minus friction clears 0.05. Four of the twenty cases asked a question, and in all four the recommendation changed. The dataset contains no real customer replies, so every response is simulated and labelled SIMULATED wherever it appears. The policy engine. Rules R1–R10 are encoded as functions that each cite their own rule. §3a, "a case is not a report", is enforced as a gate. A regulatory filing needs a fraud verdict and an aggravating condition: exposure over $1,000, a rare shared device, or an undocumented pattern. Across 5,565 closed cases, only 7.1% ended in a report. 5. Where Claude fits The copilot is claude-opus-5 at low effort, called through the Anthropic Python SDK. It reads the answer file, the diagnostics (every rubric contribution, every priced question, the decision log) and the Fraud Policy. It cites evidence as E3 and rules as R6. It may disagree out loud, but changing the decision is a human's job through the approval route. The policy and the case form a cached prefix, so a follow-up question costs about $0.02. It earned its place. Asked to "challenge the decision" on HHG-010, it pointed out that the shared-device evidence came from a different device than the flagged transaction ran on. It also noticed that the draft suspicious-activity report named the wrong device as the one the transaction "ran on". It was right. The ring query looks at every device the card used in the window, and the report builder was picking the first profile from an alphabetically sorted list. We fixed it, and the evidence text now says when the linked device isn't the transaction's own. That's the division of labour we wanted: deterministic decisions, with a model that reads them critically. 6. Results Verdicts across the 20 cases 6 fraud · 9 uncertain · 5 legitimate Regulatory reports 3 of 20 (HHG-010 over $1,000; HHG-011 and HHG-019 on a rare device shared across customers) Asked for evidence 4 cases; the recommendation changed in all 4 Actions needing a human 10 cases have an L1/L2 action awaiting sign-off Model spend on decisions $0.00 (0 model calls) Graph queries 215 across the pack; 85% of evidence items come straight from the graph Median investigation 40 ms (parquet) · ~3 s (Savanna) Validation 20/20 pass the answer-file invariants; 276 tests pass The autonomous monitor watches the 4,462 highest-risk authorisations in the book, those the bank's model scores at 0.85 or above, excluding the 20 graded ones. It investigates each end to end, lets actions routed auto run (simulated, as the brief permits), and queues everything else for a person. On a 300-alert sample it takes a median of 53 ms per alert and files reports on 12% of them. That's more than the closed-case rate of 7.1%, which fits: these are the riskiest 2% of transactions. The calibration story The monitor did more than demo well: it found a bug. Early on, it labelled 90 of 300 unseen alerts as an undocumented typology. The closed-case history has nine such cases in 5,565. We had loosened ring detection to catch a 52-card device profile named in one of the 20 cases, and that loosened link was quietly qualifying for "new typology", which carries a mandatory report. The fix was to require a rare device link. On the same alerts, undocumented dropped from 90 to 10 and reports from 33% to 12%. The same review caught two more issues, both visible only when you read the answers against the data: An online purchase labelled out_of_region_use. All 955 closed cases with that pattern are in person. A report filed on a case the rubric itself held uncertain. "Strongly suspected" now means the engine reached fraud. None of this would have surfaced if we'd only looked at the 20 graded cases. 7. Honest limits Simulated customer responses. The dataset has none, so the agent assumes the most likely answer and says so every time. A GSQL ring gap. The ring query on TigerGraph undercounts device profiles that were also active outside the investigation window, because a precomputed edge attribute spans each card pair's whole history. The graded answers use the parquet computation. The gap is tracked as a strict expected-failure test, so a fix can't go unnoticed. Vector search isn't live yet. The TigerVector upgrade, semantic policy search and hybrid similar-case retrieval, is written in vector_upgrade.gsql but wasn't deployed for the graded run. Nothing real is actioned. Blocks and reports are recorded, never executed. What is real is which actions the policy allowed to run without a human. 8. What's next A window-scoped ring traversal over ON_DEVICE, so the graph backend matches parquet exactly. TigerVector for policy retrieval and hybrid case similarity. Replaying the 5,565 closed cases as a backtest, with a calibration curve. Letting the analyst's approvals flow back into the graph as labelled outcomes.

来源报道 · 1 篇 · 以下链接均前往原始媒体

← 返回精选动态 原文

更多内容