Skip to content

refactor: Agent 관련 리팩토링#354

Merged
JanooGwan merged 2 commits intodevelopfrom
refactor/slack-ai-agent
Mar 7, 2026
Merged

refactor: Agent 관련 리팩토링#354
JanooGwan merged 2 commits intodevelopfrom
refactor/slack-ai-agent

Conversation

@JanooGwan
Copy link
Contributor

🔍 개요

  • close #이슈번호

🚀 주요 변경 내용

  • Gemini -> Claude 로 에이전트 변경했습니다.

💬 참고 사항


✅ Checklist (완료 조건)

  • 코드 스타일 가이드 준수
  • 테스트 코드 포함됨
  • Reviewers / Assignees / Labels 지정 완료
  • 보안 및 민감 정보 검증 (API 키, 환경 변수, 개인정보 등)

@JanooGwan JanooGwan requested a review from Copilot March 7, 2026 06:57
@JanooGwan JanooGwan self-assigned this Mar 7, 2026
@JanooGwan JanooGwan added the 리팩토링 리팩터링을 위한 이슈입니다. label Mar 7, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 7, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 36b2904a-6aa8-4b71-a33a-664adf237cc8

📥 Commits

Reviewing files that changed from the base of the PR and between 6ada6c7 and 98cfde6.

📒 Files selected for processing (4)
  • src/main/java/gg/agit/konect/infrastructure/claude/client/ClaudeClient.java
  • src/main/java/gg/agit/konect/infrastructure/claude/config/ClaudeProperties.java
  • src/main/java/gg/agit/konect/infrastructure/gemini/client/GeminiClient.java
  • src/main/java/gg/agit/konect/infrastructure/gemini/config/GeminiProperties.java

📝 Walkthrough

Walkthrough

Gemini 기반 AI 통합을 제거하고 Claude 기반 통합으로 교체합니다. 새로운 ClaudeClient와 ClaudeProperties를 추가하고 GeminiClient/GeminiProperties를 삭제했으며, SlackAIService 및 테스트 설정과 환경 구성 파일들을 Claude로 재연결합니다. ClaudeClient는 다중 턴 도구 호출 및 MCP 위임을 포함합니다.

Changes

Cohort / File(s) Summary
Claude 클라이언트 추가
src/main/java/gg/agit/konect/infrastructure/claude/client/ClaudeClient.java
새로운 ClaudeClient 클래스 추가: 시스템 프롬프트, 3개 도구 정의(query, list_tables, describe_table), 다중 턴 채팅 루프, 도구 호출 처리 및 MCP 위임, API 호출 및 예외 처리 구현.
Claude 설정 추가
src/main/java/gg/agit/konect/infrastructure/claude/config/ClaudeProperties.java
@ConfigurationProperties(prefix="claude") 레코드 추가: apiKey, model 필드로 구성 바인딩 및 검증 제공.
Gemini 제거
src/main/java/gg/agit/konect/infrastructure/gemini/client/GeminiClient.java, src/main/java/gg/agit/konect/infrastructure/gemini/config/GeminiProperties.java
기존 GeminiClient 및 GeminiProperties 파일 삭제: 전체 Gemini 기반 다중 턴/도구 호출 구현 제거.
서비스 의존성 교체
src/main/java/gg/agit/konect/infrastructure/slack/ai/SlackAIService.java
GeminiClient 의존성을 ClaudeClient로 교체(임포트, 생성자, 사용 호출 변경).
애플리케이션 설정 파일 업데이트
src/main/resources/application-infrastructure.yml, src/test/resources/application-test.yml
환경 설정에서 gemini 블록을 claude 블록으로 교체하고 모델 기본값을 claude-sonnet-4-20250514로 변경.
테스트 구성 업데이트 및 추가
src/test/java/gg/agit/konect/KonectApplicationTests.java, src/test/java/gg/agit/konect/support/ControllerTestSupport.java, src/test/java/gg/agit/konect/support/IntegrationTestSupport.java, src/test/java/gg/agit/konect/support/TestClaudeConfig.java
테스트 임포트에서 TestGeminiConfig → TestClaudeConfig로 변경(3개 파일). TestClaudeConfig 추가로 ClaudeClient 모킹 빈(@Primary) 제공 및 chat(...) 스텁 설정.
테스트 리소스 설정 변경
src/test/resources/application-test.yml
테스트 환경 설정에서 gemini → claude로 변경 및 모델 값 업데이트.

Sequence Diagram

sequenceDiagram
    participant Slack as SlackAIService
    participant Claude as ClaudeClient
    participant API as Claude API
    participant MCP as McpClient

    Slack->>Claude: chat(userMessage)
    Claude->>Claude: buildRequest(message, history, tools)
    Claude->>API: POST /messages (model, prompt, tools, limits)
    API-->>Claude: Response {stop_reason, content}
    alt stop_reason == end_turn
        Claude->>Claude: extractTextResponse()
        Claude-->>Slack: finalText
    else stop_reason == tool_use
        Claude->>Claude: processToolCalls(toolUseBlocks)
        loop for each tool call
            Claude->>MCP: executeToolCall(toolName, args)
            MCP-->>Claude: toolResult
        end
        Claude->>Claude: appendToolResults(toHistory)
        Claude->>API: POST /messages (updated history)
        API-->>Claude: nextResponse
        Claude-->>Slack: finalText (after iterations or end_turn)
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~32 minutes

Possibly related PRs

  • refactor: Agent 관련 리팩토링 #354: 동일한 Gemini→Claude 마이그레이션(ClaudeClient/ClaudeProperties 추가, Gemini 삭제, 서비스 및 테스트 재배선)과 직접적인 코드 일치 가능성.
  • refactor: Slack AI에 MCP 적용 #349: SlackAIService 및 MCP 도구 호출 통합과 관련된 변경을 포함하여 본 PR과 유사한 AI 클라이언트 교체 작업을 수행.
  • refactor: MCP 도구 추가 활용 #353: 다중 턴 도구 호출 흐름(도구 실행/응답 병합 등) 구현 변경을 다루며 Claude/Gemini 클라이언트 흐름과 코드 레벨 연관성 있음.

Poem

🐰 안녕, Claude여 반갑구나,
턴을 돌리고 도구를 불러오네,
MCP와 함께 표를 보고 묻고,
답이 모여서 대화가 자라나네,
햇살처럼 가벼운 코드 춤을! ✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 10.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed 제목이 변경 사항의 주요 내용을 명확하게 반영하고 있으며, Gemini에서 Claude로의 에이전트 변경이라는 핵심 변경 사항을 정확히 설명하고 있습니다.
Description check ✅ Passed 설명에서 Gemini을 Claude로 변경했다는 주요 변경 내용을 포함하고 있어, 변경 사항과 관련성이 있습니다.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/slack-ai-agent

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

이 PR은 Slack AI 서비스에서 사용하는 AI 에이전트를 Google Gemini에서 Anthropic Claude로 교체하는 리팩토링입니다. SlackAIServiceGeminiClient 대신 새로 추가된 ClaudeClient를 사용하도록 변경되었으며, 설정 프로퍼티와 테스트 인프라도 함께 업데이트되었습니다.

Changes:

  • ClaudeClientClaudeProperties 신규 추가 (Anthropic API 호출, tool use 멀티턴 루프 지원)
  • SlackAIService의 의존성을 GeminiClient에서 ClaudeClient로 교체
  • 설정 파일(application-infrastructure.yml, application-test.yml) 및 테스트 설정(TestClaudeConfig, IntegrationTestSupport, ControllerTestSupport, KonectApplicationTests)을 Claude 기반으로 업데이트

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
ClaudeClient.java Anthropic Claude API를 호출하는 신규 클라이언트 (tool use 지원)
ClaudeProperties.java Claude API 설정 바인딩 record 신규 추가
SlackAIService.java GeminiClient → ClaudeClient 의존성 교체
application-infrastructure.yml gemini 설정 블록을 claude로 교체
application-test.yml 테스트용 gemini 설정을 claude로 교체
TestClaudeConfig.java 테스트용 ClaudeClient mock 설정 신규 추가
IntegrationTestSupport.java @import에서 TestGeminiConfig → TestClaudeConfig로 변경
ControllerTestSupport.java @import에서 TestGeminiConfig → TestClaudeConfig로 변경
KonectApplicationTests.java @import에서 TestGeminiConfig → TestClaudeConfig로 변경

@@ -13,9 +13,9 @@ slack:
event: ${SLACK_WEBHOOK_EVENT}
signing-secret: ${SLACK_SIGNING_SECRET}

Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

GeminiClient@Component로 등록된 상태로 남아있고, GeminiProperties@ConfigurationProperties(prefix = "gemini")로 바인딩을 시도합니다. 하지만 application-infrastructure.yml에서 gemini 설정 블록이 claude로 교체되었기 때문에, GeminiPropertiesapiKeymodel 값은 null이 됩니다. 더 이상 사용되지 않는 GeminiClientGeminiProperties, 그리고 src/main/java/gg/agit/konect/infrastructure/gemini/ 디렉토리를 제거해야 합니다. 그렇지 않으면 죽은 코드가 애플리케이션 컨텍스트에 남아 유지보수 문제를 야기합니다.

Suggested change
gemini:
api-key: ${GEMINI_API_KEY:}
model: ${GEMINI_MODEL:}

Copilot uses AI. Check for mistakes.
@SpringBootTest
@ActiveProfiles("test")
@Import({TestSecurityConfig.class, TestJpaConfig.class, TestGeminiConfig.class})
@Import({TestSecurityConfig.class, TestJpaConfig.class, TestClaudeConfig.class})
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

TestGeminiConfig 파일이 더 이상 어떤 테스트에서도 @Import에 참조되지 않지만 삭제되지 않고 남아있습니다. 이 파일은 이번 리팩토링에서 함께 제거되어야 합니다.

Copilot uses AI. Check for mistakes.

for (int i = 0; i < MAX_TOOL_ITERATIONS; i++) {
Map<String, Object> request = buildRequest(messages);
String response = callClaudeApi(request);
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

callClaudeApi에서 RestClient의 응답이 null일 경우, 이후 objectMapper.readTree(response)에서 null이 readTree(String)에 전달되어 IllegalArgumentException 또는 NullPointerException이 발생할 수 있습니다. 외부 catch 블록이 이를 잡아주지만, null 응답에 대한 명시적인 처리가 없어 오류 원인 파악이 어렵습니다. callClaudeApi에서 null 응답을 명시적으로 검사하거나, readTree 호출 전에 null 체크를 추가하는 것이 좋습니다.

Suggested change
String response = callClaudeApi(request);
String response = callClaudeApi(request);
if (response == null) {
log.error("Claude API returned null response for request: {}", request);
throw new RestClientException("Claude API returned null response");
}

Copilot uses AI. Check for mistakes.
Comment on lines +143 to +155
if ("tool_use".equals(stopReason)) {
// Add assistant's response to messages
messages.add(Map.of(
"role", "assistant",
"content", objectMapper.convertValue(content, List.class)
));

// Process tool calls and add results
List<Map<String, Object>> toolResults = processToolCalls(content);
messages.add(Map.of(
"role", "user",
"content", toolResults
));
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

stop_reason"tool_use"임에도 processToolCalls(content)가 빈 리스트를 반환하는 경우(예: content 배열에 tool_use 타입 블록이 없는 경우), 빈 content 배열을 가진 user 메시지가 Claude API에 전송됩니다. Anthropic API는 content가 빈 배열인 메시지에 대해 오류를 반환할 수 있으므로, toolResults가 비어있을 때 적절히 처리해야 합니다.

Copilot uses AI. Check for mistakes.
## 주요 테이블 힌트
- users: 사용자 정보 (deleted_at IS NULL = 활성 사용자)
- club: 동아리 정보
- club_member: 동아리 멤버 (role: PRESIDENT, VICE_PRESIDENT, MEMBER)
Copy link

Copilot AI Mar 7, 2026

Choose a reason for hiding this comment

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

SYSTEM_PROMPTclub_member 테이블 힌트에 실제 ClubPosition enum 값인 MANAGER가 누락되어 있습니다. 실제 ClubPosition enum은 PRESIDENT, VICE_PRESIDENT, MANAGER, MEMBER 4개의 값을 가지지만, 프롬프트에는 PRESIDENT, VICE_PRESIDENT, MEMBER 3개만 기재되어 있습니다. AI가 MANAGER 역할을 가진 멤버를 누락시킬 수 있어 잘못된 쿼리 결과를 생성할 수 있습니다. MANAGER를 힌트에 추가해야 합니다.

Suggested change
- club_member: 동아리 멤버 (role: PRESIDENT, VICE_PRESIDENT, MEMBER)
- club_member: 동아리 멤버 (role: PRESIDENT, VICE_PRESIDENT, MANAGER, MEMBER)

Copilot uses AI. Check for mistakes.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/main/java/gg/agit/konect/infrastructure/claude/client/ClaudeClient.java`:
- Around line 165-167: The catch in ClaudeClient currently swallows exceptions
and returns a user-facing string; instead propagate failure by throwing a
domain-specific exception (e.g., ClaudeException) or change the method signature
to return a Result/Optional that indicates failure so callers can handle it;
specifically, in ClaudeClient (the method containing the try/catch that
currently logs and returns "죄송합니다..."), replace the catch block to throw new
ClaudeException(e) (or return a failure Result) and update callers such as
SlackAIService to handle the exception/result path rather than treating it as a
normal response.
- Around line 180-182: The code currently logs full tool inputs and Claude
responses in ClaudeClient (e.g., the log.info calls around the executeToolCall
invocation and other logging at the places that record SQL and full responses);
change these to avoid recording sensitive plaintext by removing or redacting
request/response bodies and instead log only non-sensitive metadata such as
toolName, a requestId/correlation id, timestamps, success/failure status, and
error messages; update the log statements in the methods using executeToolCall
and any other methods that log SQL or Claude responses to mask or truncate
payloads (or omit them entirely) and ensure errors still log safe diagnostic
info (stack/message) without including sensitive content.

In
`@src/main/java/gg/agit/konect/infrastructure/claude/config/ClaudeProperties.java`:
- Around line 7-10: The ClaudeProperties record's `@NotBlank` constraints aren't
enforced because it lacks the `@Validated` annotation; add `@Validated` to the
ClaudeProperties declaration so Spring performs validation at bind time for the
apiKey and model fields (i.e., annotate the ClaudeProperties record with
`@Validated` to activate constraint checks on the `@NotBlank` apiKey and model
properties).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: f57153c1-f2cb-4c8b-a55e-b9f1f6d530fc

📥 Commits

Reviewing files that changed from the base of the PR and between 678143b and 6ada6c7.

📒 Files selected for processing (9)
  • src/main/java/gg/agit/konect/infrastructure/claude/client/ClaudeClient.java
  • src/main/java/gg/agit/konect/infrastructure/claude/config/ClaudeProperties.java
  • src/main/java/gg/agit/konect/infrastructure/slack/ai/SlackAIService.java
  • src/main/resources/application-infrastructure.yml
  • src/test/java/gg/agit/konect/KonectApplicationTests.java
  • src/test/java/gg/agit/konect/support/ControllerTestSupport.java
  • src/test/java/gg/agit/konect/support/IntegrationTestSupport.java
  • src/test/java/gg/agit/konect/support/TestClaudeConfig.java
  • src/test/resources/application-test.yml
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Agent
🧰 Additional context used
📓 Path-based instructions (2)
src/main/java/**/*.java

⚙️ CodeRabbit configuration file

src/main/java/**/*.java: 아래 원칙으로 리뷰 코멘트를 작성한다.

  • 코멘트는 반드시 한국어로 작성한다.
  • 반드시 수정이 필요한 항목만 코멘트로 남기고, 단순 취향 차이는 지적하지 않는다.
  • 각 코멘트 첫 줄에 심각도를 [LEVEL: high|medium|low] 형식으로 반드시 표기한다.
  • 심각도 기준: high=운영 장애 가능, medium=품질 저하, low=개선 권고.
  • 각 코멘트는 "문제 -> 영향 -> 제안" 순서로 3문장 이내로 간결하게 작성한다.
  • 가능하면 재현 조건 및 실패 시나리오도 포함한다.
  • 제안은 현재 코드베이스(Spring Boot + JPA + Flyway) 패턴과 일치해야 한다.
  • 보안, 트랜잭션 경계, 예외 처리, N+1, 성능 회귀 가능성을 우선 점검한다.
  • 가독성: 변수/메서드 이름이 의도를 바로 드러내는지, 중첩과 메서드 길이가 과도하지 않은지 점검한다.
  • 단순화: 불필요한 추상화, 중복 로직, 과한 방어 코드가 있으면 더 단순한 대안을 제시한다.
  • 확장성: 새 요구사항 추가 시 변경 범위가 최소화되는 구조인지(하드코딩 분기/값 여부 포함) 점검한다.

Files:

  • src/main/java/gg/agit/konect/infrastructure/claude/client/ClaudeClient.java
  • src/main/java/gg/agit/konect/infrastructure/claude/config/ClaudeProperties.java
  • src/main/java/gg/agit/konect/infrastructure/slack/ai/SlackAIService.java
**/*

⚙️ CodeRabbit configuration file

**/*: 공통 리뷰 톤 가이드:

  • 모든 코멘트는 첫 줄에 [LEVEL: ...] 태그를 포함한다.
  • 과장된 표현 없이 사실 기반으로 작성한다.
  • 한 코멘트에는 하나의 이슈만 다룬다.
  • 코드 예시가 필요하면 최소 수정 예시를 제시한다.
  • 가독성/단순화/확장성 이슈를 발견하면 우선순위를 높여 코멘트한다.

Files:

  • src/main/java/gg/agit/konect/infrastructure/claude/client/ClaudeClient.java
  • src/test/java/gg/agit/konect/support/IntegrationTestSupport.java
  • src/main/java/gg/agit/konect/infrastructure/claude/config/ClaudeProperties.java
  • src/test/java/gg/agit/konect/KonectApplicationTests.java
  • src/main/resources/application-infrastructure.yml
  • src/test/java/gg/agit/konect/support/ControllerTestSupport.java
  • src/main/java/gg/agit/konect/infrastructure/slack/ai/SlackAIService.java
  • src/test/resources/application-test.yml
  • src/test/java/gg/agit/konect/support/TestClaudeConfig.java
🪛 Checkov (3.2.334)
src/test/resources/application-test.yml

[low] 126-127: Base64 High Entropy String

(CKV_SECRET_6)

🔇 Additional comments (1)
src/test/java/gg/agit/konect/support/ControllerTestSupport.java (1)

45-45: [LEVEL: approve]

LGTM! Gemini에서 Claude로의 테스트 구성 마이그레이션이 적절합니다.

TestGeminiConfig에서 TestClaudeConfig로의 변경이 PR 목표(Agent를 Gemini에서 Claude로 전환)와 일치하며, 다른 테스트 파일들(KonectApplicationTests.java, IntegrationTestSupport.java)과도 일관성 있게 적용되었습니다.

@JanooGwan JanooGwan merged commit 01a908b into develop Mar 7, 2026
1 of 2 checks passed
@JanooGwan JanooGwan deleted the refactor/slack-ai-agent branch March 7, 2026 07:19
@coderabbitai coderabbitai bot mentioned this pull request Mar 7, 2026
4 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

리팩토링 리팩터링을 위한 이슈입니다.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants