Building a Human-in-the-Loop Loan Underwriting System Using Java and LangGraph4j
Most AI applications follow a simple pattern: send a prompt to an LLM and receive a response.
But real-world business workflows are more complex. They involve multiple steps, validations, decisions, and sometimes human intervention.
I wanted to explore how to build an AI workflow that doesn’t just generate responses but can also pause, wait for human approval, and resume exactly where it stopped.
That led me to build a Commercial Loan Underwriting System using Java, Spring Boot, Spring AI, and LangGraph4j.
What does the application do?
The application automates key stages of commercial loan underwriting:
- Extract financial information from submitted documents.
- Validate whether required information is available.
- Perform compliance checks, including fraud, PEP, and sanctions screening.
- Calculate financial metrics such as Debt-to-Income (DTI).
- Assess the application’s risk level.
- Approve eligible applications or request human review.
The important part is that the system doesn’t automatically make every decision. When human intervention is required, the workflow pauses and waits.
Architecture: Workflow as a Graph
Instead of implementing everything as a sequence of method calls, I used LangGraph4j to model the underwriting process as a graph.
Each node performs a specific task, and conditional edges decide where the workflow should go next.
The main workflow includes:
- Document Extraction: Extracts revenue, debt, and credit score.
- Validation: Checks whether the required information is available.
- Document Review: Requests human review when information is missing.
- Compliance: Checks fraud indicators, PEP, and sanctions.
- Financial Analysis: Calculates financial metrics such as DTI.
- Risk Assessment: Determines the application’s risk level.
- Approval: Automatically handles eligible low-risk applications.
- Human Review: Waits for a reviewer when a manual decision is required.
The Interesting Part: Pause and Resume
One of the main challenges was handling human approval.
Imagine an application that requires a compliance review. The system should not keep an HTTP request open while waiting for someone to review it.
Instead, LangGraph4j provides checkpointing and interruptBefore, allowing the workflow to pause before specific nodes.
When the workflow reaches a configured interruption point:
- The current graph state is checkpointed.
- The application returns a
WAITING_FOR_HUMANstatus. - A reviewer can submit a decision through a separate REST API.
- The workflow resumes from its saved state.
I used a shared checkpoint saver and the application ID as the graph’s threadId to identify each application's execution.
Get Suhel Shaik’s stories in your inbox
Join Medium for free to get updates from this writer.
This allows the workflow to continue without starting the entire underwriting process again.
Two Different Human Approval Gates
During development, I discovered an important workflow-design issue.
Document approval and loan approval are not the same thing.
For example:
- Document Review: A reviewer confirms that the submitted documents are sufficient. The workflow should continue with compliance checks.
- Final Loan Review: A reviewer makes the final approve or reject decision.
Initially, I treated both as the same approval step. This could allow a document approval to skip important underwriting stages.
I fixed this by introducing separate state fields and separate workflow gates.
This was one of the most important lessons from the project: human approval should represent the actual business decision, not just a generic approval flag.
Handling LLM Reliability
LLM responses are not always predictable, so I also focused on defensive handling.
Some important considerations:
- Missing values are represented as
null, not invented as zero. - State updates handle null values safely.
- Document content is treated as untrusted input to reduce prompt-injection risks.
- An audit log tracks important state changes.
- Completed applications clear outdated human-review information.
These details are important when building AI workflows that handle business-critical decisions.
Technology Stack
- Java 21
- Spring Boot
- Spring AI
- LangGraph4j
- OpenAI
- Maven
What I Learned
Building this project helped me understand that agentic AI systems are not just about connecting LLMs and tools.
The real engineering challenges are workflow orchestration, state management, conditional routing, checkpointing, and human intervention.
The goal is not to replace the human decision-maker. It is to automate the repetitive work and know exactly when to stop and ask for human input.
GitHub Repository
The complete implementation is available here:
Note: This is a personal learning project. It uses synthetic data and is not production lending software or financial advice.









