ChatGPT Apps SDK로 출시하며 배운 점

ChatGPT Apps SDK로 제품을 출시하며 얻은 실용적인 교훈을 통해 이 아키텍처가 적합한 경우와 추가 제어가 필요한 지점을 살펴봅니다.

요약

  • 빠른 시일 내에 ChatGPT에서 워크플로를 구현해야 하거나, 맞춤형 에이전트 스택에 투자하기 전에 그곳에서 도구를 시험해 보고 싶다면 Apps SDK가 실용적인 선택입니다. 에이전트의 동작 방식을 단계마다 직접 통제해야 한다면 일반적으로 적합하지 않습니다.

  • ChatGPT가 주 사용 환경이어야 하고 완전한 채팅 제품을 구축하지 않으면서 도구와 소규모 UI를 제공하려면 Apps SDK를 선택하세요. 흐름, 메모리, 프롬프트, 쓰기 작업을 세밀하게 제어해야 한다면 자체 에이전트 스택을 선택하세요.

  • Apps SDK는 채팅에 몇 가지 짧은 UI 단계를 결합한 제품에 적합합니다. 더 빠르게 출시할 수 있지만 일부 통제권을 포기해야 합니다.

  • 저희에게 효과적이었던 것은 명확한 도구, 명확한 위젯 동작, 명확한 다음 단계였습니다. 흐름을 결정할 때 LLM이 아니라 이 요소들에 의존했습니다. 모델은 시스템이 이미 결정한 결과를 설명할 때 가장 유용했습니다.

  • 아래에서는 선택 기준부터 효과가 있었던 것과 없었던 것까지 차례로 살펴봅니다.

대부분의 팀은 여전히 AI 파일럿을 운영하거나 위험과 보상이 모두 낮은 주변 업무에 AI를 배포합니다. 사용자가 매주 이용하는 비즈니스 핵심 제품을 출시하는 팀은 드뭅니다. 전체 어시스턴트를 직접 구축하기보다 ChatGPT 안에 제품을 제공하는 것이 목표라면 ChatGPT Apps SDK로 이 격차를 줄일 수 있습니다.

Apps SDK를 사용한 이유

이번에 얻은 교훈은 ChatGPT를 주 사용 환경으로 삼고, 고객이 완전한 맞춤형 채팅 제품에 투자하지 않아도 빠르게 구현할 수 있어야 했던 고객 프로젝트에서 나왔습니다.

이 요구 사항에 비추어 볼 때 Apps SDK는 고객에게 다음이 필요했기 때문에 적합했습니다.

  • 별도로 구축하고 호스팅할 채팅 제품이 필요 없음—또 하나의 독립형 어시스턴트 틀이 아니라 ChatGPT 안에서 사용자에게 도달하고자 했습니다.

  • 채팅과 소규모 작업별 UI의 결합—워크플로 안에 또 하나의 완전한 제품을 넣는 대신 몇 가지 핵심 위젯 단계만 필요했습니다.

  • MCP 도구를 통해 노출되는 백엔드 동작—처음부터 끝까지 소유하는 맞춤형 에이전트 런타임이 아니라 표준 도구 호출이 필요했습니다.

  • ChatGPT 내에서의 검색 및 발견—사용자가 이미 일하는 곳에서 워크플로를 접할 수 있어야 했습니다.

구축 과정에서 고객과 함께 이러한 선택을 검증했습니다. 다만 절충점은 여전히 존재합니다. ChatGPT가 세션을 호스팅하면 외부 런타임은 직접 소유할 수 없습니다. 방향은 제시할 수 있지만 완전히 제어할 수는 없습니다.

Apps SDK가 제공하는 것

Apps SDK 앱은 다음 세 가지를 연결합니다.

  1. ChatGPT의 에이전트 런타임

  2. 자체 MCP 도구

  3. 자체 위젯 UI

실제 흐름:

  1. 사용자가 ChatGPT에 무언가를 요청합니다.

  2. ChatGPT가 MCP 도구 중 하나를 호출할 수 있습니다.

  3. 서버가 구조화된 도구 결과를 반환합니다.

  4. ChatGPT가 결과를 읽고 추가 도구 호출, 사용자 응답 또는 두 가지 모두 중 다음 단계를 결정합니다. 해당 도구에 위젯을 연결했다면 이 턴에 표시될 수 있습니다.

  5. 사용자는 채팅이나 위젯에서 후속 텍스트를 입력하거나, 항목을 선택하거나, 위젯이 도구 호출을 트리거하는 방식으로 계속 진행합니다. 그러면 스레드가 업데이트되고 ChatGPT가 다음 턴을 실행합니다. 작업이 끝날 때까지 2~4단계가 반복됩니다.

핵심은 채팅, 백엔드 작업, 짧은 UI 단계를 조합하는 것입니다. 이는 채팅, 도구, UI 사이의 인계 지점이 취약할 수 있다는 뜻이기도 합니다.

채팅 UI, 도구 연결, 인증 패턴, 위젯 셸을 처음부터 다시 구축할 필요가 없습니다. 많은 제품에서 개발 시간을 크게 줄여 도메인 로직과 보호 장치에 집중할 수 있습니다.

ChatGPT 안에서 구축하는 것은 자체 에이전트를 운영하는 것과 다릅니다. 프로젝트에서 어려웠던 부분은 프롬프트 기법이 아니었습니다. 모델과 UI가 일관되게 작동하도록 도구, 위젯, 다음 단계를 충분히 명확하게 만드는 일이었습니다.

선택 방법

Apps SDK는 일반적인 프런트엔드와 다른 형태의 제품을 제공하므로 어떤 상황에 가장 적합한지 알아야 합니다.

다음과 같은 경우 Apps SDK를 사용하세요

  • ChatGPT 워크플로를 빠르게 출시하려는 경우.

  • ChatGPT가 대화를 호스팅하게 하려는 경우.

  • 자연어와 몇 가지 핵심 UI 단계를 결합하려는 경우.

  • 자체 채팅 인터페이스, 에이전트 컨테이너, 검색 및 발견 기능을 구축하지 않으려는 경우.

사용자가 이미 ChatGPT를 주로 이용한다면 마지막 항목이 특히 중요합니다.

다음이 필요하다면 자체 에이전트를 구축하세요

  • 코드로 강제할 수 있는 고정된 단계별 흐름.

  • 처음부터 끝까지 직접 소유하는 맞춤형 UI와 확인 절차.

  • 자체 메모리 및 상태 모델.

  • 실행할 때마다 예측 가능해야 하는 동작.

  • 에이전트용 추적 정보, 로그, 지표.

플래너, 시스템 프롬프트, 전체 워크플로 자체가 제품이라면 일반적으로 맞춤형 스택이 더 적합합니다.

절충점 한눈에 보기

질문

ChatGPT Apps SDK

자체 에이전트

사용자 경험은 어디에서 제공되나요?

ChatGPT 내부

자체 제품 내부

대화 단계는 누가 실행하나요?

도구와 UI의 안내를 받는 ChatGPT

자체 에이전트 시스템

UI를 얼마나 구축해야 하나요?

채팅 내 핵심 위젯

필요한 만큼

프롬프트를 얼마나 제어할 수 있나요?

간접 제어

완전한 제어

고정된 반복 가능 흐름을 구현하기 쉬운가요?

세심한 설계 필요

코드로 강제하기 쉬움

첫 출시까지 걸리는 시간

대체로 더 빠름

초기에는 대체로 더 느림

직접 담당할 플랫폼 작업

적음

많음

향후 방향 전환의 여지

적음

많음

프로젝트 내내 반복해서 등장한 단어는 ‘제어’였습니다. 한쪽에는 속도와 익숙한 호스트 환경이, 다른 쪽에는 런타임에 대한 제한적인 소유권이 있었습니다. 고객은 전체 스택을 소유하는 것보다 ChatGPT에서 사용자와 만나는 것을 우선하면서 이 절충점을 받아들였습니다.

어려워지는 지점

이상적인 흐름은 간단해 보입니다. 사용자가 요청하고, 도구가 실행되고, 데이터가 돌아오며, 선택이 필요한 순간 위젯이 나타납니다.

하지만 실제로 어려웠던 부분은 인계였습니다. 위젯은 장식이 아닙니다. 화면에 나타나는 순간 모델이 보는 내용과 다음 동작이 달라집니다. 위젯 동작을 자유로운 채팅이 아니라 이름이 지정된 이벤트처럼 다루세요.

이 프로젝트의 스택은 FastMCP, Pydantic, React, TypeScript로 단순했습니다. 이들을 통합하는 데는 문제가 없었습니다. 핵심 과제는 모델, 도구, UI가 다음 동작에 대해 일치된 정보를 갖도록 하는 것이었습니다.

효과가 있었던 방법

각 인계 지점을 명확하게 만들기

도구 결과를 더 이상 가공되지 않은 백엔드 페이로드로 취급하지 않았습니다. 각 반환 결과를 하나의 인계로 만들었습니다.

잘 설계된 도구 결과는 다음을 수행합니다.

  • 위젯 렌더링에 필요한 정보를 제공합니다.

  • ChatGPT가 응답의 근거로 삼을 구조화된 사실을 제공합니다.

  • 흐름상 필요한 경우 모델이 추측하지 않도록 다음에 수행할 작업을 명시합니다.

위젯 동작이 모호한 문장을 스레드에 보내서는 안 됩니다. 사용자가 무엇을 했고 다음에 무엇을 해야 하는지 명시해야 합니다.

인계가 명확해지자 신뢰성이 높아졌습니다.

모델은 도구 출력과 위젯 동작에 포함된 짧고 명확한 지시를 잘 따릅니다.

아래는 저희가 사용한 간단한 Pydantic 구조입니다. output 필드에는 위젯을 표시할 때 필요한 구조화된 데이터와 ChatGPT가 세션에서 사용해야 할 사실이 들어갑니다. agent_directions 필드에는 어시스턴트가 다음에 해야 할 일을 알려 주는 짧은 문장이 들어갑니다. Reason은 선택 사항입니다.

Python

from typing import Generic, TypeVar
from pydantic import BaseModel
T = TypeVar("T")
class AgentDirections(BaseModel): assistant_instruction: str reason: str | None = None
class ToolResults(BaseModel, Generic[T]): agent_directions: AgentDirections output: T

위젯을 작게 유지하기

효과가 있었던 위젯은 하나의 결정을 처리한 뒤 제어권을 돌려줬습니다. 위젯을 미니 앱으로 만드는 것보다 짧은 목록, 확인 절차, 간결한 검토 화면이 더 효과적이었습니다. 흐름의 결정성을 높이고 싶을 때는 간단한 유효성 검사나 고정된 다음 단계처럼 위젯에 소량의 로직을 넣는 것도 도움이 됐습니다.

위젯 메시지에 3인칭 사용하기

위젯 후속 메시지를 사용자의 채팅처럼 쓰는 방식(“I selected…,” “I confirmed…”)을 중단했습니다. 대신 사용자의 행동을 설명하는 짧은 보고 형식(“The user selected…,” “The user confirmed…”)으로 작성했습니다. ChatGPT가 위젯 메시지를 사용자 메시지가 아니라 도구 메시지로 추가했기 때문에 이 방식을 시도했습니다.

다음 단계가 명확할 때 직접 실행하기

버튼이 다음 도구 호출을 명확히 나타낸다면 채팅 턴을 하나 더 거치게 하는 것보다 위젯에서 직접 호출하도록 하는 편이 효과적이었습니다. 단, 다음 도구 호출에 ChatGPT의 입력이 필요하지 않은 경우에만 해당합니다.

이 방식은 결정적인 흐름을 유지하는 데 도움이 됐고 추가 채팅 턴을 피함으로써 지연 시간도 줄였습니다.

오류 처리

도구 호출이 실패하면 올바른 MCP 오류 코드와 짧고 명료한 메시지를 도구에서 반환했습니다. 그러면 호출 실패 시 ChatGPT가 실제 오류 정보를 읽고 사용자에게 문제를 설명하거나 적절한 다음 단계를 선택할 수 있었습니다.

도구 컨텍스트 관리

세션 상태는 자체 서버에 보관했습니다. ChatGPT는 도구 호출과 함께 세션 범위의 컨텍스트를 전송합니다. FastMCP에서는 각 도구에 Context 매개변수를 지정해 핸들러가 해당 상태를 읽고 업데이트할 수 있게 했습니다.

  • ChatGPT가 호출할 때마다 안정적인 ID와 이전 결과를 도구 인수로 다시 전달하게 하지 않고 세션에 보관했습니다.

  • 도구 호출 루프가 발생하면 중복 호출을 감지하고 도구 결과를 통해 명확한 오류를 반환할 수 있었습니다.

  • 디버깅과 지원을 위한 세션 로그는 자체 시스템에 보관했습니다.

효과가 없었던 방법

모델이 다음 단계를 추론할 것이라고 가정하기

초기에는 위젯을 표시한 뒤 모델이 ‘이해했을 것’이라고 가정하고 올바른 후속 도구 호출을 기다렸습니다. 때로는 예상대로 작동했습니다. 하지만 그렇지 않은 경우가 많았습니다.

명확한 인계가 없으면 ChatGPT는 작업을 실행해야 할 때 내용을 요약하거나, 사용자에게 선택을 반복해 달라고 요청하거나, 멈춰야 할 때도 계속 계획을 세울 수 있습니다.

해결책은 모델이 추론하기를 기대하는 대신 구조화된 출력값과 위젯 페이로드에 다음 단계를 명시하는 것이었습니다.

여러 계층에 의미를 분산하기

Apps SDK 문서에 따라 도구 출력, 숨겨진 메타데이터, 채팅 텍스트에 응답을 나눠 담는 정교한 방식을 시도했습니다. 하지만 위젯에서는 숨겨진 메타데이터를 읽을 수 없었습니다. 따라서 이 방식을 사용할 수 없었습니다.

모델에서 도구 숨기기

Apps SDK 문서에는 에이전트가 선택하지 못하도록 도구 목록에서 숨기면서도 위젯에서는 호출할 수 있는 도구가 설명되어 있습니다. 가시성을 앱 전용으로 설정하자 해당 도구는 에이전트뿐 아니라 위젯에서도 사용할 수 없게 됐습니다. 에이전트에는 도구가 보이지 않지만 위젯에서는 계속 사용할 수 있는 설정을 끝내 구현하지 못했습니다.

불충분한 오류 처리

유용한 결과가 없는데도 아무 메시지를 표시하지 않거나 일반적인 ‘성공’ 메시지를 표시하는 것은 명확한 오류보다 나빴습니다. 그래서 도구와 위젯의 실패를 핵심 출력으로 취급했습니다. 단계를 계속 진행할 수 없으면 이를 쉬운 말로 알리고 명시적인 오류를 반환해, 렌더링은 됐지만 더 진행되지 않는 위젯을 사용자가 계속 바라보게 두지 않았습니다. 그 결과 사용성이 개선되고 모델 동작의 신뢰성도 높아졌습니다.

마치며

맞춤형 플랫폼 작업을 줄이면서 ChatGPT에서 워크플로를 구현하는 것이 목표라면 Apps SDK가 실용적인 방법입니다. 일부 통제권을 포기하는 대신 속도를 높이고 사용자가 이미 일하는 곳에서 만날 수 있습니다.

흐름의 모든 분기와 UI, 각 단계의 결정 주체를 직접 통제해야 한다면 처음부터 자체 에이전트 스택을 계획하세요. 결국 ChatGPT 안에서만 구축하는 방식으로는 부족해질 가능성이 큽니다.

채팅, 인증, 에이전트 연결 구조를 직접 구축하기 전에 Apps SDK를 사용해 ChatGPT 안에서 MCP 서버를 운영하고, 제품에 필요해지면 자체 스택으로 전환할 수도 있습니다.

비슷한 상황의 팀이라면 다음과 같이 진행하세요. 결과가 명확한 워크플로 하나를 고르고, 채팅과 도구 및 위젯 사이의 인계 방식을 문서화한 뒤, 프롬프트 조정에 많은 시간을 쓰기 전에 재시도와 오류를 집중적으로 테스트하세요.

작성자

Malan Evans