A lightweight agent that extracts key fields from FNOL (First Notice of Loss) documents, detects missing/inconsistent data, and routes the claim to the correct workflow with a human-readable explanation.
Field extraction uses a local LLM (Ollama, gpt-oss model) rather than fixed
templates — this lets it understand FNOL documents with varying wording and
layout, not just one exact format. That's the "understanding" part of the
agent.
Routing itself is deterministic Python, not the LLM. This is a deliberate design choice:
- Same input always produces the same route (no randomness/hallucination in a business-critical decision).
- The system keeps working correctly even if Ollama is down — it falls back to regex-based extraction automatically, and the demo never breaks.
- Every routing decision is traceable to one exact rule, which is what makes the "reasoning" output trustworthy rather than a vague LLM guess.
Every processed claim is automatically logged to claims_log.xlsx (created
in the project folder on first run). Each row is keyed by Policy Number:
- New policy number → a new row is appended.
- Same policy number processed again → the existing row is updated, not duplicated.
Columns include every extracted field plus Missing Fields, Recommended Route, Reasoning, Extraction Method (llm/regex_fallback), and a timestamp — giving a full audit trail of every routing decision and why it was made.
Logging failures (e.g. the file is open in Excel and locked) never break the agent — the JSON result is always returned regardless.
fnol_agent/
├── schema.py # Pydantic schema for all required fields
├── llm_client.py # Ollama Cloud API wrapper (with timeout + failure handling)
├── extractor.py # LLM extraction + regex fallback
├── router.py # Missing-field detection + routing rule engine
├── excel_logger.py # Logs every processed claim to claims_log.xlsx (upsert by policy number)
├── pipeline.py # Orchestrates the full flow, CLI entry point
├── app.py # Streamlit UI for demoing
├── requirements.txt
├── .env.example # Template for your OLLAMA_API_KEY
└── sample_fnols/ # 4 dummy FNOL docs, one per routing outcome
├── claim1_fasttrack.txt
├── claim2_missingfields.txt
├── claim3_investigation.txt
└── claim4_injury.txt
See GUIDE.md for a complete walkthrough: architecture diagram, what
each file does, why routing never depends on the LLM, the full routing
priority table, and verified test results for all 10 sample cases.
python3 test_runner.pyRuns all 10 sample FNOL documents and prints a pass/fail table comparing actual vs. expected routing — useful to run right before a demo.
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
cp .env.example .envThis project uses Ollama Cloud API for extraction (no local model download
or ollama serve needed):
- Get an API key from https://ollama.com/settings/keys
- Copy
.env.exampleto.envand fill in your values:cp .env.example .env
- Update the values in
.envbefore running the app. - Check
llm_client.py—MODEL_NAMEis set to"gpt-oss:120b-cloud". Update this to match the exact cloud model tag available in your account if different.
If the key isn't set, or the API call fails for any reason, extraction automatically falls back to regex parsing — the pipeline never crashes.
python pipeline.py sample_fnols/claim1_fasttrack.txtstreamlit run app.pyThen upload any file from sample_fnols/ (or a real FNOL .txt/.pdf) and
click "Process Claim".
- Manual Review — any mandatory field is missing.
- Investigation Flag — description contains "fraud", "inconsistent", or "staged".
- Specialist Queue — claim type is "injury".
- Fast-track — estimated damage < ₹25,000.
- Standard Review — fallback if none of the above apply.
{
"extractedFields": {},
"missingFields": [],
"recommendedRoute": "",
"reasoning": ""
}- If the API key is missing, the Ollama Cloud API is unreachable, or it returns invalid JSON, extraction automatically falls back to regex parsing — the pipeline never crashes or returns empty output.
- Routing and missing-field detection never call the LLM, so they are 100% deterministic and testable.