[Spring AI] 챗봇 만들기 (Kotlin)

2024. 9. 10. 02:20·Spring
반응형

Spring AI

 

스프링 AI 시리즈

  1. [Spring AI] 준비 (기본 개념, OpenAI API Key, 크레딧 충전) 
  2. [Spring AI] 챗봇 만들기 (Kotlin)
  3. [Spring AI] Vector Store와 RAG를 이용한 할루시네이션 방지
  4. [Spring AI] OpenAI 비용을 절감하는 방법

이제 본격적으로 OpenAI과 Spring AI를 활용한 챗봇을 만들어보자.

 

전체 파일 구조

전체 파일 구조
이번 포스팅에 필요한 파일들만 표시

build.gradle.kts

plugins {
    kotlin("jvm") version "1.9.25"
    kotlin("plugin.spring") version "1.9.25"
    id("org.springframework.boot") version "3.3.3"
    id("io.spring.dependency-management") version "1.1.6"
}

group = "org.example"
version = "0.0.1-SNAPSHOT"

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

repositories {
    mavenCentral()
    maven { url = uri("https://repo.spring.io/milestone") }
}

extra["springAiVersion"] = "1.0.0-M2"

dependencies {
    implementation("org.springframework.ai:spring-ai-openai-spring-boot-starter")
    implementation("org.springframework.boot:spring-boot-starter-web")
    implementation("org.springframework.boot:spring-boot-starter-validation")
    
    implementation("org.jetbrains.kotlin:kotlin-reflect")
    testImplementation("org.springframework.boot:spring-boot-starter-test")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit5")
    testRuntimeOnly("org.junit.platform:junit-platform-launcher")
}

dependencyManagement {
    imports {
        mavenBom("org.springframework.ai:spring-ai-bom:${property("springAiVersion")}")
    }
}

kotlin {
    compilerOptions {
        freeCompilerArgs.addAll("-Xjsr305=strict")
    }
}

tasks.withType<Test> {
    useJUnitPlatform()
}

application.yml

spring:
  application:
    name: spring-ai
  ai:
    openai:
      api-key: # 여기에 발급 받은 OpenAI API Key 값을 입력. 절대 외부(깃허브 등)에 노출 금지!!
      chat:
        options:
          model: gpt-3.5-turbo
          temperature: 0.7
          max-tokens: 200

AiChatConfig.kt

@Configuration
class AiChatConfig(
    val chatClient: ChatClient.Builder
) {
    @Bean
    fun chatClient(): ChatClient {
        return chatClient.build()
    }
}

OpenAiEmbeddingConfig.kt

@Configuration
@EnableConfigurationProperties(OpenAiEmbeddingProperties::class)
class OpenAiEmbeddingConfig(
    private val openAiEmbeddingProperties: OpenAiEmbeddingProperties
) {
    @Bean
    fun embeddingModel(): EmbeddingModel {
        return OpenAiEmbeddingModel(OpenAiApi(openAiEmbeddingProperties.apiKey))
    }
}

DTO(AiChatRequest.kt, AiChatResponse.kt)

// AiChatRequest
data class AiChatRequest(
    @NotNull(message = "User input must not be null")
    val userInput: String = ""
)


// AiChatResponse
data class AiChatResponse(val response: String

AiChatController.kt

@RestController
@RequestMapping("/api/v1/chat")
class AiChatController(
    private val aiChatService: AiChatService
) {
    @PostMapping
    fun chat(@RequestBody aiChatRequest: AiChatRequest): AiChatResponse {
        return aiChatService.chat(aiChatRequest)
    }
}

AiChatService.kt

@Service
class AiChatService(
    private val chatClient: ChatClient,
    private val aiPromptService: AiPromptService
) {

    fun chat(aiChatRequest: AiChatRequest): AiChatResponse {
        val prompt = aiPromptService.createPrompt(aiChatRequest.userInput)
        return AiChatResponse(chatClient.prompt(prompt).call().content())
    }
}

system-message.st

You are a helpful AI assistant that helps people find information. Your name is {name}
You should reply to the user's request. and do not repeat it.

user-message.st

Tell me {userInput}

AiPromptService.kt

@Service
class AiPromptService(
    @Value("classpath:prompts/chat/system-message.st")
    private val systemResource: Resource,
    @Value("classpath:prompts/chat/user-message.st")
    private val userResource: Resource,
) {
    // 유저 입력을 메시지로 변환
    private fun createUserMessage(userInput: String): Message =
        PromptTemplate(userResource).createMessage(
            mapOf("userInput" to userInput)
        )

    // 시스템 메시지 생성
    private fun createSystemMessage(): Message =
        SystemPromptTemplate(systemResource).createMessage(
            mapOf("name" to "Jerry")
        )

    // 프롬프트 생성
    fun createPrompt(userInput: String): Prompt =
        Prompt(listOf(createUserMessage(userInput), createSystemMessage()))
}

위의 PromptService는 조금 자세히 살펴보자.

systemResource: 시스템의 역할이나 행동을 정의하는 메시지를 저장한 템플릿 파일인 system-message.st
userResource: 사용자가 입력한 내용을 담는 메시지를 저장한 템플릿 파일인 user-message.st

이 두 리소스는 각각 특정 메시지 패턴을 따르며, 메시지 내부에서 동적으로 값을 바인딩할 수 있도록 구성되어 있다.

  • `createUserMessage` 함수의 경우 `userInput`에 사용자에게 입력받은 `userInput`이 바인딩이 된다.
  • `createSystemMessage` 함수의 경우 `name`에 `Jerry`가 바인딩 된다.

그래서 시스템의 이름을 물어보면 `Jerry`라고 답을 한다.

 

대화형 AI에서는 사용자의 질문에 자연스럽고 일관된 답변을 제공하기 위해, 시스템의 역할과 사용자 입력을 효과적으로 전달하는 방법이 중요하다. 

이를 위해 템플릿 파일을 서비스에 맞게 변경하거나, 템플릿 메시지를 데이터베이스에 저장하여 동적으로 활용하는 방식이 필요할 것이다.

 

추가

Ai 채팅 결과
예?

나는 배우도 아니고, 연기력이 좋지도 않다. 위처럼 AI가 잘못된 정보를 응답해주는 것을 AI 할루시네이션이라고 한다.

 

AI 할루시네이션

AI 할루시네이션이란 인공지능 모델, 특히 자연어 처리(NLP) 모델이 실제로 존재하지 않거나 잘못된 정보를 마치 사실인 것처럼 생성하거나 제공하는 현상을 의미한다. 이는 인공지능이 주어진 데이터를 바탕으로 패턴을 학습하고 추론을 하지만, 때때로 오류를 범하거나 기존의 정보와 일치하지 않는 새로운 정보를 생성할 때 발생한다.

 

다음 포스팅에서 Spring AI와 벡터 스토어(Vector Store)를 활용하여 AI 할루시네이션을 줄이고, 보다 신뢰성 있는 답변을 제공하는 방법을 알아보자.

 


REFERENCES

스프링 ai prompt - https://docs.spring.io/spring-ai/reference/api/prompt.html

반응형
저작자표시 동일조건 (새창열림)
'Spring' 카테고리의 다른 글
  • [Spring] DeepL API를 이용한 번역 기능 추가하기
  • [Spring AI] Vector Store와 RAG를 이용한 할루시네이션 방지
  • [Spring AI] 준비 (기본 개념, OpenAI API Key, 크레딧 충전)
  • [스프링 시큐리티] WebSecurityConfigurerAdapter deprecated 대응
SooJae
SooJae
코드는 효율적으로, 공부는 비효율적으로
    반응형
  • SooJae
    이수재 블로그
    SooJae
  • 전체
    오늘
    어제
    • 분류 전체보기 (60)
      • Spring (8)
      • Next.JS (4)
      • React (3)
      • Angular (1)
      • Language (6)
        • Java (1)
        • Kotlin (1)
        • Javascript (4)
      • Keycloak (5)
      • Knowledge (16)
        • Test (4)
        • Web (9)
        • Security (2)
        • Data Structure (1)
      • Infra (9)
        • Proxmox (2)
        • AWS (0)
        • Kubernetes (3)
      • Tools (1)
        • IntelliJ (1)
      • Algorithm (2)
      • Tistory (4)
      • ETC (1)
  • 블로그 메뉴

    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Auth
    spring ai
    GPT
    javascript
    ai
    스프링 ai
    keycloak
    deepl api
    springboot
    React
    test
    오블완
    웹 마스터 도구
    Functional Programming
    Kotlin
    openAI
    티스토리챌린지
    ChatGPT
    스프링 번역
    Next.js
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
SooJae
[Spring AI] 챗봇 만들기 (Kotlin)
상단으로

티스토리툴바