AWS 기술 블로그
한 줄 프롬프트에서 그래프 기반 Agent로: Amazon Bedrock AgentCore 기반 ZEP의 교육용 퀴즈 생성 아키텍처
젭(ZEP) 소개
젭은 온라인 메타버스 플랫폼 ZEP을 운영하는 스타트업입니다. ZEP은 사용자들이 온라인 공간에서도 자연스럽게 만나고 소통할 수 있는 경험을 제공하며, 오프라인의 물리적 제약을 넘어 다양한 활동이 이루어질 수 있는 환경을 만들어가고 있습니다.
ZEP은 400만 MAU 규모의 서비스 환경에서 WebRTC 기술을 내재화해 안정적인 동시 스트리밍 경험을 제공하고 있으며, 대규모 동시 접속과 상호작용을 처리하는 게임 서버, 웹 기반 공간 경험을 구현하기 위한 Phaser 렌더링 등 실시간성과 확장성이 중요한 기술 스택을 적극적으로 활용하고 있습니다. 젭은 이러한 기술적 기반 위에서 메타버스 플랫폼의 사용자 경험을 고도화하는 동시에, 조직 내부적으로도 AX(AI Transformation)를 추진하며 AI를 통한 제품 혁신을 이어가고 있습니다.
젭퀴즈(ZEP QUIZ) 소개
젭퀴즈(ZEP QUIZ)는 ZEP 플랫폼을 기반으로 한 AI 에듀테크 서비스입니다. 선생님들이 양질의 학습 콘텐츠와 평가 문항을 빠르게 생성할 수 있도록 돕고, 학생들에게는 메타버스 기반의 게임 요소를 활용한 몰입감 있는 학습 경험을 제공합니다.
젭퀴즈는 교육적 맥락을 이해하는 AI 에이전트를 중심으로 문제 생성, 학습 데이터 기반 개인화, LMS(Learning Management System) 확장 등을 고도화하고 있습니다. 이를 통해 단순한 문제 생성 도구를 넘어, 선생님에게는 수업 준비의 효율성을, 학생에게는 더 재미있고 효과적인 학습 경험을 제공하는 AI 에듀테크 플랫폼으로 발전하고자 합니다.
도메인 이해도가 충실한 AI 에이전트를 여러 실행 레이어에서 운영하기
생성형 AI로 퀴즈를 만든다고 하면 처음에는 단순한 자연어 생성 문제처럼 보입니다.
“중학교 과학 단원으로 객관식 5문제를 만들어줘.”
LLM은 이 요청만으로도 꽤 그럴듯한 문제를 생성합니다. 하지만 실제 제품 환경에서는 “그럴듯한 문제”만으로 충분하지 않았습니다. ZEP의 퀴즈 생성 시스템이 다루는 문제는 단순한 텍스트 생성이 아니라, 학습자의 이해 상태를 확인하기 위한 평가 문항 생성입니다.
운영 과정에서 특히 중요했던 제약은 네 가지였습니다.
|
제약 |
설명 |
| 오답 품질 | 오답은 임의의 틀린 문장이 아니라 학생이 실제로 가질 법한 오개념을 반영해야 함 |
| 난이도 보정 | 같은 개념도 학년과 인지 수준에 따라 요구되는 사고 과정이 달라짐 |
| 성취기준 연계 | 문항이 어떤 교육 목표를 평가하는지 명확해야 함 |
| 검증 가능성 | 정답 유일성, 근거 정합성, 연령 적합성을 구조적으로 확인할 수 있어야 함 |
처음에는 이 조건들을 프롬프트에 계속 추가했습니다. 하지만 조건이 많아질수록 프롬프트는 길어졌고, 실행 흐름은 여전히 한 번의 생성에 머물렀습니다.
결국 필요한 것은 더 긴 프롬프트가 아니라, 문제 생성 과정을 단계별로 나누고 각 단계의 판단을 명시하는 구조였습니다. ZEP의 퀴즈 생성 Agent는 이 지점에서 단일 프롬프트 기반 생성에서 LangGraph 기반 워크플로우로 진화했습니다.
LangGraph는 LLM 애플리케이션의 실행 흐름을 노드와 엣지로 구성해, 상태를 유지하면서 복잡한 에이전트 워크플로우를 명시적으로 제어할 수 있게 해주는 프레임워크입니다.
그리고 LangGraph로 정리된 하나의 생성 로직은 Amazon Bedrock AgentCore Runtime 위에서 두 가지 실행 모드로 확장됐습니다. AgentCore Runtime은 에이전트 애플리케이션을 컨테이너 기반 런타임으로 실행하고, API 호출을 통해 안전하게 호출·격리·확장할 수 있게 해주는 AWS의 관리형 런타임입니다.
- 프로덕션 실시간 서빙: 유저 요청에 따라 실시간으로 퀴즈를 생성하는 경로
- 백그라운드 배치 파이프라인: 신규 국가·신규 콘텐츠를 위한 대량 시드 퀴즈를 background에서 생성하고 평가하는 경로
LangGraph와 AgentCore runtime의 관계
이 글에서는 ZEP의 퀴즈 생성 시스템이 어떻게 교육 도메인의 제약을 LangGraph의 노드, 상태, 스키마로 표현하고, AgentCore Runtime을 통해 같은 그래프를 여러 실행 모드로 운영할 수 있게 되었는지 소개합니다.
1. 왜 단일 프롬프트로는 부족했는가
단일 프롬프트 방식은 빠르게 시작할 수 있다는 장점이 있습니다. 하지만 퀴즈 생성이 제품 기능이 되는 순간, 조건을 나열하는 것만으로는 품질을 안정적으로 유지하기 어려웠습니다.
1.1 조건은 늘어나지만 실행 흐름은 하나다
프롬프트에는 다음과 같은 요구사항이 계속 추가됩니다.
- 객관식으로 만들어줘- 난이도는 중간으로 해줘- 학생 수준에 맞춰줘- 오답은 그럴듯하게 만들어줘- 해설도 넣어줘- 성취기준을 반영해줘- 근거 없는 내용은 만들지 마- 정답은 하나만 있어야 해 |
이 조건들은 모두 중요합니다. 하지만 한 번의 생성 요청 안에 모두 넣으면, 모델이 어떤 순서로 판단해야 하는지 명확하지 않습니다.
예를 들어 “오답을 그럴듯하게 만들라”는 조건과 “학생 수준에 맞추라”는 조건은 서로 영향을 줍니다. 난이도를 높이기 위해 오답을 너무 정교하게 만들면 교육 과정을 벗어날 수 있고, 반대로 학생 수준에만 맞추면 오답이 너무 쉽게 제거될 수 있습니다.
따라서 각 조건은 단순한 프롬프트 문장이 아니라, 별도의 판단 단계로 분리되어야 했습니다.
1.2 품질 판단은 생성과 분리되어야 한다
LLM은 문항을 생성할 수 있지만, 그 문항이 교육적으로 좋은지까지 자동으로 보장하지는 않습니다. 특히 다음 항목은 생성 이후의 검증이 필요합니다.
|
검증 항목 |
예시 |
| 정답 유일성 | 선택지 중 정답이 하나만 존재하는가 |
| 오답 매력도 | 오답이 너무 터무니없거나 쉽게 제거되지 않는가 |
| 오개념 정합성 | 오답이 실제로 발생 가능하며 변별력이 있는 오개념에 기반하는가 |
| 난이도 적합성 | 난이도가 적당한 인지 능력을 요구하는가 |
| 근거 정합성 | 입력 자료 또는 성취기준과 모순되지 않는가 |
| 안전성 | 학생 대상 서비스에 부적절한 표현이 없는가 |
이 검증을 사람이 매번 수행하면 제품 확장성이 떨어집니다. 따라서 ZEP은 생성 그래프 내부에서는 구조적 검증을 수행하고, 교육적 타당성 평가는 별도의 batch 워크로드로 분리해 운영할 수 있는 구조를 선택했습니다.
2. 전체 아키텍처 개요
ZEP의 퀴즈 생성 아키텍처는 크게 두 계층으로 나뉩니다.
- 로직 레이어: LangGraph
- 문제 생성의 도메인 로직을 담당합니다.
- 노드(node), 엣지(edge), 상태(state), 스키마(schema)로 생성 과정을 명시합니다.
- SDK나 인프라에 의존하지 않는 순수 비즈니스 그래프로 유지합니다.
- 실행 레이어: Amazon Bedrock AgentCore Runtime
- 그래프 코드를 컨테이너로 감싸 실행합니다.
- InvokeAgentRuntime API를 통해 원격 함수처럼 호출됩니다.
- 인증, 실행 격리, 스케일, 트레이스 전파 등 인프라 관심사를 담당합니다.
퀴즈 생성은 요구되는 품질과 응답 속도에 따라 thorough와 fast 두 가지 모드로 구분됩니다. thorough 모드는 Amazon Bedrock AgentCore Runtime에 배포된 컨테이너에서 Amazon Bedrock의 Claude Sonnet 4.6(global.anthropic.claude-sonnet-4-6)을 호출하며, 복합적인 교육 문맥 해석과 안정적인 구조화된 출력을 우선합니다.
반면 fast 모드는 FastAPI 애플리케이션 프로세스 내부에서 타사 모델을 직접 호출해 짧은 응답 시간을 우선합니다.
| 생성 모드 | 실행 환경 | 호출 방식 |
| thorough | Amazon Bedrock AgentCore Runtime 컨테이너 | Claude Sonnet 4.6 Amazon Bedrock Runtime API |
| fast | FastAPI 애플리케이션 프로세스 내부 | 타사 모델 API 직접 호출 |
핵심 명제는 단순합니다.
One graph, multiple execution modes.
문제 생성 로직은 하나의 LangGraph로 유지하고, 실행 레이어만 분리해 프로덕션 서빙과 백그라운드 배치 생성을 동시에 운영한다.
ZEP 퀴즈 생성 에이전트 운영 아키텍처
위 다이어그램은 LangGraph 애플리케이션, AgentCore Runtime infra, 퀴즈 배치 생성, 그리고 OTel/Langfuse 계측 체계를 한 화면에서 함께 보여줍니다.
요청 흐름을 텍스트로 풀면 다음과 같습니다.
| FastAPI → InvokeAgentRuntime · SigV4 · boto3 → handler.handle_request → Pydantic validation → envelope normalization → lazy graph build → Langfuse callback attach → LangGraph StateGraph execution |
이 구조의 핵심은 로직과 실행의 분리입니다. LangGraph는 “무엇을 할 것인가”를 코드화하고, AgentCore Runtime은 “어디서 어떻게 실행할 것인가”를 담당합니다.
3. 문제 생성 그래프 설계
AgentCore Runtime에 올릴 실행 단위는 단일 프롬프트가 아니라 LangGraph로 구성된 문제 생성 워크플로우입니다.
이 그래프의 책임은 네 가지입니다. 이 글에서는 내부 노드 구조를 세세하게 풀기보다, Runtime 위에 올라가는 실행 간단히 설명합니다.
|
책임 |
설명 |
| 컨텍스트 구성 | 주제·파일·웹사이트·유튜브·성취기준을 문제 생성에 사용할 컨텍스트로 정리 |
| 문제 유형 별 서브그래프 Fan-out | OX·객관식·주관식 생성 경로로 분기 |
| 구조적 검증 | 스키마, 정답 인덱스, 선택지 수, 문항 수 검증 |
| 결과 병합 | 유형별 생성 결과를 하나의 구조화된 응답으로 병합 |
교육적 타당성, 오답 품질, 난이도 적합성과 같은 평가(evaluation)은 현재 생성 그래프 내부가 아니라 별도의 배치 생성 파이프라인에서 수행합니다. 이 경계 덕분에 프로덕션 서빙은 빠른 구조적 검증에 집중하고, 백그라운드의 퀴즈 배치 생성 파이프라인은 더 무거운 품질 평가를 수행할 수 있습니다.
퀴즈 생성 그래프 구조
4. AgentCore Runtime 적용기
LangGraph는 “무엇을 할 것인가”를 코드화합니다. 하지만 제품 환경에서는 “어디서, 어떻게 실행할 것인가”도 중요합니다.
ZEP의 퀴즈 생성 그래프는 Amazon Bedrock AgentCore Runtime 위에서 실행됩니다. Runtime은 그래프 코드를 컨테이너로 감싸고, FastAPI 애플리케이션은 InvokeAgentRuntime API를 통해 원격 함수처럼 호출합니다.
애플리케이션부터 에이전트 호출까지의 흐름
4.1 Entrypoint Shim
Runtime과 LangGraph의 결합도를 낮추기 위해, 앱과 인프라의 접점은 entrypoint shim으로 제한했습니다.
|
이 파일은 Runtime SDK와 애플리케이션 로직 사이의 얇은 어댑터입니다. 실제 비즈니스 로직은 handle_request와 LangGraph 내부에 있습니다.
이 구조의 장점은 다음과 같습니다.
| 테스트 용이성 | LangGraph 비즈니스 로직을 Runtime SDK와 분리해 단위 테스트할 수 있습니다. |
| 실행 환경 독립성 | Runtime 교체나 로컬 실행이 필요해도 애플리케이션 로직의 변경 범위를 최소화할 수 있습니다 |
| 관심사 분리 | 인프라 실행 책임과 퀴즈 생성 도메인 로직을 명확히 분리합니다. |
| 초기화 경계 명확화 | 컨테이너 부팅과 그래프 의존성 로딩 시점을 분리해 초기화 과정을 제어할 수 있습니다. |
4.2 Lazy Graph Build
그래프는 컨테이너 시작 시점이 아니라 첫 요청 처리 시점에 lazy build합니다.
|
이 방식은 무거운 의존성 로딩을 entrypoint import 시점에서 분리합니다. 특히 멀티 컨테이너 토폴로지에서는 각 Runtime의 책임이 다르므로, 필요한 의존성만 해당 Runtime에서 로드하도록 경계를 유지하는 것이 중요했습니다.
4.3 Envelope Response
Runtime 호출은 네트워크와 컨테이너 경계를 넘습니다. 따라서 예외가 발생했을 때 호출 측이 매번 HTTP 상태 코드만 보고 해석하게 만들면, 제품 코드가 복잡해집니다.
이에 Runtime 응답을 항상 ok 플래그를 포함한 일관된 envelope로 반환합니다. 그래프 결과 키는 envelope 최상위에 그대로 병합되고, 여기에 핸들러 메타가 부착됩니다.
|
실패 시에도 동일한 형태가 유지되며, error 필드에 실패 사유가 담깁니다.
|
이렇게 하면 FastAPI는 Runtime 실패를 무조건 502로 취급하지 않고, ok 플래그와 error 사유를 보고 제품이 이해할 수 있는 구조화된 실패로 처리할 수 있습니다.
5. 2-Runtime + MCP 토폴로지
초기에는 하나의 Runtime 안에서 모든 작업을 처리하는 구성이 단순해 보였습니다. 하지만 퀴즈 생성 워크플로우에는 성격이 다른 작업들이 섞여 있었습니다.
- 메인 생성 그래프 실행
- 웹 검색
- 교육과정 성취기준 조회
- 파일 추출
- 웹사이트 스크래핑
- 유튜브 자막 추출
이 작업들은 실패 가능성, 지연 시간, 인증 정보, 스케일 패턴이 서로 다릅니다. 따라서 ZEP은 Runtime과 Tool layer를 분리했습니다.
5.1 Primary Runtime: quiz_builder
quiz_builder Runtime은 메인 LangGraph를 호스팅합니다.
책임은 다음과 같습니다.
- 사용자 요청 검증
- augmented context 수신
- 문제 유형별 fan-out 및 생성
- 구조적 검증 및 문항 수 보정
- 결과 병합 및 구조화 출력
이 Runtime은 가능한 한 순수한 생성/검증 책임을 유지합니다. 외부 IO나 느린 검색 로직은 직접 들고 있지 않습니다.
5.2 Secondary Runtime: web_search
web_search Runtime은 검색 전용 컨테이너입니다.
책임은 다음과 같습니다.
- 검색 필요 여부 판단
- 검색 키워드 추출
- Wikipedia, DuckDuckGo, Tavily 등 fallback chain 실행
- 검색 결과 정리
- 메인 그래프에 전달할 web_context 구성
검색은 지연 시간이 길고 실패 가능성이 높습니다. 또한 검색용 API key 또는 LLM key를 별도로 가질 수 있습니다. 따라서 메인 생성 Runtime과 분리하면 장애 전파를 줄이고 credential scope를 좁힐 수 있습니다.
5.3 MCP Tool Server
MCP server는 IO tool을 담당합니다.
|
Tool |
역할 |
| fetch_standards | 교육과정 성취기준 조회 |
| file_extractor | 첨부 파일 텍스트 추출 |
| website_scraper | 웹사이트 본문 추출 |
| youtube_extractor | 유튜브 자막 및 본문 추출 |
MCP layer는 그래프가 외부 세계와 만나는 표준화된 도구 경계입니다. LangGraph는 도구가 어떻게 구현되어 있는지 몰라도, 명확한 contract를 통해 필요한 context를 요청할 수 있습니다.
5.4 이 토폴로지가 해결한 세 가지 격리
|
격리 |
설명 |
| IO 격리 | 느리고 실패 잦은 외부 IO가 메인 생성 그래프를 오염시키지 않음 |
| 자격 격리 | web_search만 별도 검색/LLM key를 보유하고, quiz_builder는 최소 권한으로 동작 |
| 스케일 격리 | 검색/추출 부하와 생성 부하를 독립적으로 확장 |
Runtime을 여러 개로 나눈 이유는 구조를 복잡하게 만들기 위해서가 아닙니다. 실패 양상과 스케일 특성이 다른 작업을 같은 컨테이너에 넣지 않기 위해서입니다.
6. 실행 레이어 분리가 가능케 한 것: 두 개의 병렬 워크로드
생성 로직과 실행 레이어를 분리한 가장 큰 실익은 “무엇을 바꿀 수 있는가”보다 “무엇을 동시에 돌릴 수 있는가”에 있었습니다.
동일한 LangGraph 생성 그래프를 성격이 다른 두 워크로드로 병렬 운영할 수 있었기 때문입니다.
6.1 워크로드 A: 프로덕션 실시간 서빙
첫 번째 워크로드는 실제 사용자 요청을 처리하는 프로덕션 서빙 경로입니다.
|
User Request → FastAPI → AgentCore Runtime: quiz_builder → LangGraph → Structured Quiz Output |
이 경로에서 중요한 것은 지연 시간과 가용성입니다. 사용자는 요청을 보낸 뒤 실시간으로 퀴즈 생성 결과를 기다립니다. 따라서 불필요하게 긴 배치 생성 작업이나 공격적인 재시도, 대량 생성 부하가 이 경로에 섞이면 사용자 경험에 직접 영향을 줍니다.
6.2 워크로드 B: 백그라운드 퀴즈 배치 생성 파이프라인
두 번째 워크로드는 신규 국가 또는 신규 콘텐츠를 위한 백그라운드 대량 생성 파이프라인입니다.
|
Seed Job → AgentCore Runtime: quiz_builder → same LangGraph generation logic → generated quizzes → batch rubric evaluation → improvement candidates |
이 경로의 목적은 실시간 응답이 아니라 안정적인 배치 처리와 품질 측정입니다. 대량의 퀴즈를 생성하고, 루브릭 기반 평가를 병렬로 수행하며, 품질이 낮은 문항은 개선 대상으로 분류합니다. 개선 대상이 되는 문항의 경우 llm-as-a-judge의 피드백을 반영하여 재생성 루프에 들어갑니다.
두 워크로드는 요구 특성이 정반대입니다.
| A · 프로덕션 실시간 서빙 | B · 퀴즈 배치 생성 파이프라인 | |
| 트리거 | 사용자 요청 | 독립적인 배치 작업 |
| 핵심 지표 | 응답 속도와 가용성 | 처리량과 품질 |
| 부하 특성 | 짧은 시간에 집중되는 변동성 높은 부하 |
장시간 지속되는 대량 부하 |
| 실패 처리 | 사용자 경험을 고려해 제한적으로 재시도 | 재시도, 후처리, 재평가 가능 |
| 실행 목적 | 즉시 제공 가능한 퀴즈 생성 | 신규 시장·콘텐츠용 시드 확보 및 품질 측정 |
만약 실행 레이어가 애플리케이션 프로세스에 묶여 있었다면, B의 퀴즈 배치 생성 부하가 A 프로덕션 서빙의 지연 시간 지표를 흔들거나, 배치 생성을 위해 별도 생성 파이프라인을 새로 만들어야 했을 것입니다.
AgentCore Runtime으로 실행 레이어를 분리한 덕분에, 같은 코드베이스와 같은 LangGraph를 사용하면서도 두 워크로드를 간섭 없이 병렬 운영할 수 있었습니다.
6.3 같은 그래프, 다른 실행 환경, 서로 다른 워크로드 특성
이 구조의 핵심은 그래프를 복제하지 않는 것입니다.
하나의 그래프의 2가지 실행 모드
두 실행 모드는 같은 생성 로직을 공유합니다. 차이는 “어느 Runtime에서, 어떤 모드로, 어떤 운영 목적을 가지고 호출하는가”에 있습니다.
이 방식은 세 가지 장점을 만들었습니다.
- 워크로드 격리: 백그라운드 시드 생성의 대량 부하와 재시도가 프로덕션 서빙의 지연 지표와 가용성을 오염시키지 않습니다.
- 독립 스케일·배포·권한: 각 워크로드를 별도 Runtime 또는 별도 실행 경로로 분리해 독립적으로 스케일하고 배포할 수 있습니다.
- 동일 그래프 재사용: 프로덕션 서빙이든 백그라운드 시드든 생성 로직은 하나입니다. 새 국가 시드를 위해 별도의 생성 파이프라인을 다시 만들 필요가 없습니다.
6.4 실측 기반 운영 지표
프로덕션 서빙 경로는 실제 운영 트래픽을 그대로 받아냅니다. 다음은 약 3주 정도 가량 AgentCore Runtime을 통해 운영된 프로덕션 트래픽에 대한 실측치입니다. (Amazon CloudWatch, ap-northeast-2).
|
Runtime (prod) |
Invocations | Sessions | vCPU-Hr |
Memory (GB-Hr) |
| quiz_builder | 11,370 | 11,364 | 47.81 | 465.94 |
| mcp | 22,648 | 5,665 | 25.40 | 565.79 |
| web_search | 5,792 | 5,792 | 20.58 | 49.01 |
| 합계 | 39,810 | 22,821 | 93.79 | 1,080.74 |
이와 달리 같은 그래프를 공유하는 백그라운드 경로는 실시간 응답보다 대량 처리와 품질 측정을 목표로 합니다.
백그라운드 시드 파이프라인은 생성 → 감사 → 개선 단계(self-improvement)로 이어집니다.
같은 기간 프로덕션과 동일한 기준(AgentCore Runtime 실측, AWS CloudWatch, ap-northeast-2)으로 background 실행량을 측정하면 다음과 같습니다.
|
Runtime (background) |
Invocations | Sessions | vCPU-Hr |
Memory (GB-Hr) |
| quiz_builder | 2,179 | 2,115 | 14.30 | 1,159.62 |
| mcp | 36 | 9 | 0.04 | 1.35 |
| web_search | 2,229 | 2,156 | 8.03 | 69.23 |
| 합계 | 4,444 | 4,280 | 22.37 | 1,230.20 |
두 표를 비교하면, 동일한 LangGraph 생성 그래프가 프로덕션 서빙과 백그라운드 실행 경로에서 서로 다른 부하·자원 프로파일로 재사용되고 있음을 알 수 있습니다.
정리하면, “단일 프롬프트 →그래프 구조 전환”이 가치를 갖는 이유는 그래프가 깔끔해서만이 아닙니다. 그 그래프를 실행 레이어만 바꿔 여러 워크로드로 재사용할 수 있기 때문입니다.
7. 분산 추적과 Observability
Runtime이 여러 개로 분리되면 운영 관점에서 새로운 문제가 생깁니다.
“하나의 문제 생성 요청이 FastAPI, quiz_builder Runtime, web_search Runtime, MCP server, LLM 호출을 거쳤다면, 이 흐름을 하나의 트레이스로 볼 수 있는가?”
ZEP에서는 W3C traceparent를 payload에 직렬화해 Runtime 경계를 넘깁니다.
Runtime 사이의 분산화된 traces 관리
FastAPI에서는 root span을 시작하고, 현재 트레이스의 맥락을 페이로드에 주입합니다.
|
Runtime handler에서는 페이로드에서 컨텍스트 캐리어(carrier)를 추출하고 다음 실행 단위에 부착합니다.
|
Runtime이 다시 web_search Runtime이나 MCP server를 호출할 때도 같은 방식으로 트레이스 맥락을 전달합니다. 이렇게 하면 N단계 깊이의 Runtime 호출도 같은 root 트레이스 아래로 연결됩니다.
7.1 OTel과 Langfuse의 역할 분리
관측 도구도 목적에 따라 분리했습니다.
|
관측 대상 |
도구 |
확인하는 것 |
| 실행 트레이스 | OpenTelemetry → HyperDX | Runtime invoke, MCP, SigV4, latency, error |
| 로직 트레이스 | Langfuse | LangGraph node, LLM prompt, token, reasoning path |
| 백그라운드 | Langfuse / 내부 로그 | 생성, 평가, 배치 작업, 자가 개선 흐름 |
OTel은 컨테이너와 네트워크 경계를 포함한 실행 흐름을 보여줍니다. Langfuse는 LLM과 LangGraph 중심의 로직 트레이스를 보여줍니다.
특히 프로덕션 서빙과 백그라운드 배치 처리가 분리되면 observability는 더 중요해집니다. 두 워크로드가 같은 그래프를 공유하더라도 실행 목적과 부하 패턴이 다르기 때문에, 트레이스와 평가 로그를 통해 다음 질문에 답할 수 있어야 합니다.
- 어떤 요청이 어떤 Runtime 경로로 실행됐는가?
- 어떤 그래프의 노드(node)에서 시간이 많이 걸렸는가?
- LLM 호출과 tool 호출 중 병목은 어디였는가?
- 백그라운드 생성 파이프라인에서 어떤 평가·개선 단계가 반복되는가?
- 프로덕션 서빙과 백그라운드 생성 파이프라인의 실행 패턴 차이는 무엇인가?
실행 레이어를 분리하면 시스템은 더 유연해지지만, 그만큼 관측 경계도 명확히 설계해야 합니다.
8. 배운 점
이번 프로젝트의 핵심은 “LLM으로 문제를 생성했다”가 아닙니다. 교육 도메인의 제약을 LangGraph의 실행 흐름으로 정리하고, 이 그래프를 AgentCore Runtime 위에서 여러 실행 모드로 운영할 수 있게 만들었다는 점입니다.
한 줄 프롬프트로 시작한 문제 생성은 다음과 같은 구조로 진화했습니다.
| Prompt → Workflow → Graph → Runtime topology → Multiple execution modes → Observability |
8.1 도메인 제약은 프롬프트가 아니라 그래프가 되어야 한다
오답 품질, 난이도, 성취기준, 검증 가능성은 프롬프트 한 줄에 나열할 수는 있습니다. 하지만 제품 수준에서 안정적으로 보장하려면 상태, 노드, 스키마, 검증 단계로 분리되어야 합니다.
단일 프롬프트는 조건을 “말할” 수는 있지만, 조건들 사이의 판단 순서와 실패 처리 방식까지 안정적으로 보장하기는 어렵습니다. LangGraph는 이 판단 순서를 코드로 고정하고, 실패 시 어떤 경로로 되돌아갈지 명시할 수 있게 해줍니다.
8.2 실행 레이어 분리는 같은 그래프를 여러 워크로드로 만든다
AgentCore Runtime으로 실행 레이어를 인프라로 떼어내자, 같은 LangGraph 생성 로직을 프로덕션 서빙과 퀴즈 배치 생성 파이프라인으로 병렬 운영할 수 있었습니다.
이것이 실행 환경 분리의 가장 큰 실익이었습니다.
- 프로덕션 서빙은 빠른 제공과 가용성에 집중
- 퀴즈 대량 배치 생성은 처리량과 고품질 평가에 집중
- 생성 로직은 하나의 LangGraph로 유지
- 실행 모드만 다르게 구성
즉, 그래프는 하나지만 실행 방식은 여러 개가 될 수 있습니다.
8.3 실행 경계가 늘어나면 관측 경계도 함께 설계해야 한다
Runtime을 분리하면 시스템은 더 유연해집니다. 하지만 동시에 “하나의 요청이 어떤 경로로 실행됐는가”를 추적하는 일이 더 중요해집니다.
FastAPI, quiz_builder Runtime, web_search Runtime, MCP server, LLM 호출이 서로 다른 경계를 갖더라도, 하나의 trace로 연결되어야 운영자가 병목과 실패 지점을 이해할 수 있습니다. 실행 레이어를 분리하는 설계는 observability 설계와 함께 가야 합니다.
9. 향후 계획
ZEP의 퀴즈 생성 Agent는 계속 진화하고 있습니다. 앞으로는 다음 방향으로 고도화할 수 있습니다.
- 생성 그래프 내부 평가 기준 기반 self-evaluation·revision 루프 도입
- 평가 및 자가 개선 결과를 생성 그래프 개선 루프로 연결
- 학생 풀이 데이터와 오개념 모델 연결
- 문항별 난이도 자동 보정
- 성취기준 정렬 평가 모델 고도화
- 문항 생성 품질 대시보드 구축
- 교사 편집 이력 기반 문항 수정 정책 개선
- 생성 결과에 대한 오프라인 벤치마크 구축
궁극적으로 목표는 단순히 문제를 자동 생성하는 것이 아닙니다. 학생이 무엇을 알고, 무엇을 헷갈리고, 다음에 무엇을 배워야 하는지를 더 잘 드러내는 평가 도구를 만드는 것입니다.
ZEP의 퀴즈 생성 Agent는 이 목표를 위해 프롬프트가 아니라 그래프를, 단일 실행이 아니라 Runtime 토폴로지를, 결과물이 아니라 운영 가능한 실행 구조를 선택했습니다.