본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2025. 12. 18. · 9 Views
AWS Bedrock Action Groups 완벽 가이드
AWS Bedrock의 Action Groups를 활용하여 AI 에이전트가 외부 API와 연동하는 방법을 배웁니다. OpenAPI 스키마 작성부터 파라미터 정의, 응답 형식 지정까지 실무에 필요한 모든 내용을 다룹니다.
목차
1. Action Group이란?
어느 날 이주니어 씨가 AWS Bedrock으로 AI 챗봇을 만들고 있었습니다. 그런데 문제가 생겼습니다.
"AI가 데이터베이스를 조회하거나 외부 API를 호출할 수 있게 하려면 어떻게 해야 하지?" 선배 개발자 김시니어 씨가 다가와 말했습니다. "Action Groups를 사용해보세요."
Action Group은 AI 에이전트가 외부 시스템과 상호작용할 수 있도록 하는 연결 고리입니다. 마치 전화기의 단축번호처럼, AI가 필요할 때 특정 기능을 호출할 수 있게 해줍니다.
OpenAPI 스키마를 통해 어떤 작업을 수행할 수 있는지 정의하고, Lambda 함수로 실제 로직을 구현합니다.
다음 코드를 살펴봅시다.
{
"openapi": "3.0.0",
"info": {
"title": "User Management API",
"version": "1.0.0",
"description": "사용자 정보 관리를 위한 API"
},
"paths": {
"/users/{userId}": {
"get": {
"summary": "사용자 정보 조회",
"description": "ID로 사용자 상세 정보를 가져옵니다",
"operationId": "getUser",
"parameters": [
{
"name": "userId",
"in": "path",
"required": true,
"schema": { "type": "string" }
}
]
}
}
}
}
이주니어 씨는 고객 문의를 처리하는 AI 챗봇을 개발하고 있었습니다. 고객이 "내 주문 상태 알려줘"라고 물어보면, AI가 데이터베이스를 조회해서 실시간 정보를 제공해야 했습니다.
하지만 Bedrock의 기본 AI 모델은 그저 학습된 지식으로 답변할 뿐, 실시간 데이터에 접근할 수 없었습니다. 김시니어 씨가 화이트보드에 그림을 그리며 설명했습니다.
"AI 에이전트는 똑똑하지만, 외부 세계와 연결되지 않으면 할 수 있는 일이 제한적이에요. 마치 전화가 없는 비서와 같죠." 그렇다면 Action Group이란 정확히 무엇일까요?
쉽게 비유하자면, Action Group은 마치 비서에게 주는 전화번호부와 같습니다. "고객 정보가 필요하면 이 번호로 전화해", "주문 상태를 확인하려면 저 번호로 연락해"처럼 AI에게 어떤 기능을 어떻게 사용할 수 있는지 알려주는 설명서입니다.
AI는 이 설명서를 보고 필요한 순간에 적절한 기능을 호출합니다. Action Group이 없던 시절에는 어땠을까요?
개발자들은 AI의 응답을 파싱해서 어떤 작업이 필요한지 직접 판단해야 했습니다. "아, 사용자가 주문 정보를 물어봤네.
그럼 데이터베이스를 조회해야겠다"라고 코드로 일일이 분기 처리를 했습니다. 프로젝트가 커지면 이런 조건문이 수백 개로 늘어났고, 새로운 기능을 추가할 때마다 코드를 수정해야 했습니다.
바로 이런 문제를 해결하기 위해 Action Group이 등장했습니다. Action Group을 사용하면 AI가 스스로 어떤 기능을 호출해야 하는지 판단합니다.
개발자는 그저 "이런 기능들이 있어"라고 선언만 하면 됩니다. 또한 표준 OpenAPI 스키마를 사용하기 때문에 기존 API 문서를 재활용할 수 있습니다.
무엇보다 새로운 기능을 추가할 때 스키마만 업데이트하면 되니 유지보수가 훨씬 쉬워집니다. 위의 코드를 한 줄씩 살펴보겠습니다.
먼저 openapi: "3.0.0"은 OpenAPI 스펙 버전을 명시합니다. Bedrock은 3.0.0 버전을 지원합니다.
info 섹션에서는 API의 전반적인 정보를 설명합니다. 타이틀과 버전, 설명을 명확히 작성하면 AI가 이 API의 목적을 더 잘 이해합니다.
paths 섹션이 핵심입니다. 여기에 AI가 호출할 수 있는 엔드포인트를 정의합니다.
/users/{userId} 경로에 GET 메서드를 정의했고, operationId로 고유한 식별자를 부여했습니다. AI는 이 operationId를 보고 "아, 사용자 정보를 가져오려면 getUser를 호출하면 되겠구나"라고 판단합니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 쇼핑몰 고객센터 챗봇을 만든다고 가정해봅시다.
고객이 "내 주문 어디쯤 왔어?"라고 물으면, AI는 자동으로 주문 조회 Action을 실행합니다. "환불하고 싶어요"라고 하면 환불 처리 Action을 호출합니다.
개발자가 조건문을 하나하나 작성할 필요 없이, AI가 문맥을 파악해서 적절한 기능을 선택합니다. 실제로 많은 기업들이 고객 지원, 데이터 분석, 업무 자동화 등에서 이런 패턴을 활용하고 있습니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 스키마에 설명을 부실하게 작성하는 것입니다.
"사용자 조회"라고만 쓰면 AI가 정확히 언제 이 기능을 써야 하는지 헷갈릴 수 있습니다. "ID로 사용자 상세 정보를 가져옵니다"처럼 구체적으로 작성해야 AI가 올바른 판단을 내립니다.
다시 이주니어 씨의 이야기로 돌아가 봅시다. 김시니어 씨의 설명을 들은 이주니어 씨는 눈이 반짝였습니다.
"그럼 제가 만든 API를 AI가 알아서 호출한다는 거네요!" Action Group을 제대로 이해하면 AI 에이전트의 활용 범위가 엄청나게 넓어집니다. 단순한 질문 응답을 넘어 실제 업무를 처리하는 똑똑한 비서를 만들 수 있습니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - OpenAPI 3.0.0 스펙을 정확히 따라야 Bedrock이 인식합니다
- description 필드를 상세히 작성할수록 AI의 판단 정확도가 높아집니다
- 기존 API 문서가 있다면 변환 도구를 활용해 빠르게 스키마를 생성할 수 있습니다
2. OpenAPI 스키마 작성
이주니어 씨가 첫 Action Group을 만들려고 하니 막막했습니다. "OpenAPI 스키마를 작성하라는데, 어디서부터 시작해야 하지?" 김시니어 씨가 옆에서 노트북을 열며 말했습니다.
"기본 구조부터 차근차근 만들어봅시다."
OpenAPI 스키마는 API의 설계도입니다. 어떤 엔드포인트가 있고, 무엇을 받아서 무엇을 반환하는지를 표준화된 형식으로 기술합니다.
Bedrock은 이 스키마를 읽고 AI 에이전트가 어떤 작업을 수행할 수 있는지 파악합니다. 필수 섹션은 info, paths, components입니다.
다음 코드를 살펴봅시다.
{
"openapi": "3.0.0",
"info": {
"title": "Order Management API",
"version": "1.0.0",
"description": "주문 관리 시스템 API"
},
"paths": {
"/orders": {
"post": {
"summary": "새 주문 생성",
"description": "고객의 새로운 주문을 생성합니다",
"operationId": "createOrder",
"requestBody": {
"required": true,
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/Order"
}
}
}
},
"responses": {
"200": {
"description": "주문 생성 성공"
}
}
}
}
},
"components": {
"schemas": {
"Order": {
"type": "object",
"properties": {
"productId": { "type": "string" },
"quantity": { "type": "integer" }
}
}
}
}
}
이주니어 씨는 빈 JSON 파일 앞에서 한참을 고민했습니다. "뭘 어떻게 써야 하지?
필수 항목이 뭐고, 선택 항목이 뭘까?" 옆에서 지켜보던 김시니어 씨가 웃으며 말했습니다. "처음에는 다들 그래요.
하지만 기본 뼈대만 이해하면 금방 익숙해집니다." 그렇다면 OpenAPI 스키마를 어떻게 작성해야 할까요? 쉽게 비유하자면, OpenAPI 스키마는 마치 레시피 카드와 같습니다.
"이 요리를 만들려면 재료가 이렇고, 순서는 이렇고, 완성품은 이런 모양입니다"라고 상세히 적어놓은 설명서입니다. AI는 이 레시피를 보고 정확히 어떤 재료(파라미터)가 필요하고, 어떤 결과물(응답)을 기대할 수 있는지 알게 됩니다.
OpenAPI 스키마가 표준화되지 않았던 시절에는 어땠을까요? 각 회사마다 API 문서 형식이 달랐습니다.
어떤 곳은 PDF로, 어떤 곳은 워드 문서로, 또 어떤 곳은 위키 페이지로 API를 설명했습니다. 개발자들은 문서를 읽고 머릿속으로 해석해서 코드를 작성해야 했습니다.
당연히 실수가 많았고, API가 업데이트되면 문서와 실제 구현이 따로 놀았습니다. 바로 이런 문제를 해결하기 위해 OpenAPI 스펙이 등장했습니다.
OpenAPI를 사용하면 기계가 읽을 수 있는 형식으로 API를 정의할 수 있습니다. 자동으로 문서를 생성할 수 있고, 테스트 코드도 만들 수 있습니다.
Bedrock 같은 AI 플랫폼도 이 표준을 읽고 자동으로 기능을 연동합니다. 무엇보다 전 세계 개발자들이 같은 형식을 사용하니 협업이 훨씬 쉬워집니다.
위의 코드를 한 줄씩 살펴보겠습니다. 먼저 info 섹션은 API의 메타데이터입니다.
title은 API의 이름, version은 버전 관리에 사용됩니다. Bedrock은 이 정보를 보고 어떤 API인지 식별합니다.
명확한 제목을 붙이면 나중에 여러 Action Group을 관리할 때 헷갈리지 않습니다. paths 섹션이 가장 중요합니다.
여기에 실제 엔드포인트를 정의합니다. /orders에 POST 메서드를 정의했고, operationId는 createOrder입니다.
AI가 "주문을 생성해야겠다"고 판단하면 이 operationId를 찾아 호출합니다. requestBody는 요청에 필요한 데이터 구조를 정의합니다.
$ref: "#/components/schemas/Order"는 참조 문법입니다. 같은 스키마를 여러 곳에서 재사용할 수 있게 해줍니다.
마치 프로그래밍의 변수처럼 한 곳에서 정의하고 여러 곳에서 참조하는 방식입니다. components 섹션에서는 재사용 가능한 구성 요소를 정의합니다.
Order 스키마는 productId와 quantity 두 개의 프로퍼티를 가집니다. 이렇게 정의하면 나중에 주문 수정, 주문 조회 등 다른 엔드포인트에서도 같은 스키마를 재사용할 수 있습니다.
실제 현업에서는 어떻게 활용할까요? 예를 들어 물류 관리 시스템을 개발한다고 가정해봅시다.
재고 조회, 출고 처리, 반품 접수 등 수십 개의 API가 있을 수 있습니다. 이 모든 것을 OpenAPI 스키마 하나로 정의하면, AI 에이전트가 "재고 부족하면 자동으로 발주"처럼 복잡한 워크플로우를 스스로 처리할 수 있습니다.
실제로 많은 물류 회사들이 이런 방식으로 업무 자동화를 구현하고 있습니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 모든 엔드포인트를 한 파일에 우겨넣는 것입니다. API가 10개, 20개로 늘어나면 JSON 파일이 수천 줄로 불어납니다.
이럴 때는 여러 파일로 분리하고 $ref로 참조하는 방식을 사용해야 합니다. "주문 관련은 orders.json", "고객 관련은 customers.json"처럼 도메인별로 나누면 관리가 훨씬 쉬워집니다.
다시 이주니어 씨의 이야기로 돌아가 봅시다. 김시니어 씨의 가이드를 따라 첫 스키마를 작성한 이주니어 씨는 뿌듯해했습니다.
"생각보다 간단하네요!" OpenAPI 스키마를 제대로 이해하면 API 개발이 훨씬 체계적으로 변합니다. 문서와 코드가 분리되지 않고, AI 연동도 자동으로 됩니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - Swagger Editor를 사용하면 실시간으로 스키마를 검증하고 미리보기할 수 있습니다
- $ref 참조를 적극 활용해 스키마를 모듈화하면 유지보수가 쉬워집니다
- 처음에는 최소한의 필드만 정의하고, 필요에 따라 점진적으로 확장하세요
3. 파라미터 정의하기
이주니어 씨가 API 엔드포인트를 만들었는데, AI가 제대로 호출하지 못했습니다. "왜 안 되지?
분명 경로는 맞는데..." 김시니어 씨가 스키마를 살펴보더니 말했습니다. "파라미터 정의가 빠져있네요.
AI가 뭘 전달해야 하는지 모르는 겁니다."
파라미터는 API 호출 시 전달되는 데이터입니다. 경로에 포함되는 path 파라미터, URL 뒤에 붙는 query 파라미터, 요청 본문에 담기는 request body 세 가지 유형이 있습니다.
각 파라미터는 이름, 타입, 필수 여부, 설명을 명확히 정의해야 AI가 올바르게 호출할 수 있습니다.
다음 코드를 살펴봅시다.
{
"paths": {
"/products/{productId}": {
"get": {
"summary": "상품 상세 조회",
"description": "상품 ID로 상세 정보를 가져오고, 옵션으로 재고 정보도 포함할 수 있습니다",
"operationId": "getProduct",
"parameters": [
{
"name": "productId",
"in": "path",
"required": true,
"description": "조회할 상품의 고유 ID",
"schema": { "type": "string" }
},
{
"name": "includeStock",
"in": "query",
"required": false,
"description": "재고 정보 포함 여부 (true/false)",
"schema": { "type": "boolean", "default": false }
}
]
}
}
}
}
이주니어 씨는 상품 조회 API를 만들었습니다. 테스트해보니 잘 작동했습니다.
그런데 막상 Bedrock에 연동하고 AI에게 "상품 A123 정보 알려줘"라고 하니 오류가 발생했습니다. AI가 어떤 값을 어디에 전달해야 하는지 몰라 헤매고 있었던 것입니다.
김시니어 씨가 설명했습니다. "API를 만들 때 개발자는 당연히 아는 것들이 있죠.
상품 ID를 경로에 넣는다든지, 옵션 파라미터는 쿼리스트링으로 보낸다든지. 하지만 AI는 그걸 모릅니다." 그렇다면 파라미터를 어떻게 정의해야 할까요?
쉽게 비유하자면, 파라미터 정의는 마치 택배 송장 작성법을 알려주는 것과 같습니다. "받는 사람 이름은 여기, 주소는 저기, 연락처는 필수, 메모는 선택사항"처럼 어떤 정보를 어디에 어떻게 써야 하는지 명확히 안내합니다.
AI는 이 안내서를 보고 정확히 필요한 정보를 올바른 위치에 배치합니다. 파라미터 정의가 부실했던 시절에는 어땠을까요?
개발자들은 API 문서를 읽고 "아, 이 파라미터는 경로에 넣는구나", "이건 쿼리스트링이구나"라고 추측해서 코드를 작성했습니다. 문서가 불명확하면 실제로 API를 여러 번 호출해보면서 시행착오를 거쳤습니다.
타입이 맞지 않아 400 에러가 나면 다시 수정하고, 필수 필드를 빼먹어 422 에러가 나면 또 고쳤습니다. 바로 이런 문제를 해결하기 위해 명시적인 파라미터 정의가 중요합니다.
파라미터를 명확히 정의하면 AI가 단번에 올바른 호출을 할 수 있습니다. required: true로 표시하면 AI는 반드시 그 값을 포함시킵니다.
타입을 string, integer, boolean으로 명확히 하면 데이터 형식 오류도 방지할 수 있습니다. 무엇보다 description 필드에 상세한 설명을 적으면 AI가 어떤 상황에서 어떤 값을 넣어야 하는지 스스로 판단합니다.
위의 코드를 한 줄씩 살펴보겠습니다. 첫 번째 파라미터는 path 파라미터입니다.
"in": "path"는 이 값이 URL 경로에 포함된다는 뜻입니다. /products/{productId}에서 중괄호 안의 productId와 이름이 정확히 일치해야 합니다.
required: true로 필수 표시를 했기 때문에 AI는 이 값 없이는 절대 호출하지 않습니다. 두 번째 파라미터는 query 파라미터입니다.
"in": "query"는 URL 뒤에 ?includeStock=true 형식으로 붙는다는 의미입니다. required: false이므로 선택사항입니다.
재미있는 부분은 default: false입니다. 값이 생략되면 자동으로 false가 적용됩니다.
description 필드가 특히 중요합니다. "조회할 상품의 고유 ID"라고 구체적으로 설명했기 때문에 AI는 이것이 상품 식별자임을 이해합니다.
"재고 정보 포함 여부"라고 적었기 때문에 사용자가 "재고도 같이 보여줘"라고 하면 AI는 자동으로 이 파라미터를 true로 설정합니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 여행 예약 시스템을 만든다고 가정해봅시다. 사용자가 "서울에서 부산 가는 기차표 내일 오전 표 찾아줘"라고 하면, AI는 자동으로 출발지(path), 도착지(path), 날짜(query), 시간대(query) 파라미터를 추출해서 검색 API를 호출합니다.
파라미터가 명확히 정의되어 있기 때문에 사용자가 자연어로 말해도 AI가 정확히 변환할 수 있습니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 모든 파라미터를 request body에 넣는 것입니다. REST 원칙에서는 리소스 식별자는 경로에, 필터링 옵션은 쿼리에, 생성/수정할 데이터는 바디에 넣습니다.
이 규칙을 지키면 API가 훨씬 직관적이고, AI도 패턴을 학습해서 더 정확히 호출합니다. 또 다른 실수는 description을 대충 쓰는 것입니다.
"상품 ID"라고만 쓰면 AI가 헷갈릴 수 있습니다. "조회할 상품의 고유 ID (예: P-12345)"처럼 예시까지 포함하면 AI의 이해도가 크게 높아집니다.
다시 이주니어 씨의 이야기로 돌아가 봅시다. 파라미터를 상세히 정의하고 다시 테스트하니, AI가 완벽하게 작동했습니다.
"오, 이제 제대로 되네요!" 파라미터를 제대로 정의하면 AI와 사람 모두가 API를 쉽게 사용할 수 있습니다. 문서를 보지 않아도 스키마만 보고 어떻게 호출해야 하는지 알 수 있습니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - description 필드에 예시 값을 포함하면 AI의 정확도가 높아집니다
- enum을 사용해 허용 가능한 값을 제한하면 잘못된 입력을 방지할 수 있습니다
- **정규표현식(pattern)**을 추가하면 형식 검증도 가능합니다
4. 응답 형식 지정
이주니어 씨의 API가 데이터를 잘 반환했지만, AI가 그 결과를 제대로 해석하지 못했습니다. "데이터는 오는데 왜 AI가 이상하게 대답하지?" 김시니어 씨가 응답 스키마를 보더니 고개를 저었습니다.
"응답 형식을 정의하지 않았네요. AI가 뭘 받을지 모르는 겁니다."
응답 스키마는 API가 반환하는 데이터의 구조를 정의합니다. 성공 응답(200, 201)뿐만 아니라 에러 응답(400, 404, 500)도 명시해야 AI가 상황에 맞게 대처할 수 있습니다.
각 응답 코드별로 어떤 데이터 구조를 반환하는지 상세히 기술하면, AI가 결과를 정확히 해석하고 사용자에게 적절히 전달합니다.
다음 코드를 살펴봅시다.
{
"paths": {
"/orders/{orderId}": {
"get": {
"summary": "주문 상태 조회",
"operationId": "getOrderStatus",
"responses": {
"200": {
"description": "주문 조회 성공",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"orderId": { "type": "string", "description": "주문 ID" },
"status": { "type": "string", "enum": ["pending", "shipped", "delivered"], "description": "주문 상태" },
"estimatedDelivery": { "type": "string", "format": "date", "description": "예상 배송일" }
}
}
}
}
},
"404": {
"description": "주문을 찾을 수 없음",
"content": {
"application/json": {
"schema": {
"type": "object",
"properties": {
"error": { "type": "string", "description": "에러 메시지" }
}
}
}
}
}
}
}
}
}
}
이주니어 씨는 주문 조회 API를 완성했습니다. Postman으로 테스트하니 JSON 데이터가 예쁘게 반환됐습니다.
하지만 AI 챗봇에 "내 주문 어디쯤 왔어?"라고 물으니 이상한 대답이 나왔습니다. "주문 정보를 확인했습니다"라고만 하고, 정작 배송 상태나 예상 도착일은 말해주지 않았습니다.
김시니어 씨가 설명했습니다. "API가 데이터를 주긴 했지만, AI는 그 데이터의 의미를 모릅니다.
status: 'shipped'라는 값이 배송 시작을 의미하는지, AI가 어떻게 알겠어요?" 그렇다면 응답 형식을 어떻게 지정해야 할까요? 쉽게 비유하자면, 응답 스키마는 마치 병원 검사 결과지의 범례와 같습니다.
수치가 나와 있어도 "정상 범위: 80-120", "단위: mg/dL"처럼 설명이 없으면 그 의미를 알 수 없습니다. 응답 스키마도 마찬가지로 "이 필드는 주문 상태고, 가능한 값은 pending, shipped, delivered입니다"라고 명확히 알려줘야 AI가 올바르게 해석합니다.
응답 형식을 정의하지 않던 시절에는 어땠을까요? 개발자들은 API를 호출하고 실제 응답을 보면서 "아, 이 필드가 이런 의미구나"라고 추측했습니다.
문서가 업데이트되지 않으면 코드를 뜯어보거나 개발자에게 직접 물어봤습니다. 에러가 나면 응답 바디를 일일이 확인하며 무슨 문제인지 파악했습니다.
당연히 시간이 오래 걸렸고, 통합 과정에서 오해도 많았습니다. 바로 이런 문제를 해결하기 위해 응답 스키마 정의가 필수입니다.
응답 스키마를 명확히 정의하면 AI가 데이터의 의미를 이해합니다. status 필드에 enum: ["pending", "shipped", "delivered"]를 정의하면, AI는 "shipped는 배송 중이구나"라고 판단하고 사용자에게 "고객님의 주문이 배송 중입니다"라고 자연스럽게 번역해줍니다.
또한 404 에러 응답도 정의해두면, 주문을 못 찾았을 때 "죄송합니다, 해당 주문을 찾을 수 없습니다"라고 적절히 대응합니다. 위의 코드를 한 줄씩 살펴보겠습니다.
200 응답은 성공 케이스입니다. content: application/json은 JSON 형식으로 반환한다는 뜻입니다.
schema 안에 실제 데이터 구조를 정의합니다. orderId는 문자열, status는 세 가지 값 중 하나, estimatedDelivery는 날짜 형식입니다.
enum 속성이 특히 중요합니다. status 필드가 임의의 문자열이 아니라 정해진 세 가지 값 중 하나라는 걸 명시합니다.
AI는 이걸 보고 "주문은 세 가지 상태 중 하나구나"라고 이해하고, 각 상태에 맞는 멘트를 생성합니다. 404 응답은 에러 케이스입니다.
주문을 찾지 못했을 때 어떤 구조로 에러를 반환하는지 정의합니다. error 필드에 에러 메시지가 담깁니다.
AI는 404 응답을 받으면 "주문을 찾을 수 없습니다"라고 사용자에게 설명합니다. description 필드는 각 프로퍼티의 의미를 설명합니다.
"예상 배송일"이라고 명시했기 때문에 AI는 사용자에게 "12월 25일에 도착 예정입니다"처럼 친절하게 안내할 수 있습니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 금융 서비스 챗봇을 만든다고 가정해봅시다. 계좌 잔액 조회 API가 {balance: 1500000, currency: "KRW"}를 반환하면, 응답 스키마에 currency 필드를 "통화 단위"라고 정의해둡니다.
AI는 이걸 보고 "잔액은 150만 원입니다"라고 자연스럽게 한국어로 변환합니다. 만약 currency: "USD"면 "1,500 dollars"라고 영어로 표현합니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 성공 응답만 정의하고 에러 응답을 생략하는 것입니다.
실제 운영 환경에서는 네트워크 오류, 권한 부족, 데이터 누락 등 다양한 에러가 발생합니다. 400, 401, 403, 404, 500 등 주요 에러 코드에 대한 응답 스키마를 미리 정의해두면 AI가 훨씬 견고하게 작동합니다.
또 다른 실수는 응답 스키마를 실제 구현과 다르게 정의하는 것입니다. 스키마에는 estimatedDelivery라고 써놨는데 실제로는 delivery_date를 반환하면 AI가 혼란스러워합니다.
스키마와 실제 코드를 항상 동기화해야 합니다. 다시 이주니어 씨의 이야기로 돌아가 봅시다.
응답 스키마를 상세히 정의하고 다시 테스트하니, AI가 완벽한 답변을 했습니다. "고객님의 주문은 현재 배송 중이며, 12월 20일에 도착 예정입니다!" 응답 스키마를 제대로 정의하면 AI가 데이터를 사람처럼 이해하고 자연스럽게 설명할 수 있습니다.
API 사용자들도 어떤 데이터를 받을지 명확히 알 수 있어 통합이 쉬워집니다. 여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - 모든 HTTP 상태 코드에 대해 응답 스키마를 정의하세요 (200, 400, 404, 500 등)
- enum을 적극 활용해 가능한 값의 범위를 제한하면 AI의 이해도가 높아집니다
- 실제 응답과 스키마를 자동으로 검증하는 테스트를 작성하면 불일치를 방지할 수 있습니다
5. 여러 Action 조합
이주니어 씨가 여러 개의 Action을 만들었습니다. 주문 조회, 재고 확인, 배송 추적 등 각각은 잘 작동했습니다.
하지만 사용자가 "내 주문 취소하고 환불해줘"라고 복잡한 요청을 하니 AI가 당황했습니다. 김시니어 씨가 웃으며 말했습니다.
"여러 Action을 순서대로 조합하는 방법을 AI에게 알려줘야 합니다."
여러 Action 조합은 복잡한 워크플로우를 처리하는 핵심입니다. AI는 단일 Action만 호출하는 게 아니라 여러 Action을 순차적으로 실행할 수 있습니다.
"주문 취소 → 환불 처리 → 알림 발송"처럼 비즈니스 로직이 여러 단계로 구성될 때, 각 Action의 출력을 다음 Action의 입력으로 연결하면 복잡한 작업도 자동화할 수 있습니다.
다음 코드를 살펴봅시다.
{
"paths": {
"/orders/{orderId}/cancel": {
"post": {
"summary": "주문 취소",
"description": "주문을 취소하고 취소 ID를 반환합니다. 이후 환불 처리에 사용할 수 있습니다",
"operationId": "cancelOrder",
"parameters": [
{ "name": "orderId", "in": "path", "required": true, "schema": { "type": "string" } }
],
"responses": {
"200": {
"content": {
"application/json": {
"schema": {
"properties": {
"cancellationId": { "type": "string", "description": "취소 처리 ID (환불 시 필요)" }
}
}
}
}
}
}
}
},
"/refunds": {
"post": {
"summary": "환불 처리",
"description": "취소된 주문에 대해 환불을 진행합니다. 취소 ID가 필요합니다",
"operationId": "processRefund",
"requestBody": {
"content": {
"application/json": {
"schema": {
"properties": {
"cancellationId": { "type": "string", "description": "주문 취소 시 받은 취소 ID" }
}
}
}
}
}
}
}
}
}
이주니어 씨는 뿌듯했습니다. 주문 조회, 주문 취소, 환불 처리 API를 모두 만들어 Action Group에 등록했습니다.
각각 테스트하니 완벽했습니다. 하지만 실제 고객 상담 시나리오를 시뮬레이션해보니 문제가 생겼습니다.
고객이 "주문 취소하고 환불해주세요"라고 요청하면, AI가 두 개의 Action을 따로따로 호출하려다 실패했습니다. 주문 취소는 성공했는데, 환불 처리에 필요한 취소 ID를 전달하지 못했기 때문입니다.
김시니어 씨가 설명했습니다. "Action은 독립적으로도 작동하지만, 서로 연결되도록 설계할 수도 있어요.
마치 레고 블록처럼요." 그렇다면 여러 Action 조합을 어떻게 설계해야 할까요? 쉽게 비유하자면, Action 조합은 마치 요리 과정과 같습니다.
"재료 준비 → 볶기 → 양념 추가 → 완성"처럼 각 단계의 결과물이 다음 단계의 재료가 됩니다. 첫 번째 Action이 주문 취소 ID를 만들어내면, 두 번째 Action은 그 ID를 받아서 환불을 처리합니다.
AI는 스키마를 보고 자동으로 이런 데이터 흐름을 파악합니다. Action이 분리되지 않던 시절에는 어땠을까요?
개발자들은 모든 비즈니스 로직을 하나의 거대한 함수로 작성했습니다. "주문 취소 + 환불 처리 + 알림 발송"이 전부 한 덩어리였습니다.
새로운 기능을 추가하려면 기존 코드를 수정해야 했고, 테스트도 어려웠습니다. 코드가 복잡해질수록 유지보수는 악몽이 됐습니다.
바로 이런 문제를 해결하기 위해 모듈화된 Action 설계가 중요합니다. 각 Action을 독립적으로 만들되, 서로 연결될 수 있게 설계하면 재사용성이 높아집니다.
주문 취소 Action은 단독으로 사용할 수도 있고, 환불 Action과 조합할 수도 있습니다. 나중에 "취소 후 쿠폰 지급" 기능을 추가하려면 새로운 Action만 만들고 기존 취소 Action과 연결하면 됩니다.
AI가 문맥을 파악해서 자동으로 순서를 결정합니다. 위의 코드를 한 줄씩 살펴보겠습니다.
cancelOrder Action은 주문을 취소하고 cancellationId를 반환합니다. description에 "이후 환불 처리에 사용할 수 있습니다"라고 명시했습니다.
AI는 이 설명을 보고 "아, 환불하려면 먼저 취소를 해야 하는구나"라고 이해합니다. processRefund Action은 requestBody에 cancellationId를 받습니다.
description에 "주문 취소 시 받은 취소 ID"라고 적었습니다. AI는 두 Action의 description을 비교하며 데이터 흐름을 파악합니다.
핵심은 명확한 description입니다. "환불 시 필요", "취소 ID가 필요합니다" 같은 표현으로 Action 간 의존성을 명시하면, AI가 자동으로 올바른 순서로 호출합니다.
사용자가 "취소하고 환불해줘"라고 하면 AI는 스스로 다음과 같이 계획합니다: 1단계: cancelOrder 호출 → cancellationId 획득 2단계: processRefund 호출 → cancellationId 전달 실제 현업에서는 어떻게 활용할까요? 예를 들어 은행 업무 자동화 시스템을 만든다고 가정해봅시다.
"계좌 개설 → 초기 입금 → 카드 발급 → 환영 메일 발송"처럼 복잡한 워크플로우가 있습니다. 각 단계를 독립적인 Action으로 만들고, 계좌번호를 다음 단계로 전달하도록 설계하면 AI가 전체 프로세스를 자동으로 오케스트레이션합니다.
실제로 많은 금융사들이 이런 방식으로 신규 고객 온보딩을 자동화하고 있습니다. 하지만 주의할 점도 있습니다.
초보 개발자들이 흔히 하는 실수 중 하나는 순환 참조를 만드는 것입니다. Action A가 Action B의 결과를 필요로 하고, Action B가 Action A의 결과를 필요로 하면 AI가 무한 루프에 빠질 수 있습니다.
데이터 흐름이 항상 한 방향으로 흐르도록 설계해야 합니다. 또 다른 실수는 너무 긴 체인을 만드는 것입니다.
Action이 10개, 20개로 연결되면 중간에 하나라도 실패하면 전체가 실패합니다. 적절히 그룹화하거나, 에러 복구 로직을 추가하는 게 좋습니다.
다시 이주니어 씨의 이야기로 돌아가 봅시다. Action 간 연결을 명확히 정의하고 다시 테스트하니, AI가 완벽하게 작동했습니다.
"주문 취소 완료했고, 환불도 3일 내에 처리됩니다!" 여러 Action을 조합하는 설계를 이해하면 복잡한 비즈니스 로직도 우아하게 자동화할 수 있습니다. 각 Action은 단순하게 유지하되, 조합으로 강력한 기능을 만드는 것이 핵심입니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - Action 간 의존성을 description에 명확히 적어 AI가 순서를 파악하도록 합니다
- 데이터 흐름이 단방향으로 흐르게 설계해 순환 참조를 방지하세요
- 각 Action은 독립적으로 테스트할 수 있어야 유지보수가 쉽습니다
6. 스키마 검증하기
이주니어 씨가 복잡한 OpenAPI 스키마를 완성했습니다. 자신감 있게 Bedrock에 업로드했는데 에러가 났습니다.
"Invalid schema format"이라는 메시지만 덩그러니 나왔습니다. 김시니어 씨가 다가와 말했습니다.
"배포 전에 스키마를 검증해야 합니다. 그래야 시행착오를 줄일 수 있어요."
스키마 검증은 OpenAPI 스펙을 올바르게 작성했는지 확인하는 과정입니다. JSON 문법 오류, 필수 필드 누락, 타입 불일치 등을 사전에 발견할 수 있습니다.
Swagger Editor, Spectral, OpenAPI Generator 같은 도구를 사용하면 실시간으로 검증하고, 문제가 있는 부분을 정확히 찾아낼 수 있습니다.
다음 코드를 살펴봅시다.
# Spectral을 사용한 스키마 검증 예시
# package.json에 추가
{
"scripts": {
"validate": "spectral lint openapi.json"
},
"devDependencies": {
"@stoplight/spectral-cli": "^6.0.0"
}
}
# .spectral.yaml 설정 파일
extends: ["spectral:oas"]
rules:
operation-description: error
operation-operationId: error
parameter-description: warn
# Bedrock 특화 규칙
info-contact: off
info-license: off
# 실행 명령어
# npm run validate
# 출력 예시:
# ✖ operation-description Operation must have a description
# paths./users.get
# ✖ parameter-description Parameter must have a description
# paths./users.get.parameters[0]
이주니어 씨는 며칠 동안 공들여 OpenAPI 스키마를 작성했습니다. 300줄이 넘는 JSON 파일이었습니다.
마침내 완성하고 Bedrock에 업로드하는 순간, 가슴이 두근거렸습니다. 하지만 결과는 차가운 에러 메시지였습니다.
"어디가 잘못된 거지?" 이주니어 씨는 파일을 처음부터 다시 읽어보기 시작했습니다. 하지만 300줄 중 어디에 문제가 있는지 찾기가 쉽지 않았습니다.
콤마 하나, 중괄호 하나만 빠져도 전체가 무효가 되는 게 JSON이었습니다. 김시니어 씨가 화면을 보더니 말했습니다.
"검증 도구를 사용하세요. 사람이 눈으로 찾는 건 한계가 있어요." 그렇다면 스키마 검증을 어떻게 해야 할까요?
쉽게 비유하자면, 스키마 검증은 마치 맞춤법 검사기와 같습니다. 긴 문서를 쓰고 나서 워드의 맞춤법 검사를 돌리면 오타, 띄어쓰기 오류, 문법 실수를 자동으로 찾아줍니다.
OpenAPI 검증 도구도 마찬가지로 스펙 위반, 필수 필드 누락, 타입 오류를 자동으로 잡아냅니다. 검증 도구가 없던 시절에는 어땠을까요?
개발자들은 스키마를 작성하고 직접 서버에 올려서 테스트했습니다. 에러가 나면 로그를 보고 추측했습니다.
"아마 이 부분이 문제일 거야"라고 수정하고 다시 올렸습니다. 이런 과정을 수십 번 반복했습니다.
시간도 오래 걸렸고, 정확히 무엇이 문제인지 파악하기도 어려웠습니다. 바로 이런 문제를 해결하기 위해 자동 검증 도구가 필수입니다.
Swagger Editor는 웹 브라우저에서 실시간으로 검증합니다. 코드를 입력하는 동안 오류를 바로바로 알려줍니다.
Spectral은 커맨드라인 도구로, CI/CD 파이프라인에 통합할 수 있습니다. 코드를 커밋하기 전에 자동으로 검증해서 문제가 있으면 머지를 막을 수 있습니다.
OpenAPI Generator는 스키마로부터 실제 클라이언트 코드를 생성하면서 동시에 검증합니다. 위의 코드를 한 줄씩 살펴보겠습니다.
package.json에 검증 스크립트를 추가했습니다. npm run validate 명령 하나로 스키마를 검증할 수 있습니다.
개발자가 매번 수동으로 체크하지 않아도 되니 실수가 줄어듭니다. .spectral.yaml 설정 파일에서 검증 규칙을 정의합니다.
extends: ["spectral:oas"]는 OpenAPI 표준 규칙을 사용한다는 뜻입니다. operation-description: error는 모든 operation에 description이 필수라는 규칙입니다.
Bedrock은 description을 AI 학습에 사용하기 때문에 특히 중요합니다. parameter-description: warn은 파라미터 설명이 없으면 경고를 표시합니다.
error가 아니라 warn이므로 빌드는 성공하지만, 개발자에게 "설명을 추가하면 더 좋아요"라고 알려줍니다. info-contact: off는 연락처 정보 검증을 끕니다.
내부 시스템에서는 굳이 필요 없으니까요. 실행 결과를 보면 정확히 어느 경로의 어느 부분이 문제인지 표시됩니다.
paths./users.get의 description이 빠졌다고 알려주니, 개발자는 바로 그 부분으로 가서 수정하면 됩니다. 실제 현업에서는 어떻게 활용할까요?
예를 들어 여러 팀이 협업하는 대규모 프로젝트를 진행한다고 가정해봅시다. 백엔드 팀이 API를 만들고, AI 팀이 Bedrock에 연동합니다.
백엔드 팀이 스키마를 작성할 때마다 자동 검증을 돌리면, AI 팀이 받기 전에 품질이 보장됩니다. Git hook으로 커밋 전 자동 검증을 설정하면, 잘못된 스키마가 리포지토리에 들어가는 것 자체를 막을 수 있습니다.
하지만 주의할 점도 있습니다. 초보 개발자들이 흔히 하는 실수 중 하나는 검증 도구가 알려주는 모든 경고를 무시하는 것입니다.
"어차피 작동하는데 뭐"라고 생각하기 쉽지만, 경고는 잠재적 문제를 알려줍니다. 특히 Bedrock 같은 AI 플랫폼은 스키마를 학습 데이터로 사용하기 때문에, 설명이 부실하면 AI의 성능이 떨어집니다.
또 다른 실수는 로컬에서만 검증하고 CI/CD에는 통합하지 않는 것입니다. 개발자가 깜빡하고 검증을 안 돌릴 수 있습니다.
GitHub Actions나 Jenkins에 검증 단계를 추가하면 자동으로 품질이 관리됩니다. 다시 이주니어 씨의 이야기로 돌아가 봅시다.
Spectral을 설치하고 검증을 돌리니, 금방 문제를 찾았습니다. operationId가 중복됐던 것입니다.
수정하고 다시 검증하니 모든 체크가 통과했습니다. 자신감 있게 Bedrock에 업로드하니 이번에는 성공했습니다.
스키마 검증을 습관화하면 배포 전 대부분의 문제를 미리 잡을 수 있습니다. 시행착오가 줄어들고, 팀 전체의 생산성이 높아집니다.
여러분도 오늘 배운 내용을 실제 프로젝트에 적용해 보세요.
실전 팁
💡 - CI/CD 파이프라인에 검증 단계를 추가해 자동으로 품질을 관리하세요
- Swagger Editor로 실시간 피드백을 받으며 작성하면 효율적입니다
- 커스텀 규칙을 추가해 프로젝트 특화 요구사항도 검증할 수 있습니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
Helm 마이크로서비스 패키징 완벽 가이드
Kubernetes 환경에서 마이크로서비스를 효율적으로 패키징하고 배포하는 Helm의 핵심 기능을 실무 중심으로 학습합니다. Chart 생성부터 릴리스 관리까지 체계적으로 다룹니다.
OpenAPI로 API 문서화 완벽 가이드
Spring Boot 프로젝트에서 springdoc-openapi를 사용하여 Swagger UI로 자동 API 문서를 생성하는 방법을 단계별로 배웁니다. 실무에서 바로 활용할 수 있는 어노테이션과 스키마 정의 방법까지 다룹니다.
보안 아키텍처 구성 완벽 가이드
프로젝트의 보안을 처음부터 설계하는 방법을 배웁니다. AWS 환경에서 VPC부터 WAF, 암호화, 접근 제어까지 실무에서 바로 적용할 수 있는 보안 아키텍처를 단계별로 구성해봅니다.
AWS Organizations 완벽 가이드
여러 AWS 계정을 체계적으로 관리하고 통합 결제와 보안 정책을 적용하는 방법을 실무 스토리로 쉽게 배워봅니다. 초보 개발자도 바로 이해할 수 있는 친절한 설명과 실전 예제를 제공합니다.
AWS KMS 암호화 완벽 가이드
AWS KMS(Key Management Service)를 활용한 클라우드 데이터 암호화 방법을 초급 개발자를 위해 쉽게 설명합니다. CMK 생성부터 S3, EBS 암호화, 봉투 암호화까지 실무에 필요한 모든 내용을 담았습니다.