Conversational Personal Finance Analysis: Architecture and Implementation Essentials
Conversational personal finance analysis is often mistaken for "connecting an LLM to bank statements." In practice, the product succeeds or fails on four things: compliant read-only account linking, consistent metric definitions, deterministic numeric computation, and a strict separation between what the model may say and what is actually calculated. This article breaks the architecture down layer by layer — account access and token governance, transaction normalization, rule-first categorization with model fallback, deterministic anomaly rules, constrained tool calling for orchestration, spec-driven charts, async processing and pre-aggregation, security and privacy guardrails, and a golden-set evaluation plan with phased rollout. It is written for engineers and product teams who need a working design rather than a demo, with the core principle kept explicit throughout: the model interprets intent, orchestrates queries, and phrases results, while every number comes from a testable, auditable computation path.
$$For a while now, “managing personal finances through conversation” has been a product shape that keeps coming up: users authorize access to their bank and credit card accounts, and instead of exporting statements by hand, categorizing each transaction, and pivoting in a spreadsheet, they simply ask — “Where did my money go this month?”, “Were there any duplicate charges?”, “Have any of my subscriptions gone up in price?” — and the system returns a readable conclusion that they can keep drilling into with follow-up questions.
The technical core of a product like this is not “plug an LLM into a statement file.” It is closer to a trustworthy data analysis system built for unstructured questions: the entry point is a conversation, but what decides whether the product works is the compliance of data access, the consistency of metric definitions, the determinism of numeric computation, and a strict separation between what the model expresses and what is factually computed. The rest of this article takes that architecture apart, layer by layer.
1. What the requirement really is: from expense tracker to financial Q&A system
The core paradigm of a traditional expense tracker is entry-driven plus UI-driven: the user enters or syncs transactions, the system offers fixed reports, and the user does the interpreting. The unit of interaction is the form and the chart.
A conversational approach changes three things:
- The entry point moves from forms to natural language. The same underlying dataset has to support a long tail of questions. Queries like “total interest paid this year” or “find fixed expenses whose amount rose three months in a row” are essentially impossible to design for in advance inside fixed reports.
- Analysis logic moves from preset reports to on-demand composition. Querying, aggregation, comparison, and attribution are orchestrated by the system in real time.
- The output moves from charts to “conclusion plus evidence.” Users expect a judgment (“you may have been charged twice”), not just numbers.
One architectural principle has to be established early: the LLM handles intent understanding, query orchestration, and result phrasing — it does not handle numeric computation. The moment amounts, balances, interest, or closing balances are “generated” by a model, you have introduced three risks at once: incorrectness, non-reproducibility, and non-auditability. Every number must come from a deterministic computation path; the model only restates and explains it.
2. Overall architecture, layer by layer
A system that can actually ship usually splits into seven layers:
Access layer Read-only authorization, account linking, credential custody, token lifecycleData layer Transaction normalization, merchant cleaning, categorization/tagging, pre-aggregated metricsSemantic layer Metric definitions, dimension/time semantics, whitelist of queryable fieldsOrchestration Intent recognition -> tool selection -> parameter completion -> compute call -> result synthesisCompute layer Deterministic SQL / rule engine, including anomaly detection and trend attributionPresentation Natural language generation, chart spec generation, statement calendar / dashboardGovernance Least privilege, masking, audit logs, evaluation and canary rollout
3. Account access: implementing read-only authorization correctly
Almost the entire security reputation of a conversational finance product rests on this step.
The application never touches user credentials. The standard approach is to complete bank-side identity verification through a third-party financial data aggregation service: the user signs in to their bank inside that service’s interface, and after authorizing, the aggregation service returns an access token to the application. The application neither stores account passwords nor can it initiate transfers, payments, or investments — the authorized scope is limited to “read” at the protocol level.
Least privilege should be enforced down to scope granularity:
| Authorization item | Required? | Notes |
|---|---|---|
| Account list (institution name, account name, type, last four digits) | Required | For account linking and display |
| Balance and available credit limit | Required | For closing balance and debt-ratio calculations |
| Transactions (merchant, amount, timestamp, direction) | Required | The primary dataset for analysis |
| Transfers / payments / debits | Never request | Excluded from the authorization request outright |
| Full account number, CVV, password, online banking credentials | Never collect | Not needed in any scenario |
Token governance matters just as much: access tokens are typically short-lived and need a refresh mechanism; there must be a one-click revocation entry point, after which data fetching stops immediately and already-cached data is purged; tokens and refresh credentials should be held in a key management service in encrypted form, with business processes obtaining them through short-lived credentials, so that long-lived keys never sit scattered in configuration files or code repositories.
Data-use boundaries should be stated explicitly in the product: which fields are read, how long they are retained, what they are used for, and how they are deleted. For transaction detail, keep only the window the analysis actually requires (for example, a rolling two-year cap) and retain aggregates beyond that window.
4. Data normalization: give the model clean metrics, not raw statements
Bank statements are inherently dirty: merchant names are garbled strings from payment gateways (PAYPAL *XXXX-4821), amount signs are inconsistent, time zones and currencies are mixed, and refunds show up as negative transactions. Without normalization, every downstream analysis is untrustworthy.
Normalization covers at least four things:
-- Normalized transaction model (illustrative)CREATE TABLE txn_normalized (txn_id STRING, -- Globally unique; includes source system and original txn numberaccount_id STRING,posted_at TIMESTAMP, -- Normalized to UTCamount_minor BIGINT, -- Integer amount in minor currency units; avoids floating-point errorcurrency STRING, -- ISO 4217direction STRING, -- DEBIT / CREDITraw_merchant STRING,merchant_key STRING, -- Cleaned merchant key, used for aggregation and deduplicationcategory_l1 STRING,category_l2 STRING,is_recurring BOOLEAN);
Three engineering details deserve emphasis:
- Store and compute amounts as integers in the smallest currency unit. Accumulating floats produces perceptible drift in cases that must be accurate to the cent, such as interest and fees.
merchant_keyis the shared foundation for categorization, deduplication, and subscription detection. You need a merchant normalization mapping table that converges different spellings onto the same entity.- Refunds, reversals, and cancellations must retain a link to the original transaction, otherwise “dining spend this month” will be inflated because the refund was never offset.
5. Categorization and tagging: rules first, model as fallback
Categorization quality directly determines the quality of answers to questions like “where did my money go.” A two-tier strategy is recommended:
- Rule layer: merchant whitelists, keyword matching (summary fields containing
SUBSCRIPTION,FEE,INTEREST,ATM), and amount periodicity features. Rules are explainable, regression-testable, and cost nothing at inference time. - Model layer: for transactions the rules do not cover, use text embeddings for similar-merchant retrieval, or a lightweight classifier that assigns L1/L2 categories along with a confidence score.
The key is the feedback loop: when a user says in conversation “this one isn’t dining,” that correction should be written back to a correction mapping table and hit first on the next sync, instead of being re-predicted every time. This loop is the main source of long-term accuracy.
6. Anomaly detection: encode financial common sense as deterministic rules
“Detect duplicate charges” and “spot bills that are creeping upward” are the most perceivable value points in this kind of product. Implementation is pure rules plus statistics; no model needs to participate in the judgment.
def detect_duplicate_charges(txns, window_days=7):"""Multiple successful debits with the same merchant and amount within a window"""buckets = {}for t in txns:if t.direction != "DEBIT":continuekey = (t.merchant_key, t.amount_minor, t.currency)buckets.setdefault(key, []).append(t)hits = []for key, group in buckets.items():group.sort(key=lambda x: x.posted_at)cluster = [group[0]]for cur in group[1:]:prev = cluster[-1]gap = (cur.posted_at - prev.posted_at).daysif gap <= window_days:cluster.append(cur)else:if len(cluster) > 1:hits.append(cluster)cluster = [cur]if len(cluster) > 1:hits.append(cluster)return hits
Other common rules:
- Unexpected fees: interest, late fees, foreign-currency conversion fees, out-of-network ATM fees, account maintenance fees appearing for the first time or jumping in amount.
- Subscription price increases: step-like increases in the periodic charge for the same
merchant_key, determined by differencing consecutive periods rather than guessing at a threshold. - Zombie subscriptions: fixed expenses with the same amount for N consecutive periods, but no usage signals in the most recent M periods (surface these cautiously, combined with other signals, to avoid false positives).
- Trend attribution: decompose changes in total spend into contributions, identifying which categories drove period-over-period growth.
False-positive cost must be taken seriously. One wrong “duplicate charge” accusation directly damages trust. Rules should therefore carry confidence tiers: surface high-confidence findings proactively, show low-confidence ones only when the user asks, and label them clearly as “suspected.”
7. Conversation orchestration: constrain the model’s action space with tool calling
Do not let the model freely generate queries. Package data access as a set of restricted tools that the model selects and fills in; parameters are validated server-side before execution.
[{"name": "get_accounts","description": "Returns the list of authorized, linked accounts (masked)","parameters": { "type": "object", "properties": {} }},{"name": "get_monthly_summary","description": "Aggregates income, expense, and balance per calendar month, with optional drill-down by top-level category","parameters": {"type": "object","properties": {"months": { "type": "integer", "minimum": 1, "maximum": 24 },"group_by": { "type": "string", "enum": ["none", "category_l1"] },"accounts": { "type": "array", "items": { "type": "string" } }},"required": ["months"]}},{"name": "query_transactions","description": "Searches transactions by time range, category, amount range, and merchant","parameters": {"type": "object","properties": {"from": { "type": "string", "format": "date" },"to": { "type": "string", "format": "date" },"category_l1": { "type": "string" },"limit": { "type": "integer", "minimum": 1, "maximum": 500 }},"required": ["from", "to"]}},{"name": "detect_anomalies","description": "Runs deterministic checks for duplicate charges, fee jumps, subscription price increases, and similar patterns","parameters": {"type": "object","properties": {"types": { "type": "array", "items": { "type": "string" } },"lookback_days": { "type": "integer", "minimum": 30, "maximum": 730 }}}}]
This design yields four direct benefits:
- Auditable: every answer can be traced back to specific tool calls and parameters, so errors can be located.
- Testable: tools are pure functions and can be regression-tested against a golden dataset.
- Access-controllable: the tool layer is a single authorization checkpoint. Account-level isolation is enforced there, rather than by “asking the model not to cross the line” in a prompt.
- Cacheable:
(tool, args, data_version)serves as the cache key, so high-frequency questions cost almost nothing.
The orchestration layer also needs default values and upper bounds: when no time range is specified, apply an explicit default (such as “the last three calendar months”) and state the scope in the answer; enforce a hard cap on limit to avoid pulling the entire statement in one call; and for cross-account questions, verify account ownership first.
8. Separate deterministic computation from generative phrasing
This is the most important quality gate in the whole system. Implement it as a hard constraint in the orchestration layer: any number that appears in an answer must come from a structured field returned by a tool; the model may only cite and rephrase it, and may not derive new values.
Three levels of validation are practical:
- Structural constraint: numeric placeholders in the response template are filled from computed results; the model only generates connective text.
- Consistency check: extract amounts from the model’s output and compare them against the set of computed results. On mismatch, rewrite, or fall back to a plain table.
- Refusal fallback: when data is insufficient, no account is connected, or the time range exceeds the queryable window, state the reason and the action required explicitly. Do not fill the gap with an estimate.
A separate category is concept explanation: “how is the APR calculated?” or “how much is this interest, really?” Generation can be allowed here, but with boundary constraints: explain the general concept, show the user’s own historical data, and do not give personalized investment or financing advice or forecast future returns. That is a compliance red line, and it should be enforced in two places: the system prompt and a post-generation check.
9. Presentation: charts are spec-driven, not rendered directly
What users usually want is not an image but “a chart they can keep editing.” The more robust approach is to have the model generate a chart description (spec) and let the frontend render it:
{"type": "bar","title": "Spending trend over the last 6 months","x": { "field": "month", "format": "yyyy-MM" },"y": { "field": "amount_minor", "scale": 100, "unit": "CNY" },"series": [{ "field": "category_l1", "stacked": true }],"annotations": [{ "month": "2026-03", "note": "Annual insurance premium charged in one payment" }]}
Follow-up requests like “break dining out into its own series” or “add an income comparison line” become structured edits to the spec — stable and reversible. Statement calendars and financial dashboards work the same way: they are essentially layout descriptions for several predefined metrics.
If PDF or spreadsheet export is needed, route it through an asynchronous task plus object storage: submit the task, return a task ID, write the artifact to object storage, and deliver it via a time-limited signed URL. This avoids long-request timeouts and large files sitting in application memory.
10. Engineering and operations essentials
- Asynchronization: deep analysis across 24 months can take a while. Split it into tasks decoupled through a message queue, and have the frontend poll or receive pushes for results.
- Pre-aggregation: materialize a month-by-category summary table on a schedule. Most questions hit the pre-aggregated layer directly; only detail queries drill down to the transaction table. This is the main lever for controlling cost and latency.
- Layered caching: assign different TTLs to account metadata, monthly summaries, and anomaly-detection results, and invalidate them all together once a data sync completes.
- Observability: monitor tool-call success rate and P95 latency, the numeric consistency-check failure rate, the anomaly-rule hit rate alongside the share of user feedback marked “not relevant,” and inference cost per session.
- Deployment shape: run the stateless services as containers on a container platform, with elastic scaling to handle query peaks at the start and end of each month. Send logs to a centralized logging service with transaction detail masked, and wire metrics into monitoring and alerting.
On Baidu AI Cloud, this architecture can be composed from general-purpose capabilities: a container platform to host the conversation and orchestration services, object storage for export artifacts and pre-aggregation snapshots, a message queue for asynchronous analysis tasks, logging and monitoring/alerting services for observability, and a key management service to hold tokens and encryption keys. None of these require proprietary, service-specific interfaces.
11. Security and privacy red lines
- Read-only: the authorization request contains no write scopes, and the architecture has no capability to move money.
- Least privilege: read only the fields the analysis needs, show only the last four digits of account numbers, and roll transaction detail out of storage on a fixed window.
- No plaintext at rest: TLS everywhere in transit, encryption at rest, tokens and keys held in a managed service, and no long-lived credentials in configuration or code.
- Masked logs: never write transaction detail, full account numbers, or tokens into logs and traces.
- User control: provide a transparent view of which accounts are connected and what the system has read, plus a one-click revocation entry point and a way to delete all data.
- Isolation and defense in depth: account-level isolation is implemented at both the tool layer and the data access layer, never at a single checkpoint.
- No advice: present facts and explain general concepts only; do not output personalized investment or financing recommendations.
12. Evaluation and canary rollout
Accuracy has to be quantified before experience. Build a golden test set covering balance lookups, monthly summaries, category drill-down, year-over-year and month-over-month comparisons, duplicate charges, fee jumps, subscription price increases, boundary time ranges, empty results, and unauthorized access — with the expected numeric values and expected conclusions for each case. Run the full regression before launch, and sample-recheck daily afterward.
Core metrics:
| Metric | Meaning | Target direction |
|---|---|---|
| Numeric consistency rate | Share of answers whose numbers exactly match computed results | Must be close to 100%; below target blocks release |
| Intent parsing accuracy | Share of cases where the right tool and parameters are selected | Iteratively improve prompts and tool descriptions |
| Anomaly precision | Share of flagged items that truly are anomalies | Prioritize precision; prefer missing over false alarms |
| Effective refusal rate | Share of unanswerable cases where the system says so explicitly | Refusing beats fabricating |
| P95 latency / cost per session | Balance between experience and cost | Optimize via pre-aggregation and caching |
Roll out in phases: open to a controlled user group first, limited by region and account type, collect explicit feedback (“useful / not relevant / suspected error”), then widen the scope. The frequent misjudgments from early users are the most valuable input for both the rule library and the prompts.
Closing
Conversation is only the entry point; the real difficulty lies beyond it. Compliant read-only access decides whether you can ship. Data normalization and consistent metric definitions decide whether the answers are trustworthy. Strict separation of deterministic computation from generative phrasing decides whether the product falls apart on a critical number. And the precision of the rule library decides whether users keep trusting it over time. Putting the LLM where it is actually good — understanding intent, orchestrating queries, organizing expression — while handing amounts and facts to a testable, auditable deterministic path, is the only route that takes “conversational personal finance analysis” from demo to usable.
