Build a Smart AI Financial Advisor Using Google ADK
Build an intelligent agent that analyzes U.S. tax scenarios (2025 IRS brackets), optimizes 401(k)/IRA contributions, and calculates mortgage acceleration strategies.
Join the DZone community and get the full member experience.
Join For FreeA comprehensive guide to building a specialized US financial planning agent using Google ADK, Python, and Gemini.
What You'll Build
You will create a Python-based AI agent that acts as a personal financial planner. Unlike generic chatbots, this agent uses deterministic tools for precise calculations while leveraging LLMs for reasoning and natural language explanation.
Tax Optimization
- Precise 2025 IRS tax bracket calculations
- Standard deduction logic ($15,750 Single)
- 401(k) and IRA tax-savings analysis
Mortgage Mastery
- Monthly payment calculation
- Lump-sum payoff modeling
- Interest savings projections
Debt Management
- High-interest debt detection
- "Avalanche method" prioritization
- Cash flow allocation strategy
Intelligent Advice
- Context-aware recommendations
- Synthesized financial plans
- Clear, explainable logic
Prerequisites
- Python 3.8+ is installed on your local machine.
- Google Cloud Platform Account with Vertex AI API enabled.
- Google ADK (Agent Development Kit) familiarity.
- Basic Financial Knowledge: Understanding of US progressive tax brackets, standard deductions, and retirement accounts (401k/IRA).
Architecture Overview
The system follows a standard Tool-Use Agent architecture:
- User Input: The user provides financial data (income, debts, mortgage details).
- Agent Core (Gemini 2.0): The LLM analyzes the request and decides which tools to call.
- Deterministic Tools:Python functions handle the math:
tax_tools.py: Handles IRS brackets and tax logic.mortgage_tools.py: Handles amortization and interest math.
- Synthesis: The Agent combines tool outputs into a coherent, personalized advice narrative.
STEP 1: Project Setup
Create a clean directory for your project and install the necessary dependencies.
# 1. Create project directory
mkdir ai_financial_advisor
cd ai_financial_advisor
# 2. Create virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# 3. Install dependencies
pip install google-adk numpy-financial google-cloud-aiplatform
Important:
Ensure you have authenticated with Google Cloud using gcloud auth application-default login before running the agent.
STEP 2: Tax Calculation Tools (tax_tools.py)
This module handles US-specific tax logic using 2025 IRS data. It calculates progressive tax liability and estimates savings from 401(k) contributions.
File: backend/tools/tax_tools.py
import logging
from typing import List, Dict
logger = logging.getLogger(__name__)
# --- 2025 US Federal Tax Brackets (Single Filer) ---
# Source: IRS Inflation Adjustments for Tax Year 2025
TAX_BRACKETS = [
{"limit": 11925, "rate": 0.10},
{"limit": 48475, "rate": 0.12},
{"limit": 103350, "rate": 0.22},
{"limit": 197300, "rate": 0.24},
{"limit": 250525, "rate": 0.32},
{"limit": 626350, "rate": 0.35},
{"limit": float('inf'), "rate": 0.37},
]
# 2025 Standard Deduction for Single Filers
STANDARD_DEDUCTION = 15750
def _calculate_federal_tax(gross_income):
"""Calculates US federal tax using progressive brackets."""
# Apply Standard Deduction
taxable_income = max(0, gross_income - STANDARD_DEDUCTION)
tax_owing = 0
previous_limit = 0
for bracket in TAX_BRACKETS:
limit = bracket["limit"]
rate = bracket["rate"]
# Determine income falling into this bracket
if taxable_income > previous_limit:
income_in_bracket = min(taxable_income, limit) - previous_limit
tax_owing += income_in_bracket * rate
previous_limit = limit
if taxable_income <= limit:
break
return tax_owing
def calculate_tax_scenario(
income: float,
contribution_401k: float = 0.0
) -> dict:
"""
Calculates estimated federal taxes before and after a Traditional 401(k) contribution.
"""
try:
if income < 0 or contribution_401k < 0:
return {"status": "error", "error_message": "Income and contribution cannot be negative."}
# Traditional 401(k) reduces current year taxable gross income
income_after_contrib = max(0, income - contribution_401k)
tax_before = _calculate_federal_tax(income)
tax_after = _calculate_federal_tax(income_after_contrib)
tax_savings = max(0, tax_before - tax_after)
logger.info(f"Tax Scenario: Income=${income:,.2f}, 401k=${contribution_401k:,.2f}, Savings=${tax_savings:,.2f}")
return {
"status": "success",
"gross_income": income,
"contribution_401k": contribution_401k,
"standard_deduction": STANDARD_DEDUCTION,
"estimated_tax_before_401k": round(tax_before, 2),
"estimated_tax_after_401k": round(tax_after, 2),
"estimated_tax_savings": round(tax_savings, 2)
}
except Exception as e:
logger.error(f"Error in calculate_tax_scenario: {e}", exc_info=True)
return {"status": "error", "error_message": str(e)}
def recommend_contribution_strategy(
income: float,
debts: List[dict],
available_funds: float = 0.0,
age: int = 30
) -> dict:
"""
Recommends a 401(k)/IRA strategy based on debt and 2025 contribution limits.
"""
try:
recommendations = []
remaining_funds = available_funds
# 2025 Contribution Limits
LIMIT_401K = 23500
LIMIT_IRA = 7000
# Catch-up contributions for age 50+
if age >= 50:
LIMIT_401K += 7500
LIMIT_IRA += 1000
# 1. High-Interest Debt Check (Avalanche Method)
high_interest_threshold = 7.0
high_interest_debts = [d for d in debts if d.get('interest_rate', 0) > high_interest_threshold]
if high_interest_debts:
high_interest_debts.sort(key=lambda x: x.get('interest_rate', 0), reverse=True)
top_debt = high_interest_debts[0]
recommendations.append(
f"CRITICAL: You have high-interest debt ({top_debt['type']} at {top_debt['interest_rate']}%). "
f"Prioritize paying this off before maximizing retirement contributions beyond an employer match."
)
# Allocate funds to debt first
debt_payment = min(remaining_funds, top_debt.get('balance', 0))
remaining_funds -= debt_payment
# 2. Retirement Contributions
if remaining_funds > 0:
rec_401k = min(remaining_funds, LIMIT_401K)
if rec_401k > 0:
recommendations.append(
f"Contribute ${rec_401k:,.2f} to your 401(k). This lowers your taxable income immediately. "
f"2025 Limit is ${LIMIT_401K:,.0f}."
)
remaining_funds -= rec_401k
if remaining_funds > 0:
rec_ira = min(remaining_funds, LIMIT_IRA)
recommendations.append(
f"With remaining funds, consider funding an IRA (Traditional or Roth) up to ${rec_ira:,.2f}. "
f"2025 Limit is ${LIMIT_IRA:,.0f}."
)
return {
"status": "success",
"recommendations": recommendations,
"limits_used": {"401k_limit": LIMIT_401K, "ira_limit": LIMIT_IRA}
}
except Exception as e:
logger.error(f"Error in strategy: {e}")
return {"status": "error", "error_message": str(e)}
STEP 3: Mortgage Tools (mortgage_tools.py)
This module calculates standard fixed-rate mortgage payments. It is essential for determining if a user should use their tax refund to pay down principal.
File: backend/tools/mortgage_tools.py
import logging
import numpy_financial as npf
logger = logging.getLogger(__name__)
def _calculate_monthly_payment(principal, annual_interest_rate, years):
"""Calculates the fixed monthly mortgage payment (P&I)."""
if principal <= 0 or annual_interest_rate < 0 or years <= 0:
return 0
monthly_rate = (annual_interest_rate / 100) / 12
num_payments = years * 12
# Returns negative value, so we negate it
return -npf.pmt(monthly_rate, num_payments, principal)
def analyze_mortgage_profile(
principal: float,
annual_interest_rate: float,
remaining_years: float
) -> dict:
"""
Analyzes current mortgage status.
"""
try:
monthly_payment = _calculate_monthly_payment(principal, annual_interest_rate, remaining_years)
total_paid = monthly_payment * remaining_years * 12
total_interest = total_paid - principal
return {
"status": "success",
"current_principal": principal,
"interest_rate": annual_interest_rate,
"monthly_payment": round(monthly_payment, 2),
"total_interest_remaining": round(total_interest, 2)
}
except Exception as e:
return {"status": "error", "error_message": str(e)}
def generate_acceleration_scenario(
principal: float,
annual_interest_rate: float,
remaining_years: float,
lump_sum_payment: float = 0.0
) -> dict:
"""
Calculates impact of applying a lump sum (e.g., tax refund) to principal.
"""
try:
# Baseline
orig_payment = _calculate_monthly_payment(principal, annual_interest_rate, remaining_years)
orig_interest = (orig_payment * remaining_years * 12) - principal
# New Scenario: Reduce principal immediately
new_principal = principal - lump_sum_payment
if new_principal <= 0:
return {"status": "success", "message": "Mortgage fully paid off!"}
monthly_rate = (annual_interest_rate / 100) / 12
# Calculate new number of periods (nper) keeping payment same
new_num_payments = npf.nper(monthly_rate, -orig_payment, new_principal)
new_years = new_num_payments / 12
new_total_cost = (orig_payment * new_num_payments)
new_interest = new_total_cost - new_principal
interest_saved = orig_interest - new_interest
return {
"status": "success",
"lump_sum_applied": lump_sum_payment,
"original_payoff_years": remaining_years,
"new_payoff_years": round(new_years, 2),
"years_saved": round(remaining_years - new_years, 2),
"interest_saved": round(interest_saved, 2)
}
except Exception as e:
return {"status": "error", "error_message": str(e)}
STEP 4: Financial Advisor Agent Configuration
Now we assemble the agent using Google ADK. The key here is the instruction prompt, which must strictly enforce the persona of a US financial planner.
File: backend/agents/financial_advisor_agent.py
from google.adk.agents import Agent
from tools.tax_tools import calculate_tax_scenario, recommend_contribution_strategy
from tools.mortgage_tools import analyze_mortgage_profile, generate_acceleration_scenario
# Define the tools list
financial_tools = [
calculate_tax_scenario,
recommend_contribution_strategy,
analyze_mortgage_profile,
generate_acceleration_scenario
]
# Configure the Agent
advisor_agent = Agent(
name="us_financial_advisor",
model="gemini-2.5-flash", # Fast, efficient model
description="A US-focused financial advisor for tax and debt planning.",
instruction=(
"You are an expert US Financial Advisor. Your goal is to optimize the user's financial health "
"by minimizing federal tax liability and efficiently managing debt.\n\n"
"RULES & BEHAVIORS:\n"
"1. ALWAYS prioritize high-interest debt (Credit Cards, Personal Loans > 7%) over investing.\n"
"2. Use 'calculate_tax_scenario' to show the specific dollar benefit of 401(k) contributions.\n"
"3. If the user gets a tax refund (savings), suggest applying it to their mortgage using 'generate_acceleration_scenario' IF they plan to stay in the home long-term.\n"
"4. All tax references must use 2025 IRS rules. The standard deduction is $15,750 for singles.\n"
"5. Explain concepts simply. Do not just output numbers; explain WHY a strategy works."
),
tools=financial_tools
)
STEP 5: Project Structure
Ensure your final directory looks like this. Don't forget empty `__init__.py` files to make directories treatable as packages.
ai_financial_advisor/
├── venv/
├── backend/
│ ├── __init__.py
│ ├── agents/
│ │ ├── __init__.py
│ │ └── financial_advisor_agent.py
│ └── tools/
│ ├── __init__.py
│ ├── tax_tools.py
│ └── mortgage_tools.py
└── main.py # Entry point script
STEP 6: Testing Your Agent
Create a simple `main.py` to interact with your agent.
# main.py
from backend.agents.financial_advisor_agent import advisor_agent
# Scenario: Single earner, high income, some credit card debt
user_query = (
"I make $110,000/year. I have $5,000 on a credit card at 18% APR. "
"I also have a $300,000 mortgage at 6.5% with 25 years left. "
"I have $10,000 in cash available. Should I put it in my 401k or pay off debt?"
)
response = advisor_agent.run(user_query)
print(response)
How It Works
When you run the query above, the following sequence occurs:
- Parsing: Gemini analyzes the prompt and extracts: Income ($110k), Debts (CC: $5k @ 18%), Cash ($10k).
- Tool Call 1 (Strategy): It calls
recommend_contribution_strategy. The tool sees the 18% debt and returns a "CRITICAL" warning to pay that $5k first. - Tool Call 2 (Tax): For the remaining $5k, it calls
calculate_tax_scenarioto see how much tax is saved by putting $5k into a 401(k). - Synthesis: The agent combines these. It will tell you: "Pay off the $5,000 credit card immediately because 18% interest is guaranteed loss. Then, put the remaining $5,000 into your 401(k), which will save you approximately $1,100 in taxes."
Example Use Cases
1. The "Young Professional"
Input: $85,000 income, no debt, wants to lower taxes.
Agent Action: Calculates that their marginal rate is 22%. Suggests maximizing 401(k) to reduce taxable income below the $48,475 bracket threshold if possible (though unlikely with just contributions), or simply taking the guaranteed 22% tax savings.
2. The "Mortgage Accelerator"
Input: $150,000 income, received a $4,000 tax refund.
Agent Action: Calls generate_acceleration_scenario with a $4,000 lump sum. It might show that this one-time payment saves $12,000 in interest over the life of a 30-year loan, providing a powerful incentive to invest the refund.
3. The "Debt Trap"
Input: $60,000 income, $15,000 credit card debt.
Agent Action: The agent will aggressively advise against investing. Even though 401(k) saves taxes, the 20%+ APR on credit cards destroys wealth faster. It prioritizes the "Avalanche Method."
Best Practices & Customization
- State Taxes: The current code handles Federal only. You could add a
stateparameter tocalculate_tax_scenarioand import a dictionary of state tax rates. - Catch-up Contributions: Ensure you pass the user's
ageto the strategy tool to unlock higher limits ($31,000 total for 401k) for those over 50. - Security: Never store PII (Personally Identifiable Information) in logs. Notice our loggers only record "Analysis performed" or anonymized figures.
- Database: For a production app, persist user profiles in a database (SQL/NoSQL) so they don't have to re-enter details every session.
Conclusion
By combining Python's computational accuracy with Gemini's reasoning capabilities, you've built a financial advisor that is both smart and safe. It doesn't hallucinate tax math—it calculates it—while still providing the conversational experience users expect.
Opinions expressed by DZone contributors are their own.
Comments