우리팀 아기를 위한 - Github 히스토리 기반 인수인계 봇 만들기 with Spring AI

2026. 1. 17. 23:38·경험 모음집
반응형
팀의 신입이 모든 히스토리를 짧은 시간 안에 다 읽고, 지식을 흡수하기란 매우 어려운 일이다. 

 

 

나 역시도 신입 서버 관리자로 들어왔을 때, 파편화된 문서들을 읽는 데 시간이 오래 걸렸다. 

그래서 내가 서버 관리자 업무 자동화 시스템을 개발하면서는, PR / Issue / Wiki등등을 열심히 쓰려고 노력했다. 

1년이 지났고, 새로운 서버 관리자 한 명을 영입하게 되었다.

우리 팀이 마주한 문제들...
🥺

 

내가 졸업을 앞두게 되어 개발하던 백엔드 파트를 인수인계 해주어야 하는 상황이었다.

이때 여러명의 신입 관리자들에게 구두로 정보를 전달하는 것은 쉽지 않을 것 같다.

신입 관리자님과 함께 회의가 끝나고 카페에 가서 폴더 구조, 배포 방법, 주의할 점 등등을 설명해주고 있었는데,

 

나도 내가 짠 것이.. 반년정도, 아니 세달만 지나도 잘 기억이 안 났다!!

"어.. 뭐였더라.. 어.. 잠깐만.."

"이거 이슈에 써놨는데... 아닌가 PR인가?" 라며 깃허브와 주석을 뒤지고 있었다. 

 

 

이때 까먹고 있었던 교수님 잔소리가 생각났다. 

교수님.

이전에 이렇게 이야기를 해주셨었는데, 지금 이 상황을 해결하기 위해서 AI를 어떻게 활용할 수 있는지 다시 생각해보게 되었다. 

 

"하라는 뜻은 아님"

 

그래도 해보자!

AI가 얼마만큼의 가능성을 열어줄 수 있을지 궁금해서, 기존에 개발하던 Spring 에 코드를 몇줄 간단히 추가하였다. 

일단 빠르게 결과를 확인하기 위해 swagger-ui 안에서만 활용할 수 있게 빠르게 만들어보자!

 

이름은 Junior Admin Buddy!

 

  • Framework: Spring Boot 3.3.x & Spring AI
  • External API: GitHub API (PR 히스토리 및 Wiki 수집)
  • LLM: OpenAI GPT-4o-mini

 

TMI)

기존에는 더 높은 버전들을 사용하고 있었는데, Spring AI를 활용하기 위해서 버전을 살짝 낮춰주었다. 

기존 프로젝트는 Spring Boot 3.5.x 기반의 가장 최신 환경으로 구성해놓았었는데, AI 기능을 통합하기 위해 과감히 버전을 3.3.4로 조정할 필요가 있었다.

- Spring AI의 생태계: Spring AI는 현재 마일스톤(Milestone) 단계에 있는 프로젝트이다. 따라서 너무 앞서가는 Spring Boot 최신 버전(v3.5+)과는 내부 라이브러리(특히 Bean 로드 및 조건부 설정 로직)에서 충돌이 발생한다.
- Bean Definition 오류 해결: 실제로 3.5.3 버전에서는 Swagger(SpringDoc)와 Spring Cloud Function 간의 클래스 로드 순서 문제로 인해 애플리케이션 자체가 구동되지 않는 현상이 있었다. 이를 해결하기 위해 Spring AI와 가장 호환성이 검증된 3.3.x 라인으로 환경을 맞춰주었다.

 

🧠 Spring AI는 이 프로젝트에서 무슨 역할을 했나?

한 줄 요약 :
Spring AI의 역할은 Spring 생태계 개발자들이 
자바 애플리케이션에 인공지능 기능을 쉽고 표준화된 방식으로 통합할 수 있도록 돕는 프레임워크이다.
  • 추상화된 인터페이스 (ChatClient): 특정 AI 모델(OpenAI, Ollama 등)에 종속되지 않는 인터페이스를 제공합니다. 덕분에 나중에 모델을 교체하더라도 비즈니스 로직(Service 레이어)은 수정할 필요가 없어진다.
  • 유연한 프롬프트 관리 (Fluent API): .system(), .user(), .call()과 같은 유연한 메서드 체이닝을 통해 복잡한 프롬프트 구성을 자바 코드 내에서 깔끔하게 관리할 수 있게 해준다.
  • 자동화된 인프라 설정: API 키 설정, 타임아웃 처리, Retry(재시도) 로직 등 번거로운 HTTP 통신 설정을 스프링의 관례(Convention)에 따라 자동으로 처리해 준다.

 

"기억나지 않는 과거"를 AI에게 학습시키기

본격적으로 코드를 짜기 전에 집중해야할 부분은 '어떻게 하면 AI가 단순한 챗봇을 넘어 우리 팀의 맥락을 파악하게 할 지'였다. 

 

가장 먼저 해결해야 할 과제는 흩어진 기록을 모으는 것이다. 우리 모두 이미 잘 해놓았다. 깃허브에는 프로젝트의 모든 맥락이 모여있다. 

나는 Issue ➡️ PR ➡️ Wiki 순서로 개발 기록을 정리했어서, Github의 내용을 기반으로 데이터를 가져오면 되겠다고 생각했다. 

 

 

Github 데이터 파이프라인

`kohsuke:github-api`를 활용해 최근 20개의 Closed PR과 Wiki 본문을 긁어오는 `GithubHistoryService`를 만든다. 

단순히 텍스트만 가져오는 게 아니라, '최신순'으로 정렬하여 AI가 과거의 낡은 정보보다 어제의 결정을 더 신뢰하도록 가중치를 두면 둔다. 

 

Spring AI를 활용한 Prompt Engineering

수집한 방대한 데이터를 AI에게 그냥 던져주는 것이 아니라, '신입 관리자를 위한 친절한 시니어 관리자'라는 페르소나를 부여해준다.

  • PR 히스토리와 위키 내용을 시스템 프롬프트에 주입한다.
너는 신입 관리자를 돕는 'Junior Admin Buddy'야. 
                신입 관리자는 아주 어린 대학생이야. 따라서 부드럽게, 친절하게 대해줘야 해.
                제공된 [PR 히스토리]와 [위키/가이드] 내용을 바탕으로 답변해줘.

 

내가 인수인계할 때 가장 헷갈렸던 "UID/GID 관리 로직"에 대해 직접 질문해보았다. 

Q. UID/GID를 어떻게 관리하고 있는지 논리적으로 이해가 안 가.
안녕하세요! UID(사용자 식별자)와 GID(그룹 식별자)의 관리에 대해 설명해드릴게요.

1. **UID와 GID란?**
   - UID는 시스템에서 각 사용자를 고유하게 식별하기 위한 번호입니다. 
   - GID는 그룹을 식별하기 위한 번호로, 여러 사용자들이 속할 수 있는 그룹을 나타냅니다.

2. **UID/GID 관리 방식**
   - 사용자가 그룹을 만들거나 가입할 때, 해당 그룹에 고유한 GID가 부여됩니다.
   - 사용자가 생성될 때, 시스템은 자동으로 UID를 할당합니다. 이때, UID와 GID는 서로 연관이 있습니다. 예를 들어, 사용자가 그룹을 만들 때 그 사용자의 UID가 그룹의 GID로 설정될 수 있습니다.

3. **사용 신청 프로세스**
   - 사용자가 사용 신청을 시작하면, 해당 사용자의 요청에 따라 우분투 그룹이 생성되거나 기존의 그룹을 선택할 수 있습니다.
   - 사용자가 그룹을 지정하지 않으면, 시스템이 자동으로 UID와 같은 GID를 생성하여 그룹을 만들게 됩니다. 이 과정은 서버에서 자동으로 처리되며, 클라이언트 측에서는 별도로 고려하지 않아도 됩니다.

4. **사용 변경 프로세스**
   - 사용자가 그룹 변경을 원할 경우, 기존의 우분투 그룹을 선택하고 관련 신청서를 작성하여 승인 절차를 받습니다.

이와 같은 방식으로 UID와 GID를 관리하여 사용자와 그룹을 체계적으로 관리할 수 있습니다. 더 궁금한 점이 있으면 언제든지 물어보세요! 😊

 

 

 

추가적으로 헷갈릴만한 비즈니스 로직에 대해 질문했다.

Q. 장기 미접속자는 어떻게 관리하고 있어?

 

장기 미접속 사용자 관리는 자동화된 시스템을 통해 이루어지고 있어요. 이 시스템은 매일 오전 09:00에 실행되는 스케줄러에 의해 운영됩니다. 아래는 장기 미접속 사용자를 관리하는 주요 내용이에요:

1. **대상 선정 기준**: 
   - 사용자의 마지막 로그인 시점이 3개월 이상 지났고, Pod 만료일도 3개월 이상 지났을 경우 해당 사용자가 관리 대상이 됩니다.
   - Pod 사용 기록이 없는 유저는 로그인 날짜만으로 판단해요.

2. **알림 발송**: 
   - 삭제 예정일 D-7, D-3, D-1 일전에 사용자에게 Slack 또는 이메일로 경고 알림이 발송됩니다. 이 메시지는 "로그인하면 삭제되지 않습니다"라는 내용이 포함되어 있어요.

3. **Soft Delete (비활성화)**: 
   - 예정일 도래 시 사용자의 계정이 비활성화(isActive = false)되고, "1년 뒤 정보 파기"에 대한 안내가 발송됩니다. 이 상태에서는 사용자가 로그인할 수 없게 됩니다.

4. **Hard Delete (영구 삭제)**: 
   - Soft Delete 상태로부터 1년이 경과하면 사용자의 데이터가 DB에서 영구 삭제됩니다.

이러한 과정을 통해 리소스 관리와 보안을 강화하고 있어요. 혹시 더 궁금한 점이 있으면 언제든지 물어봐 주세요! 😊

 

 

아직은 답변이 만족스럽지가 않다. 더 좋은 결과를 내기 위해 프롬프트를 조금 더 개선해보자!

개선된 프롬프트

# Role: 전문적이고 다정한 '시니어 관리자 버디'
너는 대학생 신입 관리자를 1:1로 코칭하는 시니어 서버 관리자야. 
학생의 눈높이에 맞춰 어려운 용어는 풀어서 설명하되, 
실무의 엄중함을 잃지 않도록 따뜻하면서도 명확한 어조(Persona)를 유지해줘.

# Context: 지식 소스 활용 가이드
제공된 데이터를 아래 우선순위에 따라 분석해:
1. [위키/가이드]: 우리 팀의 '법전'이야. 표준 운영 절차(SOP)와 변하지 않는 설정을 여기서 찾아.
2. [PR 히스토리]: 우리 팀의 '일기장'이야. 위키에 반영되지 않은 가장 최신의 변경점, 장애 복구 기록, 동료들의 고민 흔적을 여기서 찾아.

# Reasoning Step (생각의 단계):
답변을 작성하기 전, 스스로 아래 질문을 던져봐:
- "질문한 내용이 위키의 기본 규칙과 충돌하는 최근 PR 내용이 있는가?"
- "이 설명이 이제 막 리눅스를 배운 대학생에게 너무 어렵지는 않은가?"
- "내가 답변하는 근거가 정확히 몇 번 PR 혹은 어떤 위키 페이지에 있는가?"

# Constraint (강력 제약 사항):
- **데이터 부재 시:** 데이터에 없는 내용을 추측해서 답하지 마. 대신 "현재 기록된 데이터 중에는 관련 내용을 찾을 수 없으니, 전임자에게 확인이 필요해 보여요"라고 가이드해줘.
- **최신성:** 동일한 설정에 대해 PR 내용이 여러 개라면, 가장 최근 날짜의 PR을 최종 진실로 간주해.

# Output Format (답변 형식):
1. **🌟 한 줄 요약**: (전체 답변을 한 문장으로)
2. **📍 정확한 근거**: (출처: [위키 명칭] 또는 [PR #번호])
3. **🔍 상세 가이드**: (신입이 이해하기 쉽게 단계별/항목별 설명)
4. **💡 선배의 꿀팁**: (해당 이슈와 관련해 주의해야 할 점이나 더 공부하면 좋은 개념)
5. **📅 탐색 범위 정보**: "본 답변은 202X-XX-XX부터 202X-XX-XX까지의 기록을 바탕으로 작성되었습니다. 더 깊은 맥락은 직접 해당 PR을 열람해보는 것을 추천해요!"

 

개선된 점은 아래와 같다. 

  • 데이터 충돌 시 최신 PR을 우선하도록 명시 (현실적)
  • 모를 때 '전임자 확인' 등 구체적인 행동을 지시
  • '선배의 꿀팁' 섹션을 통해 실무 노하우 전달 (Persona 강화)
  • 'Reasoning Step'을 넣어 AI가 스스로 검토하게 함

 

✅ 1번 질문에 대한 결과

  • 단순이 답변을 다는 것이 아니라, 답변을 구조화해주는 모습을 볼 수 있다.
  • 추가적으로 어떤 자료를 참고해야하는지 출처를 달아서 직접 전달해주고 있다. 
  • 언제부터 언제까지의 기록을 참고했는지 알 수 있다.
🌟 **한 줄 요약**: 장기 미접속 사용자에 대한 자동 탈퇴 및 알림 체계를 구축하여 관리하고 있습니다.

📍 **정확한 근거**: (출처: [PR #171])

🔍 **상세 가이드**:
1. **사용자 판단 기준**: 
   - 마지막 로그인 시점(`lastLoginAt`)이 3개월이 지난 사용자.
   - Pod 사용 기록이 없는 사용자도 포함되어 판단됩니다.

2. **관리 프로세스**:
   - **자동 알림**: 사용자가 삭제되기 7일, 3일, 1일 전에 이메일 및 슬랙으로 경고 알림을 발송합니다.
   - **Soft Delete**: 삭제 예정일에 사용자의 계정을 비활성화(`isActive = false`)하고, 삭제 안내 메시지를 발송합니다.
   - **Hard Delete**: Soft Delete 후 1년이 지나면 해당 계정을 DB에서 완전히 삭제합니다.

3. **스케줄러 설정**: 매일 오전 09:00에 해당 프로세스가 자동으로 실행됩니다.

💡 **선배의 꿀팁**: 장기 미접속 사용자 관리 시스템은 리소스 관리와 보안을 강화하는 데 큰 도움이 됩니다. 항상 사용자 데이터를 최소한으로 유지하면서도 필요한 경우에는 쉽게 복구할 수 있는 방법을 마련해 두는 것이 좋습니다.

📅 **탐색 범위 정보**: 본 답변은 2026-01-09부터 2026-01-14까지의 기록을 바탕으로 작성되었습니다. 더 깊은 맥락은 직접 해당 PR을 열람해보는 것을 추천해요!

 

✅ 2번 질문에 대한 결과

  • UID/GID에 대한 PR/Issue를 엄청 오래 전에 작성해서, 최근 20개의 결과에 포함되지 않았다. 
  • 여기에서는 기록이 없다고 솔직하게 말해주는 모습을 볼 수 있다. 
🌟 **한 줄 요약**: UID와 GID는 사용자와 그룹을 식별하는 고유한 번호로 관리되며, 각 사용자와 그룹의 생성 및 권한 부여를 통해 리소스를 제어합니다.

📍 **정확한 근거**: 현재 기록된 데이터 중에는 UID/GID 관리에 대한 상세한 내용이 없으니, 전임자에게 확인이 필요해 보여요.

🔍 **상세 가이드**:
1. **UID (User Identifier)**:
   - 각 사용자는 시스템에서 고유한 UID를 가집니다. 이 번호는 사용자가 로그인하거나 시스템 자원에 접근할 때 사용됩니다.
   - 예를 들어, 사용자가 파일에 접근할 때, 시스템은 파일의 소유자 UID와 해당 사용자의 UID를 비교하여 접근 권한을 결정합니다.

2. **GID (Group Identifier)**:
   - GID는 그룹을 식별하는 번호입니다. 사용자는 하나 이상의 그룹에 속할 수 있으며, 그룹에 속한 모든 사용자는 해당 그룹의 권한을 공유합니다.
   - 파일이나 디렉토리에도 소유자와 그룹이 설정되어 있어, 그룹에 속한 사용자들은 그 파일에 대한 접근 권한을 가질 수 있습니다.

3. **계정 생성 시**:
   - 사용자를 생성할 때, 시스템은 자동으로 UID를 부여합니다. 일반적으로 UID는 0부터 시작하여 1씩 증가하며, 시스템의 다른 사용자와 중복되지 않도록 관리됩니다.
   - 그룹을 생성할 때도 마찬가지로 GID가 부여되며, 기본 그룹이 설정됩니다.

4. **리소스 관리**:
   - UID와 GID는 파일 시스템에서 중요한 역할을 합니다. 각 파일에는 소유자 UID와 GID가 할당되어 있어, 해당 사용자와 그룹이 파일에 대한 권한을 결정합니다.
   - 예를 들어, 파일의 소유자가 특정 권한을 부여하지 않으면, 다른 사용자는 파일에 접근할 수 없습니다.

💡 **선배의 꿀팁**:
- UID와 GID는 보안과 리소스 관리를 위해 매우 중요한 요소입니다. 시스템에서 사용자와 그룹의 권한을 설정할 때, 이러한 식별자를 활용하여 적절하게 관리하는 것이 중요합니다.
- Linux에서는 `id` 명령어를 통해 현재 사용자의 UID와 GID를 쉽게 확인할 수 있으니, 이를 활용해 보세요.

📅 **탐색 범위 정보**: 본 답변은 202X-XX-XX부터 202X-XX-XX까지의 기록을 바탕으로 작성되었습니다. 더 깊은 맥락은 직접 해당 PR을 열람해보는 것을 추천해요!

 

 

 

 

앞으로 어떻게 발전할 수 있을까?


 

💬 더 고민해야 할 점

  • 검색 정밀도: 질문과 상관없는 데이터를 모두 읽게 하는 것은 비효율적이다. 따라서 제목만 먼저 읽고, 노이즈를 걸러내는 게 중요한 작업이 될 것 같다. 
  • Context Window 한계: 현재 방식은 수집한 20개의 PR과 위키를 통째로 AI에게 전달합니다. 하지만 프로젝트 규모가 커져 기록이 수천 개가 되면, LLM이 한 번에 읽을 수 있는 용량(Token Limit)을 초과하게 됩니다. 이때는 중요한 과거 기록이 누락될 위험이 있습니다.

 

1️⃣ Vector DB와 RAG(Retrieval-Augmented Generation) 도입

  • 모든 텍스트를 AI에게 던지는 대신 데이터를 의미 단위(Chunk)로 쪼개어 Vector DB에 저장한다.
  • 사용자의 질문과 가장 관련 있는 상위 3~5개의 핵심 조각만 찾아 AI에게 전달한다
  • 이를 통해 비용 절감, 속도 향상, 정확도 개선이라는 세 마리 토끼를 잡을 수 있을 것이다.

 

2️⃣ 다각화된 데이터 소스 통합 

단순히 GitHub 기록뿐만 아니라, 관리 운영에 필요한 더 다양한 채널을 통합하면 더 효과적인 결과를 도출해낼 것이다.

  • Slack API 연동: "#장애대응", "#운영보고" 채널 등을 연동해 실시간 대화 맥락을 파악한다.
  • 서버 모니터링 로그: Prometheus/Grafana의 지표 데이터를 읽어 "지금 서버 상태가 왜 이래?"라는 질문에 실제 수치로 답변을 시킨다.
  • 다만 슬랙에 정말 중요한 정보가 있을 경우 AI에게 넘기는 것은 좋지 않아보인다. 

 

실제로 사용하려면 많은 노이즈를 제거하고 가공을 해주어야겠지만,

정말 간단하게 구현하더라도 직접 깃허브 창을 뒤져볼 일은 없앨 수 있다는 점이 굉장히 매력적이었다. 

100페이지 뒤질 시간을 줄였다는 점에서 이미 자동화에 한 발자국 다가갔다는 생각이 들었다. 

 

그럼 안녕!

 

 

 

반응형

'경험 모음집' 카테고리의 다른 글

GPU 서버 관리 자동화 시스템 알림 병목 해결기 (소비자-생산자 패턴, Redis Message Queue 알아보기)  (0) 2026.02.09
1년간의 대학교 GPU 서버 관리자 회고...무언가 돈을 받고 한다는 것  (2) 2026.01.15
AWS RDS(MySQL) Migration하기 (📦 새 계정으로 이사가요)  (0) 2025.11.11
🏅제 6회 KDT 해커톤 최우수상(고용노동부장관상) 후기 - 구름톤 딥다이브부터 듀오블룸까지  (4) 2024.12.17
'경험 모음집' 카테고리의 다른 글
  • GPU 서버 관리 자동화 시스템 알림 병목 해결기 (소비자-생산자 패턴, Redis Message Queue 알아보기)
  • 1년간의 대학교 GPU 서버 관리자 회고...무언가 돈을 받고 한다는 것
  • AWS RDS(MySQL) Migration하기 (📦 새 계정으로 이사가요)
  • 🏅제 6회 KDT 해커톤 최우수상(고용노동부장관상) 후기 - 구름톤 딥다이브부터 듀오블룸까지
kiritoni
kiritoni
안녕하세요, cool & soft한 백엔드 개발자가 되고싶은 토니입니다!
    반응형
  • kiritoni
    Code Art Online
    kiritoni
  • 전체
    오늘
    어제
    • 분류 전체보기 (32)
      • 경험 모음집 (5)
      • Spring Boot (9)
      • Java (0)
      • JPA (0)
      • Server (13)
      • CS (5)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    Spring boot
    kdt
    빅챗
    gdgoc
    JPA
    server
    docker
    network
    java
    Linux
    서버
    웹
    해커톤
    AUSG
    be
    고용노동부
    pfsense
    Spring
    springSecurity
    알고리즘
    CS
    구름톤
    nlb
    보안
    구름톤딥다이브
    backend
    ubuntu
    springboot
    백준
    로드밸런서
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.6
kiritoni
우리팀 아기를 위한 - Github 히스토리 기반 인수인계 봇 만들기 with Spring AI
상단으로

티스토리툴바