天天看點

大模型效能工具之智能CommitMessage

作者:閃念基因

一. 背景

随着大型語言模型的迅猛增長,各種模型在各個領域的應用如雨後春筍般迅速湧現。在研發全流程的效能方面,也出現了一系列貫穿全流程的提效和品質工具,比如針對成本較高的Oncall,首先出現了高品質的RAG助手;在開發階段的Copilot、Comate、Tabnine等輔助程式設計應工具;在測試階段,也有缺陷檢查、安全合規檢查、智能Code Review等工具;哪怕在傳遞階段,也有替代人工的自動化Agent...

當使用git commit送出代碼時,需要寫繁雜的CommitMessage,有時候寫了後卻不符合送出規範被hook,有時候還被CodeReview的同學點評寫不到點上...智能CommitMessage就是這樣一個小助手,幫你按照送出規範自動生成符合規範的CommitMessage。

以百度APP 的送出規範為例,規範包括送出類别、産品版本、需求卡片、變更摘要等,其中類别又包括:功能、更新、優化、提測、上車、Merge、FixBug等,手動抒寫較為複雜。

按照CommitMessage的組合标準,可以分為兩個部分:規範格式 + 變更摘要:

大模型效能工具之智能CommitMessage

CommitMessage組成部分

  • 普通摘要類:送出規範格式 + 變更摘要
  • FixBug類:送出規範格式 + 變更摘要(包括bug原因、影響、修複方式等)

其中運用大模型能力生成變更摘要部分,而送出規範格式及其他标簽由個性化插件定制,即可對不同業務線/産品線可定制符合送出規範的CommitMessage。

智能CommitMessage的最終使用效果如下:

大模型效能工具之智能CommitMessage

git aicommit 用法示例

下面就以智能CommitMessage為例,介紹下大模型效能工具開發流程,主要包括:

  • 簡單的功能設計
  • 應用名額和模型評估名額
  • 大模型資料處理過程
  • 模型性能優化的幾種方式

二.功能與設計

使用者入口一:git aicommit

Git是高效便捷的版本控制系統,雖然百度APP移動端已經多倉庫化,随着元件化程序的完善,有至少有一半的需求不需要跨倉庫送出而使用Git。

使用者入口二:mgit aicommit

MGit (https://github.com/baidu/m-git)是百度自研的一套開源的、基于Git的多倉庫管理工具,針對多倉庫的應用場景安全地、高效的管理多個Git倉庫,在基礎版本之上增加MGit插件即可擴充或者修改原指令。

對入口的基本要求:

  1. Git/MGit入口的使用不影響原有git/mgit commit功能的使用,隻是能力擴充
  2. 保證Git和MGit的入口分離的同時,保證功能統一,低成本維護

處理方式:抽象實作共用子產品git-aicommit,該子產品由MGit插件和Git alias指令直接調用,開發語言選型ruby,便于 MGit 插件直接調用。

git-aicommit子產品:提取所有送出倉庫中Git暫存區内的變更内容,請求模型服務生成Commit Message。

大模型效能工具之智能CommitMessage
  • MGit/Git入口,即使用者使用入口,對于MGit插件可以參考MGit如何擴充(https://github.com/baidu/m-git);Git Alias按如下配置即可:
# 給 git 添加 Alias:git aicommit
$ git config --global alias.aicommit '!f() { ruby -e '\''require "git-aicommit"; MGit::GitAICommit.run(ARGV);'\'' -- "$@"; }; f'           
  • 個性化插件:送出規範的格式定制,任何不同的送出規範均可定制為獨立的插件,詳細參考下面自定義送出規範章節。
  • 模型服務:接受git-aicommit子產品的請求,調用LLM生成CommitMessage摘要内容,加載對應的個性化插件生成最終的CommitMessage。

三. 評估名額

管理學之父彼得·德魯克說過:“If you can't measure it, you can't manage it.”。

度量名額對于模型選擇、後續Prompt調優以及SFT都至關重要,因為它決定了優化的标準。

生成CommitMessage時,既需要了解變更的代碼,也需要生成對應的摘要、評估影響等,生成式大模型适合此類任務,目前生成式大模型在市面上也百花齊放,經過綜合評估使用成本(包括資料管理、部署運維、性能調優、Prompt和模型評估)、生成品質、安全風險等方面的考慮,我們選擇了百度智能雲千帆平台的ERNIE4(文心4)。

針對此類摘要任務,常用的度量名額有BLEU Score、ROUGE Score、BERT Score、PPL、MSE等,結合生成CommitMessage的任務特性,最終确定模型和産品的核心名額:

  • 模型性能名額:MSE(Mean Squared Error,均方誤差),用于衡量生成的文本序列與參考CommitMessage的文本序列之間的語義相似度;
  • 使用者使用名額:AR(Acceptance Rate,直接采納率),也叫使用者直接滿足度,針對模型服務生成的CommitMessage,使用者直接采納的次數相對于總的使用次數的占比

丨3.1 均方誤差MSE(Mean Squared Error)

參考CommitMessage的文本序列,指高品質的、簡潔的、準确的、标準的CommitMessage,客觀标準是至少包括:為什麼修改(Why)、改了什麼(What)、影響面(可選),主觀标準是人工篩選并提取。

根據定義,計算MSE即計算兩段文本的語義相似度內插補點,簡單的分為如下三個步驟:

  1. 文本Embedding向量化:
  2. 将兩段文本轉換為向量表示。大模型時代Embedding的方式太多太多了,這裡依然直接選用了千帆的Embedding方式。
  3. 向量差異計算:
  4. 計算兩段文本的向量表示間的差異或距離時,我們選擇使用餘弦相似度;盡管歐幾裡得距離和馬氏距離也是常用的方法,但針對CommitMessage這種長度不一緻的向量時,餘弦相似度表現更為準确。
  5. 均方誤差計算:
  6. 将差異或距離平方,然後計算平均值以得到均方誤差。
  7. 其中,xi 和 yi 是兩段文本在第 i 個次元上的表示,n 是次元數量。

本文多次送出兩個概念:

參考CommitMessage:可以是RD生成已送出入庫的,也可以由大模型生成、經過人工标注的保證品質的CommitMessage,作為評估的标準yi

生成CommitMessage:由大模型生成的CommitMessage,評估輸入的判定項xi

丨3.1 直接采納率AR(Adoption Rate)

總的使用次數包括3個結果:

  • 直接采納數 CA
  • 編輯采納數 CE
  • 拒絕數 CR
大模型效能工具之智能CommitMessage

四. 資料處理

大模型應用開發為了更好的性能(包括生成品質、效率、準确度、采納率),資料處理的成本投入較高,通常占據整個應用開發投入的相當大的比例,有時甚至可能超過模型訓練和調優的工作量。總之,有效和高效的資料處理是提升模型性能的關鍵因素,是以在項目計劃和資源配置設定中應給予足夠的重視和投入。

資料處理的目标就是管理(增删改/标查)好資料集,産物是各類資料集,資料集的最終應用場景是模型的性能優化(模型選擇、Prompt優化、SFT),也就是說,如果不做性能優化,就可以不用做資料處理。

資料集與性能優化的關系如下:

  • 評估集,模型選擇、Prompt調優、SFT後都需要評估集對本次調優進行評估,是否比之前的好,是否達到調優的效果
  • 訓練集,指用于SFT的标注資料,根據特征從總資料集中篩選
  • 驗證集,驗證集是用來調整模型超參數,避免過拟合或欠拟合
  • 測試集,SFT後測試是否達到SFT的目的,比如針對某個異常case評估其泛化能力
  • 異常集,标注環節明确的低品質的CommitMessage資料,特别是大模型生成未被直接采納的資料
大模型效能工具之智能CommitMessage

這裡介紹下大體的過程及其作用,細節不做展開:

  • 定義資料結構:模型資料(需求/bug卡片标題、變更資料)、參考CommitMessage、類别資料(是否bug、變更行、倉庫數)、輔助分析資料(産品線、平台、作者、Topic)等
  • 資料采集:來源于:①線上模型服務生成的CommitMessage;②存量RD已送出入庫的CommitMessage;③其他開源資料集
  • 資料清洗:去噪、去重等處理,確定資料的品質和可用性
  • 标注與注釋:标注本條資料作為參考CommitMessage的品質,其他輔助分析資訊
  • 分類與管理:抽樣配比、過濾篩選、檢視等

根據我們目前的資料體量,選擇了Pandas(https://pandas.pydata.org/)作為資料處理工具,它對小規模資料和單機環境提供了夠用的資料處理和分析功能。然而,随着資料體量的逐漸增大,Spark(https://spark.apache.org/)将是一個不錯的選擇。

五. 性能優化

性能優化的目标是提升性能名額,包括核心名額均方誤差MSE和生成效率,進而提升使用者直接采納率AR,手段包括如下三種:

  • 停止标記(Stop Token),可提升生成效率
  • Prompt優化,可優化MSE名額和提升生成效率
  • SFT可優化MSE名額

丨5.1 停止标記

當模型對Prompt了解不完全時,容易生成多餘的解釋或注意事項等無效内容,生成更多的Token導緻生成效率降低(生成效率與生成的Token長度直接相關),而所有Transformer模型中都設計有停止标記,比如智能CommitMessage裡調用模型的輸出是一個Markdown的json,以“%STOP%”結尾,可指定停止辨別為“%STOP%”以提高生成效率。

丨5.2 Prompt優化

簡單說Prompt優化就是設計和優化輸入Prompts以獲得期望的輸出。看似一個簡單的NLP任務,卻又叫Prompt工程?因為需要讓大模型更好的了解期望的需求,确實涉及多學科的知識,比如融合語言學、心理學、計算機科學、資料科學,也包括整套工程方法:系統設計、實驗設計、品質控制、項目管理等等方面。智能CommitMessage裡涉及的兩個優化點:

1. 限制輸出内容,明确要求

CommitMessage調用模型的輸出要求是Markdown的json,如果模型輸出不是正常的json将導緻解析異常,此時在Prompt中明确要求『請僅輸出内容,不要做任何解釋』可避免生成無效内容,提高生成效率和準确性。

2. Few-shot

Prompt優化裡有個優化在限制輸出樣式的情況下非常有效 --Few-shot,以示例讓大模型了解并限制輸出樣式,要求輸出一個Markdown 的多行的 json 資料,樣例:

按以下格式輸出CommitMessage,隻是一個markdown的代碼片段,包含在"```json" 和 "```"内,『請僅輸出内容,不要做任何解釋』:
```json
{
    "summary": string  // 少于30字的中文,簡潔的、準确的描述Git Commit Message
    "reason": string  // 分析修複方式,較長的描述這個bug出現的具體原因,可以引用代碼,少于60字
    "fixup": string  // 分析修複方式,簡潔、準确的描述修複方式,可以引用代碼,少于30字
}
```           

這裡的樣例不是一個标準的json格式(多行換行時缺少“,”),大模型可能按照該格式輸出,也可能按照正确的json格式輸出,是以存在一個異常問題的不确定性,可通過完善該Few-shot完全避免該問題:

按以下格式輸出CommitMessage,隻是一個markdown的代碼片段,包含在"```json" 和 "```"内,『請僅輸出内容,不要做任何解釋』:
```json
{
    "summary": string,  // 少于30字的中文,簡潔的、準确的描述Git Commit Message
    "reason": string,  // 分析修複方式,較長的描述這個bug出現的具體原因,可以引用代碼,少于60字
    "fixup": string  // 分析修複方式,簡潔、準确的描述修複方式,可以引用代碼,少于30字
}
```           

這裡有個類似的概念:Prompt Tuning,Few-shot 和 Prompt Tuning都是優化和調整大型語言模型輸入提示的方法,但有着本質上的差別:

側重 方法 應用
Prompt Few-shot 局部,當次 自我訓練和微調 個性化的需求
Prompt Tuning 全局 Prompt示例 個性化的需求

附上智能CommitMessage的部分Prompt(持續優化中):

角色名稱:Git Commit Message Generator
通俗易懂的角色描述:基于需求描述和實作該需求的git diff變更代碼,自動生成規範的git送出資訊。
需求描述的标題如下:{{%title}}


git diff變更代碼如下:
(DIFF-START)
{{%git_diff}}
(DIFF-END)


任務拆解
1. 解析需求标題:
提取關鍵資訊,如功能點、問題點等。
對文本進行清洗,去除無關字元和格式。
2. 分析git diff變更代碼:
識别變更的檔案和代碼塊。
分析代碼變更的類型(如新增、修改、删除等)。
3. 生成Commit Message:
結合需求标題以及代碼變更分析,編寫Commit Message。
確定提取的内容符合對應項的要求,如“summary: 少于30字的中文,簡潔的、準确的描述Git Commit Message”等。
4. 驗證Commit Message:
檢查Commit Message是否清晰、準确。
5. 按以下格式輸出CommitMessage,隻是一個markdown的代碼片段,包含在"```json" 和 "```"内,『請僅輸出内容,不要做任何解釋』:
```json
{
  "summary": string  // 少于30字的中文,簡潔的、準确的描述Git Commit Message
}
```%STOP%           

丨5.3 SFT

因為文心4的模型能力已經有非常出色的生成能力,在這種大模型上做SFT成本非常高,是以一般會采用ERNIE-lite版本或者ERNIE-Speed版本,但是性能稍遜一籌,那如何保證在ERNIE-Speed版本中SFT後既能不降低整體性能,又能優化低品質case?

這裡可以采用MoE(Mixture of Experts)的政策,用一個分類器來結合ERNIE4 + (ERNIE-Speed + SFT)各自的優勢,即請求優先經過一個分類器,根據請求的特征進行分類請求ERNIE4或者經過SFT後的ERNIE-Speed模型,如下圖示例:

大模型效能工具之智能CommitMessage

部署前記得SFT評估資料集的全量評估,MSE優于線上保證本次SFT後的ERNIE-Speed模型比上次的更好。

SFT的全過程應該包含四個步驟:

  1. 确定目标:優化某個/某類低品質的資料case,微調後達到評估多少分值
  2. 資料準備:基于該case提取低品質case的特征,向資料集裡篩選出訓練集、驗證集和測試集
  3. SFT過程:如上圖所示
  4. 評估部署:根據抽樣配比的評估集進行全量評估,保證本次SFT後的ERNIE-Speed模型比上次的更好

六. 自定義送出規範

由于大模型隻生成核心的變更摘要或者Fixbug的相關資訊,而最終需要組合成各式各樣的送出規範格式,是以可以将變化抽象為接口,可擴充python package實作接口達成自定義符合送出規範的CommitMessage,按需動态加載實作的插件。

抽象接口如下:

from abc import ABC, abstractmethod


class IPluginHook(ABC):
    """插件實作的接口定義"""
    @abstractmethod
    def hook_prepare(self, ctx):
        """準備"""


    @abstractmethod
    def hook_is_fix_bug(self, ctx) -> bool:
        """是否fixbug的送出類型,預設false"""


    @abstractmethod
    def hook_language(self, ctx) -> Language:
        """生成語言,預設中文"""


    @abstractmethod
    def hook_generate_variables(self, ctx):
        """生成模闆的變量"""


    @abstractmethod
    def hook_generate_message(self, ctx) -> str:
        """根據模闆和變量,生成CommitMessage
        @warning: 該方法插件必須實作,否則将報出異常
        """           

加載某個插件的某個版本時,根據pkg_resources判定是已加載,然後配合 importlib進行import_module或者reload即可實作動态加載插件

def __install_plugin(pkg_name: str, version: str):
    """安裝插件"""
    subprocess.check_call([sys.executable, '-m', 'pip', 'install', f"{pkg_name}=={version}"])
    return __load_module(pkg_name, force=True)


def __load_module(pkg_name: str, force: bool = False):
    """加載module"""
    module_name = __module_name(pkg_name)
    loaded_module = sys.modules.get(module_name)
    if loaded_module is not None:
        if force:
            m = importlib.reload(loaded_module)
            importlib.reload(pkg_resources)
            return m
        return loaded_module
    m = importlib.import_module(module_name)
    importlib.reload(pkg_resources)
    return m           

七. 未來

大模型對各類語言的代碼了解上展現了卓越的能力,但對專有詞彙、特定配置、固定格式等的了解依然存在不足,都需要合适的資料集來逐漸優化;并且git diff擷取的變更内容有限,受限于模型Token的限制,了解時缺少代碼的上下文、依賴關系的關聯導緻生成品質存在瓶頸,結合RAG或許是一個較好的方式;使用入口的互動性、自定義送出規範都可以更AI,總之:AI Native 尚未成功,同志仍須努力。

參考文獻:

[1] LangChain:https://www.langchain.com/

[2] git:https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases

[3] pandas:https://pandas.pydata.org/

[4] Spark:https://spark.apache.org/

[5] 百度千帆:https://console.bce.baidu.com/qianfan/overview

[6] Prompt工程 大模型的應用與實踐:https://zhuanlan.zhihu.com/p/668200325

作者:zy

來源-微信公衆号:百度App技術

出處:https://mp.weixin.qq.com/s/IeENM0o59vVrvK9oD4plZA

繼續閱讀