Part 1: Chunking Strategy for Financial Data
In enterprise financial systems, naive "fixed-size" chunking (e.g., splitting every 500 tokens) is catastrophic. It severs table headers from their data, breaks legal clauses in half, and destroys the chronological flow of transaction narratives.
To solve this, we use a Dual-Track Chunking Strategy tailored to the distinct natures of Financial Documents and Transaction Narratives.
1. Financial Documents (10-Ks, Contracts, KYC Policies)
Strategy: Hierarchical / Structure-Aware Chunking (Parent-Child)
How it works: We parse documents into Markdown or HTML, preserving the DOM/Header hierarchy (e.g.,
H1 > H2 > H3). We chunk at the lowest logical level (paragraphs or clauses) but retain a "Parent" chunk (the entire section) in the vector database.Why: Financial documents rely heavily on context. If a vector search retrieves a specific clause about "wire transfer limits," the LLM needs the surrounding section (the Parent) to understand the exceptions and definitions. This prevents hallucinations and ensures legal/compliance accuracy. We also use specialized table-extraction chunking to keep tabular data intact.
2. Transaction Narratives (SWIFT messages, Ledger notes, AML alerts)
Strategy: Event-Driven / Metadata-Enriched Chunking
How it works: Transaction narratives are usually short, dense, and entity-heavy (e.g., "Wire transfer to offshore entity for consulting services"). Instead of chunking the text, we chunk by Transaction Event. The "chunk" is the narrative text, but it is heavily augmented with structured metadata:
sender_id,receiver_id,amount,currency,timestamp, andpurpose_code.Why: Transaction narratives require Hybrid Search (Vector similarity + strict Metadata filtering). If an investigator asks, "Show me transactions over $10,000 to the Cayman Islands," a pure vector search will fail. By chunking by event and attaching metadata, the retrieval system can execute a SQL/NoSQL filter first, and then use semantic search only on the filtered narrative text to understand the context.
Part 2: Real-Time Use Case & Architecture
The Use Case: Automated AML (Anti-Money Laundering) Investigation
Scenario: A high-value wire transfer triggers an AML alert. The system must investigate the client's KYC documents (to check their stated business purpose) and their transaction history (to check for structuring or suspicious narratives). Finally, it must draft a Suspicious Activity Report (SAR) recommendation.
The Multi-Agent Architecture (LangGraph)
We use a Supervisor Multi-Agent Architecture with shared state and persistent memory.
Supervisor Agent: Routes the investigation. Decides if more document research or transaction research is needed.
Document Researcher Agent: Uses the Hierarchical Retriever to find KYC/Policy context.
Transaction Investigator Agent: Uses the Metadata-Filtered Retriever to analyze transaction narratives.
Compliance Writer Agent: Synthesizes the findings into a formal SAR draft.
State & Memory:
State: A centralized
InvestigationStatetracks the alert details, retrieved context, agent thoughts, and the final report.Memory: We use LangGraph's
Checkpointer(backed by Postgres/Redis in production) for short-term thread memory, and Vector/SQL databases for long-term enterprise knowledge.

Part 3: Code Implementation
Below is the end-to-end Python implementation using langgraph, langchain, and pydantic.
Prerequisites
pip install langgraph langchain langchain-openai pydantic faiss-cpu1. Define the State and Memory
from typing import List, Dict, Any, Literal, Annotated
from pydantic import BaseModel, Field
from langgraph.graph import StateGraph, END
from langgraph.checkpoint.memory import MemorySaver
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage
# Define the shared state for the multi-agent graph
class InvestigationState(BaseModel):
alert_id: str
client_id: str
transaction_details: Dict[str, Any]
messages: List[Dict[str, str]] = Field(default_factory=list)
doc_context: List[str] = Field(default_factory=list)
txn_context: List[str] = Field(default_factory=list)
supervisor_decision: Literal["research_docs", "research_txns", "write_report", "FINISH"] = "research_docs"
final_report: str = ""
class Config:
arbitrary_types_allowed = True2. Mock Enterprise Retrievers (Reflecting our Chunking Strategy)
class FinancialDocRetriever:
"""Simulates Hierarchical/Parent-Child Retrieval for KYC/Policy Docs"""
def search(self, query: str, client_id: str) -> List[str]:
# In reality, this queries a Vector DB (like FAISS/Pinecone)
# and fetches the Parent chunk for context.
return [
f"[KYC Policy] Client {client_id} is registered as an Import/Export business. Allowed transaction limit: $50,000/month.",
f"[Contract Clause] Wire transfers to non-treaty countries require secondary approval from the Compliance Officer."
]
class TransactionNarrativeRetriever:
"""Simulates Metadata-Filtered Retrieval for Transaction Narratives"""
def search(self, query: str, filters: Dict[str, Any]) -> List[str]:
# In reality, this applies SQL/NoSQL filters (amount > X, date = Y)
# and then runs semantic search on the narrative text.
return [
f"[TXN-992] $45,000 to 'Offshore Consulting Ltd'. Narrative: 'Payment for Q3 advisory services'. (Note: Client usually transacts < $5,000).",
f"[TXN-993] $4,900 to 'Offshore Consulting Ltd'. Narrative: 'Consulting fees'. (Potential structuring detected)."
]
doc_retriever = FinancialDocRetriever()
txn_retriever = TransactionNarrativeRetriever()
Join the conversation! Your thoughts help the community grow.