AWS Cloud School 13기 91일차

Forever 김·2026년 5월 11일

AWS Cloud School

목록 보기
81/97

TIL

오늘은 Developing Generative AI Applications on AWS 강의를 들었다. 생성형 AI(Generative AI)와 Amazon Bedrock을 활용해서 실제 애플리케이션을 만드는 방법을 배웠는데, 이론부터 실습까지 꽤 알차게 진행됐다. 특히 프롬프트 엔지니어링 기법들이나 RAG 아키텍처 같은 개념들이 실제로 어떻게 코드로 구현되는지 보니까 훨씬 이해가 잘 됐다.


모듈 1: AWS의 생성형 AI 애플리케이션 구성 요소

생성형 AI(Generative AI)란?

새로운 콘텐츠 및 아이디어를 생성하는 AI 유형이다. 엄청난 양의 데이터에 대해 사전 훈련된 대규모 모델(Foundation Model, FM)에 의해 구동된다.

비지도 학습(Unsupervised Learning)을 기반으로 하며, 텍스트, 이미지, 오디오, 비디오, 구조화된 데이터, 소프트웨어 코드 등 다양한 콘텐츠 유형을 생성할 수 있다.

파운데이션 모델(Foundation Model, FM)

광범위한 일반화된 데이터와 레이블이 지정되지 않은 데이터를 기반으로 훈련된 ML 모델이다. 콘텐츠 이해, 변환, 생성을 비롯한 여러 가지 일반적인 태스크를 수행한다.

FM이 문장을 완성하는 방식은 크게 4단계로 진행된다.

  1. 토큰화 및 인코딩: 입력 문장을 개별 토큰(단어 또는 하위 단어)으로 분해하고 숫자 표현으로 변환
  2. 단어 임베딩: 토큰의 의미 및 구문 정보를 포착하는 고밀도 벡터 표현에 각 토큰을 매핑. 유사한 의미를 지닌 단어는 벡터 공간에서 서로 가까이 위치
  3. 디코딩: 셀프 어텐션 및 피드 포워드 신경망의 여러 계층을 통해 처리하여 다음 토큰을 예측
  4. 출력: 가장 가능성이 높은 다음 토큰을 생성하고 전체 문장이 완성될 때까지 반복

추론(Inference)과 컨텍스트(Context)

추론은 프롬프트를 입력으로 사용하여 파운데이션 모델을 호출하고 응답을 출력으로 가져오는 프로세스다.

컨텍스트는 모델과의 일대일 세션이다. 중요한 점은 컨텍스트에 제한이 있다는 것이다.

  • 상호 작용 간에 자동으로 지속되지 않는다
  • 포함할 수 있는 최대 토큰 수가 정해져 있다
  • 컨텍스트를 유지하려면 각 새 프롬프트에 관련 정보를 의도적으로 다시 포함해야 한다

Amazon Bedrock의 주요 이점

이점설명
간편한 통합API 하나로 다양한 AI 모델을 애플리케이션에 통합
사용자 지정자체 데이터로 모델을 미세 조정하여 맞춤형 모델 생성
개인 정보 보호데이터 및 사용자 지정 내용은 AWS 계정 내에서 비공개 유지
비용 효율성선불 비용이나 약정 없이 사용한 항목에만 비용 지불
확장성애플리케이션 수요에 맞게 자동 조정
AWS 서비스 통합포괄적인 AI/ML 워크플로를 위해 다른 AWS 서비스와 통합

생성형 AI 프로젝트 계획 4단계

  1. 범위 정의: 고객 요구 파악, 조직 역량 고려, 장단기 영향 평가
  2. 모델 선택: 사전 훈련된 모델 그대로 사용 vs 미세 조정 중 선택
  3. 모델 조정: 프롬프트 엔지니어링(RAG 포함) 또는 미세 조정 방식 선택
  4. 모델 사용: 책임감 있는 AI 관리, 사용자 피드백 계획, 성능 추적

기본 생성형 AI 애플리케이션 아키텍처

서버리스 패턴이 일반적이다.

사용자 → 프론트엔드(S3 + CloudFront) → API Gateway → Lambda → Amazon Bedrock → FM

모듈 2: Amazon Bedrock을 사용한 프로그래밍

LLM 요청의 4가지 구성 요소

  1. 입력 콘텐츠: 사용자 메시지, 대화 기록, 다중 모달 데이터
  2. 시스템 구성: 시스템 프롬프트, 페르소나 설정, 행동 지침
  3. 외부 리소스: 함수 호출, 지식 기반(RAG), 실시간 데이터
  4. 추론 파라미터: 무작위성, 독창성, 출력 구조 제어

추론 파라미터(Inference Parameters)

파라미터설명
temperature / top-p출력의 독창성과 예측 가능성 간의 균형 제어. 낮을수록 일관성, 높을수록 독창성
토큰 수응답 길이의 하드 제한. 출력이 길수록 처리 시간과 비용 증가
중지 시퀀스모델이 텍스트 생성을 중지하는 위치를 정밀하게 제어
결과 수각 프롬프트에 대해 생성하는 대체 응답의 수
페널티반복 텍스트, 특정 용어의 과도한 사용 방지

Amazon Bedrock API 3가지 접근 방식

  • AWS Management Console: 모델 테스트, 파라미터 구성, 프로토타이핑에 유용
  • AWS CLI: 스크립트 작성, 자동화, CI/CD 파이프라인 통합에 유용
  • SDK: 프로덕션 애플리케이션용. Java, JavaScript, .NET, Python 등 지원

주요 API 엔드포인트

bedrock 클라이언트 (제어 영역)

  • ListFoundationModels: 사용 가능한 모델 검색
  • CreateModelInvocationJob: 배치 처리 작업 설정
  • CreateGuardrail: 안전 및 콘텐츠 필터링 정책 수립

bedrock-runtime 클라이언트 (데이터 영역)

  • InvokeModel: 동기식 모델 호출 (실시간 애플리케이션)
  • InvokeModelWithResponseStream: 응답 스트리밍 (긴 텍스트 생성)
  • Converse: 다양한 FM에서 통합 인터페이스 제공
  • ApplyGuardrail: 안전 정책 적용

코드 예제: InvokeModel

import boto3, json

# bedrock runtime 클라이언트 인스턴스화
bedrock_runtime = boto3.client("bedrock-runtime", region_name="us-east-1")

# 모델용 페이로드 구성
body = json.dumps({
    "anthropic_version": "bedrock-2023-05-31",
    "max_tokens": 5000,
    "messages": [
        {
            "role": "user",
            "content": "Create a script to resize images"
        }
    ]
})

# Claude 모델 호출
response = bedrock_runtime.invoke_model(
    body=body,
    modelId="global.anthropic.claude-sonnet-4-5-20250929-v1:0",
    accept="application/json",
    contentType="application/json"
)

# 응답 출력
response_body = json.loads(response.get("body").read())
print(response_body["content"][0]["text"])

코드 예제: Converse API

모델 공급자에 관계없이 동일한 메시지 구조를 사용하는 통합 인터페이스다. 모델 ID만 바꾸면 코드 변경 없이 다른 모델로 전환 가능하다.

import boto3

bedrock_client = boto3.client("bedrock-runtime")

response = bedrock_client.converse(
    modelId="us.anthropic.claude-sonnet-4-5-20250929-v1:0",
    messages=[{
        "role": "user",
        "content": [{"text": "이미지 크기를 조정하는 스크립트 생성."}]
    }],
    system=[{"text": "당신은 Python에 능숙한 앱 개발자입니다. 코딩 주제에 대한 논의에만 참여하세요."}],
    inferenceConfig={"temperature": 0.7, "topP": 0.9, "maxTokens": 500},
    additionalModelRequestFields={"top_k": 200}
)

모듈 3: 개발자를 위한 프롬프트 엔지니어링

프롬프트 엔지니어링이란?

LLM 사용 방식을 최적화하는 분야다. 모델 자체를 조정하지 않고도 LLM 응답을 개선할 수 있다. 모델 가중치나 파라미터에 영향을 주지 않는다.

효율적인 프롬프트의 4가지 요소

요소설명
지침LLM이 수행할 태스크 설명
컨텍스트모델을 안내할 외부 정보
입력 데이터응답을 원하는 입력
출력 지시출력 유형 또는 형식

3가지 기본 프롬프팅 기법

Zero-Shot 프롬프팅

추가 예제 없이 LLM에 태스크를 제시하는 방식이다. 모델이 추가 컨텍스트 없이 태스크를 수행할 것으로 기대한다.

다음 소셜 미디어 게시물의 감정을 알려주고 긍정, 부정 또는 중립으로 분류하십시오.
혁신적인 전기차를 놓치지 마십시오! AnyCompany는 EV용 머슬카를 버리고...

Few-Shot 프롬프팅

모델에 태스크의 예제와 원하는 출력을 함께 제공하는 방식이다. 컨텍스트를 제공하면 모델이 태스크 지침을 더 정확하게 준수한다.

다음 헤드라인의 감정을 분류합니다.
연구 기업은 신기술이 부적절하다는 주장을 차단합니다. → 부정
반대하는 소수 강경론자가 줄면서 해상 풍력 발전소는 계속 번창하고 있습니다. → 긍정
제조 공장은 최근에 주당국의 조사 대상이 되고 있습니다. → ?

사고 사슬(Chain of Thought, CoT)

복잡한 추론 태스크를 중간 단계로 구분하는 방식이다. "단계별로 생각하십시오(Think step by step)" 라는 구문으로 CoT 추론을 유도할 수 있다.

차량 A의 총 비용은 40,000 USD이고 계약금으로 원금의 30%가 있어야 합니다.
차량 B의 총 비용은 50,000 USD이고 계약금으로 원금의 20%가 있어야 합니다.
단계별로 생각해서 선납금이 더 필요한 차량은?

→ A 차량 계약금: 40,000 × 30% = 12,000 USD
→ B 차량 계약금: 50,000 × 20% = 10,000 USD
→ 차량 A가 더 많은 선납금 필요

고급 프롬프팅 기법

기법설명
사고 트리(ToT)하나의 순차적 경로 대신 여러 경로를 고려
자체 일관성다양한 추론 경로를 샘플링하고 최종 답변을 집계
RAG외부 지식 기반에서 관련 문서를 검색하여 프롬프트 증강
ReAct추론과 액션을 결합. 외부 도구(위키피디아, SQL DB 등) 호출 가능

프롬프트 최적화 모범 사례

모범 사례나쁜 예좋은 예
구체적이고 명확하게"로그인 폼 코드 생성해줘""이메일 유효성 검사, 비밀번호 강도 표시기, 오류 처리 기능이 포함된 React 로그인 폼 생성해줘"
역할 사용"이 함수에서 취약점 분석해줘""숙련된 보안 엔지니어라고 가정하고 이 인증 함수의 잠재적 취약점을 확인해줘"
제약 조건 포함"React 컴포넌트 생성해줘""함수 컴포넌트, TypeScript, 접근성 가이드라인 준수, 인라인 주석 포함한 React 컴포넌트 생성해줘"

쿼리 분해(Query Decomposition)

복잡한 질문을 더 작은 하위 태스크로 나누는 기법이다. 모델이 각 구성 요소를 개별적으로 처리하여 더 정확한 응답을 제공한다.

예시: "이메일 인증 및 오류 처리 기능이 포함된 사용자 등록 REST API 엔드포인트 생성"을 아래처럼 분해한다.

  1. 사용자 등록 데이터 모델 설계 (JSON 스키마)
  2. /register POST 엔드포인트 구조 생성
  3. 이메일 인증 로직 추가
  4. 오류 처리 구현 (중복 이메일, 잘못된 형식, 서버 오류)
  5. 모든 구성 요소 통합

모듈 4: 공통 아키텍처에서 Amazon Bedrock API 사용

Amazon Bedrock 추론 모드 3가지

모드설명적합한 경우
배치 추론대규모 데이터 세트에서 한 번 수행일별 예측 분석, 임베딩 생성, 대규모 번역
온디맨드 추론즉시 응답 제공AI 챗봇, RAG, 개인화 추천
프로비저닝된 처리량시간당 성능 기준으로 모델 단위 구매워크로드를 일정하게 실행하는 경우

대화형 메모리 구현

파운데이션 모델은 대화 기록을 자동으로 유지하지 않는다. 애플리케이션에서 직접 구현해야 한다.

  • 단기 메모리: 현재 세션의 대화 기록을 메모리에 유지
  • 장기 메모리: DynamoDB 같은 영구 저장소에 대화 기록 저장. 사용자별, 주제별로 별도 세션 관리 가능

모듈 5: RAG를 사용한 생성형 AI 응답 사용자 지정

RAG(Retrieval-Augmented Generation)란?

외부 지식 기반에서 관련 정보를 검색하여 LLM의 응답을 개선하는 기법이다.

  • 검색(Retrieval): 외부 지식 기반에서 관련 컨텍스트 검색
  • 증강(Augmentation): 검색한 컨텍스트로 입력 프롬프트 개선
  • 생성(Generation): 증강된 프롬프트를 사용하여 더 관련성 높은 응답 생성

RAG 지식 기반 구성 3단계

  1. 데이터 추출 및 청크 분할: 기업 데이터 소스에서 문서를 추출하고 텍스트 블록으로 분할
  2. 임베딩 변환: 각 청크를 의미가 반영된 수학적 벡터 표현(임베딩)으로 변환
  3. 벡터 저장소 저장: 임베딩을 검색 가능한 상태로 저장

청크 크기 선택 고려 사항

  • 청크가 작을수록: 검색 속도 빠름, 컨텍스트 부족 가능
  • 청크가 클수록: 컨텍스트 풍부, 컴퓨팅 비용 증가, 노이즈 포함 가능

지식 기반 저장소 유형

유형적합한 경우
벡터 저장소구조화되지 않은 일반 텍스트, 시맨틱 유사성 기반 검색
그래프 데이터베이스엔터티와 관계가 명확하게 정의된 도메인, 복잡한 다단계 질문
하이브리드구조화된 도메인 + 폭넓은 시맨틱 검색이 모두 필요한 경우

Amazon Bedrock Knowledge Bases API

  • Retrieve: 쿼리와 가장 관련성 높은 소스 청크 검색
  • GenerateQuery: 자연어 쿼리를 구조화된 데이터 저장소 쿼리로 변환
  • RetrieveAndGenerate: Retrieve + InvokeModel을 결합한 전체 RAG 프로세스 수행

AWS에서 RAG 솔루션 구축 시 사용 가능한 옵션

오케스트레이션 프레임워크

  • LangChain, LlamaIndex, Haystack, Hugging Face Transformers

검색기(벡터 저장소)

  • Amazon OpenSearch Service, Amazon Aurora PostgreSQL with pgvector
  • Amazon MemoryDB, Amazon Neptune Analytics, Amazon S3 Vectors
  • Pinecone, MongoDB Atlas, Weaviate

생성기(LLM 액세스)

  • Amazon Bedrock, Amazon SageMaker AI JumpStart

모듈 6: 오픈 소스 프레임워크와 Amazon Bedrock 통합

LangChain이란?

오픈 소스 프레임워크로 Python, TypeScript, JavaScript로 제공된다. LLM과 상호 작용할 때 컨텍스트 관리나 단계 순서 관리 같은 일반적인 태스크를 효율적으로 처리할 수 있는 구성 요소를 제공한다.

LangChain으로 Amazon Bedrock 호출

from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, SystemMessage

# Amazon Bedrock 모델 초기화
model = init_chat_model(
    model="bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0",
    model_provider="bedrock_converse"
)

# 메시지 전송
messages = [
    SystemMessage("Translate the following from English into Italian"),
    HumanMessage("hi!"),
]
response = model.invoke(messages)

LangChain은 내부적으로 Amazon Bedrock Converse API를 활용하여 요청을 처리한다. 응답은 AIMessage 객체로 래핑되어 반환된다.

LangChain 프롬프트 템플릿

from langchain_core.prompts import ChatPromptTemplate

system_template = "다음을 영어에서 {language}로 번역하세요"
prompt_template = ChatPromptTemplate.from_messages(
    [("system", system_template), ("user", "{text}")]
)

prompt = prompt_template.invoke({"language": "Italian", "text": "hi!"})
response = model.invoke(prompt)

LangChain으로 대화 기록 관리

DynamoDB를 활용하여 대화 기록을 영구 저장하는 체인을 구성할 수 있다.

from langchain.chat_models import init_chat_model
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.runnables.history import RunnableWithMessageHistory

model = init_chat_model(
    model="bedrock/anthropic.claude-sonnet-4-5-20250929-v1:0",
    model_provider="bedrock_converse"
)

prompt_template = ChatPromptTemplate.from_messages([
    ("system", "You are a helpful assistant."),
    MessagesPlaceholder(variable_name="history"),
    ("human", "{question}")
])

chain = prompt_template | model

# DynamoDB로 대화 기록 영구 저장
chain_with_history = RunnableWithMessageHistory(
    chain,
    lambda session_id: DynamoDBChatMessageHistory(
        table_name="SessionTable",
        session_id=session_id
    ),
    input_messages_key="question",
    history_messages_key="history"
)

실습 정리

실습 1: 텍스트 생성 (Zero-Shot 프롬프팅)

고객 불만 이메일에 대한 응답을 Amazon Nova Lite 모델로 생성하는 실습이었다.

핵심 흐름:
1. boto3.client('bedrock-runtime') 으로 클라이언트 생성
2. 프롬프트 데이터 구성 (Zero-Shot 방식)
3. invoke_model() 또는 invoke_model_with_response_stream() 호출
4. 응답 파싱 및 출력

스트리밍 방식은 전체 응답이 생성될 때까지 기다리지 않고 청크 단위로 실시간 출력이 가능해서 사용자 경험이 훨씬 좋다.

실습 2: 텍스트 요약

AWS 블로그 게시물 텍스트를 Amazon Nova Lite 모델로 요약하는 실습이었다.

prompt_data = """
Please provide a summary of the following text:
AWS took all of that feedback from customers, and today we are excited to announce Amazon Bedrock...
"""

body = json.dumps({
    "messages": [{"role": "user", "content": [{"text": prompt_data}]}],
    "inferenceConfig": {"maxTokens": 2048, "temperature": 0, "topP": 0.9}
})

response = bedrock_client.invoke_model(
    body=body,
    modelId='amazon.nova-lite-v1:0',
    accept='application/json',
    contentType='application/json'
)

temperature=0으로 설정하면 일관성 있는 요약 결과를 얻을 수 있다.


정리

오늘 핵심은 "Amazon Bedrock을 통해 다양한 FM을 API 하나로 활용할 수 있다" 는 것이다. 직접 모델을 구축하거나 인프라를 관리할 필요 없이 프롬프트만 잘 설계하면 강력한 AI 기능을 애플리케이션에 통합할 수 있다.

특히 프롬프트 엔지니어링 기법들이 인상적이었다. Zero-Shot, Few-Shot, CoT를 상황에 맞게 조합하면 모델 재훈련 없이도 응답 품질을 크게 개선할 수 있다. 그리고 RAG 아키텍처는 기업 내부 데이터를 LLM에 연결하는 현실적인 방법이라는 게 느껴졌다. 모델이 학습하지 않은 최신 정보나 사내 문서를 검색해서 답변에 활용할 수 있으니까.

LangChain 같은 오픈 소스 프레임워크를 쓰면 Bedrock API를 직접 다루는 것보다 훨씬 편하게 개발할 수 있다는 것도 알게 됐다. 특히 대화 기록 관리나 프롬프트 템플릿 같은 반복적인 작업을 추상화해주는 게 실용적이다.

이번 velog는 AWS Kiro를 통해 작성하였다.

profile
나를 한줄로

0개의 댓글