iT邦幫忙

2024 iThome 鐵人賽

DAY 13
0
DevOps

將 AI Code Review 整進 CICD系列 第 13

將 AI Code Review 整進 CICD Day13

  • 分享至 

  • xImage
  •  

從 get_prediction 我們可以查到他試著調用 system_prompt 跟 user_prompt 並喂給 ai_handler.chat_completion 進行AI 預測。

    async def _get_prediction(self, model: str) -> str:
        """
        Generate an AI prediction for the pull request review.

        Args:
            model: A string representing the AI model to be used for the prediction.

        Returns:
            A string representing the AI prediction for the pull request review.
        """
        variables = copy.deepcopy(self.vars)
        variables["diff"] = self.patches_diff  # update diff

        environment = Environment(undefined=StrictUndefined)
        system_prompt = environment.from_string(get_settings().pr_review_prompt.system).render(variables)
        user_prompt = environment.from_string(get_settings().pr_review_prompt.user).render(variables)

        response, finish_reason = await self.ai_handler.chat_completion(
            model=model,
            temperature=get_settings().config.temperature,
            system=system_prompt,
            user=user_prompt
        )

        return response

而 system_prompt 跟 user_prompt 來自於 environment = Environment(undefined=StrictUndefined)。而 Environment 來自於外部的引入。這邊可以稍稍介紹 jinja2 Environment 的用途,他的設定 undefined=StrictUndefined 會在 Environment 是空值時拋出異常,而不是空值。所以這邊只是 environment 物件的引用。也算是多學會了對於環境的設定可以用 物件去包

from jinja2 import Environment, StrictUndefined

而實際 environment 的值來自於 get_settings(),可以得知get_setting 會從 starlette_contextcontext 獲取設定。如果沒取到,就使用global_settings

        system_prompt = environment.from_string(get_settings().pr_review_prompt.system).render(variables)
        user_prompt = environment.from_string(get_settings().pr_review_prompt.user).render(variables)

def get_settings():
    """
    Retrieves the current settings.

    This function attempts to fetch the settings from the starlette_context's context object. If it fails,
    it defaults to the global settings defined outside of this function.

    Returns:
        Dynaconf: The current settings object, either from the context or the global default.
    """
    try:
        return context["settings"]
    except Exception:
        return global_settings

我們嘗試搜尋 pr_review_prompt 找到 pr-agent/pr_agent/settings/pr_reviewer_prompts.toml

的檔案,裡面是一連串使用 Jinja2 模板的語法(呼應到前面的 Jinja2 的 Environment),

system="""You are PR-Reviewer, a language model designed to review a Git Pull Request (PR).
{%- if num_code_suggestions > 0 %}
Your task is to provide constructive and concise feedback for the PR, and also provide meaningful code suggestions.
{%- else %}
Your task is to provide constructive and concise feedback for the PR.
{%- endif %}
The review should focus on new code added in the PR diff (lines starting with '+')

render 的 variables 則代表 titlebranchdescriptiondiff

在 pr_review_prompt.system 的部分,他先定義了 AI 的角色:專門用於 Git Pull Request 審查的模型

You are PR-Reviewer, a language model designed to review a Git Pull Request (PR).

並對此角色進行任務定義,這邊會根據 num_code_suggestions 進行調整,有只給 feedback or feedback + code suggestions

{%- if num_code_suggestions > 0 %}
Your task is to provide constructive and concise feedback for the PR, and also provide meaningful code suggestions.
{%- else %}
Your task is to provide constructive and concise feedback for the PR.
{%- endif %}

想辦法讓 AI 更清楚地理解這份檔案

The format we will use to present the PR code diff:
======
## file: 'src/file1.py'

@@ ... @@ def func1():
__new hunk__
12  code line1 that remained unchanged in the PR
13 +new hunk code line2 added in the PR
14  code line3 that remained unchanged in the PR
__old hunk__
 code line1 that remained unchanged in the PR
-old hunk code line2 that was removed in the PR
 code line3 that remained unchanged in the PR

@@ ... @@ def func2():
__new hunk__
...
__old hunk__
...


## file: 'src/file2.py'
...
======
- In this format, we separated each hunk of diff code to '__new hunk__' and '__old hunk__' sections. The '__new hunk__' section contains the new code of the chunk, and the '__old hunk__' section contains the old code, that was removed.
- We also added line numbers for the '__new hunk__' sections, to help you refer to the code lines in your suggestions. These line numbers are not part of the actual code, and are only used for reference.
- Code lines are prefixed with symbols ('+', '-', ' '). The '+' symbol indicates new code added in the PR, the '-' symbol indicates code removed in the PR, and the ' ' symbol indicates unchanged code. \
The review should focus on new code added in the PR diff (lines starting with '+')
- When quoting variables or names from the code, use backticks (`) instead of single quote (').

提醒聚焦在有變更的地方

The review should focus on new code added in the PR diff (lines starting with '+')

用戶如果有想自己新增的提示,也可以補充在這

{%- if extra_instructions %}
Extra instructions from the user:
======
{{ extra_instructions }}
======
{% endif %}

研究到這邊,算是比較理解,啊,原來人家是這樣玩 AI 並把它做成工具。也比較清楚之後自己想玩的地方,之後繼續花時間拆解其他有趣部分


上一篇
將 AI Code Review 整進 CICD Day11
下一篇
將 AI Code Review 整進 CICD Day14
系列文
將 AI Code Review 整進 CICD24
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言