Solo Project · AI Agent Pipeline

Momently

사진·여행 기록을 네이버 블로그용 한국어 글로 바꿔주는 멀티에이전트 파이프라인. Spring Boot 오케스트레이터가 FastAPI LLM 에이전트 10단계를 조율하고, React 운영 콘솔과 Chromium 발행 확장까지 E2E로 1인 개발. ADR 기반 문서화.

Spring BootFastAPI (Python)LLM AgentsReact 19SSEChrome ExtensionHexagonal + ArchUnit
GitHub Org 보기

핵심 기술 구현

LLM 에이전트 조율, 상태 머신 재개, 발행 자동화까지 — AI 파이프라인의 핵심 과제 해결

10단계 에이전트 파이프라인

사진 정보 추출(EXIF) → 개인정보 검수 → 품질 점수 → 사진 그룹화 → 대표 사진 → 개요 → 초안 → 문체 → 검수 → 메타/SEO. 각 단계를 독립 FastAPI 에이전트로 분리.

상태 머신 + 재개

WorkflowStateMachine이 상태 전이를 검증하고 단계별 산출물 경로를 기록. FAILED 워크플로 재실행 시 완료된 단계의 아티팩트를 재사용해 비용이 큰 LLM 호출을 반복하지 않음.

SSE 실시간 진행 모니터링

React 콘솔이 SSE로 단계별 상태를 실시간 반영. Authorization 헤더가 필요해 EventSource 대신 fetch + ReadableStream으로 구현, 연결이 끊기면 폴링으로 자동 폴백.

안전·품질 게이트

개인정보 안전(privacy-safety) 에이전트가 민감 정보를 검수하고, 품질 점수(quality-score) 에이전트가 결과물 품질을 게이팅. 사람이 최종 편집·발행을 결정.

발행 패키지 + 브라우저 확장

제목·해시태그·메타 후보를 골라 본문과 묶은 발행 패키지 생성. Chromium 확장(Manifest V3)이 네이버 SmartEditor에 보조 입력해 발행 마찰 최소화.

Stub 어댑터 테스트 전략

@Profile("stub-agents")로 실제 HTTP·LLM 호출 없이 정해진 산출물로 전체 흐름을 검증. 헥사고날 패키지 경계는 ArchUnit 테스트로 강제.

아키텍처 하이라이트

01

Orchestrator-Worker 구조

다음 단계를 결정하는 주체는 항상 오케스트레이터, 에이전트는 자기 단계만 처리. 에이전트 자율 협상 대신 중앙 상태 머신으로 재현성·재개·비용 통제를 확보.

Spring orchestrator → FastAPI agents (HTTP + retry)
02

Hexagonal + 프로필 스왑

같은 포트에 stub 어댑터와 실 HTTP 클라이언트, InMemory와 Postgres 저장소를 프로필로 교체. 도메인은 순수 자바, 경계는 ArchUnit으로 CI에서 자동 검증.

@Profile("stub-agents") · @Profile("memory"|"postgres")
03

아티팩트 저장 전략

큰 JSON 산출물·블로그 문서는 DB 본문이 아닌 파이프라인 출력 폴더에 두고, DB에는 워크플로 메타데이터와 상태 기록만 보관. 재개 시 아티팩트 경로로 이어서 실행.

DB: metadata/state · FS: artifacts
04

비동기 실행 + 이중 전달 채널

워크플로 실행은 @Async로 즉시 반환하고, 진행 상태는 SSE 스트림 또는 폴링으로 조회. 콘솔은 연결 모드(live/polling)를 UI에 노출해 투명하게 동작.

@Async run → SSE(fetch stream) → polling fallback
10
Pipeline Steps
6+
LLM Agents
4
Apps (서버·콘솔·에이전트·확장)
ADR
Driven Docs

기술적 의사결정

DECISION 01

왜 중앙 오케스트레이터인가

에이전트끼리 자율 협의하는 구조는 재현·디버깅·비용 추적이 어려움. 상태 머신 기반 중앙 조율로 어떤 단계에서 무엇이 나왔는지 항상 추적 가능하고, 실패 지점부터 재개 가능.

DECISION 02

왜 아티팩트 재사용인가

LLM 호출은 파이프라인에서 가장 비싼 자원. 완료 단계 산출물을 파일로 남기고 재실행 시 재사용해, 후반 단계 실패가 전체 재비용으로 이어지지 않도록 설계.

DECISION 03

왜 Stub 프로필인가

LLM이 낀 파이프라인은 테스트가 느리고 비결정적. 포트 단위 stub 어댑터로 흐름·상태 전이를 결정적으로 검증하고, 실 에이전트 연동은 프로필 전환만으로 테스트.

DECISION 04

왜 EventSource가 아닌 fetch 스트림인가

JWT 무상태 인증에서 SSE에 Authorization 헤더를 실어야 하는데 EventSource는 커스텀 헤더 불가. fetch + ReadableStream으로 직접 파싱하고, 끊김 시 폴링 폴백으로 신뢰성 확보.