-
Notifications
You must be signed in to change notification settings - Fork 9
[고객지원 챗봇 만들기] 신관규 제출합니다. #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Soundbar91
wants to merge
45
commits into
cho-log:main
Choose a base branch
from
Soundbar91:soundbar91
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
45 commits
Select commit
Hold shift + click to select a range
34a7b8b
build: Lombok 의존성 추가
Soundbar91 ef83a9c
feat: POST /api/chat 초기 스켈레톤 코드 추가
Soundbar91 31a476e
fix: 요청/응답 DTO 클래스 네이밍 수정
Soundbar91 4518ab0
feat: OpenAI API 연동
Soundbar91 71f066d
feat: FAQ 컨텍스트 제공 추가
Soundbar91 336c798
feat: 정책 컨텍스트 제공 추가
Soundbar91 5019f9d
chore: LLM 요청/응답 로깅 추가
Soundbar91 f53777e
fix: 폐지 정책 컨텍스트 제공 삭제
Soundbar91 afd182a
fix: 시스템 프롬프트 수정
Soundbar91 7073245
chore: 토큰 사용량 로깅 추가
Soundbar91 28a05aa
fix: 시스템 프롬프트 수정
Soundbar91 289c43e
fix: 잘못된 파일 이름 추가 로직 수정
Soundbar91 69d8b5a
fix: AI 응답 메소드 호출부 수정
Soundbar91 f06ef96
build: VectorStore 의존성 추가
Soundbar91 27e5167
build: MarkdownReader 의존성 추가
Soundbar91 0b39720
fix: 평가 스크립트에서 영어로 질문하도록 수정
Soundbar91 f0d94de
feat: VectorStore 설정 클래스 추가
Soundbar91 478262e
feat: ChatClient 설정 클래스 추가
Soundbar91 3602fb0
fix: 파일 읽기 로직 삭제
Soundbar91 88b0967
feat: FAQ 리더 클래스 추가
Soundbar91 6f5011f
fix: VectorStore에서 컨텍스트를 조회하도록 수정
Soundbar91 36fc12c
feat: Policy 리더 클래스 추가
Soundbar91 fcaa431
feat: VectorStore에 Document 적재 로직 추가
Soundbar91 4373bf0
fix: 시스템 프롬프트 수정
Soundbar91 0db51d6
feat: 각 Layer별로 Document를 조회할 수 있는 로직 추가
Soundbar91 00d7534
feat: Chatlog 리더 클래스 추가
Soundbar91 4b8ab69
fix: 평가 기준 수정
Soundbar91 a121fba
fix: 시스템 프롬프트 수정
Soundbar91 df3badc
fix: 임베딩 데이터 수정에 따른 Reader 클래스 수정
Soundbar91 cb26abd
fix: 임베딩 데이터 수정에 따른 Reader 클래스 수정
Soundbar91 8c9cac2
chore: 패키징
Soundbar91 417cb4f
fix: 검증 프롬프트 수정
Soundbar91 640c7bd
fix: ChatService 내부 레코드 클래스 삭제
Soundbar91 28e468e
fix: InternalPolicy 메타 데이터 수정
Soundbar91 ab270bc
fix: 시스템 프롬프트 수정
Soundbar91 70c53bd
chore: 코드 포멧팅
Soundbar91 ccfeb1c
fix: InternalPolicy filterExpression 수정
Soundbar91 14f0f85
fix: 로깅 삭제
Soundbar91 29f2289
docs: wall-report 작성
Soundbar91 d21404a
build: 미사용 의존성 삭제
Soundbar91 486ebf4
chore: eof 수정
Soundbar91 52598a3
Update src/main/java/com/cholog/bootcamp/reader/ChatLogReader.java
Soundbar91 7801477
Update src/main/java/com/cholog/bootcamp/reader/CurrentPolicyReader.java
Soundbar91 6f39a50
Update src/main/java/com/cholog/bootcamp/reader/FaqReader.java
Soundbar91 c88bb20
Update src/main/java/com/cholog/bootcamp/reader/InternalPolicyReader.…
Soundbar91 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| "total": 150, | ||
| "correct": 112, | ||
| "incorrect": 38, | ||
| "error": 0, | ||
| "accuracy": 0.7466666666666667, | ||
| "tier_results": { | ||
| "easy": { | ||
| "correct": 23, | ||
| "total": 30 | ||
| }, | ||
| "medium": { | ||
| "correct": 69, | ||
| "total": 94 | ||
| }, | ||
| "hard": { | ||
| "correct": 20, | ||
| "total": 26 | ||
| } | ||
| }, | ||
| "elapsed_seconds": 556.8951289653778 | ||
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
15 changes: 15 additions & 0 deletions
15
src/main/java/com/cholog/bootcamp/config/ChatClientConfig.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| package com.cholog.bootcamp.config; | ||
|
|
||
| import org.springframework.ai.chat.client.ChatClient; | ||
| import org.springframework.ai.chat.model.ChatModel; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
|
|
||
| @Configuration | ||
| public class ChatClientConfig { | ||
|
|
||
| @Bean | ||
| public ChatClient chatClient(ChatModel chatModel) { | ||
| return ChatClient.builder(chatModel).build(); | ||
| } | ||
| } |
49 changes: 49 additions & 0 deletions
49
src/main/java/com/cholog/bootcamp/config/VectorStoreConfig.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,49 @@ | ||
| package com.cholog.bootcamp.config; | ||
|
|
||
| import java.util.ArrayList; | ||
| import java.util.List; | ||
|
|
||
| import org.springframework.ai.document.Document; | ||
| import org.springframework.ai.embedding.EmbeddingModel; | ||
| import org.springframework.ai.vectorstore.SimpleVectorStore; | ||
| import org.springframework.ai.vectorstore.VectorStore; | ||
| import org.springframework.boot.ApplicationRunner; | ||
| import org.springframework.context.annotation.Bean; | ||
| import org.springframework.context.annotation.Configuration; | ||
|
|
||
| import com.cholog.bootcamp.reader.ChatLogReader; | ||
| import com.cholog.bootcamp.reader.CurrentPolicyReader; | ||
| import com.cholog.bootcamp.reader.FaqReader; | ||
| import com.cholog.bootcamp.reader.InternalPolicyReader; | ||
|
|
||
| import lombok.extern.slf4j.Slf4j; | ||
|
|
||
| @Slf4j | ||
| @Configuration | ||
| public class VectorStoreConfig { | ||
|
|
||
| @Bean | ||
| public VectorStore vectorStore(EmbeddingModel embeddingModel) { | ||
| return SimpleVectorStore.builder(embeddingModel).build(); | ||
| } | ||
|
|
||
| @Bean | ||
| public ApplicationRunner vectorStoreInitializer( | ||
| FaqReader faqReader, | ||
| CurrentPolicyReader currentPolicyReader, | ||
| InternalPolicyReader internalPolicyReader, | ||
| ChatLogReader chatLogReader, | ||
| VectorStore vectorStore | ||
| ) { | ||
| return args -> { | ||
| List<Document> documents = new ArrayList<>(); | ||
| documents.addAll(faqReader.read()); | ||
| documents.addAll(currentPolicyReader.read()); | ||
| documents.addAll(internalPolicyReader.read()); | ||
| documents.addAll(chatLogReader.read()); | ||
|
|
||
| vectorStore.add(documents); | ||
| log.info("Loaded {} documents into VectorStore", documents.size()); | ||
| }; | ||
| } | ||
| } |
27 changes: 27 additions & 0 deletions
27
src/main/java/com/cholog/bootcamp/controller/ChatController.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| package com.cholog.bootcamp.controller; | ||
|
|
||
| import org.springframework.http.ResponseEntity; | ||
| import org.springframework.web.bind.annotation.PostMapping; | ||
| import org.springframework.web.bind.annotation.RequestBody; | ||
| import org.springframework.web.bind.annotation.RequestMapping; | ||
| import org.springframework.web.bind.annotation.RestController; | ||
|
|
||
| import com.cholog.bootcamp.dto.QuestionAskRequest; | ||
| import com.cholog.bootcamp.dto.QuestionAskResponse; | ||
| import com.cholog.bootcamp.service.ChatService; | ||
|
|
||
| import lombok.RequiredArgsConstructor; | ||
|
|
||
| @RestController | ||
| @RequiredArgsConstructor | ||
| @RequestMapping("/api/chat") | ||
| public class ChatController { | ||
|
|
||
| private final ChatService chatService; | ||
|
|
||
| @PostMapping | ||
| public ResponseEntity<QuestionAskResponse> askQuestion(@RequestBody QuestionAskRequest request) { | ||
| QuestionAskResponse response = chatService.askQuestion(request); | ||
| return ResponseEntity.ok(response); | ||
| } | ||
| } |
7 changes: 7 additions & 0 deletions
7
src/main/java/com/cholog/bootcamp/dto/QuestionAskRequest.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package com.cholog.bootcamp.dto; | ||
|
|
||
| public record QuestionAskRequest( | ||
| String question | ||
| ) { | ||
|
|
||
| } |
27 changes: 27 additions & 0 deletions
27
src/main/java/com/cholog/bootcamp/dto/QuestionAskResponse.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| package com.cholog.bootcamp.dto; | ||
|
|
||
| public record QuestionAskResponse( | ||
| String answer, | ||
| InnerTokenUsageResponse tokenUsage | ||
| ) { | ||
| public record InnerTokenUsageResponse( | ||
| Integer promptTokens, | ||
| Integer completionTokens, | ||
| Integer totalTokens | ||
| ) { | ||
| public static InnerTokenUsageResponse from( | ||
| Integer promptTokens, Integer completionTokens, Integer totalTokens | ||
| ) { | ||
| return new InnerTokenUsageResponse(promptTokens, completionTokens, totalTokens); | ||
| } | ||
| } | ||
|
|
||
| public static QuestionAskResponse from( | ||
| String answer, Integer promptTokens, Integer completionTokens, Integer totalTokens | ||
| ) { | ||
| return new QuestionAskResponse( | ||
| answer, | ||
| InnerTokenUsageResponse.from(promptTokens, completionTokens, totalTokens) | ||
| ); | ||
| } | ||
| } |
87 changes: 87 additions & 0 deletions
87
src/main/java/com/cholog/bootcamp/reader/ChatLogReader.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| package com.cholog.bootcamp.reader; | ||
|
|
||
| import java.io.IOException; | ||
| import java.nio.charset.StandardCharsets; | ||
| import java.nio.file.Files; | ||
| import java.nio.file.Path; | ||
| import java.util.ArrayList; | ||
| import java.util.HashMap; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.stream.Stream; | ||
|
|
||
| import org.springframework.ai.document.Document; | ||
| import org.springframework.stereotype.Component; | ||
|
|
||
| import com.fasterxml.jackson.databind.JsonNode; | ||
| import com.fasterxml.jackson.databind.ObjectMapper; | ||
|
|
||
| @Component | ||
| public class ChatLogReader { | ||
|
|
||
| private static final Path DIRECTORY = Path.of("data/layer3_chatlogs"); | ||
|
|
||
| private final ObjectMapper objectMapper = new ObjectMapper(); | ||
|
|
||
| public List<Document> read() { | ||
| try (Stream<Path> paths = Files.list(DIRECTORY)) { | ||
| List<Document> documents = new ArrayList<>(); | ||
| paths.forEach(path -> documents.addAll(readFile(path))); | ||
| return documents; | ||
| } catch (IOException e) { | ||
| throw new RuntimeException("채팅 로그 디렉토리를 읽는 중 오류가 발생했습니다.", e); | ||
| } | ||
| } | ||
|
|
||
| private List<Document> readFile(Path path) { | ||
| try (Stream<String> lines = Files.lines(path, StandardCharsets.UTF_8)) { | ||
| List<Document> documents = new ArrayList<>(); | ||
| lines.forEach(line -> { | ||
| Document document = parse(path, line); | ||
| if (document != null) { | ||
| documents.add(document); | ||
| } | ||
| }); | ||
| return documents; | ||
| } catch (IOException e) { | ||
| throw new IllegalArgumentException(""); | ||
| } | ||
| } | ||
|
|
||
| private Document parse(Path path, String line) { | ||
| try { | ||
| JsonNode root = objectMapper.readTree(line); | ||
| if (!"correct".equals(root.path("agent_accuracy").asText())) { | ||
| return null; | ||
| } | ||
|
|
||
| return toDocument(path, root); | ||
| } catch (IOException e) { | ||
| throw new IllegalArgumentException(""); | ||
| } | ||
| } | ||
|
|
||
| private Document toDocument(Path path, JsonNode root) { | ||
| Map<String, Object> metadata = new HashMap<>(); | ||
| metadata.put("layer", "layer3_chatlogs"); | ||
| metadata.put("filepath", path.toString()); | ||
| metadata.put("conversation_id", root.path("conversation_id").asText()); | ||
| metadata.put("primary_intent", root.path("primary_intent").asText()); | ||
| metadata.put("agent_accuracy", root.path("agent_accuracy").asText()); | ||
|
|
||
| return new Document(turns(root.path("turns")), metadata); | ||
| } | ||
|
|
||
| private String turns(JsonNode turns) { | ||
| StringBuilder sb = new StringBuilder(); | ||
|
|
||
| for (JsonNode turn : turns) { | ||
| sb.append(turn.path("role").asText()) | ||
| .append(": ") | ||
| .append(turn.path("text").asText()) | ||
| .append('\n'); | ||
| } | ||
|
|
||
| return sb.toString().trim(); | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
빈 메시지 throw 안티패턴이 보이네요.
이 코드가 production에서 발화하면 다음과 같은 문제가 있습니다.
같은 패턴이
CurrentPolicyReader:51,FaqReader,InternalPolicyReader에서 반복되고 있어요.최소한 아래와 같이 정보를 담아주면 좋겠습니다.
추가로, 만약 이 reader가 부팅 시점이 아니라 runtime에 도구로 호출된다면 (예: 운영 중 FAQ 추가), 이 메시지가 LLM의 다음 결정에 활용 가능한 형태여야 한다는 것도 같이 고민해보면 좋겠습니다~