惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

D
DataBreaches.Net
SecWiki News
SecWiki News
博客园_首页
人人都是产品经理
人人都是产品经理
博客园 - 聂微东
P
Palo Alto Networks Blog
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
WordPress大学
WordPress大学
NISL@THU
NISL@THU
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Privacy & Cybersecurity Law Blog
Jina AI
Jina AI
AWS News Blog
AWS News Blog
Scott Helme
Scott Helme
Martin Fowler
Martin Fowler
C
Cybersecurity and Infrastructure Security Agency CISA
Forbes - Security
Forbes - Security
H
Heimdal Security Blog
小众软件
小众软件
I
Intezer
A
Arctic Wolf
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
O
OpenAI News
S
Security Affairs
阮一峰的网络日志
阮一峰的网络日志
Latest news
Latest news
G
GRAHAM CLULEY
Blog — PlanetScale
Blog — PlanetScale
J
Java Code Geeks
N
News and Events Feed by Topic
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
V2EX - 技术
V2EX - 技术
Stack Overflow Blog
Stack Overflow Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
L
LINUX DO - 最新话题
博客园 - Franky
P
Proofpoint News Feed
aimingoo的专栏
aimingoo的专栏
博客园 - 司徒正美
P
Proofpoint News Feed
S
Secure Thoughts
Google DeepMind News
Google DeepMind News
Microsoft Security Blog
Microsoft Security Blog
T
The Exploit Database - CXSecurity.com
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
F
Full Disclosure
Security Latest
Security Latest

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant Common SOC 2 Failures (Real World) Stop Vibe-Checking Your AI App: A Practical Guide to Evals How to Use SonarQube and SonarScanner Locally to Level Up Your Code Quality Your Next To-Do App Is Dead — I Replaced Mine with an OpenClaw AI Sign a Nostr event in 60 lines of Python using coincurve — no nostr-sdk, no nbxplorer, no rust toolchain ITGC Audit Explained Like You’re in Big 4 Patch Tuesday abril 2026: Microsoft parcha 163 vulnerabilidades y un zero-day en SharePoint Stop scraping everything: a better way to track competitor price changes Listing on MCPize + the Official MCP Registry while routing payments OUTSIDE the marketplace — how I kept 100% of my x402 revenue Building an AI-Powered Risk Intelligence System Using Serverless Architecture Why We Ripped Function Overloading Out of Our AI Toolchain Testing AI-Generated Code: How to Actually Know If It Works SaaS Churn Is Killing Your Business. Here Is What to Do About It (Without a Support Team) The Speed of AI Is No Longer Linear - And Self-Improving Models Are Why How to Implement RBAC for MCP Tools: A Practical Guide for Engineering Teams From Standard Quote to Persuasive Proposal: AI Automation for Arborists I built a CLI that scaffolds complete multi-tenant SaaS apps Axios CVE-2025–62718: The Silent SSRF Bug That Could Be Hiding in Your Node.js App Right Now The dashboard that ended our friendship Data Pipelines Explained Simply (and How to Build Them with Python) The Hidden Cost of AI Systems Nobody Talks About. undefined vs undeclared, and how typeof behaves Switching from file-based jobs to NATS/Kafka in Rust without changing code io_uring Adventures: Rust Servers That Love Syscalls Why Agentic AI is Killing the Traditional Database The POUR principles of web accessibility for developers and designers Quantum Neural Network 3D — A Deep Dive into Interactive WebGL Visualization How To Install Caveman In Codex On macOS And Windows Automation Pipeline Reliability: Why Your Workflow Breaks When Nobody Is Watching I Built an 'Open World' AI Coding Agent — It Works From ANY Folder From Freelancing to Product: A Tech Service Company's SaaS Transformation China's AI Giants: Adding Tencent Hunyuan & ByteDance Doubao to AI University (74 Providers) On the Vibe Coders and Their Lies clerk: Auto-Summarize Your Claude Code Sessions AI Weekly — 2026/04/10–04/17 | The Model Lockdown Is Here, but the Toolchain Is the Real Battleground AI 週報 — 2026/04/10–2026/04/17 模型封鎖潮來了,但工具鏈才是真戰場 Maybe this is how Open-Source apps are born... 🚀 Fine-Tune LLMs with LoRA and QLoRA: 2026 Guide tRPC v11 + Next.js App Router: End-to-End Type Safety Without the Boilerplate ShadCN UI in 2026: Why I Stopped Installing Component Libraries and Started Owning My Components SaaS Billing in React Server Components: Stripe + Supabase Without a Single `useEffect` Join our DEV Weekend Challenge — $1,000 in Prizes Across TEN winners! Submissions Due April 20 at 6:59 AM UTC. Implementing FSRS Spaced Repetition in Flutter + Supabase — Adding Memory Science to an AI Learning App "I Texted My Localhost From the Train — Claude Code Fixed the Bug Before I Got Home" I Built a Sales Prep AI and It Went Deeper Than Expected Design to Code #2: One JSON, Eleven Outputs Solving the 100M-Row Problem: A Summary Table Pattern for High-Volume Push Notification Logs Flutter Web With Wasm: What Actually Changes For Developers I Built 50 Royalty-Free Soundtracks for My Side Project in a Weekend Using AI Music Generation The Vibe Coding Security Checklist: 7 Things to Check Before You Ship Stop Letting Googlebot Guess Fix Your React App's SEO Right Desconstruindo o Streaming do LinkedIn: Como Criar um Engine de Extração de Vídeo de Alta Performance com HLS e FFmpeg (EDA Part-1) EDA (Exploratory Data Analysis) Explained With Real Life — Why Looking at Your Data Is the Most Important Step in Machine Learning Brand Relationship Management at Scale: Our 4-Touch Outreach System for 200+ Brands Why String.fromEnvironment() Might Return an Empty String in Dart JGuardrails 1.0.0 — Hardening Java LLM Apps Against Jailbreaks, Toxicity, and Prompt Injection Plan and Schedule a Full Week of Threads Content From One Claude Conversation Coding Cat Oran Ep3, Five Tables Changed Everything Updated: BFF Pattern I'm done watching freelancers get buried by 200 proposals. So I'm building the alternative. This is my first post BFS Algorithm in Java Step by Step Tutorial with Examples Tracking LLM Pricing Monthly: An Open Dataset for 22 AI Models How We Measure Content ROI on a Comparison Site: Revenue Attribution Without Perfect Data Introducing Nova AI Ops: The AI-Native Operating System for SRE Teams I built a free desktop video downloader for Windows — Grabbit How Talkie OCR Helps Vision-Impaired & Dyslexic Users Read the World Around Them VRCFaceTracking安装和iPhone面捕配置教程,有bug Even CrowdStrike Can't See Your Agents The Automation Gold Rush: What n8n Workflows and Claude Are Opening Up for Developers Right Now
Building AI Agents for Compliance Monitoring in Finance: Architecture That Passes Auditors
Dextra Labs · 2026-05-28 · via DEV Community

The compliance AI that can't explain its decisions is worse than no compliance AI. Here's how to build one that can.

There's a specific failure mode that kills fintech AI projects that traditional software projects don't have.

The system works. The accuracy is good. The false positive rate is acceptable. And then your compliance officer asks: "Why did this transaction get flagged?" And the answer is "the model gave it a score of 0.87", which is not an answer a regulator will accept.

Explainability in compliance AI isn't a nice-to-have. It's a regulatory requirement. FINRA, FCA, RBI, every major financial regulator has issued guidance making clear that automated compliance decisions require documented reasoning that a human auditor can review and challenge. "The AI said so" is not documented reasoning.

This tutorial covers how to build a compliance monitoring agent architecture that produces decisions an auditor can actually work with.

The Architecture Overview

REGULATORY DATA FEEDS
(OFAC, FATF, FinCEN, local watchlists)
         ↓
[INGESTION AGENT] — normalise, deduplicate, version
         ↓
TRANSACTION STREAM (real-time)
         ↓
[SCREENING AGENT] — rule-based + Claude analysis
         ↓ 
         ├── LOW RISK → auto-clear + audit log
         ├── MEDIUM RISK → flag + evidence package → analyst queue
         └── HIGH RISK → block + SAR draft → senior review
                    ↓
         [AUDIT TRAIL AGENT] — immutable decision log
                    ↓
         [REPORTING AGENT] — SAR generation, regulatory reporting

Every stage produces a structured, human-readable decision record. This isn't a post-processing step, it's built into every agent's output schema from day one.

Agent 1: Regulatory Data Ingestion

Regulatory watchlists change constantly. OFAC updates the SDN list multiple times a week. FATF grey/black lists update quarterly. Local regulators issue updates on irregular schedules.

from anthropic import Anthropic
from datetime import datetime
import hashlib
import json

client = Anthropic()

class RegulatoryIngestionAgent:
    def __init__(self, db_connection, audit_logger):
        self.db = db_connection
        self.audit = audit_logger

    async def ingest_watchlist_update(
        self, 
        source: str,
        raw_data: bytes,
        update_metadata: dict
    ) -> dict:
        """
        Ingests watchlist updates with full provenance tracking.
        Every entry gets a source, version and effective date.
        """

        # Parse with Claude for flexible format handling
        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=4000,
            system="""Parse regulatory watchlist data into 
            structured entities. Handle variations in format
            across different regulatory sources.

            Extract for each entity:
            - canonical_name (primary identifier)
            - aliases (all alternative names)
            - entity_type (individual/organisation/vessel/aircraft)
            - identifiers (passport, tax ID, registration numbers)
            - addresses (with country codes)
            - listing_reason (sanctions program or crime category)
            - effective_date
            - source_reference (regulatory document ID)

            Return JSON array of entities.
            Flag any entries with ambiguous identity markers.""",
            messages=[{
                "role": "user",
                "content": f"Source: {source}\n\n{raw_data.decode('utf-8', errors='replace')}"
            }]
        )

        entities = json.loads(response.content[0].text)

        # Version control for watchlist entries
        for entity in entities:
            entity['_provenance'] = {
                'source': source,
                'ingest_timestamp': datetime.utcnow().isoformat(),
                'source_document_hash': hashlib.sha256(raw_data).hexdigest(),
                'regulatory_effective_date': update_metadata.get('effective_date'),
                'version_id': self.generate_version_id(entity, source)
            }

        await self.db.upsert_watchlist_entities(entities)

        self.audit.log({
            'event': 'watchlist_update_ingested',
            'source': source,
            'entities_added': len(entities),
            'timestamp': datetime.utcnow().isoformat()
        })

        return {
            'entities_processed': len(entities),
            'flagged_for_review': [e for e in entities if e.get('ambiguous')]
        }

The provenance tracking matters for audit purposes. When an auditor asks "was this entity on the watchlist at the time of this transaction?", you need to be able to answer precisely, not "yes, they're on the list now" but "this entity was added to the OFAC SDN list on [date] under [regulatory reference] and was active in our database from [timestamp]."

Agent 2: Real-Time Transaction Screening

This is the core compliance agent. It needs to be fast, blocking a payment for 30 seconds to run compliance checks is not acceptable in most contexts and it needs to produce explainable decisions.

class TransactionScreeningAgent:

    RISK_THRESHOLDS = {
        'auto_clear': 0.25,
        'analyst_review': 0.6,
        'block_and_escalate': 0.85
    }

    async def screen_transaction(
        self, 
        transaction: dict
    ) -> dict:
        """
        Screens transaction against watchlists and risk models.
        Returns decision with full reasoning chain for audit trail.
        """

        # Fast rule-based pre-screen
        rule_matches = await self.run_rule_engine(transaction)

        if rule_matches['exact_match']:
            return self.build_decision(
                transaction, 
                risk_score=0.95,
                decision='BLOCK',
                reasoning_type='exact_watchlist_match',
                evidence=rule_matches
            )

        # Claude analysis for fuzzy matching and context
        entity_context = await self.get_entity_context(
            transaction['counterparty']
        )

        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=1500,
            system="""You are a compliance analyst screening 
            financial transactions. Analyse the transaction
            against the provided entity context and risk factors.

            Provide a structured risk assessment with:
            1. Risk score (0.0-1.0)
            2. Primary risk factors (list each with evidence)
            3. Mitigating factors (if any)
            4. Decision rationale (2-3 sentences, auditor-readable)
            5. Recommended action: AUTO_CLEAR / ANALYST_REVIEW / BLOCK
            6. Confidence level: HIGH / MEDIUM / LOW

            Be specific. Cite the exact data points that 
            influenced the score. Vague rationale fails audits.

            Return as JSON with schema:
            {
                "risk_score": float,
                "risk_factors": [{"factor": str, "evidence": str, "weight": str}],
                "mitigating_factors": [str],
                "decision_rationale": str,
                "recommended_action": str,
                "confidence": str,
                "additional_checks_required": [str]
            }""",
            messages=[{
                "role": "user",
                "content": f"""Transaction details:
Amount: {transaction['amount']} {transaction['currency']}
Counterparty: {transaction['counterparty_name']}
Counterparty country: {transaction['counterparty_country']}
Transaction type: {transaction['type']}
Reference: {transaction.get('reference', 'None')}
Originating account risk tier: {transaction['account_risk_tier']}

Entity context from watchlist database:
{json.dumps(entity_context, indent=2)}

Fuzzy name match results:
{json.dumps(rule_matches['fuzzy_matches'], indent=2)}"""
            }]
        )

        analysis = json.loads(response.content[0].text)

        return self.build_decision(
            transaction,
            risk_score=analysis['risk_score'],
            decision=analysis['recommended_action'],
            reasoning_type='claude_analysis',
            evidence=analysis
        )

    def build_decision(
        self, 
        transaction: dict,
        risk_score: float,
        decision: str,
        reasoning_type: str,
        evidence: dict
    ) -> dict:
        """
        Builds the decision record that goes to audit trail.
        Every field that an auditor might ask about is explicit.
        """
        return {
            'transaction_id': transaction['id'],
            'screening_timestamp': datetime.utcnow().isoformat(),
            'decision': decision,
            'risk_score': risk_score,
            'reasoning_type': reasoning_type,
            'evidence': evidence,
            'agent_version': AGENT_VERSION,
            'watchlist_versions_consulted': self.get_active_watchlist_versions(),
            'regulatory_basis': self.get_applicable_regulations(transaction),
            'human_review_required': risk_score >= self.RISK_THRESHOLDS['analyst_review']
        }

The watchlist_versions_consulted field is one of the most important for audit purposes. When a regulator asks "was this screened against the current OFAC list?", you can provide the exact version ID of the list that was active at screening time.

Agent 3: The Audit Trail Agent

The audit trail is not a log. It's an immutable, queryable record of every compliance decision with enough context to reconstruct the reasoning from scratch.

class AuditTrailAgent:

    def __init__(self, immutable_store):
        # Immutable store — append only, no updates, no deletes
        self.store = immutable_store

    async def record_decision(self, decision_record: dict) -> str:
        """
        Records a compliance decision with full provenance.
        Returns the immutable record ID for reference.
        """

        # Generate explainability summary for human review
        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=800,
            system="""Generate a plain-language explanation of 
            this compliance decision suitable for regulator review.

            The explanation must:
            1. State the decision and its risk basis clearly
            2. Identify the specific factors that drove the decision
            3. Note any watchlist matches with regulatory references
            4. Explain what additional review was triggered, if any
            5. Be written so a non-technical compliance officer
               can understand and defend it

            Maximum 200 words. No jargon. No model internals.
            The reader is an auditor, not a data scientist.""",
            messages=[{
                "role": "user",
                "content": json.dumps(decision_record, indent=2)
            }]
        )

        human_readable_explanation = response.content[0].text

        audit_record = {
            **decision_record,
            'human_readable_explanation': human_readable_explanation,
            'record_created_at': datetime.utcnow().isoformat(),
            'record_id': self.generate_record_id(decision_record)
        }

        record_id = await self.store.append(audit_record)

        return record_id

    async def generate_examination_report(
        self,
        date_range: tuple,
        transaction_ids: list = None,
        include_auto_cleared: bool = False
    ) -> dict:
        """
        Generates examination-ready compliance report.
        Format designed for regulatory examination.
        """

        records = await self.store.query(
            date_range=date_range,
            transaction_ids=transaction_ids,
            include_auto_cleared=include_auto_cleared
        )

        response = client.messages.create(
            model="claude-sonnet-4-5",
            max_tokens=3000,
            system="""Compile a compliance examination report 
            from transaction screening records.

            Structure the report as regulators expect:
            1. Executive summary (screening volume, decision distribution)
            2. High-risk transaction summary (blocked and escalated)
            3. Watchlist match analysis (by source, match type)
            4. False positive analysis (analyst overrides)
            5. System performance metrics
            6. Notable patterns or anomalies

            Be factual. Cite specific transaction IDs for examples.
            Format for readability — this goes to regulators.""",
            messages=[{
                "role": "user",
                "content": f"Records for period {date_range}:\n{json.dumps(records, indent=2)}"
            }]
        )

        return {
            'report': response.content[0].text,
            'record_count': len(records),
            'period': date_range,
            'generated_at': datetime.utcnow().isoformat()
        }

The Explainability Requirement in Practice

The human-readable explanation generation is the piece that compliance teams consistently cite as the most valuable. Not the risk score, the explanation.

When an analyst reviews a flagged transaction, they need to understand not just that the system flagged it but why, in terms they can defend to a regulator. "Risk score: 0.73" tells them nothing they can act on. "Transaction flagged: counterparty name 'Al-Rashid Trading LLC' returns 0.87 similarity to sanctioned entity 'Al-Rasheed Trading' on OFAC SDN list (added 2024-03-15, Program: SDGT). Transaction amount ($47,000) above standard trade threshold for counterparty country. Pattern consistent with structuring indicators from FinCEN Advisory FIN-2023-A001" tells them exactly what to investigate.

The AI agents for compliance monitoring in finance article covers the full regulatory framework mapping, which specific regulations require which types of documentation, in detail.

What Auditors Actually Check

Three things that compliance AI architectures consistently fail on during examination:

Decision immutability: Auditors check that compliance records can't be modified after the fact. Your audit trail store must be append-only. If your logging goes to a database where records can be updated, you'll fail this check.

Watchlist version traceability: "We screened against the watchlist" is not sufficient. "We screened against OFAC SDN List version 20260415-1423, which was active from 2026-04-15 14:23 UTC" is sufficient.

Override documentation: When analysts override an automated decision, clearing a flagged transaction or escalating an auto-cleared one, the rationale must be documented in the compliance record. Systems that allow override without documentation create audit exposure.

Compliance Is One Layer

The architecture above handles transaction screening and AML monitoring. It's one component of a full agentic AI banking stack. For the complete architecture covering KYC automation, fraud detection, lending decisioning and portfolio risk management, the agentic AI in banking guide covers the full system design that compliance monitoring plugs into.

Compliance is just one banking use case. For the complete architecture guide covering lending, KYC, fraud detection and portfolio management, we published the complete agentic AI in banking guide. The compliance layer described here is designed to integrate cleanly with each of those use cases.

Published by Dextra Labs | AI Consulting & Enterprise Agent Development