spring ai 6,7,8일차 / , springai4

2026. 5. 18. 20:10대우개발원 수업 내용/spring기반 ai

반응형

• 동기 응답과 스트리밍 응답 비교
• Zero-Shot / Few-Shot 프롬프트 비교
• System Prompt 활용
• Reactive Stream(flux) 처리
를 하기 위해서

 

springai4 프로젝트 생성

 

해당 내용 확인


application.properties
수정 api키 입력

더보기
spring.application.name=springai4
spring.ai.openai.api-key= 

resources 폴더 안에 prompt.txt 추가

더보기
You are a helpful AI assistant.
Answer questions clearly and concisely in Korean.
Be friendly and professional.

java 패키지 안에 service 패키지 추가

ChatService 클래스도 추가

더보기
package com.example.springai4.service;

import org.springframework.ai.chat.client.ChatClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.nio.charset.StandardCharsets;

@Service
public class ChatService {
    private final ChatClient chatClient;
    @Value("classpath:prompt.txt") private Resource promptResource;

    public ChatService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    public String syncChat(String userMessage) {
        String systemPrompt = "";
        try {
            //prompt.txt 내용을 UTF-8 문자열로 읽기
            systemPrompt = promptResource.getContentAsString(StandardCharsets.UTF_8);
        } catch (IOException e) {
            e.printStackTrace();
        }
        String s = chatClient.prompt()
                .system(systemPrompt)
                .user(userMessage)
                .call()
                .content();
        return s;
    }

    // Project Reactor 에서 제공하는 비동기 스트림 타입
    public Flux<String> streamChat(String userMessage) {
        try {
            //prompt.txt 내용을 UTD-8 문자열로 읽기
            String systemPrompt = promptResource.getContentAsString(StandardCharsets.UTF_8);
            // 스트리밍 방식 AI 호출
            Flux<String> f = chatClient.prompt()
                    .system(systemPrompt)
                    .user(userMessage)
                    .stream()
                    .content();
            // Flux<String>
            return f;
        } catch (IOException e) {
            // 예외 발생 시 Flux 에러 반환
            return Flux.error(e);
        }
    }
}

controller 패키지 생성

ChatControllert 클래스 생성

더보기
package com.example.springai4.controller;


import com.example.springai4.service.ChatService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import reactor.core.publisher.Flux;

@Controller
public class ChatController {
    private final ChatService chatService;
    public ChatController(ChatService chatService) {
        this.chatService = chatService;
    }

    @GetMapping("/syncchat")
    public String chatForm1() { return "syncchat"; } // syncchat 메서드 호출

    @GetMapping("/streamchat")
    public String chatForm2() { return "streamchat"; } // streamChat 메서드 호출

    // 응답을 할 수 있는 코드를 호출

    @GetMapping(value = "/api/chat/sync")
    @ResponseBody
    public String syncChat(@RequestParam String message) {
        return chatService.syncChat(message);
    }
    
    @GetMapping(value = "/api/chat/stream")
    @ResponseBody
    public Flux<String> streamChat(@RequestParam String message) {
        return chatService.streamChat(message);
    } // stream() 사용
}

chat.css

streamchat.html

syncchat.html 추가


실행해보면

http://localhost:8080/syncchat

http://localhost:8080/streamchat


service 패키지 안에

ZeroShotFewShotService추가

더보기
package com.example.springai4.service;

import org.springframework.ai.chat.client.ChatClient;

public class ZeroShotFewShotService {
    private final ChatClient chatClient;

    public ZeroShotFewShotService(ChatClient.Builder chatClientBuilder) {
        this.chatClient = chatClientBuilder.build();
    }

    public String runZeroShot(String inputText) {
        System.out.println("---- 1. 제로샷 실행 -----");
        return chatClient.prompt()
                .user(inputText)
                .call()
                .content();
    }

    public String runFewShot(String inputText) {
        System.out.println("--- 2. 퓨샷 실행 ---");
        // context 정보 제공
        String userPrompt = """
                                질문에 대한 답은 다음과 같이 과정과 답으로 나눠서 작성해주세요.
                                10개의 공이 있었는데 3개를 가져가고 2개를 돌려받았다. 몇 개인가?
                                과정: (10-3)+2=9
                                답: 9개.
                                
                                질문내용: %s """.formatted(inputText);
        return chatClient.prompt()
                .user(userPrompt)
                .call()
                .content();
    }
}

 


domain 패키지를 추가하고

Result 레코드를 추가

더보기
package com.example.springai4.domain;

public record Result(
        String type,
        String result
) {}

 


ChatController 수정

더보기
package com.example.springai4.controller;


import com.example.springai4.domain.Result;
import com.example.springai4.service.ChatService;
import com.example.springai4.service.ZeroShotFewShotService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import reactor.core.publisher.Flux;

import java.util.ArrayList;
import java.util.List;

@Controller
public class ChatController {
    private final ChatService chatService;
    private final ZeroShotFewShotService shotService;

    public ChatController(ChatService chatService,
                          ZeroShotFewShotService shotService) {
        this.chatService = chatService;
        this.shotService = shotService;
    }

    @GetMapping("/syncchat")
    public String chatForm1() { return "syncchat"; } // syncchat 메서드 호출

    @GetMapping("/streamchat")
    public String chatForm2() { return "streamchat"; } // streamChat 메서드 호출

    // 응답을 할 수 있는 코드를 호출

    @GetMapping(value = "/api/chat/sync")
    @ResponseBody
    public String syncChat(@RequestParam String message) {
        return chatService.syncChat(message);
    }

    @GetMapping(value = "/api/chat/stream")
    @ResponseBody
    public Flux<String> streamChat(@RequestParam String message) {
        return chatService.streamChat(message);
    } // stream() 사용

    @GetMapping("/compare")
    @ResponseBody
    public List<Result> comparePrompts() {
        String testInput = "5명이서 피자 8조각을 나누어 먹는데, 2명이 추가되면 피자 1인당 몇 조각을 먹게 될까";

        String zeroShotResult = shotService.runZeroShot(testInput);
        String fewShotResult = shotService.runZeroShot(testInput);
        List<Result> list = List.of(
                new Result("제로샷의 결과", zeroShotResult),
                new Result("퓨샷의 결과", fewShotResult)
        );
        return list;
    }
}

 



실행하면

http://localhost:8080/compare