Skip to content

[고객지원 챗봇 만들기] 김수민 제출합니다.#4

Open
boyekim wants to merge 7 commits into
cho-log:mainfrom
boyekim:boyekim
Open

[고객지원 챗봇 만들기] 김수민 제출합니다.#4
boyekim wants to merge 7 commits into
cho-log:mainfrom
boyekim:boyekim

Conversation

@boyekim
Copy link
Copy Markdown
Member

@boyekim boyekim commented May 20, 2026

구현 내용

  • Spring AI ChatClient를 사용해 /api/chat에서 사용자 질문에 대한 답변을 생성하도록 구현했습니다.
  • FAQ, 현행 정책, 상담 로그 데이터를 DocumentLoader에서 읽고 Spring AI Document로 변환했습니다.
  • FAQ는 ###, 정책은 ## 기준으로 chunking하고, 상담 로그는 JSONL을 ObjectMapper로 파싱해 agent_accuracy=correct인 데이터만 사용했습니다.
  • 응답에는 답변과 함께 promptTokens, completionTokens, totalTokens를 포함했습니다.

Copy link
Copy Markdown

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request implements a RAG-based chatbot using Spring AI, featuring document loading and chunking for FAQs, policies, and chat logs, alongside a REST API for chat interactions. It also refactors Gradle environment variable loading and updates the Python evaluation script for detailed result tracking. Review feedback identifies a potential NullPointerException in response handling, suggests externalizing hardcoded file paths to configuration properties, and recommends implementing vector data caching to reduce application startup latency and API costs.

Comment on lines +67 to +74
return new ChatAnswerResponse(
response.getResult().getOutput().getText(),
new ChatAnswerResponse.TokenUsage(
usage == null || usage.getPromptTokens() == null ? 0 : usage.getPromptTokens(),
usage == null || usage.getCompletionTokens() == null ? 0 : usage.getCompletionTokens(),
usage == null || usage.getTotalTokens() == null ? 0 : usage.getTotalTokens()
)
);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

LLM 응답 결과가 비어있을 경우 response.getResult()null을 반환하여 NullPointerException이 발생할 수 있습니다. 응답 존재 여부를 확인한 후 안전하게 텍스트를 추출하도록 개선이 필요합니다.

        String answer = (response.getResult() != null && response.getResult().getOutput() != null)
            ? response.getResult().getOutput().getText()
            : "고객센터에 문의해주세요.";

        return new ChatAnswerResponse(
            answer,
            new ChatAnswerResponse.TokenUsage(
                usage == null || usage.getPromptTokens() == null ? 0 : usage.getPromptTokens(),
                usage == null || usage.getCompletionTokens() == null ? 0 : usage.getCompletionTokens(),
                usage == null || usage.getTotalTokens() == null ? 0 : usage.getTotalTokens()
            )
        );

Comment on lines +21 to +23
private static final Path FAQ_DIRECTORY = Path.of("data/layer1_faq");
private static final Path CURRENT_POLICY_DIRECTORY = Path.of("data/layer2_policies/current");
private static final Path CHATLOG_DIRECTORY = Path.of("data/layer3_chatlogs");
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

데이터 디렉토리 경로가 하드코딩되어 있습니다. 운영 환경이나 테스트 환경에 따라 경로가 달라질 수 있으므로, RagProperties를 통해 application.yml에서 관리하도록 수정하는 것을 권장합니다.

)
);
} catch (IOException e) {
throw new UncheckedIOException("Failed to parse chatlog line in file: " + path.getFileName(), e);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

상담 로그 파일의 특정 라인이 유효하지 않은 JSON일 경우 UncheckedIOException이 발생하며 애플리케이션 시작이 중단됩니다. 데이터의 결함으로 인해 전체 시스템이 마비되지 않도록, 오류 발생 시 해당 라인을 건너뛰고 로그를 남기는 방식이 더 안전합니다.

Suggested change
throw new UncheckedIOException("Failed to parse chatlog line in file: " + path.getFileName(), e);
return null;


@PostConstruct
void loadFaqContext() {
vectorStore.add(documentLoader.load());
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

현재 구조는 애플리케이션이 시작될 때마다 모든 문서를 다시 읽고 임베딩하여 VectorStore에 추가합니다. 이는 시작 시간을 지연시키고 불필요한 API 비용을 발생시킵니다. SimpleVectorStoresave/load 기능을 사용하여 벡터 데이터를 파일로 캐싱하거나, 영구 저장소 기반의 VectorStore 도입을 고려해 보세요.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant