DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Related

  • Using LLMs to Automate Data Cleaning and Transformation Pipelines
  • Stop Debugging Glue Jobs Manually: Building an Agentic Observability Layer for Data Pipelines
  • Microsoft Fabric AI Functions: A Practical Overview for Data Engineers
  • DataFlow — An Open-Source Data Preparation System Accelerating LLM Training

Trending

  • Selective Deployment in Azure Data Factory: A Practical Blueprint for Safer CI/CD
  • Implementing Asynchronous Communication Between Microservices Using Kafka and Spring Boot
  • Why DDoS Protection Is an Architectural Decision for Developers
  • High-Cardinality Threat Detection: Why MapReduce Breaks and Heuristics Win
  1. DZone
  2. Data Engineering
  3. AI/ML
  4. Building a Mortgage Agent With FRED Data, FastAPI, and LLM Tool Calling

Building a Mortgage Agent With FRED Data, FastAPI, and LLM Tool Calling

A walkthrough of an open-source intelligent FastAPI app that pairs Freddie Mac benchmarks from FRED with a first-time buyer chat assistant.

By 
Sushma Kukkadapu user avatar
Sushma Kukkadapu
·
Jul. 07, 26 · Analysis
Likes (0)
Comment
Save
Tweet
Share
39 Views

Join the DZone community and get the full member experience.

Join For Free

If you have ever tried to build a “mortgage rates today” feature, you have probably landed on the same fork in the road I did. Consumer finance sites publish attractive numbers, but those pages are editorial HTML, not APIs. Layout changes break scrapers, terms of use are unclear, and it is hard to explain what statistic you are actually showing. For a developer project meant to be forked on GitHub, that path is a dead end.

I wanted something smaller and more honest: national 30-year and 15-year fixed benchmarks from a source economists already cite, plus a separate surface where first-time buyers could ask basic questions without handing over sensitive data. The result is US Homes Mortgage Agent, an open-source FastAPI application with two clear jobs. One page shows macro rates and a chart. Another page hosts a conversational assistant that is grounded in the same data and in plain Python math.

This article explains the problem framing, the architecture, and the implementation choices that kept the project maintainable.

The Problem: Rates Pages Are Not Data Products

Headline mortgage rates on news sites are useful for humans scanning a story. They are awkward for software. The number in the article may come from a weekly survey, a lender panel, or a marketing table, and the HTML around it changes often. Automating that extraction couples your app to someone else’s front-end design.

There is a second trap that is easy to miss. The most common free national series for conventional fixed rates, Freddie Mac’s Primary Mortgage Market Survey, is published weekly through the Federal Reserve Economic Data service (FRED). Series MORTGAGE30US and MORTGAGE15US are the ones you will see referenced in macro commentary. If your UI promises “today’s rate” and refreshes every morning, users will still see the same value for several days. That is correct behavior given the underlying data, but it looks like a bug unless you show the observation date.

First-time buyers add a different problem. A chart alone does not answer “what is pre-approval?” or “what is the difference between principal and interest and a full housing payment?” A chat interface helps only if you constrain it. Letting a model invent rates or amortization is worse than no chat at all.

What the Application Does

The app splits responsibilities instead of blending them into one screen.

On the rates and chart view, the server exposes the latest national benchmarks and a history chart with ranges of 7 days, 30 days, 90 days, and one year. Data comes from FRED. A scheduled job runs every day at 9:00 in a configurable timezone (I use America/New_York by default) and stores a snapshot in SQLite. That snapshot powers the headline tiles and feeds one of the assistant’s tools.

From the first-time buyer's view, the user gets a simple chat UI. Messages stay in the browser for the session. The server does not write chat history to the database. When the user sends a message, the backend calls an LLM with a system prompt oriented toward education, not legal or tax advice, and with two callable tools: one to read the current benchmark snapshot, and one to compute fixed-rate principal and interest with standard amortization formulas.

The product is intentionally not a lender marketplace, not a credit product, and not personalized underwriting advice. It is a reference implementation for macro transparency plus responsible LLM integration.

Why FRED, and Why SQLite Only for Benchmarks

FRED gives documented time series with a free API key. For this project, that was the right trade: legal programmatic access, stable identifiers, and enough history for charts without building an ETL pipeline on day one.

The SQLite database holds one concern: daily benchmark snapshots. Each successful refresh upserts a row keyed by calendar date with 30-year and 15-year values, the FRED observation dates for each series, and a fetched_at timestamp. Chart data for longer windows is fetched from FRED on demand when the user changes the range. I accepted extra API calls on chart loads in exchange for not maintaining a large local history store.

Chat content never lands in that schema. If you are cloning the repo, your local data/ directory is git ignored along with .env, so you start fresh without accidentally publishing keys or a test database.

Architecture at a Glance

The deployment model is deliberately boring: one FastAPI process, static assets, Jinja templates, and an in-process APScheduler cron job. That keeps the project easy to run locally with uvicorn and easy to reason about for readers who want to fork it.

Logical component diagram: browser, FastAPI, SQLite, FRED API, and LLM HTTP API

At runtime, three paths matter.

Page load for rates. The browser requests HTML, then calls /api/rates/today for the cached snapshot and /api/rates/chart for series data. If FRED is slow on a 90-day or one-year range, the UI shows a loading state and disables the range control so users know the chart is working.

Scheduled refresh. At 9:00 local time, the job pulls the latest observations for both series and upserts the snapshot. Between weekly FRED releases, the values may not change. The UI still benefits from a daily pull because you pick up new observations as soon as they exist.

Assistant chat. The client posts the in-memory conversation to /api/chat. The server prepends a system prompt that includes the current benchmark context, calls the LLM with tool definitions, and loops if the model requests tool execution. When tools return JSON, the model produces the final natural-language answer.

US homes mortgage rates

US home mortgage rates

US home mortgage rates

Grounding the LLM With Tools

The pattern I cared about most was keeping numbers out of the model’s imagination.

The assistant exposes two tools. get_benchmark_rates reads the same SQLite snapshot as the dashboard tiles and returns structured JSON with rates and observation dates. estimate_monthly_pi takes the loan amount, annual rate, and term, then runs deterministic amortization in Python. Taxes, insurance, and PMI are out of scope for that calculation, and the prompt tells the model to say so.

Here is the core amortization helper. It is small on purpose: easy to test, easy to audit.

def monthly_principal_interest(loan_amount, annual_rate_percent, years):
    n = years * 12
    r = (annual_rate_percent / 100.0) / 12.0
    if r == 0:
        return round(loan_amount / n, 2)
    payment = loan_amount * (r * (1 + r) ** n) / ((1 + r) ** n - 1)
    return round(payment, 2)


The system prompt reinforces guardrails: stay educational, refuse to handle sensitive identifiers like SSNs, and point users toward HUD counselors or licensed lenders for personal decisions. That does not replace compliance review if you productize this, but it sets a baseline for an open demo.

LLM Provider Choice

The reference code uses OpenAI’s Chat Completions API with OPENAI_API_KEY and defaults the model to gpt-4o-mini. The HTTP client posts to OPENAI_BASE_URL, which defaults to https://api.openai.com/v1. In practice, any host that implements a compatible chat completions endpoint and supports tool calling can be configured the same way, including several OpenAI-compatible gateways. You should verify tool-call behavior and error formats on your chosen provider before relying on it in production.

The rates dashboard works with only FRED_API_KEY. The assistant returns a clear configuration error until an LLM key is present, which makes local development predictable.

Operations and Open Source Hygiene

For a public GitHub repository, secrets stay in .env. FRED and LLM keys are required at runtime but must not be committed. SQLite files live under data/ and are ignored by git.

If you deploy behind a reverse proxy, terminate TLS there and probe /api/health. One caveat for horizontal scaling: APScheduler runs inside each process. Multiple replicas without coordination will each run the 9:00 job. For a demo, that is harmless. For production, you would externalize scheduling or elect a single worker for the cron task.

LLM calls have cost and retention implications on the provider side. Even though this app does not store chats server-side, the provider still processes prompt content under its own policies. Plan for that if you expose the assistant publicly.

What I Would Extend Next

National weekly averages are the right free starting point, not the final word. State-level pricing, daily lender indices, and streaming chat responses are all reasonable extensions, each with its own licensing or infrastructure cost. Automated tests against mocked FRED responses and golden tests for the amortization helper would be the first engineering upgrades I would prioritize.

Closing Thoughts

The useful analysis from this build is the separation of concerns. Macro data comes from FRED with explicit observation dates. Education flows through an LLM that is allowed to explain and summarize, not to invent rates. Math runs in code the way it always should have.

If you want to explore the implementation, the project is open source. Clone it, add your own API keys, and treat it as a starting point rather than a finished financial product.

Data (computing) Fred (chatterbot) large language model

Opinions expressed by DZone contributors are their own.

Related

  • Using LLMs to Automate Data Cleaning and Transformation Pipelines
  • Stop Debugging Glue Jobs Manually: Building an Agentic Observability Layer for Data Pipelines
  • Microsoft Fabric AI Functions: A Practical Overview for Data Engineers
  • DataFlow — An Open-Source Data Preparation System Accelerating LLM Training

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

  • RSS
  • X
  • Facebook

ABOUT US

  • About DZone
  • Support and feedback
  • Community research

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 215
  • Nashville, TN 37211
  • [email protected]

Let's be friends:

  • RSS
  • X
  • Facebook