PR-Agent Improve 기능 분석

Tasker_Jang·2025년 4월 29일
0

PR Agent의 Improve 기능은 AI를 활용해 풀 리퀘스트(PR)의 코드를 분석하고 개선 방안을 제시해주는 도구입니다.

Improve 기능이 하는 일

/improve 명령어를 사용하면 AI가 PR 코드를 꼼꼼히 살펴보고 이런 개선점을 찾아줍니다:

  • 🐞 잠재적 버그 해결: "이 조건문에는 null 체크가 필요합니다"
  • 🔐 보안 개선: "이 입력 값은 검증 후 사용해야 안전합니다"
  • 🚀 성능 최적화: "이 반복문은 O(n²)에서 O(n)으로 개선할 수 있습니다"
  • 📝 가독성 향상: "이 변수명을 더 명확하게 바꾸면 코드 이해가 쉬워집니다"
  • 🧰 모범 사례 적용: "이 패턴을 사용하면 더 안정적인 코드가 됩니다"
  • 💻 직접 적용 가능한 코드: "이렇게 코드를 바꿔보세요" (GitHub에서 바로 적용 가능)

내부 동작 원리 살펴보기

Improve 기능의 핵심은 pr_agent/tools/pr_code_suggestions.py 파일에 있는 PRCodeSuggestions 클래스입니다. 이 클래스가 어떻게 작동하는지 살펴보겠습니다:

class PRCodeSuggestions:
    def __init__(self, pr_url: str, ...):
        # PR 정보와 설정 초기화
        
    async def run(self):
        # 1. PR 정보 수집 
        # 2. AI 모델로 개선 제안 생성
        # 3. 제안에 대한 자체 평가
        # 4. 결과 처리 및 댓글 게시

전체 과정은 이렇게 진행됩니다:

  1. 정보 수집: PR의 모든 변경사항(파일, diff, 언어 등)을 분석합니다
  2. 청크 분할: 큰 PR은 여러 청크로 나눠서 효율적으로 처리합니다
  3. AI 제안 생성: 각 청크마다 AI가 코드 개선 제안을 생성합니다
  4. 자체 평가: 만들어진 제안의 품질과 중요도를 자체 평가합니다
  5. 결과 정리: 중요도에 따라 제안을 정렬 및 구조화합니다
  6. 제안 게시: 깔끔한 테이블이나 인라인 코드 제안으로 PR에 게시합니다

Improve 설정 분석

configuration.toml 파일에서 설정을 조정해 원하는 대로 개선 기능을 커스터마이징할 수 있습니다:

[pr_code_suggestions]
max_context_tokens=24000                # 최대 컨텍스트 토큰 수
commitable_code_suggestions = false     # GitHub에서 바로 적용 가능한 형식으로 제안할지
focus_only_on_problems=true             # 심각한 문제에만 집중할지
suggestions_score_threshold=0           # 제안 점수 기준값 (0-10)
num_code_suggestions_per_chunk=4        # 청크당 최대 제안 수
parallel_calls = true                   # 병렬 처리 사용
new_score_mechanism=true                # 새 점수 체계 사용 (High/Medium/Low)

# 셀프 리뷰 설정
demand_code_suggestions_self_review=false  # 작성자 셀프 리뷰 체크박스 추가
code_suggestions_self_review_text= "..."   # 체크박스 텍스트
approve_pr_on_self_review=false            # 셀프 리뷰 후 자동 승인

특히 focus_only_on_problems 옵션으로 심각한 문제만 보거나, 코드 품질 전반에 관한 제안까지 모두 받을 수 있습니다.

프롬프트

Improve 기능의 시스템 프롬프트를 살펴보면:

당신은 PR-Reviewer, PR 코드 분석과 제안을 전문으로 하는 AI입니다.
코드 diff를 검토하고, 새로 추가된 코드('+' 접두사가 있는 줄)에 집중해서
간결하고 실행 가능한 제안을 제공해 주세요.

특히 다음을 중점적으로 확인해 주세요:
- 잠재적 버그와 문제
- 보안 취약점
- 코드 품질과 성능 개선점
...

사용자 프롬프트에는 실제 PR 정보가 포함됩니다:

PR 정보:
제목: '새로운 로그인 기능 추가'

PR Diff:
======
## File: 'src/auth/login.js'
@@ ... @@ function login():
__new hunk__
11  const validateUser = (user) => {
12  return db.findUser(user);
13 +const processLogin = (username, password) => {
14 +  const user = { name: username, pwd: password };
15 +  return validateUser(user);
16 +}
...
======

이 두 프롬프트를 받은 AI는 코드를 분석하고 실용적인 개선 방안을 제안해줍니다.

대규모 PR 처리

큰 규모의 PR을 처리할 때 PR Agent는 몇 가지 전략을 사용합니다:

1. 코드 청크 분할

self.patches_diff_list = get_pr_multi_diffs(
    self.git_provider,
    self.token_handler,
    model,
    max_calls=get_settings().pr_code_suggestions.max_number_of_calls
)

큰 PR을 여러 조각으로 나눠서 각 부분을 따로 분석합니다.

2. 병렬 처리

if get_settings().pr_code_suggestions.parallel_calls:
    prediction_list = await asyncio.gather(
        *[self._get_prediction(model, patches_diff, patches_diff_no_line_numbers) 
          for patches_diff, patches_diff_no_line_numbers in zip(...)]
    )

여러 코드 청크를 동시에 처리해서 속도를 높입니다.

3. 중요도 기반 필터링

score_threshold = max(1, int(get_settings().pr_code_suggestions.suggestions_score_threshold))
for prediction in predictions["code_suggestions"]:
    score = int(prediction.get("score", 1))
    if score >= score_threshold:
        data["code_suggestions"].append(prediction)

중요도 점수를 기준으로 필터링해서 가장 중요한 제안에 집중할 수 있습니다.

AI가 제안하는 코드

AI의 코드 개선 방안은 YAML 구조로 만들어집니다:

code_suggestions:
- relevant_file: "src/auth/login.js"
  language: "javascript"
  existing_code: "const processLogin = (username, password) => {\n  const user = { name: username, pwd: password };\n  return validateUser(user);\n}"
  suggestion_content: "비밀번호는 평문으로 저장하거나 전송하면 안 됩니다. 비밀번호를 해싱해서 사용하세요."
  improved_code: "const processLogin = (username, password) => {\n  const hashedPwd = hashPassword(password);\n  const user = { name: username, pwd: hashedPwd };\n  return validateUser(user);\n}"
  one_sentence_summary: "비밀번호 해싱 추가"
  label: "security"
  score: 9
  score_why: "보안 취약점으로, 사용자 비밀번호가 노출될 위험이 있습니다."

이 제안은 두 가지 방식으로 보여질 수 있습니다:

1. 테이블 형식 (기본)

## PR Code Suggestions ✨

<table>
  <thead><tr><td><strong>Category</strong></td><td><strong>Suggestion</strong></td><td><strong>Impact</strong></td></tr>
  <tbody>
    <tr>
      <td>Security</td>
      <td>
        <details><summary>비밀번호 해싱 추가</summary>
        
        **비밀번호는 평문으로 저장하거나 전송하면 안 됩니다. 비밀번호를 해싱해서 사용하세요.**
        
        [src/auth/login.js [13-16]](링크)
        
        ```diff
        - const processLogin = (username, password) => {
        -   const user = { name: username, pwd: password };
        -   return validateUser(user);
        - }
        + const processLogin = (username, password) => {
        +   const hashedPwd = hashPassword(password);
        +   const user = { name: username, pwd: hashedPwd };
        +   return validateUser(user);
        + }
        ```
        </details>
      </td>
      <td align=center>High</td>
    </tr>
  </tbody>
</table>

2. 인라인 코드 제안 (바로 적용 가능한 형태)

**Suggestion:** 비밀번호는 평문으로 저장하거나 전송하면 안 됩니다. 비밀번호를 해싱해서 사용하세요. [Security, importance: 9]
```suggestion
const processLogin = (username, password) => {
  const hashedPwd = hashPassword(password);
  const user = { name: username, pwd: hashedPwd };
  return validateUser(user);
}

특별한 기능들

자체 평가 메커니즘

response_reflect = await self.self_reflect_on_suggestions(
    data["code_suggestions"],
    patches_diff, 
    model=model_reflect_with_reasoning
)

AI가 만든 제안을 다시 한번 검토해서 품질과 중요도를 평가합니다. 이렇게 하면 제안의 정확성과 유용성이 더 높아집니다.

코드 위치 자동 감지

for suggestion in data_above_threshold['code_suggestions']:
    relevant_file = suggestion['relevant_file'].strip()
    relevant_lines_start = int(suggestion['relevant_lines_start'])
    relevant_lines_end = int(suggestion['relevant_lines_end'])

코드를 변경해야 할 정확한 위치(파일과 라인 번호)를 자동으로 찾아줍니다.

코드 들여쓰기 자동 조정

def dedent_code(self, relevant_file, relevant_lines_start, new_code_snippet):
    # 원본 코드의 들여쓰기를 유지하도록 새 코드를

제안된 코드가 원본 코드의 들여쓰기 스타일을 그대로 유지하도록 자동으로 맞춰줍니다.

profile
ML Engineer 🧠 | AI 모델 개발과 최적화 경험을 기록하며 성장하는 개발자 🚀 The light that burns twice as bright burns half as long ✨

0개의 댓글