LLM

[PR Agent] 1. 환경설정 및 테스트

코줍 2025. 5. 2. 16:24

https://qodo-merge-docs.qodo.ai/usage-guide/

 

Usage guide - Qodo Merge (and open-source PR-Agent)

None

qodo-merge-docs.qodo.ai

PR Agent 란 

PR-Agent는 Pull Request를 보다 효율적으로 리뷰하고 처리할 수 있도록 도와주는 오픈소스 도구로, 이번 OSSCA에서 기여할 프로젝트이다.
오픈소스 기여의 초석을 다지기 위해, 해당 프로젝트의 환경 설정 과정을 먼저 살펴보았다.

 

Run from source

https://qodo-merge-docs.qodo.ai/installation/locally/#run-from-source

1. pr-agent 오픈소스 레포 클론

git clone https://github.com/OSSCA-2025-Egg-Benedict/pr-agent.git

2. 가상환경 설정

 

패키지 설치 전 가상환경을 만드는 이유는?
  • 프로젝트마다 필요한 패키지 버전이 달라 발생할 수 있는 충돌을 사전에 방지하기 위함이다.
    • 예를 들어, pydantic 패키지가 A 프로젝트에서는 2.10.6 버전인데, B 프로젝트는 2.11.4버전을 쓰다면, 전역으로 패키지 설치할 경우 버전 충돌이 발생할 수 있다. 이때, 가상환경 내에서 작업할 경우, 독립된 패키지 공간을 만들어 이러한 충돌을 방지할 수 있다.
  • 의존성 관리를 확실하게 하기 위함이다.

3. 로컬 패키지 개발모드 설치

pip install -e .
  • -e : editable 모드로 패키지 설치
일반적인 패키지 설치와 다른 점은?
  • pip install . 로 설치를 하면, 파이썬 코드를 zip 처럼 포장해서
  • python이 사용하는 디렉토리 ( site-pacakages/ )에 복사해서 코드를 넣는다.
  • 여기에 복사된 코드를 실행하게 된다. 
    • 그래서 원본코드를 수정해도 site-packages에 있는 복사본에는 변화가 없기 때문에 수정한 내용이 반영되지 않는다.

반면에, editable 모드로 설치하게 되면, .egg-link 파일만 만들어서 원본 코드 디렉토리를 가르키게 하여 더이상 복사본이 아닌 실시간으로 내가 수정한 소스코드 파일의 위치를 참조해서 반영하게 된다. ( like 심볼릭 링크

 

4. 보안 설정 파일 .secrets.toml 준비

1. 보안설정파일 준비

cp pr_agent/settings/.secrets_template.toml pr_agent/settings/.secrets.toml
chmod 600 pr_agent/settings/.secrets.toml
# Edit .secrets.toml file

 

cp : 파일 복사 명령어

  • pr_agent/settings/.secrets_template.toml ( 템플릿 파일 )
  • pr_agent/settings/.secrets.toml ( 비밀키 설정 파일 )

chmod : 파일 권한설정 명령어

600 : 소유자만 읽기/쓰기 가능

  • 6 = 읽기(4) + 쓰기(2) = rw-
  • 0 = 그룹 권한 없음 = --
  • 0 = 기타 사용자 권한 없음 = --
  • pr_agent/settings/.secrets.toml
왜 .secret.toml 파일에 chmod 600으로 권한 설정을 하는가?

secret.toml 파일에는 Github personal access Token이나 OpenAI API Key 같은 민감한 정보를 포함하고 있다.

이런 정보가 노출되지 않으면서, 소유자에게만 권한을 부여함으로써 보안 이슈에 대비할 수 있게된다.


2. Gemini API key, Github Token 설정

  1. 깃헙 토큰 발급
    • settings > Developer settings > personal access token > generate new token > Resource owner로 Egg benedict Organization 선택 > 생성된 key 반드시 저장
  2. Gemini API key 발급 
  3. pr-agent/settings/.secrets.toml 파일에 깃헙토큰, Gemini API key 작성
# pr-agent/settings/.secrets.toml

[github]
# ---- Set the following only for deployment type == "user"
user_token = "..."  # A GitHub personal access token with 'repo' scope.
deployment_type = "user" #set to user by default

[google_ai_studio]
gemini_api_key = "..." # the google AI Studio API key

 

4. configuration.toml 파일에서 OpenAI의 LLM 모델 -> Gemini LLM모델로 변경

[config] # in configuration.toml
# models
model="gemini/gemini-1.5-flash"
fallback_models=["gemini/gemini-1.5-flash"]
gemini_api_key = "${GEMINI_API_KEY}"

 

5. 테스트 용 PR 날리기

클론한 pr-agent 소스코드에 테스트용 수정을 한 뒤 PR 날려보았다.

https://github.com/OSSCA-2025-Egg-Benedict/pr-agent/pull/1

 

Enhancements to PR Description Generation and Error Handling by jihan-chillin · Pull Request #1 · OSSCA-2025-Egg-Benedict/pr-

User description 📌 작업 내용 f-string으로 인한 포맷팅 에러 수정 테스트용 PR Type Enhancement Description Improved code formatting. Enhanced error handling. Optimized large PR handling. Added support for m...

github.com

 

6. CLI 테스트

python3 -m pr_agent.cli --pr_url https://github.com/OSSCA-2025-Egg-Benedict/pr-agent/pull/1 describe

 


트러블 슈팅 : 403 “Resource not accessible by personal access token”

 

오류 원본 구문

더보기

2025-05-01 15:34:14.559 | INFO | pr_agent.git_providers.utils:apply_repo_settings:46 - Applying repo settings: {'PR_REVIEWER': {'enable_review_labels_effort': True, 'enable_auto_approval': True}} 2025-05-01 15:34:16.441 | INFO | pr_agent.git_providers.git_provider:get_user_description:169 - Existing description was generated by the pr-agent, but it doesn't contain a user description 2025-05-01 15:34:18.106 | INFO | pr_agent.git_providers.git_provider:get_user_description:169 - Existing description was generated by the pr-agent, but it doesn't contain a user description 2025-05-01 15:34:18.117 | INFO | pr_agent.tools.pr_description:run:95 - Generating a PR description for pr_id: ossca-2025/pr-agent/2 Traceback (most recent call last): File "/Users/kimjihan77/Project/pr-agent/pr_agent/tools/pr_description.py", line 100, in run self.git_provider.publish_comment("Preparing PR description...", is_temporary=True) File "/Users/kimjihan77/Project/pr-agent/pr_agent/git_providers/github_provider.py", line 385, in publish_comment response = self.pr.create_issue_comment(pr_comment) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/kimjihan77/Project/pr-agent/myenv/lib/python3.12/site-packages/github/PullRequest.py", line 517, in create_issue_comment headers, data = self._requester.requestJsonAndCheck( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/kimjihan77/Project/pr-agent/myenv/lib/python3.12/site-packages/github/Requester.py", line 442, in requestJsonAndCheck return self.__check( ^^^^^^^^^^^^^ File "/Users/kimjihan77/Project/pr-agent/myenv/lib/python3.12/site-packages/github/Requester.py", line 487, in __check raise self.__createException(status, responseHeaders, data) github.GithubException.GithubException: 403 {"message": "Resource not accessible by personal access token", "documentation_url": "https://docs.github.com/rest/issues/comments#create-an-issue-comment", "status": "403"} During handling of the above exception, another exception occurred: Traceback (most recent call last): File "", line 198, in _run_module_as_main File "", line 88, in _run_code File "/Users/kimjihan77/Project/pr-agent/pr_agent/cli.py", line 99, in run() File "/Users/kimjihan77/Project/pr-agent/pr_agent/cli.py", line 93, in run result = asyncio.run(inner()) ^^^^^^^^^^^^^^^^^^^^ File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py", line 195, in run return runner.run(main) ^^^^^^^^^^^^^^^^ File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/runners.py", line 118, in run return self._loop.run_until_complete(task) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Library/Frameworks/Python.framework/Versions/3.12/lib/python3.12/asyncio/base_events.py", line 691, in run_until_complete return future.result() ^^^^^^^^^^^^^^^ File "/Users/kimjihan77/Project/pr-agent/pr_agent/cli.py", line 84, in inner result = await asyncio.create_task(PRAgent().handle_request(args.pr_url, [command] + args.rest)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "/Users/kimjihan77/Project/pr-agent/pr_agent/agent/pr_agent.py", line 108, in handle_request await command2class[action](pr_url, ai_handler=self.ai_handler, args=args).run() File "/Users/kimjihan77/Project/pr-agent/pr_agent/tools/pr_description.py", line 195, in run get_logger().error(f"Error generating PR description {self.pr_id}: {e}", File "/Users/kimjihan77/Project/pr-agent/myenv/lib/python3.12/site-packages/loguru/_logger.py", line 2056, in error __self._log("ERROR", False, __self._options, __message, args, kwargs) File "/Users/kimjihan77/Project/pr-agent/myenv/lib/python3.12/site-packages/loguru/_logger.py", line 2021, in _log log_record["message"] = message.format(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ KeyError: '"message"'

pr-agent에 token을 설정했다 하더라도, 일부권한이 부여되지 않아서 발생하는 오류이다.

이럴 땐 아래와 같은 방법으로 기능권한을 부여해주면 된다.

 

settings > Developer settings > personal access token > 아까 생성한 토큰 클릭 > Edit 버튼 > Repository access > Permission 메뉴에서 Contents, Issues, Pull requests 기능에 Read/Write 권한 부여한다.

 

권한부여 후, 다시 CLI 실행해보면 description이 자동으로 생성된 것을 확인할 수 있다.

'LLM' 카테고리의 다른 글

[ PR Agent ] CLI 방식 동작구조  (0) 2025.05.08