AMZN Mktp US가 3개월 치 보고서를 조용히 망쳐놓기 전까지는 내 금융 에이전트가 똑똑하다고 생각했다
요약
금융 자동화 에이전트 구축 시 발생하는 분류 오류 사례를 통해, 자율성보다 신뢰성이 중요함을 강조합니다. 모호한 데이터(판매자 문자열)를 처리할 때 LLM이 확신 없이 불확실성을 보고하도록 설계해야 함을 조언합니다.
핵심 포인트
- 유효한 JSON 출력이 반드시 올바른 판단을 의미하지는 않음
- 자율성(Autonomy)보다 불확실성을 인지하는 설계가 중요함
- 모호한 데이터에 대해 '확신 없음'을 반환하는 에이전트가 더 신뢰할 수 있음
- LLM 기반 자동화 파이프라인 구축 시 실패 모드 주의 필요
AMZN Mktp US가 3개월 치 보고서를 조용히 망쳐놓기 전까지는 내 금융 에이전트가 똑똑하다고 생각했다
AMZN Mktp US가 은행 알림에 나타났습니다.
내 에이전트는 그것을 software라고 자신 있게 분류했습니다.
그 단 한 번의 잘못된 추측이 내가 알아차리기 전까지 3개월 치 카테고리 합계를 오염시켰습니다.
짜증 나는 점은, 자동화 자체는 훌륭해 보였다는 것입니다.
- Gmail 알림 수신
- n8n이 이를 가져옴
- GPT-5.4가 판매자(merchant) + 금액을 JSON으로 추출
- PostgreSQL에 행(row) 저장
- Google Sheets가 대시보드 업데이트
깔끔한 파이프라인. 유효한 JSON. 충돌 없음.
하지만 틀렸습니다.
해당 구매는 소프트웨어가 아니라 Amazon에서 구매한 무작위 생활용품이었습니다. 하지만 내가 에이전트를 회의적인 비서가 아닌, 아주 작은 '척척박사'처럼 만들었기 때문에, 지저분한 판매자 문자열(merchant strings)에 대해 계속해서 같은 종류의 실수를 저질렀습니다.
그 사건은 금융 에이전트에 대한 나의 생각을 바꾸어 놓았습니다.
솔직히 말해서, 에이전트 설계 전반에 대한 나의 생각을 바꾸어 놓았습니다.
내가 실제로 신뢰할 수 있는 첫 번째 금융 에이전트는 모든 것을 자동으로 분류하는 에이전트가 아닙니다. _"이 항목에 대해서는 확신이 없습니다."_라고 말하는 에이전트입니다.
다른 개인 자동화 설정들을 살펴보던 중, Coolify를 사용하여 VPS에서 OpenClaw를 실행하는 것에 관한 이 r/openclaw 스레드를 접하게 되었습니다. 사용 사례는 다르지만 교훈은 같습니다. LLM을 당신의 삶에 연결할 수 있다고 해서, 자율형(autonomous) 버전이 반드시 좋은 버전이라는 뜻은 아닙니다.
진짜 버그: 판매자 문자열은 쓰레기다
인간은 종종 기억을 통해 AMZN Mktp US가 무엇을 의미하는지 추론할 수 있습니다.
모델은 그렇게 할 수 없습니다. 적어도 신뢰할 수 있는 방식으로는 말이죠.
그 문자열은 다음과 같은 것들을 의미할 수 있습니다:
- 도서
- 배터리
- HDMI 케이블
- 사무용품
- 식료품
- 커피 그라인더
만약 당신이 GPT-5.4, Claude Opus 4.6, 또는 Grok 4.20에게 매번 카테고리를 선택하도록 강요한다면, 당신은 지능을 구축하고 있는 것이 아닙니다.
당신은 자신감 넘치는 오류 생성기(error generator)를 만들고 있는 것입니다.
그것이 나의 실수였습니다. 나는 자율성(autonomy)을 최우선으로 최적화했습니다.
원래의 워크플로우
이것이 첫 번째 버전이었습니다:
Gmail 은행 알림
-> n8n 이메일 트리거 (email trigger)
-> GPT-5.4 추출 (extraction) + 분류 (categorization)
...
그리고 페이로드 (payload)는 다음과 같은 모습이었습니다:
{
"merchant": "AMZN Mktp US",
"amount": 47.18,
...
아무것도 고장 나지 않았습니다.
바로 그 점이 이러한 유형의 워크플로우 (workflow)가 위험한 이유입니다.
JSON은 유효했습니다. 파이프라인 (pipeline)은 성공했습니다. 구조화된 출력 (Structured Outputs)은 제 역할을 다했습니다.
하지만 유효한 JSON이 올바른 판단과 동일한 것은 아닙니다.
만약 여러분이 n8n, Make, Zapier, OpenClaw 또는 커스텀 OpenAI 호환 스택 (OpenAI-compatible stack)에서 자동화 (automations)를 구축하고 있다면, 이것이 바로 주의해야 할 실패 모드 (failure mode)입니다.
무서운 워크플로우는 요란하게 충돌하며 멈추는 것이 아닙니다.
틀린 채로 완벽하게 실행되는 워크플로우가 진짜 무서운 것입니다.
금융 데이터에 있어 완전한 자율성 (full autonomy)이 잘못된 목표인 이유
완전 자율형 분류기 (autonomous categorizer)는 마찰 (friction)을 제거해주기 때문에 우아하게 느껴집니다.
- 검토 대기열 (review queue) 없음
- 중단 없음
- 인간의 승인 단계 없음
- 지저분한 예외 상황 (edge-case) 처리 없음
하지만 그러한 설계는 금융 데이터에 있어 더 나쁩니다.
단 하나의 잘못된 라벨 (label)이 복리로 쌓입니다.
만약 LLM이 고객 지원 티켓 (support ticket)을 잘못 읽는다면, 누군가가 약간 어색한 답변을 받을 뿐일지도 모릅니다.
하지만 만약 LLM이 반복적인 거래 (recurring transactions)를 잘못 분류한다면, 여러분의 보고 계층 (reporting layer)은 허구가 되어버립니다.
그것은 훨씬 더 비용이 많이 드는 실패입니다.
더 나은 패턴: 신뢰할 수 있는 추출, 신중한 분류
몇 가지 설정을 테스트한 후, 나는 "어떤 모델이 가장 똑똑한가?"를 신경 쓰는 대신 워크플로우의 경계 (workflow boundaries)를 신경 쓰기 시작했습니다.
나의 결론은 다음과 같습니다:
- GPT-5.4는 은행 알림 이메일로부터 일관된 추출 (extraction)을 수행하는 데 강력했습니다.
- Claude Opus 4.6은 불확실성 (uncertainty)에 대한 추론 (reasoning)이 필요할 때 종종 더 나았습니다.
- Grok 4.20은 괜찮았지만, 더 엄격한 '추출 후 분류(extraction-plus-triage)' 흐름보다 이 작업에 더 낫지는 않았습니다.
승자는 단일 모델이 아니었습니다.
승자는 워크플로우였습니다.
패배한 설계는 다음과 같았습니다:
모든 결제 건을 자동으로 분류한다
승리한 설계는 다음과 같았습니다:
신뢰할 수 있게 추출하고, 신뢰도 (confidence)가 높을 때만 분류하며, 나머지는 검토 (review)로 보낸다
덜 마법 같지만,
훨씬 더 유용합니다.
재설계: 첫 번째는 은행 알림 이메일, 두 번째는 PostgreSQL, 마지막은 스프레드시트
해결책은 "더 많은 지능을 추가하는 것"이 아니었습니다.
해결책은 "표면적(surface area)을 줄이는 것"이었습니다.
1단계: 은행 알림 이메일만 모니터링하기
저는 가능한 모든 금융 신호를 수집하려는 시도를 중단했습니다.
이제 워크플로(workflow)는 특정 Gmail 라벨(label)이나 발신자 패턴만 모니터링합니다.
수신함 전체가 아닙니다.
CSV 덤프(dumps)도 아닙니다.
다섯 군데 소스에서 전달된 영수증도 아닙니다.
개인적인 설정의 경우, 다음과 같이 간단할 수 있습니다:
Gmail label: bank-alerts
n8n에서는 더 좁은 트리거(trigger)를 의미합니다.
Make, Zapier, OpenClaw 또는 커스텀 워커(custom worker)에서도 개념은 동일합니다. 모델이 확인하기 전에 노이즈가 섞인 입력값(noisy inputs)을 줄이는 것입니다.
2단계: PostgreSQL이 기록 시스템(system of record)이 되다
이것은 그 어떤 프롬프트(prompt) 수정보다 더 중요했습니다.
저는 다음과 같은 구조를 먼저 저장하기 시작했습니다:
create table transactions (
id bigserial primary key,
raw_email_id text unique not null,
...
그 결정 하나가 많은 것을 해결했습니다:
- 동일한 트랜잭션(transaction)의 반복적인 파싱(parsing) 방지
- 데이터베이스인 척하는 스프레드시트(spreadsheet) 방지
- 재분류 루프(reclassification loops) 방지
- 제안된 카테고리와 승인된 카테고리 간의 명확한 분리
스프레드시트는 뷰(view)가 되었습니다.
두뇌가 아니라 말입니다.
무엇을 자동화하고 무엇을 검토로 보낼 것인가?
이것이 실제 설계 질문입니다.
다음과 같은 질문이 아닙니다:
- 어떤 모델이 가장 좋은가?
- 어떻게 하면 100% 자율적으로 만들 수 있는가?
- 어떻게 하면 더 예쁜 JSON을 얻을 수 있는가?
유용한 질문은 다음과 같습니다:
어느 지점에서 확실성이 자동화하기에 충분히 높으며, 어느 지점에서 모호함이 프로세스를 멈춰야 하는가?
저의 현재 규칙 세트는 간단합니다.
자동 승인 (Auto-approve)
- 안정적인 이력이 있는 명확한 이름의 가맹점(merchants)
- 이전에 이미 승인한 정기 결제 항목
- 확신을 가지고 매핑할 수 있을 만큼 충분한 컨텍스트(context)가 있는 알림
검토로 전송 (Send to review)
AMZN Mktp US와 같은 모호한 문자열- 처음 보는 가맹점
- 설명이 불완전한 대기 중인 트랜잭션
- 모델의 설명이 추측처럼 들리는 모든 경우
이 검토 체크포인트(checkpoint)가 제품의 핵심입니다.
이것이 없다면, 에이전트(agent)는 그저 서식이 깔끔한 스프레드시트 파괴자에 불과합니다.
실용적인 분류 계약 (A practical classification contract)
만약 제가 오늘날 이 기능을 깔끔하게 구현한다면, 모델이 불확실성 (uncertainty)을 명시적으로 반환하도록 강제할 것입니다.
다음과 같은 방식 말이죠:
{
"merchant": "AMZN Mktp US",
"amount": 47.18,
...
이것은 가짜 정밀도 (fake precision)보다 훨씬 더 나은 결과입니다.
n8n 의사결정 로직 예시 (Example n8n decision logic)
이것이 바로 제가 처음부터 적용했기를 바랐던 종류의 분기 로직 (branching logic)입니다.
const confidence = $json.confidence_score ?? 0;
const ambiguous = $json.ambiguity_flag === true;
const firstSeenMerchant = $json.first_seen_merchant === true;
...
그런 다음 review를 다음으로 라우팅합니다:
- Slack 메시지
- 작은 내부 검토 UI
- Airtable 큐 (queue)
- Notion 데이터베이스
- 정 필요하다면 간단한 Google Sheet 탭
핵심은 우아함이 아닙니다.
핵심은 조용한 데이터 오염 (silent corruption)을 방지하는 것입니다.
이 아키텍처가 토큰 사용량도 줄여주는 이유
이것은 기분 좋은 놀라움이었습니다.
제가 발견한 LLM 사용량을 줄이는 가장 좋은 방법은 더 나은 프롬프팅 (prompting)이 아니었습니다.
그것은 더 나은 경계 (boundaries)를 설정하는 것이었습니다.
1. 좁은 트리거 (Narrow triggers)
은행 알림 이메일만 모니터링하는 것은 모델 호출 (model calls) 횟수를 줄여줍니다.
2. 한 번만 추출 (Extract once)
구조화된 결과 (structured results)를 저장하고, 모델이 동일한 사실을 다시 발견하도록 요청하는 것을 중단하십시오.
3. 상태 재사용 (Reuse state)
PostgreSQL은 다른 LLM 호출보다 "이 가맹점을 이전에 본 적이 있는가?"라는 질문에 더 빠르고 저렴하게 답할 수 있습니다.
4. 모호함을 유효한 출력으로 취급 (Treat ambiguity as valid output)
모델이 확신하지 못한다면 거기서 멈추십시오.
파이프라인 (pipeline)이 완성된 것처럼 보이게 하려고 억지로 카테고리를 지정하지 마십시오.
토큰당 비용을 지불하고 있다면 이 점은 더욱 중요합니다
많은 개발자가 실수로 다음과 같이 비용이 많이 드는 에이전트 루프 (agent loops)를 구축합니다:
새 이메일 도착
-> 모델 호출
-> 행(row) 쓰기
...
이것이 바로 작은 자동화가 비용 누수 (cost leak)로 변하는 방식입니다.
만약 n8n, Make, Zapier, OpenClaw 또는 커스텀 OpenAI 호환 워크플로우 (workflow)에서 에이전트를 지속적으로 실행하고 있다면, 아키텍처는 프롬프트의 영리함보다 더 중요합니다.
그리고 토큰당 과금 방식에 묶여 있다면, 모든 불필요한 재처리 단계는 두 배의 타격을 줍니다:
- 더 많은 비용
- 모델이 확신을 가지고 틀릴 (confidently wrong) 확률 증가
이것이 바로 상시 가동되는 자동화(always-on automations)를 위해 정액제 컴퓨팅(flat-rate compute)이 매력적인 정확한 이유입니다. 라우팅(routing), 재시도(retries), 검토 큐(review queues), 구조화된 추출(structured extraction)을 반복할 때, 워크플로우를 개선할 때마다 토큰 비용에 대한 불안감(token anxiety)을 느끼는 것은 가장 피하고 싶은 상황이기 때문입니다.
저는 모든 것을 다시 작성하지 않고도 제공업체를 교체할 수 있는 OpenAI 호환 설정을 테스트하면서 이 점에 대해 더 깊이 고민해 왔습니다. 그런 맥락에서 Standard Compute는 흥미로운데, 월 정액제로 OpenAI 호환 엔드포인트(endpoint)를 제공하기 때문입니다. 이는 개발자들이 실제로 에이전트를 구축하는 방식, 즉 수많은 재시도, 수많은 오케스트레이션(orchestration), 수많은 백그라운드 실행, 그리고 예상치 못한 청구(surprise billing)를 참을 수 없는 방식에 딱 들어맞습니다.
현재 제가 추천하는 최소한의 아키텍처 (Minimal architecture)
만약 제가 이것을 처음부터 다시 구축해야 한다면, 저는 지루하게 유지할 것입니다.
Gmail 은행 알림
-> n8n 트리거
-> LLM 추출
...
이 설계는 다음과 같습니다:
- 더 저렴함
- 더 차분함
- 디버깅(debug)이 더 쉬움
- 조용히 오염(poison)시키기가 훨씬 더 어려움
빠른 구현 스케치 (Quick implementation sketch)
검토 쿼리 예시 (Example review query)
select
id,
merchant_string,
...
가맹점 이력 조회 예시 (Example merchant history lookup)
select final_category, count(*) as usage_count
from transactions
where merchant_string = $1
...
승인 업데이트 예시 (Example approval update)
update transactions
set final_category = $2,
review_status = 'approved',
...
에이전트 빌더를 위한 더 넓은 교훈
이것은 사실 개인 금융에 관한 것이 아닙니다.
이것은 에이전트 아키텍처(agent architecture)에 관한 것입니다.
동일한 규칙이 다음 항목에도 적용됩니다:
- 송장 라우팅 (invoice routing)
- 리드 자격 검증 (lead qualification)
- 지원 분류 (support triage)
- 조달 워크플로우 (procurement workflows)
- 내부 운영 자동화 (internal ops automations)
입력값이 무질서할 때, 불확실성(uncertainty)은 일급 출력(first-class output)이 되어야 합니다.
만약 당신의 에이전트가 항상 확신에 찬 것처럼 말하도록 강요받는다면, 결국 매우 세련된 방식으로 당신에게 거짓말을 하게 될 것입니다.
그것이 바로 버그(bug)입니다.
제 금융 에이전트의 이전 버전은 데모(demo)에서 더 좋아 보였습니다.
하지만 새로운 버전은 제가 실제로 신뢰할 수 있는 버전입니다.
금융 에이전트 (finance agent)에서 LLM 사용량을 줄이는 가장 좋은 방법은 에이전트를 더 자율적으로 만드는 것이 아닙니다. 오히려 더 회의적(skeptical)으로 만드는 것입니다. 즉, 은행 알림 이메일(bank-alert emails)만 모니터링하고, 구조화된 결과(structured results)를 PostgreSQL에 저장하며, 모호한 결제 내역(ambiguous charges)은 단 하나의 잘못된 레이블(label)이 수개월 치의 데이터를 오염시키기 전에 검토 단계로 보내는 것입니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기