Read-Only AI Finance Assistant: Connecting an LLM to Bank Accounts for Insight, Not for Moving Money
An AI assistant that connects to bank accounts is useful mainly as a read-only aggregation and analysis tool, not as a tool that moves money. This article walks through a practical architecture for building one: how open banking and financial data aggregation grant read-only access without exposing bank credentials, how raw transactions are normalized into computable entities and categories, and why the assistant must generate restricted queries against predefined read-only views rather than letting a model write SQL against a production database. It also covers high-value proactive insights such as duplicate charges, recurring-bill increases, and subscription detection, along with the privacy, security, prompt injection, compliance, and evaluation practices such a system requires, and a phased roadmap for rolling it out.
1. Scenario and Goal: Let the Assistant “Read the Numbers,” Not Move Money
Bringing a large language model assistant into personal finance is, at its core, a solution to information fragmentation. An ordinary user’s money is spread across a debit card, a credit card, a repayment account, and an e-wallet. To answer questions such as “Where did my money go this month?” or “How much is left before payday?”, users have to switch between several apps and add up the totals by hand.
The foundational positioning of this kind of feature is therefore a read-only tool for information aggregation and analysis, not a tool for moving funds. This is not marketing copy; it is a hard constraint of the technical architecture. It determines the permission model, the data model, and the security boundaries of the entire pipeline. Any design that mixes “read” and “write” in the same set of credentials and interfaces will be rejected outright during compliance review and security assessment.
2. Architecture Overview
A complete pipeline can be broken down into five layers:
- Connection layer: Account authorization is completed through the industry-standard open banking / financial data aggregation channels. The assistant never touches the user’s bank password.
- Acquisition layer: Balances, credit limits, and transaction records are pulled incrementally, deduplicated idempotently, and stored in normalized form.
- Semantic layer: Raw transactions are mapped to stable entities, categories, and metric definitions. This layer is the foundation of answer quality.
- Q&A layer: Natural language is converted into restricted queries (controlled views + allowlists + read-only credentials), with verifiable computation steps returned to the user.
- Security and governance layer: Data isolation, key management, auditing, masking, prompt injection protection, and policies that prohibit using the data for training cut across all of the layers above.
3. Connection Layer: The Authorization Flow and the Credential Lifecycle
A typical authorization flow works like this:
- The user initiates “Connect account” from the assistant. The server creates a one-time session ticket.
- The user is redirected to the data aggregator’s page and completes bank login and identity verification there, never in the assistant.
- The aggregator returns an access token with read-only scopes (it does not contain bank login credentials).
- The assistant’s backend exchanges the token for the account list and transactions. The token is stored encrypted in a key management service and never written to disk in plaintext.
A few engineering details that must be handled:
- Token expiration and renewal: Tokens from most aggregation APIs have a limited lifetime and need to be refreshed silently in the background. If a refresh fails, the assistant should degrade to a “data is stale” notice rather than showing the user a stack trace.
- Incremental sync: Fetch records using the cursor or timestamp of the last transaction as a watermark. When writing records, use “account + provider transaction ID” as the idempotency key so duplicate imports cannot inflate the totals.
- Degradation strategy: When the aggregator rate-limits or times out, return the “last successful sync time” and clearly label how fresh the data is.
POST /v1/finance/connections{ "scopes": ["balances:read", "transactions:read"], "consent_ttl_days": 90 }# The server stores only an encrypted token reference{ "connection_id": "conn_xxx","provider_ref": "kms://finance/token/conn_xxx", # a reference, not plaintext"permissions": ["read_only"], # enforced at the architecture level"synced_at": "2026-08-26T13:10:00Z" }
4. Data Model: Turning Transactions into Computable Entities
Raw transaction feeds are poor quality. Merchant names are truncated strings, categories are missing, refunds and charge reversals are mixed in with debits, and installments and interest are bundled into a single statement line. The job of the semantic layer is to converge this noise into stable definitions.
Suggested normalized fields:
{"txn_id": "sha256(account_id + provider_txn_id)","account_id": "acc_001","account_mask": "****4821","account_type": "credit","posted_at": "2026-08-14T09:22:00Z","amount_minor": -4230000,"currency": "USD","direction": "debit","merchant_raw": "STRIPE*PAYMNT*8823","merchant_norm": "Example Merchant","category": "housing.rent","category_confidence": 0.97,"category_source": "rule | model | user_override","tags": ["recurring", "monthly"],"reversal_of": null}
Categorization follows a three-tier priority order: user corrections first, then deterministic rules (keywords, amounts, recurrence) plus the user’s historical mappings, then model-assisted classification with a confidence score. Items whose confidence falls below the threshold are shown as “Needs confirmation” in the UI so the user can correct them in one click. This improves the experience and creates a low-cost feedback loop for data labeling at the same time.
Calculation conventions must be defined in advance, or the same question will get different answers at different times:
- Accounting period: a calendar month or a rolling 30 days, and which side of a month a cross-month statement belongs to (by posting date or by transaction date).
- Whether refunds and charge reversals reduce the corresponding category.
- How credit card purchases and their repayments avoid being counted as two separate expenses.
- Whether installment fees, annual fees, and interest are listed separately rather than mixed into spending categories.
5. Q&A Layer: Why the Model Should Not Just Write SQL
Passing natural language directly to a model to generate SQL against a production database hits three problems at once: hallucinated fields and functions that cause errors, over-broad queries that reach into other users’ rows, and wrong numbers delivered with a confident tone.
A workable approach is restricted query generation: the model works only on top of predefined read-only views and the semantic layer of metrics.
-- Allowlisted view: no sensitive fields; row-level security is enforced by the connection-scoped user contextCREATE VIEW fin_v_monthly_category ASSELECT user_id, account_id, month, category,SUM(amount_minor) FILTER (WHERE direction='debit') AS spend_minor,SUM(amount_minor) FILTER (WHERE direction='credit') AS income_minorFROM fin_txn_normGROUP BY 1,2,3,4;-- Execution role: read-only + row-level filtering + statement timeout + result row capGRANT SELECT ON fin_v_monthly_category TO svc_readonly;
The accompanying constraints are:
- Semantic allowlist: The model outputs references to semantic metrics (such as
spend.by_category), not arbitrary SQL. - Read-only credentials, a statement timeout, and a cap on returned rows, enforced at the database level as a backstop.
- Convention disclosure: Every answer must state the conventions it used (time range, account scope, whether repayments are included), making “verifiable” part of the output.
- Numeric conservation check: The sum of per-category spending must equal total spending. If it does not, the assistant refuses to output the numbers and falls back to the deterministic calculation path.
High-risk intents must be intercepted at the entry classification stage. Transfers, changing a payment password, adding a new payee, and investment advice (such as “should I buy this asset?” or “should I pay off my mortgage early?”) all fall outside a read-only scope. They should be refused explicitly, with a clear statement of the boundary, rather than answered half-heartedly.
A sound implementation order is this: anything that deterministic code can compute should not be handed to the model. The model handles intent understanding, assembling conventions, and generating explanations and chart descriptions. The numbers come from a tested calculation layer.
6. Anomalies and Insights: From Summaries to Alerts
The real value comes from proactively surfacing problems. High-value rules include:
- Duplicate charges: the same merchant, the same amount, and a time gap shorter than the normal cycle. Dedup should combine amount precision with the normalized merchant name.
- Recurring bill increases: build a historical baseline for merchants identified as monthly or annual subscriptions, and alert when the month-over-month increase exceeds a threshold, so users do not stay unaware of a price hike.
- Suspected subscriptions: high-frequency, small, fixed-amount transactions from the same merchant that recur across months are aggregated into a “subscription list + annualized cost.”
- Unusual single transactions: use robust statistics on the amount distribution (median + MAD rather than mean and variance, which resists outliers better) and flag for review when a value deviates beyond the threshold.
import statisticsdef robust_outlier(values, x, z=3.5):med = statistics.median(values)mad = statistics.median([abs(v - med) for v in values]) or 1return abs(x - med) / (1.4826 * mad) > z
The key engineering principle here is low false positives first. One wrong “duplicate charge” alert significantly erodes user trust. Each alert must therefore include evidence (the transactions involved, the amounts, the timestamps, and the reasoning behind the judgment) and let the user mark it as “normal,” with that feedback flowing back into the rule weights.
7. Privacy and Security: Where This Pipeline Is Most Likely to Go Wrong
- Data minimization: Request only the fields needed for balances, credit limits, and transactions. Keep only the last four digits of each account number as a mask, and never let full account numbers enter the analytics store.
- Data isolation and no training use: Conversations involving financial data should be kept in a separate data domain and explicitly excluded from model training. Enforce this in the pipeline configuration (data tagging plus a training-data admission check), not just in documentation.
- Encryption and key management: Encrypt data in transit and at rest. Hold tokens and credentials in a key management service with permissions bound at the connection level.
- Auditing and traceability: Record who queried which accounts, when, which queries were run, and how many rows were returned. The audit logs themselves must be masked.
- Prompt injection protection: Transaction notes and merchant names are untrusted, user-supplied text. They must be rendered as data, not interpreted as instructions. At the output layer, such text must never be able to trigger a write operation or an outbound request.
- Data retention and deletion: Set a retention period. When an account is unlinked, delete the normalized data and caches at the same time, and provide export and one-click delete options.
- Observability: Centralize logs, and cover sync failure rate, token failure rate, query error rate, and numeric validation mismatch rate with monitoring and alerting.
General-purpose cloud services are usually enough to support these capabilities: a container platform for compute jobs, a message queue to smooth out spikes and retries for sync jobs, object storage for archiving cold data, a key management service for credentials, and logging plus monitoring for observability.
8. Compliance and Risk Control
For consumer-facing financial data features, product copy is not enough; you also need compliance controls built into the engineering:
- Not investment advice: Keep all outputs to “describing the past and the current state.” Never recommend buying or selling.
- Data source disclaimer: Clearly state that model output may contain errors, that authoritative amounts come from the bank’s records, and provide a link in the UI to verify the figures.
- Business model separation: Do not insert ads, do not offer paid ranking, and do not sell credit or savings products. This is both a differentiator and a requirement that code must forbid commercial fields from entering the answer context.
- Capability evaluation: Build a golden Q&A set covering convention boundaries, refunds and reversals, cross-month statements, credit card repayments, and anomaly detection. Run a regression on every prompt or semantic layer change, focusing on numeric consistency rate and correct refusal rate.
9. Roadmap Recommendations
In phase one, build only “summary + categorization + explanation,” and stabilize the normalization pipeline and convention definitions. In phase two, add anomaly detection and subscription insights to create proactive value. In phase three, add budget planning and scenario simulation. The reverse order, chasing complex reasoning first and fixing data quality later, almost inevitably leads to rework on inconsistent conventions and wrong numbers. On this pipeline, investment in data quality and security boundaries has a far better return than fine-tuning the choice of model.
