Tools4AI와 Ollama를 사용하여 Java로 로컬 AI 에이전트 구축하기: 보험 청구 사례 연구
요약
Tools4AI와 Ollama를 활용하여 Java 기반의 완전한 오프라인 로컬 AI 에이전트를 구축하는 방법을 소개합니다. 민감한 데이터를 외부로 유출하지 않고 보험 청구와 같은 규제 산업에서 사용할 수 있는 보안 중심의 에이전트 구현 사례를 다룹니다.
핵심 포인트
- Tools4AI를 사용해 Java 메서드를 AI 액션으로 자동 변환 가능
- Ollama를 통한 로컬 모델 실행으로 데이터 보안 및 프라이버시 확보
- 어노테이션 기반의 간편한 에이전트 기능 구현 및 함수 스키마 자동화
- 보험 산업 등 규제 준수가 중요한 분야를 위한 온프레미스 솔루션 제공
Tools4AI는 어노테이션(annotated)이 지정된 모든 Java 메서드를 AI가 호출 가능한 액션(action)으로 변환하는 100% Java 에이전트형 AI 프레임워크입니다. Ollama는 Llama 3.1 및 Phi-4와 같은 오픈 모델을 로컬에서 실행하고 OpenAI 호환 API를 제공합니다. Tools4AI를 http://localhost:11434/v1로 지정하면 데이터가 네트워크를 절대 벗어나지 않는 완전한 오프라인 온프레미스(on-premise) AI 에이전트를 구축할 수 있습니다. 이 튜토리얼에서는 청구인의 자유 형식 사고 보고서를 읽고, 이를 적절한 비즈니스 액션으로 라우팅하며, 구조화된 데이터를 추출하고, 고액 지급 건에 대해 인간의 승인 단계를 거치며, 컴플라이언스 감사 추적(audit trail)을 기록하는 보험 청구 분류(triage) 에이전트를 구축합니다.
대상 독자: 민감한 데이터를 제3자 API로 전송하지 않고 에이전트형 AI를 사용하고자 하는 규제 산업(보험, 은행, 의료)의 Java 개발자, 솔루션 아키텍트 및 엔지니어링 리더.
목차
보험 산업에서 로컬 AI 에이전트가 중요한 이유
보험 산업은 이름, 주소, 증권 번호, 의료 세부 정보, 차량 데이터 및 손실 설명과 같은 **개인 식별 정보 (PII, Personally Identifiable Information)**를 기반으로 운영됩니다. 이러한 데이터를 호스팅된 LLM API로 전송하는 것은 규제, 계약 및 평판 리스크를 초래합니다. 동시에, 보험 청구 팀은 사고 발생 최초 통지 (FNOL, First Notice of Loss) 보고서, 손해 사정사 메모, 이메일 및 통화 녹취록과 같은 비정형 텍스트 데이터에 압도당하고 있습니다.
A 로컬 AI 에이전트는 이 두 가지 문제를 동시에 해결합니다:
- 데이터가 귀사의 구내를 절대 벗어나지 않습니다. 모델은 Ollama를 통해 귀하의 자체 하드웨어에서 실행됩니다.
- 결정론적 비즈니스 로직이 Java에 유지됩니다. LLM은 *무엇(what)*을 할지 결정하고, 감사 및 테스트를 거친 귀하의 Java 코드는 어떻게(how) 할지를 결정합니다.
- **인간 참여형(Human-in-the-loop) 및 감사 추적(audit trails)**이 기본적으로 제공되므로 컴플라이언스 검토자를 만족시킬 수 있습니다.
프라이빗 추론(private inference)과 통제된 실행(governed execution)의 결합 — 이것이 바로 Tools4AI + Ollama가 제공하는 핵심입니다.
Tools4AI란 무엇인가?
Tools4AI (io.github.vishalmysore:tools4ai Maven Central 기준)는 가볍고 순수 Java로 작성된 **에이전트형 AI 프레임워크 (agentic AI framework)**이자 ADK입니다. 이 프레임워크의 핵심 아이디어는 단순하면서도 강력합니다.
Java 클래스에
@Agent를, 메서드에@Action을 어노테이션(Annotation)으로 추가하기만 하면 됩니다. Tools4AI는 클래스패스(classpath)를 스캔하며, 런타임(runtime) 시 **자연어 프롬프트 (natural-language prompt)**를 올바른 메서드에 매핑하고, 파라미터(parameter)를 추출하여 호출합니다. 즉, 수동으로 함수 스키마 (function schemas)를 작성할 필요가 없습니다.
이 글에서 사용되는 주요 기능:
| 기능 | 역할 |
|---|---|
| 액션 라우팅 (Action routing) | 프롬프트를 적절한 @Action 메서드에 자동으로 매핑 |
| ... |
Tools4AI는 제공자 불가지론적 (provider-agnostic)이기 때문에, 동일한 코드를 Gemini, OpenAI, Anthropic에서 실행할 수 있으며, 본 예제에서 수행할 것처럼 OpenAI 호환 엔드포인트를 통해 로컬 Ollama 모델에서도 실행할 수 있습니다.
왜 Ollama + Java가 규제 대상 데이터에 적합한가
Ollama는 http://localhost:11434/v1에서 OpenAI 호환 REST API를 통해 오픈 웨이트 모델 (Llama 3.1, Phi-4, Mistral, Gemma 등)을 제공합니다. Tools4AI의 OpenAiActionProcessor가 이미 해당 프로토콜을 지원하므로, 두 가지를 연결하는 것은 단순한 설정 작업일 뿐이며, 어댑터나 새로운 코드가 필요하지 않습니다.
- ✅ 데이터 외부 유출 제로 (Zero data egress) — 추론 (inference)이 로컬에서 수행됩니다.
- ✅ API 키 불필요, 토큰당 과금 없음.
- ✅ 에어갭 (air-gapped) / VPC 환경에서 실행 가능.
- ✅ 동일한 Tools4AI 코드를 나중에 클라우드 제공업체와 함께 사용할 수도 있습니다.
사전 요구 사항
- Java 8 이상 (Tools4AI는 Java 8 바이트코드로 컴파일됨) 및 Maven
- Ollama 설치 — 여기서 다운로드
- 성능이 준수한 명령 수행 모델 (instruction model)을 위해 약 8GB 이상의 여유 RAM (많을수록 좋음)
1단계 — Ollama 설치 및 실행
함수 호출 (function calling) 능력이 뛰어난 모델을 가져오고(pull) 실행합니다:
ollama pull llama3.1
ollama run llama3.1
이제 Ollama가 로컬에서 OpenAI 호환 API를 제공합니다. 다음을 통해 확인하세요:
curl http://localhost:11434/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model":"llama3.1","messages":[{"role":"user","content":"Say OK"}],"stream":false}'
이렇게 하면 응답으로 "content": "OK"를 포함하는 JSON을 받게 됩니다.
Step 2 — Tools4AI 의존성 추가 (Add the Tools4AI dependency)
<dependency>
<groupId>io.github.vishalmysore</groupId>
<artifactId>tools4ai</artifactId>
...
최신 버전은 Maven Central에서 확인하세요. 소스에서 빌드할 경우, Tools4AI가 메서드 매개변수 이름을 읽을 수 있도록 -parameters 컴파일러 플래그를 활성화하는 것을 잊지 마세요.
Step 3 — Tools4AI를 Ollama에 연결 (Point Tools4AI at Ollama)
클래스패스(예: src/main/resources/tools4ai.properties)에 tools4ai.properties 파일을 생성하세요:
## 비어있지 않은 값이라면 어떤 것이든 작동합니다 — Ollama는 키를 무시하지만,
## Tools4AI는 키가 존재할 때만 모델을 빌드합니다.
openAiKey=ollama
...
알아두면 좋은 두 가지 함정(gotchas):
LocalAIActionProcessor는 스텁(stub)입니다 — 메서드가null을 반환합니다. 사용하지 마세요. 위의 OpenAI 호환 경로는 작동하는 경로입니다.- Properties 파일이
-DVM 옵션보다 우선합니다. Tools4AI는 먼저tools4ai.properties를 읽고, 파일 값이 비어 있을 때만-DopenAiModelName=...로 폴백(fallback)합니다. VM 옵션에 의존하는 경우, 해당 속성(property)을 빈 값으로 두세요.
Step 4 — 첫 번째 로컬 AI 호출 (Your first local AI call)
import com.t4a.processor.OpenAiActionProcessor;
public class Hello {
...
이 단일 query() 호출만으로도 Tools4AI의 설정 로더, langchain4j, 그리고 사용자의 로컬 Ollama 모델을 거쳐 라운드 트립(round-trip)됩니다. 만약 PONG이 출력되면, 완전히 오프라인 상태이며 에이전트를 구축할 준비가 된 것입니다.
보험 사용 사례: FNOL 청구 분류 에이전트 (The insurance use case: an FNOL claims triage agent)
실제 작동하는 것을 만들어 봅시다. 첫 통보 손실(First Notice of Loss, FNOL) — 정책 소유자가 사고를 보고하는 순간을 처리하는 에이전트입니다. 우리의 에이전트는 다음 작업을 수행할 것입니다:
- 청구인의 메시지를 적절한 비즈니스 액션(정책 확인, 청구 접수, 지급액 산정 또는 에스컬레이션)으로 **라우팅 (Route)**합니다.
- 자유 형식의 사고 설명문으로부터 구조화된 청구 기록을 **추출 (Extract)**합니다.
- 고액 지급 건에 대해 필수적인 인간의 승인을 거치도록 **게이트 (Gate)**를 설정합니다.
- 준수 사항 확인을 위해 모든 액션을 **감사 (Audit)**합니다.
1. 비즈니스 액션을 에이전트로 정의하기
이것이 Tools4AI를 사용하는 핵심 이유입니다. 여러분의 비즈니스 로직은 그저 일반적인 Java 클래스일 뿐입니다. 클래스에 @Agent를 어노테이션(Annotation)하고, 호출 가능한 각 메서드에 @Action을 어노테이션하면 끝납니다 — 구현해야 할 인터페이스도, 반복적인 상용구 코드(Boilerplate)도 없습니다. Tools4AI는 클래스패스(Classpath)를 스캔하여 모든 @Action 메서드를 등록하고(클래스당 여러 개도 가능), 여러분을 대신해 클래스를 인스턴스화하며, 어노테이션에서 riskLevel을 직접 읽어옵니다.
import com.t4a.annotations.Action;
import com.t4a.annotations.Agent;
import com.t4a.api.ActionRisk;
...
알아야 할 두 가지. (1)
riskLevel은@Agent가 아니라@Action에 속합니다 (@Agent는groupName,groupDescription, 그리고 선택 사항인prompt만 가집니다). (2) 클래스에는 인자가 없는 public 생성자(no-arg constructor)가 필요합니다 — Tools4AI가 이를 대신 인스턴스화해 줍니다.(액션 클래스가
implements JavaMethodAction을 사용하는 구식 스타일이 있습니다. 꼭 필요한 경우가 아니라면 피하세요. 해당 방식은 클래스당 첫 번째@Action메서드만 등록하고@Action(riskLevel=…)을 무시합니다. 즉, 모든 액션을 별도의 클래스로 분리하고getActionRisk()를 오버라이드(Override)해야 합니다. 위에서 설명한 일반적인@Agent클래스는 이러한 제한이 없습니다.)
### 2. 자연어 액션 라우팅
...
java
import com.t4a.processor.OpenAiActionProcessor;
OpenAiActionProcessor agent = new OpenAiActionProcessor();
// AI가 checkPolicyStatus를 선택하고 policyNumber = "AUTO-88213"을 추출합니다.
Object status = agent.processSingleAction(
"Can you tell me if my policy AUTO-88213 is still active?");
System.out.println(status);
// -> Policy AUTO-88213 is ACTIVE, auto coverage, $500 deductible
// AI가 fileClaim을 선택하고 세 가지 인자(arguments)를 모두 추출합니다.
Object claim = agent.processSingleAction(
"I need to file a claim on policy AUTO-88213. Someone rear-ended my car " +
"in a parking lot and the bumper is cracked.");
System.out.println(claim);
// -> Opened claim CLM-12345 (collision) for policy AUTO-88213
사용할 기능(capability)을 이미 알고 있는 경우, 액션을 명시적으로 전달할 수도 있습니다 (`agent.processSingleAction(prompt, new FileClaimAction())`). 이는 결정론적(deterministic)이고 단일 목적을 가진 엔드포인트(endpoint)를 구축할 때 유용합니다.
...
import com.t4a.annotations.Prompt;
import java.util.Date;
public class ClaimReport {
public String claimantName;
public String policyNumber;
public String incidentType; // 예: collision, theft, fire, water damage
@Prompt(describe = "미국 달러 기준 예상 손해액, 숫자만 입력")
public double estimatedDamage;
...
}
```java
import com.t4a.transform.OpenAIPromptTransformer;
OpenAIPromptTransformer transformer = new OpenAIPromptTransformer();
String fnol =
"Hi, this is Priya Sharma, policy HOME-55021. On July 12th 2026 a burst pipe " +
"flooded my kitchen in Austin. A plumber estimated about $3,200 in damage.";
ClaimReport report = (ClaimReport) transformer.transformIntoPojo(fnol, ClaimReport.class.getName());
System.out.println(report);
// -> ClaimReport{name=Priya Sharma, policy=HOME-55021, type=water damage,
// damage=$3200.0, date=2026-07-12, location=Austin}
단 한 번의 호출로 비정형 보고서(unstructured report)를 보험 청구 파이프라인(claims pipeline)에서 즉시 사용할 수 있는 검증된 타입의 레코드(typed record)로 변환할 수 있습니다.
...
```java
import com.t4a.detect.FeedbackLoop;
import com.t4a.detect.HumanInLoop;
import java.util.Map;
public class AdjusterApproval implements HumanInLoop {
private final boolean approve; // 실제 승인 채널에 연결
public AdjusterApproval(boolean approve) { this.approve = approve; }
@Override
public FeedbackLoop allow(String prompt, String methodName, Map<String, Object> params) {
return () -> approve;
...
}
ClaimsAgent는 일반적인 @Agent POJO(Plain Old Java Object, 단순 자바 객체)이므로 (AIAction이 아님), Tools4AI의 레지스트리(registry)에서 등록된 액션을 이름으로 가져와 명시적으로 호출합니다:
import com.t4a.api.AIAction;
import com.t4a.predict.PredictionLoader;
import com.t4a.processor.LogginggExplainDecision;
import com.t4a.processor.OpenAiActionProcessor;
OpenAiActionProcessor agent = new OpenAiActionProcessor();
AIAction settle = PredictionLoader.getInstance().getAiAction("settleClaim");
// 사람이 거절함 -> settleClaim이 실행되지 않음; "Human verification failed" 메시지를 받게 됨
agent.processSingleAction("Settle claim CLM-12345 for $8000, approved by Vishal",
settle, new AdjusterApproval(false), new LogginggExplainDecision());
// 사람이 승인함 -> 정산(settlement)이 실행됨
Object result = agent.processSingleAction("Settle claim CLM-12345 for $8000, approved by Vishal",
settle, new AdjusterApproval(true), new LogginggExplainDecision());
// -> SETTLED CLM-12345 for $8000.0 approved by Vishal
@Action에riskLevel = HIGH가 선언되어 있기 때문에, 1단계에서의 자동 예측 거부(auto-prediction refusal)가 추가 코드 없이 작동합니다.
...
// 에이전트 툴킷(com.t4a.agent.*)이 포함된 Tools4AI 빌드가 필요합니다.
AuditTrail trail = new JsonFileAuditTrail("/var/claims/audit.jsonl");
AIProcessor audited = new AuditedActionProcessor(new OpenAiActionProcessor(), trail);
audited.processSingleAction("File a claim on policy AUTO-88213 for a cracked bumper");
가용성 참고 사항: 에이전트 툴킷(agent toolkit)은 최신 Tools4AI 빌드의 일부이며, 모든 Maven Central 배포 버전에 포함되어 있지 않을 수 있습니다. 임포트(import)하기 전에 해결된 jar 파일에
com.t4a.agent.*가 존재하는지 확인하십시오. 위의 InsureJAI 데모는 코어(core) 전용을 사용하므로, 게시된 아티팩트(artifact) 그대로 빌드됩니다. 멀티 턴(multi-turn) 청구의 경우, 동일한 툴킷의AgentMemory/PersistentFileAgentMemory를 사용하여 턴과 재시작 간의 대화 컨텍스트(conversation context)를 유지할 수 있습니다.
...
java
AIProcessor claimsAgent =
new AuditedActionProcessor( // 최종 결과 기록
new MeteredActionProcessor( // 지연 시간 + 오류율 측정
new RiskGatedActionProcessor( // 고위험 정산 건에 대한 인간 승인 필요
new RetryActionProcessor( // 일시적인 모델 오류에서 생존
new OpenAiActionProcessor(), // -> 로컬 Ollama 모델 사용
3, 500, null),
new AdjusterApproval()),
metrics),
new JsonFileAuditTrail("/var/claims/audit.jsonl"));
바깥쪽에서 안쪽으로 읽기(Reading outside-in): *최종* 결정 감사, *사용자에게 보이는* 지연 시간 측정, 승인 필요 *횟수 제한*(재시도당 아님), 그리고 모델에 가장 가까운 곳에서 일시적 실패 재시도. 레이어를 재배열하면 의미론이 변경되므로 신중하게 선택해야 합니다.
## 자주 묻는 질문
**청구 데이터가 제 네트워크를 벗어나나요?**
아니요. Ollama를 사용하면 모델이 로컬에서 실행되며 Tools4AI는 `http://localhost:11434`와 통신합니다. 호스팅된 API로 아무것도 전송되지 않습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기