1. 소개
이 실습에서는 퀴즈를 생성하는 웹 서비스를 빌드하고 이를 재미있는 작동 앱에 통합합니다. 이전과 다른 프로그래밍 언어인 영어를 사용합니다.
실습할 내용…
- 일련의 기준에 따라 퀴즈를 생성하는 프롬프트를 작성합니다.
- 간단한 웹 앱을 빌드하고 개발 환경에서 예상대로 실행되는지 확인합니다.
- 일련의 입력 매개변수에 따라 퀴즈를 생성하는 API 서버로 전환하기 위해 웹 앱에 로직을 점진적으로 추가합니다.
- Google Cloud Run을 사용하여 퀴즈 생성 서비스를 클라우드에 얼마나 쉽게 배포할 수 있는지 알아봅니다.
- 마지막으로 배포된 퀴즈 생성기 서비스를 사용하도록 실제 앱 ( quizaic.com)을 구성하면 출력을 기반으로 실시간 퀴즈를 플레이할 수 있습니다.
학습할 내용…
- 대규모 언어 모델 (LLM)용 템플릿 프롬프트를 만드는 방법
- Python에서 간단한 웹 서버 앱을 만드는 방법
- 웹 앱에 Google의 LLM 지원을 추가하는 방법
- 누구나 새 창작물을 사용해 볼 수 있도록 앱을 클라우드에 배포하는 방법
- 퀴즈 생성기를 더 큰 앱에 통합하는 방법
필요한 항목…
- Chrome 웹브라우저
- Google 계정
- 결제가 사용 설정된 Cloud 프로젝트
이 실습은 초보자를 포함한 모든 수준의 개발자를 대상으로 합니다. Python을 사용하지만 Python 프로그래밍에 익숙하지 않아도 됩니다. 표시되는 모든 코드를 설명해 드리기 때문입니다.
2. 설정

이 섹션에서는 실습을 시작하는 데 필요한 모든 사항을 다룹니다.
자습형 환경 설정
- Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.



- 프로젝트 이름은 이 프로젝트 참가자의 표시 이름입니다. 이는 Google API에서 사용하지 않는 문자열이며 언제든지 업데이트할 수 있습니다.
- 프로젝트 ID는 모든 Google Cloud 프로젝트에서 고유하며, 변경할 수 없습니다(설정된 후에는 변경할 수 없음). Cloud 콘솔은 고유한 문자열을 자동으로 생성합니다. 일반적으로는 신경 쓰지 않아도 됩니다. 대부분의 Codelab에서는 프로젝트 ID (일반적으로
PROJECT_ID로 식별됨)를 참조해야 합니다. 생성된 ID가 마음에 들지 않으면 다른 임의 ID를 생성할 수 있습니다. 또는 직접 시도해 보고 사용 가능한지 확인할 수도 있습니다. 이 단계 이후에는 변경할 수 없으며 프로젝트 기간 동안 유지됩니다. - 참고로 세 번째 값은 일부 API에서 사용하는 프로젝트 번호입니다. 이 세 가지 값에 대한 자세한 내용은 문서를 참고하세요.
- 다음으로 Cloud 리소스/API를 사용하려면 Cloud 콘솔에서 결제를 사용 설정해야 합니다. 이 Codelab 실행에는 많은 비용이 들지 않습니다. 이 튜토리얼이 끝난 후에 요금이 청구되지 않도록 리소스를 종료하려면 만든 리소스 또는 프로젝트를 삭제하면 됩니다. Google Cloud 신규 사용자는 300달러(USD) 상당의 무료 체험판 프로그램에 참여할 수 있습니다.
Cloud Shell 시작
이 실습에서는 Google의 클라우드에서 실행되는 가상 머신이 호스팅하는 명령어 인터프리터인 Cloud Shell 세션에서 작업합니다. 이 섹션은 사용자의 컴퓨터에서 로컬로 쉽게 실행할 수도 있지만, Cloud Shell을 사용하면 모든 사람이 일관되고 재현 가능한 환경에 액세스할 수 있습니다. 실습을 마치고 로컬 컴퓨터에서 이 섹션을 다시 시도하셔도 됩니다.

Cloud Shell 활성화
- Cloud Console에서 Cloud Shell 활성화
를 클릭합니다.

Cloud Shell을 처음 시작하는 경우 설명이 포함된 중간 화면이 제공됩니다. 중간 화면이 표시되면 계속을 클릭합니다.

Cloud Shell을 프로비저닝하고 연결하는 작업은 몇 분이면 끝납니다.

이 가상 머신에는 필요한 개발 도구가 모두 로드되어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 Codelab에서 대부분의 작업은 브라우저로 수행할 수 있습니다.
Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 해당 프로젝트 ID로 설정된 것을 확인할 수 있습니다.
- Cloud Shell에서 다음 명령어를 실행하여 인증되었는지 확인합니다.
gcloud auth list
명령어 결과
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
- Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project
명령어 결과
[core] project = <PROJECT_ID>
또는 다음 명령어로 설정할 수 있습니다.
gcloud config set project <PROJECT_ID>
명령어 결과
Updated property [core/project].
일부 API 사용 설정
이러한 서비스가 필요한 경우와 그 이유는 이후 단계에서 설명하겠습니다. 우선 이 명령어를 실행하여 프로젝트에 Cloud Build, Artifact Registry, Vertex AI, Cloud Run에 대한 액세스 권한을 부여해 보겠습니다.
gcloud services enable cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
aiplatform.googleapis.com \
run.googleapis.com
그러면 다음과 비슷한 성공 메시지가 표시될 것입니다.
Operation "operations/acf.cc11852d-40af-47ad-9d59-477a12847c9e" finished successfully.
3. 프롬프트 - 자연어로 프로그래밍

먼저 대규모 언어 모델을 위한 프롬프트를 개발하는 방법을 알아보겠습니다. Google Cloud 콘솔 > Vertex AI > Vertex AI Studio (언어)로 이동합니다. 다음과 같은 페이지가 표시됩니다.

Generate Text에서 Text Prompt 버튼을 클릭합니다. 다음 대화상자에서 다음 요구사항에 따라 퀴즈를 생성하는 데 효과적일 수 있다고 생각되는 프롬프트를 입력합니다.
- 주제: 세계사
- 질문 수: 5
- 난이도: 중급
- 언어: 영어
'제출' 버튼을 클릭하여 출력을 확인합니다.
다음 스크린샷에 표시된 것처럼 오른쪽 패널에서 사용할 모델을 선택하고 일부 설정을 미세 조정할 수 있습니다.

사용 가능한 설정은 다음과 같습니다.
- 리전은 생성 요청이 실행되어야 하는 위치입니다.
- 모델은 사용할 대규모 언어 모델을 선택합니다. 이 Codelab에서는 'gemini-1.0-pro-001'을 사용하세요.
- 강도는 토큰 선택의 무작위성 수준을 제어합니다. 강도가 낮을수록 참 또는 정답이 예상되는 프롬프트에 적합한 반면, 강도가 높을수록 보다 다양하거나 예기치 않은 결과가 발생할 수 있습니다.
- 토큰 한도는 프롬프트 1개의 최대 텍스트 출력량을 결정합니다. 토큰 1개는 약 4자(영문 기준)입니다. 기본값은 1024입니다.
- Top-K는 모델이 출력용 토큰을 선택하는 방식을 변경합니다. Top-K가 1이면 선택된 토큰이 모델의 어휘에 포함된 모든 토큰 중에서 가장 확률이 높다는 의미입니다('그리디 디코딩'이라고도 함). 반면에 Top-K가 3이면 온도를 사용하여 가장 확률이 높은 토큰 3개 중에서 다음 토큰이 선택된다는 의미입니다. 기본 최상위 K 값은 40입니다.
- Top-P는 모델이 출력용 토큰을 선택하는 방식을 변경합니다. 토큰의 확률 합계가 Top-P 값과 같아질 때까지 확률이 가장 높은 순에서 낮은 순으로 토큰이 선택됩니다.
- 최대 대답 수는 프롬프트당 생성되는 최대 모델 대답 수입니다.
- 중지 시퀀스는 모델에서 응답이 발생할 경우 응답 생성을 중지하는 일련의 문자(공백 포함)입니다.
- 스트리밍 응답은 응답이 생성되는 대로 인쇄할지 아니면 저장했다가 완료되면 표시할지를 선택합니다.
- 안전 필터 기준점은 유해할 수 있는 대답이 표시될 가능성을 조정합니다.
위에서 언급한 요구사항에 따라 합리적인 퀴즈를 생성하는 프롬프트가 있으면 맞춤 코드를 사용하여 이 퀴즈를 파싱할 수 있지만, LLM이 프로그램에 직접 로드할 수 있는 구조화된 형식으로 퀴즈를 생성하는 것이 더 좋지 않을까요? 이 실습의 후반부에서 생성기를 호출하는 데 사용할 프로그램은 퀴즈가 구조화된 데이터를 나타내는 인기 있는 교차 언어 형식인 JSON으로 표현되기를 기대합니다.
이 실습의 퀴즈는 객체 배열로 표현되며, 각 객체에는 질문, 해당 질문에 대한 가능한 응답 배열, 정답이 포함됩니다. 이 실습의 퀴즈에 대한 JSON 인코딩은 다음과 같습니다.
[
{
"question": "Who was the first person to walk on the moon?",
"responses": [
"Neil Armstrong",
"Buzz Aldrin",
"Michael Collins",
"Yuri Gagarin"
],
"correct": "Neil Armstrong"
},
{
"question": "What was the name of the war that took place between the British and the French in North America from 1754 to 1763??",
"responses": [
"The French and Indian War",
"The Seven Years' War",
"The War of the Austrian Succession",
"The Great War"
],
"correct": "The French and Indian War"
},
...
]
프롬프트를 수정하여 이제 필요한 JSON 형식으로 퀴즈를 출력할 수 있는지 확인합니다.
- 찾고 있는 정확한 형식을 단어로 지정합니다 (예: 위의 기울임체 문장).
- 프롬프트에 원하는 JSON 형식의 예를 포함합니다.
원하는 사양에 따라 퀴즈를 생성하는 프롬프트가 있으면 페이지 오른쪽 상단에 있는 GET CODE 버튼을 클릭하여 Vertex AI LLM에 프로그래매틱 방식으로 프롬프트를 제출하는 데 사용할 수 있는 Python 코드를 확인합니다. Python 이외의 프로그래밍 언어를 사용하려면 https://cloud.google.com/vertex-ai/docs/samples?text=generative를 참고하세요.
4. 간단한 웹 서버 빌드

이제 작동하는 프롬프트가 있으므로 이를 더 큰 앱에 통합하려고 합니다. 물론 프롬프트를 더 큰 앱의 소스 코드에 삽입할 수도 있지만, 생성기가 다른 앱에 퀴즈 생성 서비스를 제공하는 마이크로서비스로 작동하기를 원합니다. 이를 위해서는 간단한 웹 서버를 만들어 공개적으로 제공해야 합니다. 다음 단계에서 이를 수행합니다.
Cloud Shell 패널 상단의 Open Editor 버튼을 클릭하여 시작합니다. 상태 메시지가 표시됩니다.

그러면 Visual Studio Code와 유사한 IDE 환경이 표시되며, 여기에서 프로젝트를 만들고, 소스 코드를 수정하고, 프로그램을 실행하는 등의 작업을 할 수 있습니다.
화면이 너무 좁은 경우 콘솔과 편집/터미널 창 사이의 구분선을 확장하거나 축소할 수 있습니다. 두 영역 사이의 가로 막대를 드래그하면 됩니다.

Open Editor 및 Open Terminal 버튼을 클릭하여 편집기와 터미널 간에 전환할 수 있습니다. 이제 이 두 환경을 번갈아 전환해 보세요.
다음으로, 폴더 추가 버튼
을 클릭하고 quiz-generator을 입력한 후 Enter 키를 눌러 이 실습의 작업을 저장할 폴더를 만듭니다. 이 실습에서 만드는 모든 파일과 Cloud Shell에서 수행하는 모든 작업은 이 폴더에서 이루어집니다.
이제 requirements.txt 파일을 만듭니다. 이렇게 하면 앱이 종속된 라이브러리가 Python에 알려집니다. 이 간단한 웹 앱에서는 웹 서버를 빌드하는 데 Flask,, google-cloud-aiplatform 클라이언트 라이브러리, gunicorn라는 웹 서버 프레임워크라는 인기 있는 Python 모듈을 사용합니다. 파일 탐색 창에서 quiz-generator 폴더를 마우스 오른쪽 버튼으로 클릭하고 다음과 같이 New file 메뉴 항목을 선택합니다.

새 파일의 이름을 묻는 메시지가 표시되면 requirements.txt를 입력하고 Enter 키를 누릅니다. 새 파일이 quiz-generator 프로젝트 폴더에 있는지 확인합니다.
새 파일에 다음 줄을 붙여넣어 앱이 Python flask 패키지, gunicorn 웹 서버, google-cloud-aiplatform 클라이언트 라이브러리 및 각 라이브러리의 연결된 버전에 종속된다고 지정합니다.
flask==3.0.0 gunicorn==21.2.0 google-cloud-aiplatform==1.47.0
Cloud Editor에서 변경사항을 자동으로 저장하므로 이 파일을 명시적으로 저장할 필요는 없습니다.
동일한 기법을 사용하여 main.py라는 새 파일을 만듭니다. 이 파일이 앱의 기본 (이자 유일한) Python 소스 파일이 됩니다. 새 파일이 quiz-generator 폴더에 저장되는지 다시 한번 확인합니다.
다음 코드를 이 파일에 삽입합니다.
from flask import Flask
import os
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# The app.route decorator routes any GET requests sent to the root path
# to this function, which responds with a "Hello world!" HTML document.
@app.route("/", methods=["GET"])
def say_hello():
html = "<h1>Hello world!</h1>"
return html
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
터미널로 다시 전환하고 다음 명령어를 사용하여 프로젝트 폴더로 변경합니다.
cd quiz-generator
다음 명령어를 실행하여 프로젝트 종속 항목을 설치합니다.
pip3 install -r requirements.txt
종속 항목을 설치하면 다음과 같이 끝나는 출력이 표시됩니다.
Successfully installed flask-3.0.0
이제 터미널에서 다음 명령어를 실행하여 앱을 실행합니다.
flask --app main.py --debug run --port 8080
이제 앱이 Cloud Shell 세션 전용 가상 머신에서 실행됩니다. Cloud Shell에는 전 세계 인터넷의 어느 곳에서나 가상 머신에서 실행되는 웹 서버 (방금 시작한 서버와 같은)에 액세스할 수 있도록 지원하는 프록시 메커니즘이 포함되어 있습니다.
web preview 버튼을 클릭한 다음 Preview on Port 8080 메뉴 항목을 클릭합니다.

그러면 실행 중인 앱이 웹브라우저 탭에 열리며 다음과 같이 표시됩니다.

5. 매개변수 파싱을 사용하여 생성 메서드 추가
이제 generate라는 새 메서드를 필드에 추가하는 지원을 추가하려고 합니다. HTTP 요청을 조작하는 import 문을 추가하고 이 요청을 파싱하고 매개변수를 출력하도록 기본 경로를 수정하여 이를 수행합니다.
from flask import Flask
from flask import request #<-CHANGED
import os
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# The app.route decorator routes any GET requests sent to the /generate
# path to this function, which responds with "Generating:" followed by
# the body of the request.
@app.route("/", methods=["GET"]) #<-CHANGED
def generate(): #<-CHANGED
params = request.args.to_dict() #<-CHANGED
html = f"<h1>Quiz Generator</h1>" #<-CHANGED
for param in params: #<-CHANGED
html += f"<br>{param}={params[param]}" #<-CHANGED
return html #<-CHANGED
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
이제 기존 웹브라우저 탭을 새로고침하여 결과를 확인합니다. 이번에는 '퀴즈 생성기'와 함께 URL에 자동으로 추가된 쿼리 매개변수 (authuser)가 표시됩니다. 브라우저의 주소 표시줄에 있는 URL 끝에 '`¶m1=val1¶m2=val2`' 문자열을 추가하여 매개변수 두 개를 추가하고 페이지를 새로고침하면 다음과 같은 결과가 표시됩니다.

URL에서 쿼리 매개변수를 전송하고 파싱하는 방법을 살펴봤으므로 퀴즈 생성기에 전송할 특정 매개변수(다음과 같음)에 대한 지원을 추가하겠습니다.
topic- 원하는 퀴즈 주제num_q- 원하는 질문 수diff- 원하는 난이도 (쉬움, 보통, 어려움)lang- 원하는 퀴즈 언어
from flask import Flask
from flask import request
import os
# Default quiz settings #<-CHANGED
TOPIC = "History" #<-CHANGED
NUM_Q = "5" #<-CHANGED
DIFF = "intermediate" #<-CHANGED
LANG = "English" #<-CHANGED
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# This function takes a dictionary, a name, and a default value.
# If the name exists as a key in the dictionary, the corresponding
# value is returned. Otherwise, the default value is returned.
def check(args, name, default): #<-CHANGED
if name in args: #<-CHANGED
return args[name] #<-CHANGED
return default #<-CHANGED
# The app.route decorator routes any GET requests sent to the /generate
# path to this function, which responds with "Generating:" followed by
# the body of the request.
@app.route("/", methods=["GET"])
# This function generates a quiz using Vertex AI.
def generate():
args = request.args.to_dict() #<-CHANGED
topic = check(args, "topic", TOPIC) #<-CHANGED
num_q = check(args, "num_q", NUM_Q) #<-CHANGED
diff = check(args, "diff", DIFF) #<-CHANGED
lang = check(args, "lang", LANG) #<-CHANGED
html = f"""
<h1>Quiz Generator</h1><br>
{topic=}<br>
{num_q=}<br>
{diff=}<br>
{lang=}""" #<-CHANGED
return html
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
이제 기존 웹브라우저 탭을 새로고침하여 결과를 확인합니다. 다음과 같은 웹페이지가 표시됩니다.

URL을 변경하여 다양한 매개변수의 값을 설정해 보세요. 예를 들어 주소 표시줄의 URL 끝에 '?authuser=0&topic=Literature&num_q=10&diff=easy&lang=French' 접미사를 사용해 보세요.

6. 프롬프트 추가 및 형식 지정
다음으로 퀴즈 생성기에 전송할 특정 매개변수를 지원하도록 추가합니다.
topic- 원하는 퀴즈 주제num_q- 원하는 질문 수diff- 원하는 난이도 (쉬움, 보통, 어려움)lang- 원하는 퀴즈 언어
이전 단계에서 Vertex Generative AI Studio로 개발한 프롬프트를 복사하되, 주제, 질문 수, 난이도에 대한 하드코딩된 값을 다음 문자열로 변경합니다.
- {topic}
- {num_q}
- {diff}
- {lang}
from flask import Flask
from flask import request
import os
# Default quiz settings
TOPIC = "History"
NUM_Q = 5
DIFF = "intermediate"
LANG = "English"
PROMPT = """
Generate a quiz according to the following specifications:
- topic: {topic}
- num_q: {num_q}
- diff: {diff}
- lang: {lang}
Output should be (only) an unquoted json array of objects with keys:
"Question", "responses", and "correct".
""" #<-CHANGED
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# This function takes a dictionary, a name, and a default value.
# If the name exists as a key in the dictionary, the corresponding
# value is returned. Otherwise, the default value is returned.
def check(args, name, default):
if name in args:
return args[name]
return default
# The app.route decorator routes any GET requests sent to the /generate
# path to this function, which responds with "Generating:" followed by
# the body of the request.
@app.route("/", methods=["GET"])
# This function generates a quiz using Vertex AI.
def generate():
args = request.args.to_dict()
topic = check(args, "topic", TOPIC)
num_q = check(args, "num_q", NUM_Q)
diff = check(args, "diff", DIFF)
lang = check(args, "lang", LANG)
prompt = PROMPT.format(topic=topic, num_q=num_q, diff=diff, lang=lang) #<-CHANGED
html = f"<h1>Prompt:</h1><br><pre>{prompt}</pre>" #<-CHANGED
return html
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
이제 기존 웹브라우저 탭을 새로고침하여 결과를 확인합니다. 다음과 같은 웹페이지가 표시됩니다.

URL을 수정하여 이 네 가지 매개변수를 변경해 보세요.
7. Vertex AI 클라이언트 라이브러리 추가
이제 Vertex AI Python 클라이언트 라이브러리를 사용하여 퀴즈를 생성할 준비가 되었습니다. 이렇게 하면 3단계에서 실행한 대화형 프롬프트가 자동화되고 생성기 서비스가 Google의 LLM 기능에 프로그래매틱 방식으로 액세스할 수 있습니다. 다음과 같이 main.py 파일을 업데이트합니다.
'YOUR_PROJECT'를 실제 프로젝트 ID로 바꿔야 합니다.
from flask import Flask
from flask import request
from flask import Response #<-CHANGED
import os
import vertexai
from vertexai.generative_models import GenerativeModel #<-CHANGED
# Default quiz settings
TOPIC = "History"
NUM_Q = 5
DIFF = "intermediate"
LANG = "English"
MODEL = "gemini-1.0-pro" #<-CHANGED
PROMPT = """
Generate a quiz according to the following specifications:
- topic: {topic}
- num_q: {num_q}
- diff: {diff}
- lang: {lang}
Output should be (only) an unquoted json array of objects with keys "question", "responses", and "correct".
"""
app = Flask(__name__) # Create a Flask object.
PORT = os.environ.get("PORT") # Get PORT setting from environment.
if not PORT:
PORT = 8080
# Initialize Vertex AI access.
vertexai.init(project="YOUR_PROJECT", location="us-central1") #<-CHANGED
parameters = { #<-CHANGED
"candidate_count": 1, #<-CHANGED
"max_output_tokens": 1024, #<-CHANGED
"temperature": 0.5, #<-CHANGED
"top_p": 0.8, #<-CHANGED
"top_k": 40, #<-CHANGED
} #<-CHANGED
model = GenerativeModel(MODEL) #<-CHANGED
# This function takes a dictionary, a name, and a default value.
# If the name exists as a key in the dictionary, the corresponding
# value is returned. Otherwise, the default value is returned.
def check(args, name, default):
if name in args:
return args[name]
return default
# The app.route decorator routes any GET requests sent to the /generate
# path to this function, which responds with "Generating:" followed by
# the body of the request.
@app.route("/", methods=["GET"])
# This function generates a quiz using Vertex AI.
def generate():
args = request.args.to_dict()
topic = check(args, "topic", TOPIC)
num_q = check(args, "num_q", NUM_Q)
diff = check(args, "diff", DIFF)
lang = check(args, "lang", LANG)
prompt = PROMPT.format(topic=topic, num_q=num_q, diff=diff, lang=lang)
response = model.generate_content(prompt, generation_config=parameters) #<-CHANGED
print(f"Response from Model: {response.text}") #<-CHANGED
html = f"{response.text}" #<-CHANGED
return Response(html, mimetype="application/json") #<-CHANGED
# This code ensures that your Flask app is started and listens for
# incoming connections on the local interface and port 8080.
if __name__ == "__main__":
app.run(host="0.0.0.0", port=PORT)
이제 기존 웹브라우저 탭을 새로고침하여 결과를 확인합니다. 이제 실제로 LLM 요청을 하므로 몇 초가 걸릴 수 있습니다. 다음과 같은 웹페이지가 표시됩니다.

URL을 변경하여 다른 퀴즈 주제, 질문 수, 난이도를 요청해 보세요.
이로써 마이크로서비스가 완성되었습니다. 축하합니다. 다음 단계에서는 누구나 어디서나 액세스할 수 있도록 클라우드에 서비스를 배포하는 방법을 알아봅니다.
8. 클라우드로!

이제 나만의 퀴즈 생성기를 만들었으니 이 멋진 기능을 전 세계와 공유할 차례입니다. 클라우드에 배포해 보세요. 하지만 단순히 공유하는 것 이상을 하고 싶을 것입니다. 다음 사항을 확인해야 합니다.
- 안정적으로 실행됨 - 앱을 실행하는 컴퓨터가 비정상 종료되는 경우 자동 내결함성 제공
- 자동 확장: 앱이 대규모 트래픽을 처리하고 사용하지 않을 때는 공간을 자동으로 줄입니다.
- 사용하지 않는 리소스에 대한 비용을 청구하지 않아 비용을 최소화합니다. 트래픽에 응답하는 동안 소비된 리소스에 대해서만 비용이 청구됩니다.
- 커스텀 도메인 이름을 통해 액세스할 수 있습니다. 서비스를 커스텀 도메인 이름에 할당하는 원클릭 솔루션에 액세스할 수 있습니다.
- 훌륭한 응답 시간을 제공합니다. 콜드 스타트는 적절하게 응답하지만 최소 인스턴스 구성을 지정하여 미세 조정할 수 있습니다.
- 표준 SSL/TLS 웹 보안을 사용한 엔드 투 엔드 암호화 지원: 서비스를 배포하면 표준 웹 암호화와 해당 필수 인증서가 무료로 자동으로 제공됩니다.
Google Cloud Run에 앱을 배포하면 위의 모든 기능과 그 이상의 기능을 사용할 수 있습니다. Cloud Run과 앱을 공유하기 위한 기본 구성요소는 컨테이너입니다.
컨테이너를 사용하면 모든 종속 항목이 번들로 묶인 애플리케이션을 실행할 수 있는 모듈식 상자를 만들 수 있습니다. 컨테이너는 거의 모든 가상 또는 실제 서버에서 사용할 수 있으므로 온프레미스에서 클라우드까지 원하는 곳에 애플리케이션을 배포하고 한 서비스 제공업체에서 다른 서비스 제공업체로 애플리케이션을 이동할 수도 있습니다.
컨테이너와 Google Cloud Run에서의 작동 방식에 대해 자세히 알아보려면 Cloud Run으로 3단계 만에 개발에서 프로덕션까지 Codelab을 확인하세요.
Cloud Run에 앱 배포
Cloud Run은 리전 서비스입니다. 즉, Cloud Run 서비스를 실행하는 인프라가 특정 리전에 위치해 있으며, 해당 리전 내의 모든 영역에서 중복으로 사용할 수 있도록 Google이 관리합니다. 간단하게 하기 위해 이 실습에서는 하드코딩된 리전 us-central1를 사용합니다.
빌드팩이라는 것을 사용하여 컨테이너를 자동으로 생성할 것입니다. Cloud Editor에서 Procfile이라는 새 파일을 만들고 다음 한 줄의 텍스트를 삽입합니다.
web: gunicorn --bind :$PORT --workers 1 --threads 8 --timeout 0 main:app
이렇게 하면 빌드팩 시스템에 자동 생성된 컨테이너에서 앱을 실행하는 방법이 표시됩니다. 그런 다음 Cloud Shell 터미널에서 다음 명령어를 실행합니다 (동일한 quiz-generator 디렉터리에서).
gcloud run deploy quiz-generator \
--source . \
--region us-central1 \
--allow-unauthenticated
이렇게 하면 gcloud 명령어에 현재 디렉터리에서 찾은 소스 파일을 기반으로 빌드팩을 사용하여 컨테이너 이미지를 만들도록 지시합니다 (--source .의 dot은 현재 디렉터리의 약어임). 서비스에서 컨테이너 이미지를 암시적으로 처리하므로 이 gcloud 명령어에서 이미지를 지정할 필요가 없습니다.
그런 다음 배포가 완료될 때까지 잠시 기다립니다. 성공하면 gcloud 명령어에 새 서비스의 URL이 표시됩니다.
Building using Buildpacks and deploying container to Cloud Run service [quiz-generator] in project [YOUR_PROJECT] region [YOUR_REGION] OK Building and deploying new service... Done. OK Creating Container Repository... OK Uploading sources... OK Building Container... Logs are available at [https://console.cloud.google.com/cloud-build/builds/0cf1383f-35db-412d -a973-557d5e2cd4a4?project=780573810218]. OK Creating Revision... OK Routing traffic... OK Setting IAM Policy... Done. Service [quiz-generator] revision [quiz-generator-00001-xnr] has been deployed and is serving 100 percent of traffic. Service URL: https://quiz-generator-co24gukjmq-uc.a.run.app
다음 명령어를 사용하여 서비스 URL을 가져올 수도 있습니다.
gcloud run services describe quiz-generator \ --region us-central1 \ --format "value(status.url)"
다음과 같이 표시됩니다.
https://quiz-generator-co24gukjmq-uc.a.run.app
이 링크는 Cloud Run 서비스의 전용 URL이며 TLS 보안이 적용됩니다. 이 링크는 서비스가 사용 중지되지 않는 한 영구적이며 인터넷 어디에서나 사용할 수 있습니다. 일시적인 가상 머신에 의존하는 앞서 언급한 Cloud Shell의 프록시 메커니즘을 사용하지 않습니다.
강조 표시된 Service URL를 클릭하여 실행 중인 앱의 웹브라우저 탭을 엽니다. 결과가 개발 환경에서 본 것과 동일한지 확인합니다. 또한 URL 끝에 매개변수를 제공하여 생성된 퀴즈를 조정할 수 있는지 확인합니다.
축하합니다. 이제 앱이 Google Cloud에서 실행됩니다. 앱은 TLS (HTTPS) 암호화와 함께 공개적으로 제공되며, 엄청난 수준의 트래픽에 맞게 자동으로 확장됩니다.
9. 모든 조각을 하나로 합치기
마지막 단계에서는 quizaic 앱의 일부로 퀴즈 생성기를 실행할 준비가 되었습니다. quizaic URL을 방문하고 Google 계정에 로그인한 후 Create Quiz 탭으로 이동합니다. 생성기 유형 Custom를 선택하고 Cloud Run URL을 URL 필드에 붙여넣고 기타 필수 필드를 입력한 후 양식을 제출합니다.

잠시 후 AI 생성 썸네일 이미지가 포함된 새 퀴즈가 표시됩니다 (아래 이미지의 '새 퀴즈' 참고). 해당 버튼을 통해 퀴즈를 수정하거나, 플레이하거나, 복제하거나, 삭제할 수 있습니다. 이 새로운 퀴즈는 템플릿 프롬프트를 기반으로 방금 배포한 웹 서비스를 사용하여 만들어졌습니다.

10. 삭제

Cloud Run에서는 서비스를 사용하지 않을 때 비용이 청구되지 않지만 빌드된 컨테이너 이미지를 저장하는 데 요금이 부과될 수 있습니다.
GCP 프로젝트를 삭제하여 비용 발생을 피하거나(해당 프로젝트 내에서 사용된 모든 리소스에 대한 청구가 중단됨) 간단하게 다음 명령어를 사용하여 컨테이너 이미지를 삭제할 수 있습니다.
gcloud config set artifacts/repository cloud-run-source-deploy gcloud config set artifacts/location us-central1 gcloud artifacts docker images list # Note image tag for resulting list gcloud artifacts docker images delete <IMAGE-TAG>
Cloud Run 서비스를 삭제하려면 다음 명령어를 사용합니다.
gcloud run services delete quiz-generator --region us-central1 --quiet
11. 잘하셨습니다!

수고하셨습니다. LLM 프롬프트를 성공적으로 작성하고 해당 프롬프트를 사용하여 Cloud Run 마이크로서비스를 배포했습니다. 이제 자연어로 프로그래밍하고 만든 작품을 전 세계와 공유할 수 있습니다.
한 가지 중요한 질문을 드리고 싶습니다.
개발자 환경에서 앱을 작동시킨 후 Cloud Run에서 제공하는 모든 프로덕션 등급 속성을 사용하여 클라우드에 배포하려면 몇 줄의 코드를 수정해야 하나요?
물론 답은 0입니다. :)
확인해 볼 만한 다른 Codelab
- Cloud Run으로 3단계 만에 개발에서 프로덕션으로 전환하기
- Vertex AI 및 Svelte Kit을 사용한 텍스트 요약 앱
- Cloud Run의 PaLM API를 사용한 채팅 앱
- PaLM Text Bison 모델을 래핑하는 Cloud 함수
- Spanner 및 Vertex AI Imagen API를 사용한 데이터에서 생성형 AI로
참조 문서…
12. 클릭 유도 문구
이 Codelab이 마음에 들었고 Google Cloud를 직접 사용해 보는 데 더 많은 시간을 할애할 계획이라면 지금 바로 Google Cloud Innovators에 가입하세요.

Google Cloud Innovators는 무료이며 다음과 같은 혜택이 제공됩니다.
- Google 직원이 직접 전하는 최신 소식을 알아볼 수 있는 실시간 토론, AMA, 로드맵 세션
- 받은편지함에서 바로 최신 Google Cloud 뉴스 확인
- 디지털 배지 및 화상 회의 배경
- Skills Boost의 실습 및 학습 500 크레딧
등록하려면 여기를 클릭하세요.
