1. 개요
오늘날 AI를 사용한 빌드는 어디서 시작해야 할까요? 대부분의 경우 간단한 질문으로 시작합니다. '모델이 내가 생각하고 있는 문제를 실제로 해결하는 데 도움이 될 수 있을까?' 이때 Google AI Studio가 유용합니다. 무엇이든 빠르게 프로토타입을 제작할 수 있는 곳입니다. 주방을 리모델링하고 싶은데 Gemini가 도움이 될 것 같아요. 하지만 저는 엔지니어이지 일반 계약자가 아닙니다. 규정, 설비 등 고려해야 할 사항이 너무 많아서 무엇을 요청해야 할지 모르겠어요. 그러니 이 문제를 해결하기 위해 Gemini가 매우 상세한 프롬프트를 생성하도록 하고, 전체 리모델링 계획을 생성하고 리모델링을 시각화해 보겠습니다. 하지만 잠깐만요. 여기에서 비즈니스를 확장하려면 어떻게 해야 할까요? 상담사를 입력하세요.
에이전트는 AI 모델과 소통하면서 보유한 도구와 컨텍스트를 사용해 목표 기반 작업을 수행하는 자율 프로그램으로, 사실에 기반한 자율적인 의사 결정을 내릴 수 있습니다.
에이전트 개발 키트 (ADK)
에이전트 개발 키트 (ADK)는 AI 에이전트를 개발하고 배포하기 위한 유연한 모듈식 프레임워크입니다. ADK는 여러 개의 개별 에이전트 인스턴스를 멀티 에이전트 시스템 (MAS)으로 구성하여 정교한 애플리케이션을 빌드하는 것을 지원합니다.
ADK에서 멀티 에이전트 시스템은 다양한 에이전트가 더 큰 목표를 달성하기 위해 협업하거나 조정하는 애플리케이션입니다. 이러한 에이전트는 계층 구조를 형성하는 경우가 많습니다. 이러한 방식으로 애플리케이션을 구조화하면 향상된 모듈성, 전문성, 재사용성, 유지관리 용이성, 전용 워크플로 에이전트를 사용한 구조화된 제어 흐름 정의 기능 등 상당한 이점이 있습니다.
빌드할 항목
프로토타입 프롬프트에서 에이전트 빌드로 이동할 준비가 되셨나요? 주방 리모델링 프로젝트의 제안서 문서를 생성하는 데 도움이 되는 에이전트를 만들어 보겠습니다. 이 실습에서는 다음 작업을 수행합니다.
- ADK로 리모델링 제안서 문서를 생성하는 간단한 에이전트 빌드
- 생성된 리모델링 제안서 문서를 Cloud Storage 버킷에 저장
- Cloud Shell 및 에이전트 웹 출력에서 에이전트 테스트
요구사항
2. 시작하기 전에
프로젝트 만들기
- Google Cloud 콘솔의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.
- Cloud 프로젝트에 결제가 사용 설정되어 있는지 확인합니다. 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요 .
- 이 글을 읽고 Google Cloud를 시작하고 ADK를 사용하는 데 도움이 되는 크레딧을 받으려면 이 링크를 사용하여 크레딧을 사용하세요.
- 여기의 안내에 따라 여기 사용할 수 있습니다. 이 링크는 2025년 7월 15일까지 사용 가능합니다.
- 이 링크를 클릭하여 Cloud Shell을 활성화합니다. Cloud Shell에서 해당 버튼을 클릭하여 Cloud Shell 터미널 (클라우드 명령어 실행용)과 편집기 (프로젝트 빌드용) 간에 전환할 수 있습니다.
- Cloud Shell에 연결되면 다음 명령어를 사용하여 인증이 완료되었고 프로젝트가 해당 프로젝트 ID로 설정되었는지 확인합니다.
gcloud auth list
- Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project
- 프로젝트가 설정되지 않은 경우 다음 명령어를 사용하여 설정합니다.
gcloud config set project <YOUR_PROJECT_ID>
- Python 3.9 이상이 있어야 합니다.
기타 gcloud 명령어 및 사용법은 문서를 참조하세요.
3. 프로토타입
Google AI Studio로 이동합니다. 프롬프트를 입력하기 시작합니다. 프롬프트는 다음과 같습니다.
I want to renovate my kitchen, basically just remodel it. I don't know where to start. So I want to use Gemini to generate a plan. For that I need a good prompt. Give me a short yet detailed prompt that I can use.
오른쪽의 매개변수를 조정하고 구성하여 최적의 대답을 얻으세요.
이 간단한 설명을 바탕으로 Gemini가 리모델링을 시작할 수 있는 매우 상세한 프롬프트를 만들어 주었습니다. 결과적으로 Gemini를 사용하여 AI Studio와 모델에서 훨씬 더 나은 대답을 얻고 있습니다. 사용 사례에 따라 사용할 모델을 선택할 수도 있습니다.
Gemini 2.5 Pro를 선택했습니다. 이 모델은 Thinking 모델로, 긴 형식의 분석과 자세한 문서에 대해 더 많은 출력 토큰(이 경우 최대 65,000개)을 얻을 수 있습니다. Gemini 사고 상자는 기본 추론 기능이 있고 긴 컨텍스트 요청을 처리할 수 있는 Gemini 2.5 Pro를 사용 설정하면 표시됩니다.
아래에서 응답 스니펫을 확인하세요.

AI Studio가 내 데이터를 분석하여 캐비닛, 카운터탑, 백스플래시, 바닥, 싱크, 응집력, 색상 팔레트, 소재 선택과 같은 모든 요소를 생성했습니다. Gemini는 출처도 인용합니다.
이제 다른 프롬프트로 아이디어를 구현해 보세요.
- 이 프롬프트를 복사하여 프롬프트 편집기에 붙여넣습니다.
Add flat and circular light accessories above the island area for my current kitchen in the attached image.
- 현재 주방의 이미지를 첨부합니다 (또는 샘플 주방 이미지를 사용해도 됨).
- 이미지를 생성할 수 있도록 모델을 'Gemini 2.0 Flash 프리뷰 이미지 생성'으로 변경합니다.
다음과 같은 출력이 표시됩니다.

이것이 바로 Gemini의 힘입니다.
동영상 이해부터 네이티브 이미지 생성, Google 검색으로 실제 정보에 그라운딩하는 작업까지 이 모든 건 Gemini로만 가능합니다.
AI Studio에서 이 프로토타입을 가져와 API 키를 획득하고 Vertex AI ADK의 기능을 사용하여 완전한 에이전트 애플리케이션으로 확장할 수 있습니다.
4. ADK 설정
이제 '시작하기 전에' 섹션에서 활성화한 Cloud Shell 터미널로 이동합니다.
- 가상 환경 만들기 및 활성화 (권장)
Cloud Shell 터미널에서 가상 환경을 만듭니다.
python -m venv .venv
가상 환경을 활성화합니다.
source .venv/bin/activate
- ADK 설치
pip install google-adk
5. 프로젝트 구조
- Cloud Shell 터미널에서 원하는 프로젝트 위치에 에이전트 앱의 루트 디렉터리를 만듭니다.
mkdir agentic-apps
- 기본 디렉터리 내에 현재 프로젝트에 해당하는 폴더를 하나 만듭니다.
mkdir renovation-agent
- Cloud Shell 편집기로 이동하여 파일을 만들어 다음 프로젝트 구조를 만듭니다 (처음에는 비어 있음).
renovation-agent/
__init__.py
agent.py
requirements.txt
.env
6. 소스 코드
- 'init.py'로 이동하여 다음 콘텐츠로 업데이트합니다.
from . import agent
- agent.py로 이동하여 다음 경로의 다음 콘텐츠로 파일을 업데이트합니다.
agent.py에서 필요한 종속 항목을 가져오고 .env 파일에서 구성 매개변수를 검색하고 제안서 문서를 생성하여 Cloud Storage 버킷에 저장하는 root_agent를 정의합니다. Cloud Storage 단계를 실행하기 위해 store_pdf라는 도구를 사용합니다.
참고: 현재 PDF는 서식이 지정되어 있지 않습니다. 커뮤니티 개발자의 PR에 따라 다음 스니펫이 여기에 포함되었습니다[테스트되지 않음]. store_pdf 메서드 내에서 이를 수용하세요.
doc = SimpleDocTemplate(
pdf_buffer,
pagesize=letter,
rightMargin=0.75 * inch,
leftMargin=0.75 * inch,
topMargin=0.75 * inch,
bottomMargin=0.75 * inch
)
styles = getSampleStyleSheet()
story = []
# --- CUSTOM STYLES FOR HEADERS ---
# Define a new style for section headers
styles.add(ParagraphStyle(name='SectionHeader',
parent=styles['Normal'],
fontName='Helvetica-Bold', # Make it bolder
fontSize=14, # Make it slightly larger
leading=16, # Line spacing
spaceAfter=0.15 * inch, # Space after the header
spaceBefore=0.25 * inch, # Space before the header
textColor=black # Ensure color is bright/black (default is usually black, but explicit is good)
))
# Define a style for the main document title
styles.add(ParagraphStyle(name='DocumentTitle',
parent=styles['Normal'],
fontName='Helvetica-Bold',
fontSize=20,
leading=24,
spaceAfter=0.25 * inch,
alignment=TA_CENTER, # Center align the title
textColor=black
))
# ---------------------------------
paragraphs_raw = pdf_text.split('\n\n')
# Heuristic for the garbled line issue (as before, temporary)
if paragraphs_raw and len(paragraphs_raw[-1]) < 50 and any(char in paragraphs_raw[-1] for char in ['io', 'og', 'al', 'op']):
logger.warning("Detected potentially garbled last paragraph. Attempting to trim/omit.")
paragraphs_raw[-1] = "11. Entire Agreement:\nThis proposal constitutes the entire agreement between the parties and supersedes all prior discussions and agreements."
for i, para_text in enumerate(paragraphs_raw):
para_text = para_text.strip()
if not para_text:
continue
# Special handling for the main document title (PROPOSAL DOCUMENT)
if i == 0 and "PROPOSAL DOCUMENT" in para_text.upper():
p = Paragraph("PROPOSAL DOCUMENT", styles['DocumentTitle'])
story.append(p)
story.append(Spacer(1, 0.15 * inch)) # Add space after the title
# Skip the rest of this initial block if it's just the title
remaining_text_lines = para_text.splitlines()[1:]
if remaining_text_lines:
formatted_text = "<br/>".join(remaining_text_lines)
p = Paragraph(formatted_text, styles['Normal'])
story.append(p)
story.append(Spacer(1, 0.1 * inch))
continue # Move to the next paragraph
# Check if the paragraph looks like a section header (e.g., starts with a number and dot or just bold text)
# This is a heuristic and might need fine-tuning based on actual proposal content variability.
is_section_header = False
# Check for numbered sections (e.g., "1. Scope of Work:")
if para_text.startswith(('1.', '2.', '3.', '4.', '5.', '6.', '7.', '8.', '9.', '10.', '11.')):
is_section_header = True
# Check for Exhibit headers (e.g., "Exhibit A: Cabinet Design") or Roman numeral headings
elif para_text.startswith(('Exhibit ', 'I.', 'II.', 'III.', 'IV.', 'V.', 'VI.', 'VII.')):
is_section_header = True
# Check for specific known headers
elif para_text.strip().upper() in ["IN WITNESS WHEREOF,", "EXHIBITS:"]:
is_section_header = True
if is_section_header:
p = Paragraph(para_text, styles['SectionHeader'])
story.append(p)
# No additional Spacer here, as SectionHeader style has spaceAfter
else:
formatted_text = para_text.replace('\n', '<br/>')
p = Paragraph(formatted_text, styles['Normal'])
story.append(p)
story.append(Spacer(1, 0.1 * inch)) # Standard space after body paragraphs
doc.build(story)
pdf_buffer.seek(0)
# Upload the PDF to GCS
storage_client = storage.Client()
bucket = storage_client.bucket(STORAGE_BUCKET)
blob = bucket.blob(PROPOSAL_DOCUMENT_FILE_NAME)
blob.upload_from_file(pdf_buffer, content_type="application/pdf")
logger.info(f"Successfully uploaded PDF to gs://{STORAGE_BUCKET}/{PROPOSAL_DOCUMENT_FILE_NAME}")
except Exception as e:
logger.error(f"Error writing text to PDF and uploading: {e}")
raise
finally:
if 'pdf_buffer' in locals():
pdf_buffer.close()
return "Successfully uploaded PDF to GCS!!"
- Cloud Storage 버킷이 있는지 확인
에이전트가 생성하는 제안서 문서를 저장하기 위한 것입니다. Vertex AI로 만든 에이전트 시스템이 액세스할 수 있도록 만들고 액세스 권한을 프로비저닝합니다. 방법은 다음과 같습니다.
https://cloud.google.com/storage/docs/creating-buckets#console
버킷 이름을 'next-demo-store'로 지정합니다. 다른 이름으로 지정하는 경우 .env 파일 (ENV Variables Setup 단계)에서 STORAGE_BUCKET 값을 업데이트해야 합니다.
- 버킷에 대한 액세스 권한을 설정하려면 Cloud Storage 콘솔로 이동하고 스토리지 버킷으로 이동합니다 (이 경우 버킷 이름은 'next-demo-storage'임: https://console.cloud.google.com/storage/browser/next-demo-storage).
권한 -> 주 구성원 보기 -> 액세스 권한 부여로 이동합니다. 주 구성원을 'allUsers'로, 역할을 '스토리지 객체 사용자'로 선택합니다.
Make sure to not enable "prevent public access". Since this is a demo/study application we are going with a public bucket. Remember to configure permission settings appropriately when you are building your application.
- 종속 항목 목록 만들기
requirements.txt에 모든 종속 항목을 나열합니다. 저장소에서 이를 복사할 수 있습니다.
단일 에이전트 시스템 소스 코드 설명
agent.py 파일은 에이전트 개발 키트 (ADK)를 사용하여 주방 리모델링 멀티 에이전트 시스템의 구조와 동작을 정의합니다. 주요 구성요소를 자세히 살펴보겠습니다.
에이전트 정의
루트 에이전트 (조정자): proposal_agent
root_agent는 이 단일 에이전트 시스템의 오케스트레이터 역할을 합니다. 초기 리모델링 요청을 수신하고 요청의 필요에 따라 호출할 도구를 결정합니다.
그런 다음 root_agent가 도구의 응답을 수집하고 이를 결합하여 사용자에게 포괄적인 응답을 제공합니다. 이 경우 도구는 'store_pdf' 하나만 있습니다.
7. 데이터 흐름 및 주요 개념
사용자가 ADK 인터페이스 (터미널 또는 웹 UI)를 통해 요청을 시작합니다.
- 요청이 root_agent에 의해 수신됩니다.
- root_agent는 요청을 분석하고 필요한 경우 도구로 라우팅합니다.
- 'store_pdf' 도구는 수정된 텍스트 콘텐츠를 PDF 파일에 작성한 다음 Google Cloud Storage에 업로드하도록 설계되었습니다.
- 그러면 응답이 root_agent에 반환됩니다.
- root_agent는 대답을 결합하여 사용자에게 최종 출력을 제공합니다.
LLM (대규모 언어 모델)
에이전트는 LLM을 사용하여 텍스트를 생성하고, 질문에 답하고, 추론 작업을 수행합니다. LLM은 에이전트가 사용자 요청을 이해하고 응답할 수 있는 능력의 '두뇌'입니다. 이 애플리케이션에서는 Gemini 2.5를 사용합니다.
Google Cloud Storage
생성된 리모델링 제안서 문서를 저장하는 데 사용됩니다. 버킷을 만들고 에이전트가 버킷에 액세스할 수 있도록 필요한 권한을 부여해야 합니다.
Cloud Run (선택사항)
OrderingAgent는 Cloud Run 함수를 사용하여 AlloyDB와 인터페이스합니다. Cloud Run은 HTTP 요청에 대한 응답으로 코드를 실행하는 서버리스 환경을 제공합니다.
AlloyDB
OrderingAgent를 사용하는 경우 주문 정보를 저장할 AlloyDB 데이터베이스를 설정해야 합니다.
.env 파일
.env 파일에는 API 키, 데이터베이스 사용자 인증 정보, 버킷 이름과 같은 민감한 정보가 저장됩니다. 이 파일을 안전하게 유지하고 저장소에 커밋하지 않는 것이 중요합니다. 또한 에이전트 및 Google Cloud 프로젝트의 구성 설정을 저장합니다. 일반적으로 root_agent 또는 지원 함수는 이 파일에서 값을 읽습니다. .env 파일에 필요한 모든 변수가 올바르게 설정되어 있는지 확인합니다. 여기에는 Cloud Storage 버킷 이름이 포함됩니다.
8. 모델 설정
사용자 요청을 이해하고 응답을 생성하는 에이전트의 기능은 대규모 언어 모델 (LLM)에 의해 지원됩니다. 에이전트가 이 외부 LLM 서비스에 보안 호출을 해야 하며, 이를 위해서는 인증 사용자 인증 정보가 필요합니다. 유효한 인증이 없으면 LLM 서비스에서 에이전트의 요청을 거부하고 에이전트가 작동할 수 없습니다.
- Google AI Studio에서 API 키를 가져옵니다.
- .env 파일을 설정하는 다음 단계에서
<<your API KEY>>를 실제 API 키 값으로 바꿉니다.
9. 환경 변수 설정
- 이 저장소의 템플릿 .env 파일에서 매개변수 값을 설정합니다. 제 경우에는 .env에 다음과 같은 변수가 있습니다.
GOOGLE_GENAI_USE_VERTEXAI=FALSE
GOOGLE_API_KEY=<<your API KEY>>
GOOGLE_CLOUD_LOCATION = us-central1 <<or your region>>
GOOGLE_CLOUD_PROJECT = <<your project id>>
PROJECT_ID = <<your project id>>
GOOGLE_CLOUD_REGION=us-central1 <<or your region>>
STORAGE_BUCKET = next-demo-store <<or your storage bucket name>>
자리표시자를 값으로 바꿉니다.
10. 에이전트 실행
- 터미널을 사용하여 에이전트 프로젝트의 상위 디렉터리로 이동합니다.
cd agentic-apps/renovation-agent
- 모든 종속 항목 설치
pip install -r requirements.txt
- Cloud Shell 터미널에서 다음 명령어를 실행하여 에이전트를 실행할 수 있습니다.
adk run .
- 다음 명령어를 실행하여 ADK 프로비저닝 웹 UI에서 실행할 수 있습니다.
참고: 에이전트 프로젝트 폴더 외부에서 이 명령어를 실행하고 한 단계 벗어난 후 실행해야 합니다.
adk web
- 다음 프롬프트로 테스트합니다.
user>>
Hello. Generate Proposal Document for the kitchen remodel requirement in a proper format that applies to a renovation contract. Remember this text will eventually be stored as a pdf file so make sure to have the formatting appropriate. I have no other specification.
11. 결과
adk run 명령어의 경우 결과는 다음과 같습니다.'


...

리모델링 제안서 문서가 Cloud Storage 버킷에 생성되었는지 확인할 수 있습니다.
12. Cloud Run에 배포
- 프로젝트 루트 폴더 내에 Dockerfile이라는 파일을 만듭니다.
cd agentic-apps/renovation-agent
- GitHub 저장소에서 콘텐츠 복사
https://github.com/AbiramiSukumaran/adk-renovation-single-agent/blob/main/Dockerfile
이 Dockerfile 파일에
- 다음 명령어를 사용하여 Cloud Run에 배포합니다.
adk deploy cloud_run --project=abis-345004 --region=us-central1 --service_name=renovation-agent --app_name=renovation-app --with_ui .
이상입니다. 배포가 완료되면 터미널에 엔드포인트가 표시되며, 이를 사용할 수 있습니다.
13. 삭제
이 게시물에서 사용한 리소스의 비용이 Google Cloud 계정에 청구되지 않도록 하려면 다음 단계를 수행하세요.
- Google Cloud 콘솔에서 리소스 관리 페이지로 이동합니다.
- 프로젝트 목록에서 삭제할 프로젝트를 선택하고 삭제를 클릭합니다.
- 대화상자에서 프로젝트 ID를 입력하고 종료를 클릭하여 프로젝트를 삭제합니다.
14. 축하합니다
축하합니다. ADK를 사용하여 멀티 에이전트 앱을 만들고 상호작용했습니다. 멀티 에이전트 시스템은 제안서 생성, 허가 확인, 주문 상태 추적과 같은 작업을 자동화하여 주방 리모델링 절차를 간소화하도록 설계되었습니다. 각 에이전트에는 특정 역할이 있으며 root_agent는 포괄적인 솔루션을 제공하기 위해 활동을 조정합니다. 이 시스템은 LLM, Google Cloud 서비스, 잠재적으로 외부 API를 활용하여 기능을 제공합니다. 제품 문서 링크는 여기를 클릭하세요.