FastAPI를 사용하여 LangGraph API 구축하기
요약
본 튜토리얼은 FastAPI를 사용하여 LangGraph 워크플로우 주변에 OpenAI와 호환되는 API 경계를 구축하는 방법을 다룹니다. 클라이언트가 기대하는 표준화된 요청/응답 형식과 내부의 복잡한 LangGraph 로직을 분리하여, 안정적이고 검증 가능한 아키텍처를 설계하는 데 중점을 둡니다.
핵심 포인트
- FastAPI로 LangGraph API 경계를 구축하는 방법을 배웁니다.
- 클라이언트 기대치(OpenAI 형식)와 내부 워크플로우를 분리해야 합니다.
- 호환성 어댑터가 요청 검증 및 응답 조립을 담당합니다.
- 스트리밍 시, 의미론적 이벤트를 방출하는 직렬화기가 필요합니다.
🚀 기술 브리핑: 이 튜토리얼은 Gate of AI의 에이전트 워크플로우(Agentic Workflows) 심층 분석 시리즈의 일부입니다. 전체 기술 분석, 인터랙티브 코드 샌드박스 및 네이티브 아랍어 번역을 보려면 원문 기사 바로가기를 방문하십시오.
튜토리얼 · 고급
FastAPI를 사용하여 LangGraph API 구축하기
LangGraph 워크플로우 주변에 OpenAI와 호환되는 API 경계(boundary)를 계획하는 방법을 배웁니다. 이 가이드는 애플리케이션의 워크플로우와 공개 HTTP 계약 간의 검증된 아키텍처적 구분을, 그리고 일반 응답과 서버 전송 이벤트(SSE)에 필요한 호환성 검사에 중점을 둡니다. 이는 미검증된 복사-붙여넣기 RAG 구현을 제시하는 것은 아닙니다.
이 튜토리얼에서 다루는 내용
클라이언트는 OpenAI 형태의 Chat Completions 요청 및 응답을 기대할 수 있지만, 엔드포인트 뒤에 있는 애플리케이션은 LangGraph 워크플로우일 수 있습니다. 이는 서로 다른 관심사입니다. 요청 및 응답 형식은 공개 인터페이스에 속하며; 상태(state), 라우팅(routing), 도구(tools), 모델 호출(model calls), 스트리밍(streaming), 영속성(persistence) 및 인간 개입형 실행(human-in-the-loop execution)은 워크플로우 구현에 속합니다.
이러한 분리는 FastAPI를 통해 노출되는 LangGraph 서비스의 핵심 설계 지점입니다. 호환성 어댑터(compatibility adapter)는 공개 요청을 수신하고 검증하며, 애플리케이션 소유 표현(application-owned representation)을 사용하여 그래프를 호출하고, 클라이언트가 기대하는 형식으로 응답을 조립합니다. 스트리밍이 제공되는 경우, 별도의 SSE 직렬화기(serializer)가 의도된 의미론을 가진 이벤트를 방출해야 합니다. 이러한 책임들을 분리함으로써, 단순히 그래프의 내부 이벤트들이 자동으로 호환 가능한 공개 API를 구성한다고 가정하는 대신 각 경계에 대해 추론할 수 있게 됩니다.
검증된 자료는 이 아키텍처를 지원하며 중요한 테스트 교훈을 강조합니다. 즉, 하나의 요청에 대한 성공적인 시연은 좁은 형태의 전송 호환성만을 증명할 뿐입니다. 이는 엔드포인트가 전체 요청 표면(request surface)을 준수하는지, 예상되는 응답 필드를 보존하는지, 유효한 의미론을 스트리밍하는지, 또는 공개 게이트웨이를 통해 올바르게 작동하는지를 보여주지는 못합니다. 따라서 아래 단계들은 특정 검증되지 않은 코드베이스, 모델 버전, 데이터베이스 또는 승인 정책을 주장하기보다는 해당 '계약(contract)'을 정의하고 검증하는 데 중점을 둡니다.
전제 조건 및 범위
- HTTP 요청 및 응답 형식에 대한 숙지.
- FastAPI 라우트와 LangGraph 워크플로우에 대한 기본적인 이해.
- 명확하게 문서화된 클라이언트 대상 요청 및 응답 계약(contract).
- 스트리밍이 인터페이스의 일부인 경우, 비스트리밍 응답과 SSE 모두를 위한 테스트 계획.
사용 가능한 자료들은 현재 패키지 매트릭스, 모델 가용성, 의존성 고정(dependency pins), 벡터 데이터베이스 또는 특정 RAG 설계를 명시하지 않습니다. 이 튜토리얼은 의도적으로 이를 만들지 않습니다. 배포를 위한 버전과 인프라를 선택하고 구현하기 전에 해당 공식 문서를 통해 검증하십시오.
1단계: 그래프 어댑터를 구축하기 전에 공개 계약 정의하기
클라이언트가 전송할 수 있는 것과 받을 자격이 있는 것을 문서로 작성합니다. OpenAI와 호환되는 엔드포인트의 경우, 의도한 클라이언트가 사용하는 요청 형태부터 시작하고, 서비스가 지원할 필드를 포함해야 합니다. 그런 다음 어댑터가 반환할 응답 필드와 최종 그래프 출력을 어떻게 표현하는지를 포함하여 응답 형태를 정의합니다.
친숙해 보이는 JSON 본문이 완전한 호환성을 의미한다고 간주해서는 안 됩니다. 검증된 호환성 분석은 이 구분을 명확히 합니다. OpenAI 형태의 Chat Completions 요청을 수락하고, 그래프를 호출하며, choices 배열을 반환하는 것은 하나의 요청에 대한 성공적인 경로(happy path)를 보여줄 뿐입니다. 이것 자체가 해당 엔드포인트가 더 광범위한 요청 표면(request surface)을 준수하거나 클라이언트가 의존하는 응답 필드를 보존한다는 것을 증명하지는 않습니다.
구현 전에 다음 질문에 답하는 계약 체크리스트를 작성하세요:
- 엔드포인트가 어떤 요청 필드를 수락할 것인가?
- 어떤 필드가 검증되고, 사용되며, 무시되거나 거부될 것인가?
- 어댑터는 수락된 요청을 그래프 입력으로 어떻게 변환할 것인가?
- 어떤 응답 필드가 반환될 것이며, 최종 그래프 메시지는 그것들에 어떻게 매핑될 것인가?
- 요청이 유효하지 않거나 그래프가 최종 결과를 제공할 수 없을 때 클라이언트는 무엇을 관찰해야 하는가?
- 엔드포인트가 스트리밍(streaming) 응답, 비스트리밍(non-streaming) 응답, 또는 둘 다를 지원할 것인가?
이것들은 디자인 및 테스트 질문이며, 특정 구현이 자동으로 답한다는 주장이 아닙니다. 의도된 동작을 기록하고 테스트하세요. 어댑터가 구현하지 않은 필드나 동작에 대해 침묵하며 지원한다고 주장하는 것을 피하세요.
2단계: API 어댑터를 LangGraph 상태와 분리하기
공개 프로토콜과 애플리케이션 워크플로우 사이를 번역하는 경계 계층(boundary layer)을 사용하세요. 개념적으로, 이 서비스는 다섯 부분으로 구성됩니다. OpenAI 클라이언트가 요청을 보내고; FastAPI 라우트가 이를 수신하며; 검증기 및 호환성 어댑터가 이를 확인하고 변환합니다. 이후 어댑터가 LangGraph를 호출하고; 응답 조립기(response assembler)가 결과를 직렬화합니다. 응답 조립기는 요청과 서비스의 문서화된 동작에 따라 비스트리밍 직렬화기 또는 SSE 직렬화기를 선택할 수 있습니다.
이것을 구현 레시피라기보다는 책임 지도(responsibility map)로 생각하세요:
- 요청 유효성 검사 (Request validation): 들어오는 공개 요청이 해당 엔드포인트가 실제로 지원하는 계약(contract)과 일치하는지 확인합니다.
- 요청 변환 (Request translation): 수락된 공개 필드를 그래프가 예상하는 애플리케이션 입력으로 변환합니다.
- 워크플로우 실행 (Workflow execution): LangGraph가 내부 그래프 상태를 외부 와이어 형식(wire format)을 모방하도록 강제하기보다, 애플리케이션 오케스트레이션(orchestration)을 담당하게 합니다.
- 응답 조립 (Response assembly): 그래프의 최종 결과를 문서화된 공개 응답으로 변환합니다.
- 프로토콜 직렬화 (Protocol serialization): 일반 응답 또는 SSE 스트림에 적절한 직렬화기(serializer)를 사용합니다.
이러한 분리는 중요한 아키텍처 경계(architectural boundary)를 유지합니다. 즉, LangGraph의 상태 및 이벤트 모델은 OpenAI 와이어 프로토콜처럼 보일 필요가 없습니다. 애플리케이션은 자체 워크플로우를 표현할 수 있으며, 어댑터(adapter)가 공개 계약을 소유합니다. 이는 워크플로우가 변경되더라도 모든 내부 그래프 세부 사항이 API의 일부가 될 필요가 없을 때 유용합니다.
구현체를 검토할 때는 하나의 요청이 각 경계를 통과하는 과정을 추적해야 합니다. 라우트(route)가 무엇을 받는지, 유효성 검사기(validator)가 무엇을 수락하는지, 그래프에 어떤 입력이 도달하는지, 그리고 응답 조립기가 무엇을 반환하는지를 확인하세요. 그래프가 최종 메시지를 생성했다고 해서 직렬화된 HTTP 응답이 반드시 클라이언트 계약을 충족한다고 가정해서는 안 됩니다.
3단계: 일반 응답을 별도의 호환성 사례로 처리하기
의도된 서비스에 비스트리밍(non-streaming) 요청이 포함되어 있다면 그것부터 시작하세요. 전체 경로를 실행합니다. 즉, 대표적인 요청을 제출하고, 이를 유효성 검사하며, 그래프를 호출하고, 최종 결과를 얻은 다음, 그 결과를 문서화된 응답 형태의 모양으로 직렬화해야 합니다. 응답에 클라이언트 계약이 약속하는 필드가 포함되어 있는지 확인하세요. 단지 하나의 기본적인 클라이언트 예제가 작동하는 것처럼 보이게 하는 필드만으로는 충분하지 않습니다.
가장 간단한 성공 요청 이상의 테스트를 수행하세요. 지원되는 필드를 다양하게 변경하는 요청과 유효성 검사에 실패해야 하는 요청을 포함하세요. 모든 경우에 대해 실제 응답을 명시적인 기대치와 비교하세요. 목표는 어댑터가 단순히 클라이언트가 라우트에 연결할 수 있는지 여부가 아니라, 계약(contract)을 구현하는지 발견하는 것입니다.
그래프의 내부 표현은 API 계약이 의도적으로 노출하지 않는 한 공개 응답에 포함시키지 마세요. 검증된 아키텍처는 그래프가 애플리케이션을 나타내고 어댑터가 공개 계약을 소유해야 한다고 권장합니다. 이렇게 하면 호환성 결정이 한 곳에 유지되고, 내부 상태나 그래프 이벤트의 변경이 외부 응답을 실수로 변경하는 것을 방지할 수 있습니다.
소스들은 모든 서비스가 지원해야 하는 OpenAI 요청 필드 또는 응답 필드의 완전한 목록을 명시하지 않습니다. 가정된 목록에 기반하여 보편적인 호환성을 암시하지 마세요. 엔드포인트가 구현하는 프로필을 정의하고, 그 한계를 문서화하며, 이를 사용할 클라이언트 및 게이트웨이와 함께 해당 특정 약속들을 테스트하세요.
4단계: SSE 스트리밍을 자체 프로토콜 구현으로 취급하기
스트리밍은 단순히 비(非)스트리밍 응답을 임의의 조각들로 나눈 것이 아닙니다. 검증된 분석에 따르면 FastAPI 라우트가 서버 전송 이벤트(Server-Sent Events, SSE)를 추가할 수 있고 공식 SDK가 이를 소비할 수 있지만, 이 관찰이 유효한 스트리밍 의미론(streaming semantics)의 증거는 아니라는 경고도 있습니다. 공개 스트림은 시퀀스이자 전체로서 테스트되어야 합니다.
그래프는 어댑터가 OpenAI 형태의 청크를 내보내기 전에 자신의 이벤트들을 보유하거나, 변환하거나, 결합할 수 있습니다. 게이트웨이는 또한 사용량 이벤트를 주입하거나 델타(deltas)를 정규화할 수도 있습니다. 이러한 이유로, 각 이벤트를 개별적으로 검증하는 것은 필요하지만 충분하지 않습니다. 스트림은 개별적으로 그럴듯한 이벤트들로 구성되어 있어도, 클라이언트가 전체 응답을 소비할 때 여전히 유효하지 않거나 오해의 소지가 있는 시퀀스를 생성할 수 있습니다.
클라이언트가 받는 정확한 이벤트를 기록하는 스트리밍 테스트를 구축합니다. 해당 이벤트들로부터 스트림을 재구성하고, 전체 시퀀스를 엔드포인트가 약속하는 동작과 비교하여 평가합니다. 최소한 다음 사항들을 확인해야 합니다: 시퀀스가 실제 클라이언트가 의도한 대로 소비될 수 있는지, 응답이 문서화된 규칙에 따라 종료되는지, 그리고 배포된 경로의 모든 게이트웨이가 결과적인 의미론(semantics)을 변경하지 않는지 여부입니다.
스트림이 SSE 콘텐츠 타입을 반환하거나 청크를 방출한다고 해서 호환된다고 주장해서는 안 됩니다. 전송 전달(transport delivery)과 프로토콜 동작은 관련이 있지만 별개의 문제입니다. 검증된 소스는 하나의 요청에 대한 전송 호환성이 유효한 스트리밍 의미론이나 공개 게이트웨이를 통한 복원력을 확립하지 않는다고 명시적으로 경고합니다. 이 두 가지를 각각 별도의 테스트 목표로 다루십시오.
5단계: 게이트웨이를 포함한 전체 경로 테스트
호환성 테스트는 클라이언트가 관찰하는 것에 초점을 맞춰 구성해야 합니다. 일반 응답의 경우, 제출된 요청과 반환되는 필드를 엔드포인트 계약(endpoint contract)과 비교합니다. 스트리밍의 경우, 전체 시퀀스를 캡처하고 재구성합니다. 서비스가 게이트웨이 뒤에 배포된 곳에서는, FastAPI 라우트에 직접 접근하는 것에만 의존하기보다 해당 게이트웨이를 통해 동일한 테스트를 실행해야 합니다.
유용한 테스트 매트릭스는 다음 항목들에 대한 독립적인 케이스를 갖습니다:
- 엔드포인트가 문서화하는 필드를 사용한 허용된 요청(Accepted requests).
- 무효하거나 지원되지 않는 입력을 가진 요청(Requests with invalid or unsupported input).
- 스트리밍이 아닌 응답 및 해당 문서화된 필드.
- SSE 이벤트 전송과 재구성된 시퀀스의 의미.
- 요청이 의도된 게이트웨이를 통과할 때의 동작.
공개 계약(public contract)과 테스트 기대치(test expectations)를 함께 유지하세요. 어댑터나 그래프가 변경될 때마다 영향을 받은 경계(boundary)를 커버하는 테스트를 다시 실행해야 합니다. 게이트웨이가 변경되면 외부에서 보이는 동작을 다시 테스트해야 합니다. 이는 특정 성능, 가용성 또는 보안 보장을 확립하는 것은 아니지만, 관찰 가능한 인터페이스가 문서화된 동작을 계속 충족하는지 확인하는 체계적인 방법을 제공합니다.
Hugging Face의 분석은 호환성 엔드포인트를 구축하는 팀들에게 실질적인 경고를 제공합니다. 성공적인 데모는 만들기가 쉽지만, 정확한 호환성 명세(specification)는 더 어렵습니다. 데모를 모든 클라이언트 상호작용, 응답 필드, 스트림 시퀀스 또는 게이트웨이 경로가 검증되었다는 증거로 취급하지 말고, 초기 연결 확인으로 간주하세요.
영속성 및 수동 검토의 역할
LangGraph는 검증된 컨텍스트에서 상태 저장 워크플로우(stateful workflows), 스트리밍, 영속성(persistence), 그리고 인간 개입형 실행(human-in-the-loop execution)을 위한 오케스트레이션 런타임으로 설명됩니다. 이러한 기능들은 애플리케이션 워크플로우 동작과 관련이 있습니다. 이들이 잘 정의된 외부 API 어댑터의 필요성을 제거하는 것은 아니며, 특정 영속성 백엔드나 승인 설계(approval design)를 확립하는 것도 아닙니다.
만약 워크플로우가 상태, 영속성 또는 수동 검토를 사용한다면, 이러한 애플리케이션 개념들을 호출자에게 어떻게 표현할지 결정해야 합니다. 내부 그래프 이벤트를 자동으로 공개 프로토콜 이벤트로 노출하지 마세요. 대신, API 계약이 무엇을 약속하는지 결정하고 경계에서 관련 애플리케이션 결과를 번역하세요. 제공된 출처들은 아키텍처적 분리를 지원하지만, 특정 승인 엔드포인트, 데이터베이스 스키마, 접근 제어 정책 또는 감사 로그 구현을 검증하지는 않습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기