1. 소개
책을 자세히 살펴보는 것을 좋아하지만 너무 많은 선택지에 압도 당하시나요? 완벽한 읽을거리를 추천할 뿐만 아니라 선택한 장르에 따라 간결한 요약을 제공하여 책의 본질을 엿볼 수 있는 AI 기반 앱이 있다고 상상해 보세요. 이 Codelab에서는 Gemini 기반 BigQuery 및 Cloud Functions를 사용하여 이러한 앱을 빌드하는 방법을 알아봅니다.
프로젝트 개요
Google의 사용 사례는 다음 4가지 주요 구성요소를 중심으로 이루어집니다.
- 도서 데이터베이스: 방대한 인터넷 자료실 도서의 BigQuery 공개 데이터 세트는 Google의 포괄적인 도서 카탈로그 역할을 합니다.
- AI 요약 엔진: Gemini-Pro 언어 모델을 갖춘 Google Cloud Functions는 사용자 요청에 맞는 유용한 요약 정보를 생성합니다.
- BigQuery 통합: Cloud 함수를 호출하여 주문형 도서 요약 및 테마를 전달하는 BigQuery 내의 원격 함수입니다.
- 사용자 인터페이스: 사용자가 결과를 볼 수 있는 웹 애플리케이션을 제공하는 Cloud Run에서 호스팅되는 웹 앱입니다.
구현은 다음 3개의 Codelab으로 나뉩니다.
Codelab 1: Gemini를 사용하여 Gemini 애플리케이션용 Java Cloud 함수를 빌드합니다.
Codelab 2: Gemini를 사용하여 BigQuery로 SQL 전용 생성형 AI 애플리케이션을 빌드합니다.
Codelab 3: Gemini를 사용하여 BigQuery와 상호작용하는 Java Spring Boot 웹 애플리케이션을 만듭니다.
2. Gemini를 사용하여 Java Cloud 함수에서 서버리스로 생성형 AI 앱 빌드
빌드할 항목
다음과 같은
- Gemini 1.0 Pro를 구현하여 특정 프롬프트를 JSON 배열 형식으로 입력받고 응답('replies'라는 라벨이 지정된 Json 값)을 반환하는 Java Cloud Functions 애플리케이션
- Gemini의 도움을 받아 빌드 및 배포 단계를 실행합니다.
3. 요구사항
다음은 기본 요건입니다.
프로젝트 만들기
- Google Cloud 콘솔의 프로젝트 선택기 페이지에서 Google Cloud 프로젝트를 선택하거나 만듭니다.
- Cloud 프로젝트에 결제가 사용 설정되어 있어야 하므로 프로젝트에 결제가 사용 설정되어 있는지 확인하는 방법을 알아보세요.
Cloud Shell 활성화
- bq가 미리 로드되어 제공되는 Google Cloud에서 실행되는 명령줄 환경인 Cloud Shell을 사용합니다.
Cloud 콘솔에서 오른쪽 상단에 있는 Cloud Shell 활성화를 클릭합니다. 
- Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 해당 프로젝트 ID로 이미 설정된 것을 볼 수 있습니다. Cloud Shell에서 다음 명령어를 실행하여 인증되었는지 확인합니다.
gcloud auth list
- Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project
- 프로젝트가 설정되지 않은 경우 다음 명령어를 사용하여 설정합니다.
gcloud config set project <YOUR_PROJECT_ID>
gcloud 명령어 및 사용법은 문서를 참조하세요.
4. Gemini for Google Cloud 및 필요한 API 사용 설정
Gemini 사용 설정
- Marketplace의 Google Cloud를 위한 Gemini로 이동하여 API를 사용 설정합니다. 다음 명령어를 사용할 수도 있습니다.
gcloud services enable cloudaicompanion.googleapis.com --project PROJECT_ID
- Gemini 페이지를 방문하여 '채팅 시작'을 클릭합니다.
중요: 이 Codelab의 1단계와 2단계를 따라 Gemini를 시작하고 Cloud Shell IDE에서 Gemini를 사용 설정하세요.
기타 필요한 API 사용 설정
어떻게 하면 좋을까요? Gemini에 물어볼까요? 하지만 그 전에 다음 사항을 기억하세요.
LLM은 비결정적입니다. 따라서 이러한 프롬프트를 입력하는 동안 수신하는 대답이 스크린샷과 다르게 보일 수 있습니다.
Google Cloud 콘솔의 검색창 옆에 있는 오른쪽 상단의 'Gemini 열기' 아이콘을 클릭하여 Gemini 채팅 콘솔로 이동합니다.

'여기에 프롬프트 입력' 섹션에 다음 질문을 입력합니다.
How do I enable the cloud functions api using a gcloud command?
다음과 비슷한 응답을 받게 됩니다.
gcloud services enable cloudfunctions.googleapis.com
이를 복사하고 (명령어 스니펫 상단의 복사 아이콘 사용) Cloud Shell 터미널에서 실행하여 Cloud Functions를 사용 설정합니다. Cloud Functions를 빌드하고 배포하려면 둘 다 필요하므로 Cloud Run에 대해서도 동일한 작업을 실행합니다.
gcloud services enable \
cloudfunctions.googleapis.com \
aiplatform.googleapis.com \
run.googleapis.com \
cloudbuild.googleapis.com
5. Gemini로 Cloud Functions 템플릿 준비
이 시점에서 Cloud Shell IDE에 Gemini가 이미 사용 설정되어 있다고 가정합니다.
Cloud Shell 터미널 오른쪽 상단에 있는 편집기 열기 아이콘을 클릭하여 Cloud Shell 편집기를 엽니다. 보통 터미널과 편집기를 별도의 탭에서 동시에 열어 한 탭에서 코드를 작성하고 다른 탭에서 빌드하는 것을 선호합니다.

편집기를 연 후 편집기 콘솔의 오른쪽 하단에 있는 Gemini 로고가 활성화되어 있고 취소되지 않았는지 확인합니다. 또한 왼쪽 하단의 Google Cloud 프로젝트가 작업하려는 현재 활성 프로젝트를 가리키는지 확인합니다. 비활성 상태라면 클릭하여 승인하고 연결할 Google Cloud 프로젝트를 선택하여 활성화합니다.
둘 다 활성화되면 왼쪽 하단의 프로젝트 이름을 클릭하고 'Cloud Code'라는 팝업 목록이 열리면 아래로 스크롤하여 'New Application(새 애플리케이션)'으로 이동합니다.

목록에서 Cloud Functions 애플리케이션을 선택합니다. 팝업 목록에서 Java를 선택합니다.

결과 목록에 helloworld 대신 프로젝트 이름 'duetai-gemini-calling'을 입력하고 확인을 클릭합니다.

축하합니다. 여러분은 Gemini를 사용해 간단한 Java Cloud Functions 애플리케이션을 부트스트랩했고, 구성을 사용 설정하고 활성화하는 것 외에는 별로 많은 작업을 하지 않았습니다.
여러분이 보게 될 프로젝트 구조는 다음과 같습니다.

이제 함수를 배포할 수 있습니다. 하지만 이것이 우리가 이 작업을 시작한 이유는 아닙니다. Java SDK를 사용하여 이 Cloud 함수에서 Gemini Pro API 구현을 빌드해 보겠습니다.
이제 이 Cloud Functions에서 Gemini Pro 모델을 호출하는 사용 사례의 기능을 빌드해 보겠습니다. 이를 위해 자유롭게 프롬프트를 추가하고 Gemini를 사용하여 코드를 점진적으로 개발하거나 로직을 직접 작성할 수 있습니다. 이 두 가지를 혼합해 보겠습니다.
6. 종속 항목을 추가합니다.
Gemini 채팅 콘솔 (왼쪽 창의 Cloud Code Editor 내에 있는 콘솔)에 다음 프롬프트를 입력합니다.
what is the maven dependency for com.google.cloud.vertexai library
제가 com.google.cloud.vertexai 패키지를 구체적으로 요청하는 이유는 Gemini 호출 코드를 구현하는 소스 코드에서 이 패키지를 사용하고 있기 때문입니다.
다음과 같은 결과가 나왔습니다.

<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-vertexai</artifactId>
<version>0.1.0</version>
</dependency>
이를 복사하여 pom.xml 파일의 </dependencies> 태그 바로 앞에 붙여넣습니다. 버전을 0.1.0으로 바꿉니다. Spring Cloud GCP BOM을 사용하여 spring-cloud-gcp 버전 번호를 관리하는 경우 <version> 태그를 삭제해도 됩니다.
종속 항목 섹션은 다음과 같이 표시됩니다.

필요한 경우 버전 번호를 위와 일치하도록 업데이트합니다. 여기에는 또 다른 종속 항목도 포함되어 있습니다.
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10</version>
</dependency>
7. 함수 진입점 및 클래스 이름 수정
- '.vscode' 폴더에서 'launch.json' 파일로 이동합니다. 함수 이름을 'function-hello-world'에서 'function-gemini-calling'으로 수정합니다.
- entryPoint 값을 'cloudcode.helloworld.HelloWorld'에서 'cloudcode.bookshelf.Bookshelf'로 업데이트합니다.
- 이제 Java 클래스 파일 'HelloWorld.java'로 이동합니다. 패키지 이름을 package cloudcode.bookshelf로 변경합니다. 팝업되는 오류에서 노란색 전구를 클릭하고 'HelloWorld.java를 cloudcode.bookshelf 패키지로 이동'이라는 옵션을 클릭합니다.

- 클래스 이름을 Bookshelf로 업데이트하고 표시되는 오류에서 작은 노란색 전구를 클릭하고 'Rename file to Bookshelf.java'(파일 이름을 Bookshelf.java로 변경)를 선택합니다. 이 옵션을 선택합니다.
8. Gemini Pro를 호출하는 메서드 만들기
Bookshelf.java 클래스에서 이 기능을 구현해 보겠습니다. Bookshelf.java를 아래 코드로 바꿉니다.
package cloudcode.bookshelf;
import java.io.BufferedWriter;
import com.google.cloud.functions.HttpFunction;
import com.google.cloud.functions.HttpRequest;
import com.google.cloud.functions.HttpResponse;
import com.google.cloud.vertexai.VertexAI;
import com.google.cloud.vertexai.api.GenerateContentResponse;
import com.google.cloud.vertexai.api.GenerationConfig;
import com.google.cloud.vertexai.generativeai.preview.GenerativeModel;
import com.google.cloud.vertexai.generativeai.preview.ResponseHandler;
import java.io.IOException;
import java.util.List;
import java.util.Arrays;
import java.util.Map;
import java.util.LinkedHashMap;
import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.JsonArray;
public class Bookshelf implements HttpFunction {
private static final Gson gson = new Gson();
@Override
public void service(HttpRequest request, HttpResponse response) throws Exception {
BufferedWriter writer = response.getWriter();
// Get the request body as a JSON object.
JsonObject requestJson = new Gson().fromJson(request.getReader(), JsonObject.class);
JsonArray calls_array = requestJson.getAsJsonArray("calls");
JsonArray calls = (JsonArray) calls_array.get(0);
String context = calls.get(0).toString().replace("\"", "");
//Invoke Gemini model
String raw_result = callGemini(context);
raw_result = raw_result.replace("\n","");
String trimmed = raw_result.trim();
List<String> result_list = Arrays.asList(trimmed);
Map<String, List<String>> stringMap = new LinkedHashMap<>();
stringMap.put("replies", result_list);
// Serialization
String return_value = gson.toJson(stringMap);
writer.write(return_value);
}
public String callGemini(String context) throws IOException{
String res = "";
try (VertexAI vertexAi = new VertexAI("REPLACE_WITH_YOUR_PROJECT_ID", "us-central1"); ) {
GenerationConfig generationConfig =
GenerationConfig.newBuilder()
.setMaxOutputTokens(2048)
.setTemperature(0.4F)
.setTopK(32)
.setTopP(1)
.build();
GenerativeModel model = new GenerativeModel("gemini-pro", generationConfig, vertexAi);
GenerateContentResponse response = model.generateContent(context);
res = ResponseHandler.getText(response);
}catch(Exception e){
System.out.println(e);
}
return res;
}
}
이 클래스는 아래와 같은 JSON 구조의 입력을 예상합니다.
{ "calls": [["YOUR_PROMPT_HERE"]] }
다음과 같은 응답이 반환됩니다.
(Json) Map<String, List<String>> {"replies": ["response"]}
왼쪽 창의 Cloud Shell 편집기에서 Gemini 채팅 옵션을 사용하여 코드를 설명해 보세요. 또는 코드를 모두 선택하고 선택 항목의 왼쪽 상단에 있는 노란색 전구를 클릭한 다음 '설명' 옵션을 선택할 수도 있습니다.

9. Cloud 함수 배포
이제 Cloud 함수가 준비되었으므로 Gemini에게 배포 방법을 물어보겠습니다. Cloud Code 편집기에서 Gemini 채팅으로 이동하여 다음을 입력합니다.
How to deploy this Cloud Function with a gcloud command?
다음과 같은 응답을 받았습니다.

이제 더 자세히 살펴보고 싶었습니다. 그래서 Gemini에게 전체 gcloud functions deploy 명령어를 알려 달라고 요청했습니다. 응답은 아래와 같습니다.

동일한 대답을 받으실지는 모르겠지만, 아래 이미지와 같이 몇 가지 세부정보를 추가해 깜짝 놀랐습니다.
요청 본문 형식:

및
응답 형식:

이제 Gemini가 제공한 gcloud 명령어를 실행하여 함수를 배포해 보겠습니다. 이를 위해 Cloud Shell 터미널을 열어야 합니다. https://console.cloud.google.com에서 새 탭을 열고 올바른 프로젝트가 선택되어 있는지 확인합니다. 콘솔의 오른쪽 상단에 있는 Cloud Shell 활성화 아이콘을 클릭하여 Cloud Shell 터미널을 열고 아래 명령어를 사용하여 올바른 프로젝트 폴더에 있는지 확인합니다.
cd duetai-gemini-calling
다음 명령어를 실행합니다.
gcloud functions deploy bookshelf --runtime java17 --trigger-http --entry-point cloudcode.bookshelf.Bookshelf --allow-unauthenticated
'새 함수 [bookshelf]의 인증되지 않은 호출을 허용하시겠어요?'라는 메시지가 표시됩니다. 'y'를 입력하고 Enter 키를 누릅니다. 그 후 해당하는 경우 몇 가지 질문이 표시되며 배포된 URL(https://us-central1-*******.cloudfunctions.net/bookshelf)로 서버리스 Cloud Functions가 배포됩니다.
이제 배포된 Cloud 함수를 호출하여 테스트해 보겠습니다.
참고: 실수로 '인증되지 않은 호출 허용' 질문을 건너뛰거나 '아니요'를 선택한 경우 Cloud 함수의 결과에 액세스할 수 없으며 추가 IAM 설정을 부여하지 않으면 '권한 오류'가 표시됩니다. 따라서 이 점에 유의하세요.
10. 배포된 Cloud 함수 호출
Gemini에게 물어볼까요? 프롬프트를 입력했습니다.
How to call the deployed cloud function?
다음과 같은 결과가 표시됩니다. (정확히 동일한 대답이 표시되지 않을 수도 있습니다. 프롬프트를 자유롭게 사용해 보고 대답의 차이를 확인해 보세요.)

배포된 함수를 호출하는 대체 방법, gcloud 명령어를 사용한 호출 등에 관한 구체적인 질문으로 채팅을 유도합니다. 아래 프롬프트를 제출했습니다.
how to call the deployed cloud function using gcloud
다음과 같은 대답을 받았습니다. 
터미널에서 이 응답('gcloud functions call' 명령어)을 수정하여 시나리오에 맞게 사용할 수 있습니다. 또는 프롬프트 자체에 매개변수를 전달하여 응답에서 자세한 gcloud functions call을 가져올 수 있는지 확인해 보세요.
gcloud functions call bookshelf --region=us-central1 --gen2 --data '{"calls":[["Hello! This is my test prompt."]]}'
결과는 다음과 같습니다.

11. 삭제
Cloud 함수의 세부정보 페이지에서 삭제 버튼을 클릭하여 이전에 만든 Cloud 함수를 삭제할 수 있습니다.
12. 축하합니다
Gemini를 사용하여 Gemini 1.0 Pro를 호출하는 Java Cloud 함수를 빌드, 배포, 테스트했습니다. 이 애플리케이션은 도서 추천과 관련된 입력 프롬프트를 도서의 요약 및 테마와 함께 사용합니다.