PaLM 및 LangChain4J를 사용하여 Java로 생성형 AI 텍스트 생성

1. 소개

최종 업데이트: 2023년 11월 27일

생성형 AI란 무엇인가요?

생성형 AI 또는 생성형 인공지능은 AI를 사용하여 텍스트, 이미지, 음악, 오디오, 동영상과 같은 새로운 콘텐츠를 만드는 것을 의미합니다.

생성형 AI는 요약, Q&A, 분류 등의 바로 사용 가능한 태스크를 멀티태스킹하고 수행할 수 있는 기반 모델(대규모 AI 모델)을 기반으로 합니다. 또한 최소한의 학습으로 기반 모델을 예시 데이터가 거의 없는 타겟 사용 사례에 맞게 조정할 수 있습니다.

생성형 AI는 어떻게 작동하나요?

생성형 AI는 ML (머신러닝) 모델을 사용하여 사람이 만든 콘텐츠의 데이터 세트에서 패턴과 관계를 학습합니다. 그런 다음 학습된 패턴을 사용하여 새 콘텐츠를 생성합니다.

생성형 AI 모델을 학습시키는 가장 일반적인 방법은 지도 학습을 사용하는 것입니다. 지도 학습을 사용하면 모델에 사람이 만든 콘텐츠와 해당 라벨이 지정됩니다. 그런 다음 사람이 만든 콘텐츠와 유사하고 동일한 라벨이 지정된 콘텐츠를 생성하는 방법을 학습합니다.

일반적인 생성형 AI 애플리케이션이란 무엇인가요?

생성형 AI는 방대한 콘텐츠를 처리하여 텍스트, 이미지, 사용자 친화적인 형식을 통해 유용한 정보와 답변을 제공합니다. 생성형 AI는 다음과 같은 용도로 사용할 수 있습니다.

  • 향상된 채팅 및 검색 환경을 통해 고객 상호작용 개선
  • 대화형 인터페이스와 요약을 통해 방대한 양의 비정형 데이터 탐색하기
  • 제안 요청서 (RFP)에 답장하고, 5개 언어로 마케팅 콘텐츠를 현지화하고, 고객 계약의 규정 준수 여부를 확인하는 등 반복적인 작업을 지원합니다.

Google Cloud에는 어떤 생성형 AI 제품이 있나요?

Vertex AI를 사용하면 ML 전문 지식이 거의 없거나 전혀 없어도 기반 모델과 상호작용하고 이를 맞춤설정하여 애플리케이션에 삽입할 수 있습니다. Model Garden에서 기반 모델에 액세스하거나, Generative AI Studio에서 간단한 UI를 통해 모델을 조정하거나, 데이터 과학 노트북에서 모델을 사용할 수 있습니다.

Vertex AI Search and Conversation은 개발자가 생성형 AI 기반 검색엔진과 챗봇을 가장 빠르게 빌드할 수 있는 방법을 제공합니다.

또한 Google Cloud와 IDE 전반에서 사용할 수 있는 AI 기반 공동작업 도구인 Duet AI를 사용하면 더 많은 작업을 더 빠르게 수행할 수 있습니다.

이 Codelab에서 중점을 두는 부분은 무엇인가요?

이 Codelab에서는 모든 머신러닝 제품과 서비스를 포괄하는 Google Cloud Vertex AI에서 호스팅되는 PaLM 2 대규모 언어 모델 (LLM)에 중점을 둡니다.

Java를 사용하여 LangChain4J LLM 프레임워크 조정자와 함께 PaLM API와 상호작용합니다. 질의 응답, 아이디어 도출, 항목 및 구조화된 콘텐츠 추출, 요약에 LLM을 활용할 수 있도록 구체적인 여러 사례를 살펴봅니다.

LangChain4J 프레임워크에 대해 자세히 알아보기

LangChain4J 프레임워크는 LLM 자체와 같은 다양한 구성요소뿐만 아니라 벡터 데이터베이스 (시맨틱 검색용), 문서 로더 및 스플리터 (문서 분석 및 학습용), 출력 파서 등의 다른 도구도 조정하여 Java 애플리케이션에 대규모 언어 모델을 통합하기 위한 오픈소스 라이브러리입니다.

c6d7f7c3fd0d2951.png

학습할 내용

  • PaLM 및 LangChain4J를 사용하도록 Java 프로젝트를 설정하는 방법
  • PaLM 텍스트 모델을 처음으로 호출하여 콘텐츠를 생성하고 질문에 답하는 방법
  • 구조화되지 않은 콘텐츠에서 유용한 정보를 추출하는 방법 (항목 또는 키워드 추출, JSON 출력)
  • 퓨 샷 프롬프팅으로 콘텐츠 분류 또는 감정 분석 방법

필요한 항목

  • Java 프로그래밍 언어에 관한 지식
  • Google Cloud 프로젝트
  • 브라우저(예: Chrome 또는 Firefox)

2. 설정 및 요건

자습형 환경 설정

  1. Google Cloud Console에 로그인하여 새 프로젝트를 만들거나 기존 프로젝트를 재사용합니다. 아직 Gmail이나 Google Workspace 계정이 없는 경우 계정을 만들어야 합니다.

295004821bab6a87.png

37d264871000675d.png

96d86d3d5655cdbe.png

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

Cloud Shell 시작

Google Cloud를 노트북에서 원격으로 실행할 수도 있지만 이 Codelab에서는 Cloud에서 실행되는 명령줄 환경인 Cloud Shell을 사용합니다.

Cloud Shell 활성화

  1. Cloud Console에서 Cloud Shell 활성화d1264ca30785e435.png를 클릭합니다.

cb81e7c8e34bc8d.png

Cloud Shell을 처음 시작하는 경우에는 무엇이 있는지 설명하는 중간 화면이 표시됩니다. 중간 화면이 표시되면 계속을 클릭합니다.

d95252b003979716.png

Cloud Shell을 프로비저닝하고 연결하는 데 몇 분 정도만 걸립니다.

7833d5e1c5d18f54.png

가상 머신에는 필요한 개발 도구가 모두 들어 있습니다. 영구적인 5GB 홈 디렉터리를 제공하고 Google Cloud에서 실행되므로 네트워크 성능과 인증이 크게 개선됩니다. 이 Codelab에서 대부분의 작업은 브라우저를 사용하여 수행할 수 있습니다.

Cloud Shell에 연결되면 인증이 완료되었고 프로젝트가 자신의 프로젝트 ID로 설정된 것을 확인할 수 있습니다.

  1. 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`
  1. Cloud Shell에서 다음 명령어를 실행하여 gcloud 명령어가 프로젝트를 알고 있는지 확인합니다.
gcloud config list project

명령어 결과

[core]
project = <PROJECT_ID>

또는 다음 명령어로 설정할 수 있습니다.

gcloud config set project <PROJECT_ID>

명령어 결과

Updated property [core/project].

3. 개발 환경 준비

이 Codelab에서는 Cloud Shell 터미널과 코드 편집기를 사용하여 Java 프로그램을 개발합니다.

Vertex AI API 사용 설정

  1. Google Cloud 콘솔에서 프로젝트 이름이 Google Cloud 콘솔 상단에 표시되는지 확인합니다. 그렇지 않은 경우 프로젝트 선택을 클릭하여 프로젝트 선택기를 열고 원하는 프로젝트를 선택합니다.
  2. Google Cloud 콘솔의 Vertex AI 부분이 아닌 경우 다음을 수행합니다.
  3. 검색에서 Vertex AI를 입력한 다음
  4. 검색 결과에서 Vertex AI를 클릭합니다. Vertex AI 대시보드가 표시됩니다.
  5. Vertex AI 대시보드에서 모든 권장 API 사용 설정을 클릭합니다.

이렇게 하면 여러 API가 사용 설정되지만 Codelab에서 가장 중요한 API는 aiplatform.googleapis.com로, 명령줄의 Cloud Shell 터미널에서 다음 명령어를 실행하여 사용 설정할 수도 있습니다.

$ gcloud services enable aiplatform.googleapis.com

Gradle로 프로젝트 구조 만들기

자바 코드 예를 빌드하려면 Gradle 빌드 도구 및 자바 버전 17을 사용해야 합니다. Gradle로 프로젝트를 설정하려면 Cloud Shell 터미널에서 디렉터리 (여기: palm-workshop)를 만들고 해당 디렉터리에서 gradle init 명령어를 실행합니다.

$ mkdir palm-workshop
$ cd palm-workshop

$ gradle init

Select type of project to generate:
  1: basic
  2: application
  3: library
  4: Gradle plugin
Enter selection (default: basic) [1..4] 2

Select implementation language:
  1: C++
  2: Groovy
  3: Java
  4: Kotlin
  5: Scala
  6: Swift
Enter selection (default: Java) [1..6] 3

Split functionality across multiple subprojects?:
  1: no - only one application project
  2: yes - application and library projects
Enter selection (default: no - only one application project) [1..2] 1

Select build script DSL:
  1: Groovy
  2: Kotlin
Enter selection (default: Groovy) [1..2] 1

Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no] 

Select test framework:
  1: JUnit 4
  2: TestNG
  3: Spock
  4: JUnit Jupiter
Enter selection (default: JUnit Jupiter) [1..4] 4

Project name (default: palm-workshop): 
Source package (default: palm.workshop): 

> Task :init
Get more help with your project: https://docs.gradle.org/7.4/samples/sample_building_java_applications.html

BUILD SUCCESSFUL in 51s
2 actionable tasks: 2 executed

애플리케이션 (옵션 2)을 자바 언어 (옵션 3)를 사용하여 하위 프로젝트를 사용하지 않고 (옵션 1), 빌드 파일에 Groovy 문법 (옵션 1)을 사용하고, 새로운 빌드 기능을 사용하지 않음 (옵션 1), JUnititer로 테스트를 생성하고 (옵션 4), 프로젝트 이름으로 palm-workshop.palm 패키지를 사용할 수 있습니다.

프로젝트 구조는 다음과 같습니다.

├── gradle 
│   └── ...
├── gradlew 
├── gradlew.bat 
├── settings.gradle 
└── app
    ├── build.gradle 
    └── src
        ├── main
        │   └── java 
        │       └── palm
        │           └── workshop
        │               └── App.java
        └── test
            └── ...

app/build.gradle 파일을 업데이트하여 필요한 종속 항목을 추가해 보겠습니다. guava 종속 항목이 있는 경우 이를 삭제하고, LangChain4J 프로젝트의 종속 항목과 로깅 라이브러리로 대체하여 누락된 로거 메시지가 발생하지 않도록 할 수 있습니다.

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // Logging library
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
}

LangChain4J에는 두 가지 종속 항목이 있습니다.

  • 하나는 핵심 프로젝트에 있고
  • 하나는 전용 Vertex AI 모듈용입니다

프로그램을 컴파일하고 실행하는 데 자바 17을 사용하려면 plugins {} 블록 아래에 다음 블록을 추가합니다.

java {
    toolchain {
        languageVersion = JavaLanguageVersion.of(17)
    }
}

한 가지 더 변경할 사항이 있습니다. app/build.gradleapplication 블록을 업데이트하여 사용자가 빌드 도구를 호출할 때 명령줄에서 실행되도록 기본 클래스를 재정의할 수 있도록 합니다.

application {
    mainClass = providers.systemProperty('javaMainClass')
                         .orElse('palm.workshop.App')
}

빌드 파일에서 애플리케이션을 실행할 준비가 되었는지 확인하려면 간단한 Hello World! 메시지를 출력하는 기본 기본 클래스를 실행하면 됩니다.

$ ./gradlew run -DjavaMainClass=palm.workshop.App

> Task :app:run
Hello World!

BUILD SUCCESSFUL in 3s
2 actionable tasks: 2 executed

이제 LangChain4J 프로젝트를 사용하여 PaLM 대규모 언어 텍스트 모델로 프로그래밍할 준비가 되었습니다.

참고로, 이제 전체 app/build.gradle 빌드 파일은 다음과 같습니다.

plugins {
    // Apply the application plugin to add support for building a CLI application in Java.
    id 'application'
}

java {
    toolchain {
        // Ensure we compile and run on Java 17
        languageVersion = JavaLanguageVersion.of(17)
    }
}

repositories {
    // Use Maven Central for resolving dependencies.
    mavenCentral()
}

dependencies {
    // Use JUnit Jupiter for testing.
    testImplementation 'org.junit.jupiter:junit-jupiter:5.8.1'

    // This dependency is used by the application.
    implementation 'dev.langchain4j:langchain4j-vertex-ai:0.24.0'
    implementation 'dev.langchain4j:langchain4j:0.24.0'
    implementation 'org.slf4j:slf4j-jdk14:2.0.9'
}

application {
    mainClass = providers.systemProperty('javaMainClass').orElse('palm.workshop.App')
}

tasks.named('test') {
    // Use JUnit Platform for unit tests.
    useJUnitPlatform()
}

4. PaLM의 텍스트 모델을 처음으로 호출하기

이제 프로젝트가 올바르게 설정되었으므로 PaLM API를 호출할 차례입니다.

app/src/main/java/palm/workshop 디렉터리에 기본 App.java 클래스와 함께 TextPrompts.java라는 새 클래스를 만들고 다음 콘텐츠를 입력합니다.

package palm.workshop;

import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.vertexai.VertexAiLanguageModel;

public class TextPrompts {
    public static void main(String[] args) {
        VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(500)
            .build();

        Response<String> response = model.generate("What are large language models?");

        System.out.println(response.content());
    }
}

이 첫 번째 예시에서는 Response 클래스와 PaLM용 Vertex AI 언어 모델을 가져와야 합니다.

다음으로, main 메서드에서 VertexAiLanguageModel용 빌더를 사용해 언어 모델을 구성하여 다음을 지정합니다.

  • 엔드포인트,
  • 프로젝트,
  • 리전,
  • 게시자
  • 모델 이름 (text-bison@001)입니다.

이제 언어 모델이 준비되었으므로 generate() 메서드를 호출하고 '프롬프트'를 전달할 수 있습니다. (즉, LLM에 보낼 질문이나 안내) 여기서 LLM이 무엇인지에 대해 간단한 질문을 합니다. 하지만 이 프롬프트를 자유롭게 변경하여 다른 질문이나 작업을 시도해 보세요.

이 클래스를 실행하려면 Cloud Shell 터미널에서 다음 명령어를 실행합니다.

./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

다음과 비슷한 출력이 표시됩니다.

Large language models (LLMs) are artificial intelligence systems that can understand and generate human language. They are trained on massive datasets of text and code, and can learn to perform a wide variety of tasks, such as translating languages, writing different kinds of creative content, and answering your questions in an informative way.

LLMs are still under development, but they have the potential to revolutionize many industries. For example, they could be used to create more accurate and personalized customer service experiences, to help doctors diagnose and treat diseases, and to develop new forms of creative expression.

However, LLMs also raise a number of ethical concerns. For example, they could be used to create fake news and propaganda, to manipulate people's behavior, and to invade people's privacy. It is important to carefully consider the potential risks and benefits of LLMs before they are widely used.

Here are some of the key features of LLMs:

* They are trained on massive datasets of text and code.
* They can learn to perform a wide variety of tasks, such as translating languages, writing different kinds of creative content, and answering your questions in an informative way.
* They are still under development, but they have the potential to revolutionize many industries.
* They raise a number of ethical concerns, such as the potential for fake news, propaganda, and invasion of privacy.

VertexAILanguageModel 빌더를 사용하면 재정의할 수 있는 일부 기본값이 이미 있는 선택적 매개변수를 정의할 수 있습니다. 예를 들면 다음과 같습니다.

  • .temperature(0.2): 원하는 창의적 응답 정의 정의 (0은 낮은 광고 소재이고 대체로 사실에 기반함, 1은 더 많은 광고 소재 결과물에 해당)
  • .maxOutputTokens(50): 이 예시에서는 생성된 답변을 얼마나 오래 표시할지에 따라 토큰 500개 (토큰 3개는 대략 4단어와 동일함)가 요청되었습니다.
  • .topK(20): 텍스트 완성을 위해 가능한 최대 단어 수 (1~40) 중에서 무작위로 단어를 선택합니다.
  • .topP(0.95): 총 확률의 합이 부동 소수점 수 (0과 1 사이)가 되는 가능한 단어를 선택합니다.
  • .maxRetries(3): 시간별 요청 할당량을 초과하여 실행 중인 경우 모델이 호출을 3회 재시도하도록 할 수 있습니다. 예를 들면 다음과 같습니다.

대규모 언어 모델은 매우 강력하며, 복잡한 질문에 대한 답변을 제공할 수 있고, 다양하고 흥미로운 작업을 처리할 수 있습니다. 다음 섹션에서는 유용한 작업인 텍스트에서 구조화된 데이터 추출을 살펴보겠습니다.

5. 구조화되지 않은 텍스트에서 정보 추출

이전 섹션에서는 텍스트 출력을 생성했습니다. 이 출력을 최종 사용자에게 직접 표시하려는 경우에는 괜찮습니다. 하지만 이 출력에 언급된 데이터를 검색하려면 비정형 텍스트에서 어떻게 정보를 추출해야 할까요?

그 사람의 약력이나 설명을 통해 사람의 이름과 나이를 추출하고자 한다고 가정해 보겠습니다. 프롬프트를 다음과 같이 조정하여 대규모 언어 모델에 JSON 데이터 구조를 생성하도록 지시할 수 있습니다 (일반적으로 '프롬프트 엔지니어링'이라고 함).

Extract the name and age of the person described below.

Return a JSON document with a "name" and an "age" property, 
following this structure: {"name": "John Doe", "age": 34}
Return only JSON, without any markdown markup surrounding it.

Here is the document describing the person:
---
Anna is a 23 year old artist based in Brooklyn, New York. She was 
born and raised in the suburbs of Chicago, where she developed a 
love for art at a young age. She attended the School of the Art 
Institute of Chicago, where she studied painting and drawing. 
After graduating, she moved to New York City to pursue her art career. 
Anna's work is inspired by her personal experiences and observations 
of the world around her. She often uses bright colors and bold lines 
to create vibrant and energetic paintings. Her work has been 
exhibited in galleries and museums in New York City and Chicago.
---

JSON: 

위의 전체 텍스트 프롬프트를 전달하도록 TextPrompts 클래스의 model.generate() 호출을 수정합니다.

Response<String> response = model.generate("""
    Extract the name and age of the person described below.
    Return a JSON document with a "name" and an "age" property, \
    following this structure: {"name": "John Doe", "age": 34}
    Return only JSON, without any markdown markup surrounding it.
    Here is the document describing the person:
    ---
    Anna is a 23 year old artist based in Brooklyn, New York. She was born and 
    raised in the suburbs of Chicago, where she developed a love for art at a 
    young age. She attended the School of the Art Institute of Chicago, where 
    she studied painting and drawing. After graduating, she moved to New York 
    City to pursue her art career. Anna's work is inspired by her personal 
    experiences and observations of the world around her. She often uses bright 
    colors and bold lines to create vibrant and energetic paintings. Her work 
    has been exhibited in galleries and museums in New York City and Chicago.    
    ---
    JSON: 
    """
);

TextPrompts 클래스에서 이 프롬프트를 실행하면 다음 JSON 문자열이 반환되며, 이 문자열을 GSON 라이브러리와 같은 JSON 파서로 파싱할 수 있습니다.

$ ./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

> Task :app:run
{"name": "Anna", "age": 23}

BUILD SUCCESSFUL in 24s
2 actionable tasks: 1 executed, 1 up-to-date

예. Anna는 23세입니다.

6. 프롬프트 템플릿 및 구조화된 프롬프트

질의 응답 그 이상

PaLM과 같은 대규모 언어 모델은 질문에 답하는 데 효과적이지만 더 많은 작업에 사용할 수 있습니다. 예를 들어 Generative AI Studio에서 다음 프롬프트를 사용해 보세요 (또는 TextPrompts 클래스를 수정하여). 자신의 아이디어로 대문자를 변경하고 출력을 검토합니다.

  • 번역 — "다음 문장을 프랑스어로 번역해 줘. YOUR_SENTENCE_HERE"
  • 요약 — '다음 문서의 요약을 제공해 주세요. PASTE_YOUR_DOC'
  • 광고 소재 생성 — "TOPIC_OF_THE_POEM에 관한 시 쓰기"
  • 프로그래밍 — 'PROGRAMMING_LANGUAGE로 피보나치 함수를 작성하는 방법'

프롬프트 템플릿

번역, 요약, 광고 소재 생성 또는 프로그래밍 작업에 위의 프롬프트를 시도했다면 자리표시자 값을 직접 만든 아이디어로 대체했습니다. 하지만 일부 문자열을 맹글링하는 대신 '프롬프트 템플릿'을 활용하여 자리표시자 값을 정의하고 나중에 빈칸을 데이터로 채울 수도 있습니다.

main() 메서드의 전체 콘텐츠를 다음 코드로 대체하여 맛있고 창의적인 프롬프트를 살펴보겠습니다.

VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(300)
            .build();

PromptTemplate promptTemplate = PromptTemplate.from("""
    Create a recipe for a {{dish}} with the following ingredients: \
    {{ingredients}}, and give it a name.
    """
);

Map<String, Object> variables = new HashMap<>();
variables.put("dish", "dessert");
variables.put("ingredients", "strawberries, chocolate, whipped cream");

Prompt prompt = promptTemplate.apply(variables);

Response<String> response = model.generate(prompt);

System.out.println(response.content());

다음 가져오기를 추가합니다.

import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;

import java.util.HashMap;
import java.util.Map;

그런 다음 애플리케이션을 다시 실행합니다. 출력은 다음과 같이 표시됩니다.

$ ./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

> Task :app:run
**Strawberry Shortcake**

Ingredients:

* 1 pint strawberries, hulled and sliced
* 1/2 cup sugar
* 1/4 cup cornstarch
* 1/4 cup water
* 1 tablespoon lemon juice
* 1/2 cup heavy cream, whipped
* 1/4 cup confectioners' sugar
* 1/4 teaspoon vanilla extract
* 6 graham cracker squares, crushed

Instructions:

1. In a medium saucepan, combine the strawberries, sugar, cornstarch, water, and lemon juice. Bring to a boil over medium heat, stirring constantly. Reduce heat and simmer for 5 minutes, or until the sauce has thickened.
2. Remove from heat and let cool slightly.
3. In a large bowl, combine the whipped cream, confectioners' sugar, and vanilla extract. Beat until soft peaks form.
4. To assemble the shortcakes, place a graham cracker square on each of 6 dessert plates. Top with a scoop of whipped cream, then a spoonful of strawberry sauce. Repeat layers, ending with a graham cracker square.
5. Serve immediately.

**Tips:**

* For a more elegant presentation, you can use fresh strawberries instead of sliced strawberries.
* If you don't have time to make your own whipped cream, you can use store-bought whipped cream.

맛있어요!

프롬프트 템플릿을 사용하면 텍스트 생성 메서드를 호출하기 전에 필수 매개변수를 피드할 수 있습니다. 이는 데이터를 전달하고 사용자가 제공하는 다양한 값에 대한 메시지를 맞춤설정하는 좋은 방법입니다.

클래스 이름에서 알 수 있듯이 PromptTemplate 클래스는 템플릿 프롬프트를 만듭니다. 개발자는 자리표시자 이름과 값의 맵을 적용하여 자리표시자 요소에 값을 할당할 수 있습니다.

구조화된 프롬프트 (선택사항)

프롬프트를 구성하는 또 다른 방법은 더 풍부한 객체 지향 접근 방식을 사용하려는 경우 @StructuredPrompt 주석을 사용하는 것입니다. 이 주석을 사용하여 클래스에 주석을 달면 필드는 프롬프트에 정의된 자리표시자에 해당합니다. 그 과정을 살펴보겠습니다.

먼저 몇 가지 새로운 가져오기가 필요합니다.

import java.util.Arrays;
import java.util.List;
import dev.langchain4j.model.input.structured.StructuredPrompt;
import dev.langchain4j.model.input.structured.StructuredPromptProcessor;

그런 다음 TextPrompts 클래스 내에 @StructuredPrompt 주석에 설명된 프롬프트의 자리표시자를 전달하는 데 필요한 데이터를 수집하는 내부 정적 클래스를 만들 수 있습니다.

@StructuredPrompt("Create a recipe of a {{dish}} that can be prepared using only {{ingredients}}")
static class RecipeCreationPrompt {
    String dish;
    List<String> ingredients;
}

그런 다음 새 클래스를 인스턴스화하고 레시피의 요리와 재료를 피드합니다. 이전과 같이 프롬프트를 만들어 generate() 메서드에 전달합니다.

RecipeCreationPrompt createRecipePrompt = new RecipeCreationPrompt();
createRecipePrompt.dish = "salad";
createRecipePrompt.ingredients = Arrays.asList("cucumber", "tomato", "feta", "onion", "olives");
Prompt prompt = StructuredPromptProcessor.toPrompt(createRecipePrompt);

Response<String> response = model.generate(prompt);

맵을 통해 공백을 메우는 대신, IDE에서 보다 안전한 방식으로 자동 완성할 수 있는 필드가 있는 Java 객체를 사용할 수 있습니다.

다음은 이러한 변경사항을 TextPrompts 클래스에 더 쉽게 붙여넣으려면 전체 코드입니다.

package palm.workshop;

import java.util.Arrays;
import java.util.List;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.vertexai.VertexAiLanguageModel;
import dev.langchain4j.model.input.structured.StructuredPrompt;
import dev.langchain4j.model.input.structured.StructuredPromptProcessor;

public class TextPrompts {

    @StructuredPrompt("Create a recipe of a {{dish}} that can be prepared using only {{ingredients}}")
    static class RecipeCreationPrompt {
        String dish;
        List<String> ingredients;
    }
    public static void main(String[] args) {
        VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(300)
            .build();

        RecipeCreationPrompt createRecipePrompt = new RecipeCreationPrompt();
        createRecipePrompt.dish = "salad";
        createRecipePrompt.ingredients = Arrays.asList("cucumber", "tomato", "feta", "onion", "olives");
        Prompt prompt = StructuredPromptProcessor.toPrompt(createRecipePrompt);

        Response<String> response = model.generate(prompt);
        
        System.out.println(response.content());
    }
}

7. 텍스트 분류 및 감정 분석

이전 섹션에서 배운 내용과 유사하게, PaLM 모델이 텍스트를 분류하거나 감정을 분석하도록 하는 또 다른 '프롬프트 엔지니어링' 기법을 살펴보겠습니다. 퓨샷 프롬프팅에 대해 알아보겠습니다. 몇 가지 예시를 통해 프롬프트를 개선하여 언어 모델을 원하는 방향으로 조종하여 인텐트를 더 잘 이해할 수 있는 방법입니다.

프롬프트 템플릿을 활용하도록 TextPrompts 클래스를 다시 작업해 보겠습니다.

package palm.workshop;

import java.util.Map;

import dev.langchain4j.model.output.Response;
import dev.langchain4j.model.vertexai.VertexAiLanguageModel;
import dev.langchain4j.model.input.Prompt;
import dev.langchain4j.model.input.PromptTemplate;

public class TextPrompts {
    public static void main(String[] args) {
        VertexAiLanguageModel model = VertexAiLanguageModel.builder()
            .endpoint("us-central1-aiplatform.googleapis.com:443")
            .project("YOUR_PROJECT_ID")
            .location("us-central1")
            .publisher("google")
            .modelName("text-bison@001")
            .maxOutputTokens(10)
            .build();

        PromptTemplate promptTemplate = PromptTemplate.from("""
            Analyze the sentiment of the text below. Respond only with one word to describe the sentiment.

            INPUT: This is fantastic news!
            OUTPUT: POSITIVE

            INPUT: Pi is roughly equal to 3.14
            OUTPUT: NEUTRAL

            INPUT: I really disliked the pizza. Who would use pineapples as a pizza topping?
            OUTPUT: NEGATIVE

            INPUT: {{text}}
            OUTPUT: 
            """);

        Prompt prompt = promptTemplate.apply(
            Map.of("text", "I love strawberries!"));

        Response<String> response = model.generate(prompt);

        System.out.println(response.content());
    }
}

프롬프트에서 몇 가지 입력 및 출력 예시를 제공하는 접근 방식에 주목하세요. '퓨샷' LLM이 동일한 구조를 따르도록 도와줍니다. 그런 다음 모델이 입력을 받으면 입력/출력 패턴과 일치하는 출력을 반환하고자 할 것입니다.

프로그램을 실행하면 POSITIVE 단어만 반환됩니다. 딸기도 맛있기 때문입니다.

$ ./gradlew run -DjavaMainClass=palm.workshop.TextPrompts

> Task :app:run
POSITIVE

감정 분석도 콘텐츠 분류 시나리오입니다. 동일한 '퓨샷 프롬프팅' 방식을 적용하여 여러 문서를 다양한 카테고리 버킷으로 분류할 수 있습니다.

8. 축하합니다

수고하셨습니다. LangChain4J 및 PaLM API를 사용하여 Java로 첫 번째 생성형 AI 애플리케이션을 빌드했습니다. 그 과정에서 대규모 언어 모델이 꽤 강력하며 질문/답변, 데이터 추출, 요약, 텍스트 분류, 감정 분석과 같은 다양한 작업을 처리할 수 있다는 사실을 알게 되었습니다.

다음 단계

Java에서 PaLM을 더 자세히 살펴보려면 다음 Codelab을 확인하세요.

추가 자료

참조 문서