How I Built an LLM Agent that Calculates Real‑Time Remittance Values for Nepal

Ever tried to tell a data‑science colleague, “I need to know how much NPR a family will receive if I send $500 today,” and watched them stare at a static model while the real exchange rate keeps changing? I faced that exact dead‑end while consulting a Nepali remittance startup. The answer wasn’t a better regression—it was an LLM that could call a live API on my behalf. In this tutorial you’ll build exactly that: an autonomous agent that fetches current USD‑NPR rates, applies a fee, and returns the net amount, all from a single natural‑language prompt.

Key Takeaways

  • Custom tools let LLMs act on live data instead of static knowledge.
  • A thin wrapper around an HTTP request is enough to expose a financial service to an agent.
  • LangChain’s Tool and AgentExecutor simplify the “LLM + function” pattern for production‑ready prototypes.
  • Proper error handling (network failures, invalid currencies, missing API keys) keeps the agent reliable.
  • For FinTech use‑cases, keep the prompt persona focused on the domain to reduce hallucinations.

The Problem

Data scientists excel at building predictive models, but many FinTech teams need an assistant that can act—pull the latest exchange rate, apply business rules, and report a concrete number. Without a mechanism for the model to invoke external services, the assistant is limited to stale knowledge and can’t support real‑time decisions.

Data and Sources

We use the free ExchangeRate.host API for live currency conversion. The endpoint https://api.exchangerate.host/latest?base=USD&symbols=NPR returns a JSON payload with the current USD→NPR rate.
Data accessed on 2026-11-03.

Loading the Data

The first building block is a robust HTTP client that returns a float or raises a meaningful exception.

import requests

def get_exchange_rate(base_currency: str, target_currency: str) -> float:
    """Fetch a live conversion rate from ExchangeRate.host."""
    url = f"https://api.exchangerate.host/latest?base={base_currency}&symbols={target_currency}"
    try:
        resp = requests.get(url, timeout=5)
        resp.raise_for_status()
    except requests.RequestException as exc:
        raise ConnectionError(f"Failed to contact exchange‑rate service: {exc}") from exc

    try:
        data = resp.json()
        rate = data["rates"][target_currency]
        if not isinstance(rate, (int, float)):
            raise ValueError("Rate is not numeric")
        return float(rate)
    except (KeyError, ValueError, TypeError) as exc:
        raise RuntimeError(f"Unexpected response format: {exc}") from exc

Step 1 — The Agentic Shift: Why Custom Tools?

Traditional pipelines stop at predict(). By exposing a function, we give the LLM a new “action” it can call when the prompt demands up‑to‑date data. The agent decides when to invoke the tool, keeping the conversation natural while staying grounded in reality.

Step 2 — Crafting Our FinTech Tool: Live Exchange Rate Fetcher

The function above is the core tool. It isolates network logic, validates the payload, and presents a clean float to the caller. This separation makes it easy to replace the provider or add caching later.

Step 3 — Exposing the Tool: Bridging Python to LLM Agent

LangChain’s Tool class turns any callable into something the LLM can discover. The name and description are critical—they guide the model’s tool‑selection logic.

from langchain.tools import Tool

exchange_tool = Tool(
    name="get_exchange_rate",
    func=get_exchange_rate,
    description=(
        "Retrieves the current conversion rate from a base currency to a target currency. "
        "Inputs must be ISO 4217 codes, e.g., 'USD' and 'NPR'. Returns a float."
    ),
)

Step 4 — Orchestrating the Agent: Defining Purpose and Capabilities

We give the LLM a persona—“Nepal FinTech Analyst”—so it knows the business context. The AgentExecutor wires the LLM, the tool, and the prompt template together.

import os
from langchain.chat_models import ChatOpenAI
from langchain.agents import AgentExecutor, AgentType, initialize_agent

def build_agent():
    api_key = os.getenv("OPENAI_API_KEY")
    if not api_key:
        raise EnvironmentError("OPENAI_API_KEY not set in environment")

    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.0)  # cheap, fast
    tools = [exchange_tool]

    system_prompt = (
        "You are a Nepal FinTech analyst. Your job is to answer user queries about "
        "remittances, fees, and conversions using live exchange rates. "
        "When a conversion is needed, call the provided `get_exchange_rate` tool."
    )

    agent = initialize_agent(
        tools,
        llm,
        agent=AgentType.OPENAI_FUNCTIONS,
        verbose=False,
        agent_kwargs={"system_message": system_prompt},
    )
    return agent

Step 5 — Real‑World Scenario: Estimating Remittance Value

Now we ask the agent a realistic question. The agent decides to invoke get_exchange_rate, receives the rate, applies a 2 % fee, and returns the net NPR amount.

def estimate_remittance(agent, amount_usd: float, fee_pct: float = 2.0):
    query = (
        f"If a Nepali worker sends ${amount_usd:,.2f} from the US to Nepal, "
        f"how much NPR will the family receive after a {fee_pct}% bank fee?"
    )
    try:
        response = agent.run(query)
        return response
    except Exception as exc:
        return f"Agent failed: {exc}"

Putting It Together

We wire loading, agent creation, and the query into a single script. Edge cases—missing API key, network outage, malformed response—are caught and reported.

if __name__ == "__main__":
    try:
        agent = build_agent()
        result = estimate_remittance(agent, amount_usd=500)
        print("🧮 Result:", result)
    except Exception as e:
        print("❌ Fatal error:", e)

Complete Script

The full runnable script combining all steps:

#!/usr/bin/env python3
"""
LLM Agent that fetches live USD→NPR rates and computes net remittance.
Requires:
  - openai (for ChatOpenAI)
  - langchain
  - requests
Set OPENAI_API_KEY in the environment before running.
"""

import os
import requests
from langchain.chat_models import ChatOpenAI
from langchain.agents import initialize_agent, AgentType
from langchain.tools import Tool

# ---------- Step 2: Live Exchange Rate Fetcher ----------
def get_exchange_rate(base_currency: str, target_currency: str) -> float:
    """Fetch a live conversion rate from ExchangeRate.host."""
    url = f"https://api.exchangerate.host/latest?base={base_currency}&symbols={target_currency}"
    try:
        resp = requests.get(url, timeout=5)
        resp.raise_for_status()
    except requests.RequestException as exc:
        raise ConnectionError(f"Failed to contact exchange‑rate service: {exc}") from exc

    try:
        data = resp.json()
        rate = data["rates"][target_currency]
        if not isinstance(rate, (int, float)):
            raise ValueError("Rate is not numeric")
        return float(rate)
    except (KeyError, ValueError, TypeError) as exc:
        raise RuntimeError(f"Unexpected response format: {exc}") from exc

# ---------- Step 3: Expose as LangChain Tool ----------
exchange_tool = Tool(
    name="get_exchange_rate",
    func=get_exchange_rate,
    description=(
        "Retrieves the current conversion rate from a base currency to a target currency. "
        "Inputs must be ISO 4217 codes, e.g., 'USD' and 'NPR'. Returns a float."
    ),
)

# ---------- Step 4: Build the Agent ----------
def build_agent():
    api_key = os.getenv("OPENAI_API_KEY")
    if not api_key:
        raise EnvironmentError("OPENAI_API_KEY not set in environment")

    llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.0)
    tools = [exchange_tool]

    system_prompt = (
        "You are a Nepal FinTech analyst. Your job is to answer user queries about "
        "remittances, fees, and conversions using live exchange rates. "
        "When a conversion is needed, call the provided `get_exchange_rate` tool."
    )

    agent = initialize_agent(
        tools,
        llm,
        agent=AgentType.OPENAI_FUNCTIONS,
        verbose=False,
        agent_kwargs={"system_message": system_prompt},
    )
    return agent

# ---------- Step 5: Query the Agent ----------
def estimate_remittance(agent, amount_usd: float, fee_pct: float = 2.0):
    query = (
        f"If a Nepali worker sends ${amount_usd:,.2f} from the US to Nepal, "
        f"how much NPR will the family receive after a {fee_pct}% bank fee?"
    )
    try:
        response = agent.run(query)
        return response
    except Exception as exc:
        return f"Agent failed: {exc}"

# ---------- Main Execution ----------
if __name__ == "__main__":
    try:
        agent = build_agent()
        result = estimate_remittance(agent, amount_usd=500)
        print("🧮 Result:", result)
    except Exception as fatal:
        print("❌ Fatal error:", fatal)

Expected Output

Running python script.py prints something similar to:

🧮 Result: After a 2% fee, $500 converts to approximately 65,400 NPR (USD→NPR rate: 130.80). 

The exact number will vary with the live rate.

Limitations and Tradeoffs

This prototype assumes a single free exchange‑rate provider and a modest fee model. In production you’d need:

  • Rate‑limit handling or caching (e.g., functools.lru_cache with TTL).
  • Secure storage of API credentials for premium providers.
  • Stateful conversation buffers if the user asks follow‑up questions.
  • Compliance checks for financial regulations in Nepal.

If the provider goes down, the agent will return a clear error instead of a stale number, but you’d likely want a fallback service.

Frequently Asked Questions

Do I need an OpenAI API key to run the agent?

Yes. Set the OPENAI_API_KEY environment variable before executing the script.

Can I swap ExchangeRate.host for another service?

Absolutely. Implement a function with the same signature (base, target → float) and wrap it with Tool. The agent will discover the new tool automatically.

What happens if the API returns an unexpected currency code?

The function raises a RuntimeError, which the surrounding estimate_remittance catches and returns a friendly message.

Is the agent stateless across multiple queries?

In this minimal example each run starts fresh. For multi‑turn dialogs keep the AgentExecutor instance alive and pass a conversation buffer.

How can I avoid hitting rate limits in production?

Introduce a thin cache (e.g., functools.lru_cache with a time‑to‑live) or batch requests when possible. Monitoring and exponential back‑off also help.

What I'd Change

If I were to ship this to a fintech startup, I’d replace the free API with a paid, SLA‑backed provider, add Redis‑based caching with a 60‑second TTL, and wrap the agent in a FastAPI endpoint so the front‑end can query it over HTTP. The extra plumbing costs a few extra lines, but the reliability gain is worth it for any production‑grade financial product.

إرسال تعليق

Hi! How can we help you? Send us a message and we'll get back to you.