写点什么

大模型效能工具之智能 CommitMessage

作者:百度Geek说
  • 2024-05-23
    上海
  • 本文字数:6244 字

    阅读完需:约 20 分钟

01 背景

随着大型语言模型的迅猛增长,各种模型在各个领域的应用如雨后春笋般迅速涌现。在研发全流程的效能方面,也出现了一系列贯穿全流程的提效和质量工具,比如针对成本较高的 Oncall,首先出现了高质量的 RAG 助手;在开发阶段的 Copilot、Comate、Tabnine 等辅助编程应工具;在测试阶段,也有缺陷检查、安全合规检查、智能 Code Review 等工具;哪怕在交付阶段,也有替代人工的自动化 Agent...


当使用 git commit 提交代码时,需要写繁杂的 CommitMessage,有时候写了后却不符合提交规范被 hook,有时候还被 CodeReview 的同学点评写不到点上...智能 CommitMessage 就是这样一个小助手,帮你按照提交规范自动生成符合规范的 CommitMessage。


以百度 APP 的提交规范为例,规范包括提交类别、产品版本、需求卡片、变更摘要等,其中类别又包括:功能、更新、优化、提测、上车、Merge、FixBug 等,手动抒写较为复杂。


按照 CommitMessage 的组合标准,可以分为两个部分:规范格式 + 变更摘要:



CommitMessage 组成部分


  • 普通摘要类:提交规范格式 + 变更摘要

  • FixBug 类:提交规范格式 + 变更摘要(包括 bug 原因、影响、修复方式等)


其中运用大模型能力生成变更摘要部分,而提交规范格式及其他标签由个性化插件定制,即可对不同业务线/产品线可定制符合提交规范的 CommitMessage。


智能 CommitMessage 的最终使用效果如下:查看原文



git aicommit 用法示例


下面就以智能 CommitMessage 为例,介绍下大模型效能工具开发流程,主要包括:


  • 简单的功能设计

  • 应用指标和模型评估指标

  • 大模型数据处理过程

  • 模型性能优化的几种方式

02 功能与设计

用户入口一: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。



  • 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。

03 评估指标

管理学之父彼得·德鲁克说过:“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,用户直接采纳的次数相对于总的使用次数的占比


均方误差 MSE(Mean Squared Error)


参考 CommitMessage 的文本序列,指高质量的、简洁的、准确的、标准的 CommitMessage,客观标准是至少包括:为什么修改(Why)、改了什么(What)、影响面(可选),主观标准是人工筛选并提取。


根据定义,计算 MSE 即计算两段文本的语义相似度差值,简单的分为如下三个步骤:


1.文本 Embedding 向量化:


  • 将两段文本转换为向量表示。大模型时代 Embedding 的方式太多太多了,这里依然直接选用了千帆的 Embedding 方式。


2.向量差异计算:


  • 计算两段文本的向量表示间的差异或距离时,我们选择使用余弦相似度;尽管欧几里得距离和马氏距离也是常用的方法,但针对 CommitMessage 这种长度不一致的向量时,余弦相似度表现更为准确。


3.均方误差计算:


  • 将差异或距离平方,然后计算平均值以得到均方误差。

  • 其中,xi 和 yi 是两段文本在第 i 个维度上的表示,n 是维度数量。


本文多次提交两个概念:

参考 CommitMessage:可以是 RD 生成已提交入库的,也可以由大模型生成、经过人工标注的保证质量的 CommitMessage,作为评估的标准 yi

生成 CommitMessage:由大模型生成的 CommitMessage,评估输入的判定项 xi


直接采纳率 AR(Adoption Rate)


总的使用次数包括 3 个结果:


  • 直接采纳数 CA

  • 编辑采纳数 CE

  • 拒绝数 CR


04 数据处理

大模型应用开发为了更好的性能(包括生成质量、效率、准确度、采纳率),数据处理的成本投入较高,通常占据整个应用开发投入的相当大的比例,有时甚至可能超过模型训练和调优的工作量。总之,有效和高效的数据处理是提升模型性能的关键因素,因此在项目计划和资源分配中应给予足够的重视和投入。


数据处理的目标就是管理(增删改/标查)好数据集,产物是各类数据集,数据集的最终应用场景是模型的性能优化(模型选择、Prompt 优化、SFT),也就是说,如果不做性能优化,就可以不用做数据处理。


数据集与性能优化的关系如下:


  • 评估集,模型选择、Prompt 调优、SFT 后都需要评估集对本次调优进行评估,是否比之前的好,是否达到调优的效果

  • 训练集,指用于 SFT 的标注数据,根据特征从总数据集中筛选

  • 验证集,验证集是用来调整模型超参数,避免过拟合或欠拟合

  • 测试集,SFT 后测试是否达到 SFT 的目的,比如针对某个异常 case 评估其泛化能力

  • 异常集,标注环节明确的低质量的 CommitMessage 数据,特别是大模型生成未被直接采纳的数据



这里介绍下大体的过程及其作用,细节不做展开:


  • 定义数据结构:模型数据(需求/bug 卡片标题、变更数据)、参考 CommitMessage、类别数据(是否 bug、变更行、仓库数)、辅助分析数据(产品线、平台、作者、Topic)等

  • 数据采集:来源于:①线上模型服务生成的 CommitMessage;②存量 RD 已提交入库的 CommitMessage;③其他开源数据集

  • 数据清洗:去噪、去重等处理,确保数据的质量和可用性

  • 标注与注释:标注本条数据作为参考 CommitMessage 的质量,其他辅助分析信息

  • 分类与管理:抽样配比、过滤筛选、查看等


根据我们当前的数据体量,选择了 Pandas(https://pandas.pydata.org/)作为数据处理工具,它对小规模数据和单机环境提供了够用的数据处理和分析功能。然而,随着数据体量的逐步增大,Spark(https://spark.apache.org/)将是一个不错的选择。

05 性能优化

性能优化的目标是提升性能指标,包括核心指标均方误差 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 中明确要求『请仅输出内容,不要做任何解释』可避免生成无效内容,提高生成效率和准确性。


  1. 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 都是优化和调整大型语言模型输入提示的方法,但有着本质上的区别:



附上智能 CommitMessage 的部分 Prompt(持续优化中):


通俗易懂的角色描述:基于需求描述和实现该需求的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 模型,如下图示例:



部署前记得 SFT 评估数据集的全量评估,MSE 优于线上保证本次 SFT 后的 ERNIE-Speed 模型比上次的更好。


SFT 的全过程应该包含四个步骤:


  1. 确定目标:优化某个/某类低质量的数据 case,微调后达到评估多少分值

  2. 数据准备:基于该 case 提取低质量 case 的特征,向数据集里筛选出训练集、验证集和测试集

  3. SFT 过程:如上图所示

  4. 评估部署:根据抽样配比的评估集进行全量评估,保证本次 SFT 后的 ERNIE-Speed 模型比上次的更好

06 自定义提交规范

由于大模型只生成核心的变更摘要或者 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
复制代码

07 未来

大模型对各类语言的代码理解上展现了卓越的能力,但对专有词汇、特定配置、固定格式等的理解依然存在不足,都需要合适的数据集来逐步优化;并且 git diff 获取的变更内容有限,受限于模型 Token 的限制,理解时缺少代码的上下文、依赖关系的关联导致生成质量存在瓶颈,结合 RAG 或许是一个较好的方式;使用入口的交互性、自定义提交规范都可以更 AI,总之:AI Native 尚未成功,同志仍须努力。


——————END——————


参考资料:


[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


推荐阅读:


基于afx透明视频的视觉增强前端方案


百度一站式数据自助分析平台(TDA)建设


浅析如何加速商业业务实时化


登录系统演进、便捷登录设计与实现


一文带你完整了解Go语言IO基础库


用户头像

百度Geek说

关注

百度官方技术账号 2021-01-22 加入

关注我们,带你了解更多百度技术干货。

评论

发布
暂无评论
大模型效能工具之智能CommitMessage_百度_百度Geek说_InfoQ写作社区