你接手了一家经营二十年的老饭馆,后厨仓库里堆满了几十只没有标签的纸箱。有的渗着油渍,有的爬着霉斑,唯一认得这些箱子的大师傅退休时只留下一句“都在那儿了,自己看”。你只能一只只开箱、辨认、手写标签——如果此时有位助手扫一眼箱子内部就脱口而出“秘制豆瓣酱,需冷藏保存”,你大概会感动得想给他加鸡腿。这位助手,就是代码摘要生成。它要做的,是读懂“沉默的代码”,替每个函数写上清清爽爽的自然语言说明。这门技术从“看箱子外形猜内容”的土办法,一路进化到“见过几百万间仓库的老管家”,还配套了“标签验收单”(BLEU 指标)。读完这篇文章,你不仅能把旧项目的“仓库”整理得井井有条,还能让后来者翻代码就像翻一本贴着标签的相册。
学习代码摘要生成,能让你在接手历史项目、构建代码知识库、搭建文档治理体系时,用 AI 自动化取代人肉补注释,大幅降低文档维护成本,是 AI 工程师迈向“代码智能”领域的必修课。
可视化演示
交互展示大语言模型对齐评估的核心流程:多维对齐基准测试、红队安全对抗检测与人类反馈强化优化,可视化从评估到改进的闭环。
本节配有交互动效(进入视口后自动加载,约 3KB)。
多维对齐基准评估 有用性、无害性、诚实性三维度评估 基准数据集自动评分与排名 Score = \u03a3 w_i \u00d7 s_i 加权聚合多维度对齐得分
摘要生成概述
你接到一个整理老饭馆后厨仓库的任务:几十只没有标签的纸箱堆在墙角,有的渗着油渍,有的爬着霉斑,唯一认得这些箱子的大师傅已经退休。你只能一只只打开、辨认、再手写标签贴上去。如果此时有位助手能扫一眼箱子内部,直接脱口而出“秘制豆瓣酱,需冷藏保存”,你会不会激动得想给他涨工资?这位助手,就是代码摘要生成——它天生擅长让“沉默的代码”开口介绍自己。
在软件世界里,代码就是那些沉默的纸箱,函数是箱子,docstring 是标签。代码摘要生成(Code Summarization)指让程序自动阅读一段源代码,输出一句流畅的自然语言描述,说清楚“这段代码做了什么、怎么用、有哪些坑”。它的价值在于:接手历史项目时不再依赖“大师傅”口述,AI 自动把缺失的文档补回来;后续任何人翻代码都像看标签一样一目了然,文档维护成本被大幅压缩。
从数学视角看,这是一个条件语言模型问题。设 C 是输入的代码,S 是所有可能的描述句子,任务就是在所有句子中找出最合理的那句——也就是条件概率最高的 S。式中的竖线表示“在给定 C 的条件下”。
给纸箱贴标签看似简单,实际门道很深:太粗的标签等于没贴,太细的标签浪费笔墨,更别说有些箱子自带“伪装色”。正因如此,这项技术经历了一条清晰演进路线。接下来,我们就从最古老的土办法讲起,看看一代代“仓库管理员”是怎么把这件事越做越好的。
- 代码输入 C一段待解释的函数或代码块,模型从这里读取变量名、调用关系、控制流等语义线索。
- 条件概率 P(S|C)衡量“句子 S 是代码 C 的合格说明”的可能性,数值在 0 到 1 之间,越接近 1 越自信。
- argmax 选择把候选句子集合全部过一遍,挑出概率最高的那一句作为最终摘要。
基于规则方法
最早的贴标签办法很朴素:看纸箱的长相。四四方方的大纸箱八成装干货,长条形的盒子多半是调味料瓶——这个规律百试百灵,于是有人把它写成一本《纸箱辨认手册》。对应到代码上,就是一系列启发式规则:看到动词 get 就写“获取”,看到函数名带 byId 就补上“根据 ID”,再按“动词 + 对象 + 参数”的模板拼成句子。
这类方法称为基于规则的方法,本质是两步走。第一步做结构分析,把代码拆成可识别的部件:主要做了什么动作(动词)、作用在什么对象上(名词)、在什么条件下(参数);第二步做模板匹配,把部件填入预设的句子模板。规则库的构建依赖领域专家经验,用正则表达式和抽象语法树就能实现,成本极低,结果确定,这也是它至今仍被用作兜底方案的原因。
形式化地看,规则方法是一个复合函数:
其中 $\rho$ 把代码抽成结构化特征,$\mu$ 把特征映射到模板。
规则方法像一本装订考究的《纸箱辨认手册》,翻得快、零成本,但只认手册里画过的箱子。一旦遇到“细长箱子装干货”这种反常识的存在,它就果断翻车。于是下一代管理员开始思考:能不能不背手册,直接翻翻仓库角落那本旧台账,看看老前辈是怎么写标签的?
- 特征抽取 ρ(C)从函数名、注释、控制流中抽出“动作、对象、条件”三元组,例如 fetchUserById 被拆成“获取、用户、按 ID”。
- 模板映射 μ把三元组填入预设的句子模板,动词配宾语、条件作状语,拼成自然语句。
- 输出摘要 S返回完整的句子,作为该函数的 docstring 候选。
基于检索方法
仓库角落搁着一本泛黄的台账,记录着过去每只箱子的内容和标签。面对新箱子,你不必开箱,只需翻台账找一只“看起来最像”的箱子,把它的标签抄过来稍加改动——这就是基于检索的方法。它不追求从零造句,而是在已有“历史答案”中找参照。
检索方法的核心是相似代码检索。首先把代码表示成向量——常见做法是按 token 频次构建词袋向量,每个维度对应一个词条的权重;然后计算当前代码与库中代码的接近程度,选出最相近的几条,把它们的摘要直接复用,必要时将多段摘要做邻接拼接后稍作修剪。它继承了“以史为鉴”的优点:在垂直领域,检索结果可解释、可信度高,而且完全不需要训练模型。
相似度的计算最常用余弦公式:
检索法本质是“抄作业”,仓库越大、台账越全,命中率越高;可要是台账里根本没出现过同类箱子,或者老前辈当初就把标签写错了,它只能将错就错。要想真正“无中生有”地造句,还得靠能自动统计语言规律的办法。
- 代码向量 v当前代码 C 的向量表示,每个维度是某个词条的出现权重。
- 点积分子计算两个向量对应维度乘积之和,反映“协同出现”的强度。
- 模长归一化分母向量长度之积用于剔除代码长短带来的偏差,保证相似度落在有意义区间。
统计语言模型
如果既不想背手册,也没有旧台账可翻,还有一个更“笨”但更灵活的思路:把仓库里所有旧标签摊开,统计字词规律。比如一百张酱料标签里有八十五张出现“冷藏保存”,那么当一句话出现了“酱料”,模型就有把握补上“冷藏保存”。这就是统计语言模型的思想。
最经典的实现是 n-gram 模型。它假设当前词只与前 n-1 个词有关,用大规模语料中的词频概率估计条件概率。生成摘要时,模型几乎不看代码特征,单纯按概率从词表里挑选下一个词,逐个拼出整句——这就是序列生成。虽然“懂”得很浅,但它第一次让机器学会了“概率化造句”,而不是死记硬背。
以 bigram(n=2)为例,条件概率的估计公式为:
统计学徒的世界里只有词和频率,没有语法更没有语义,它造得出“冷藏、酱料、保存”这样断断续续的高频词串,却组织不出通顺的长句。要让标签写得像真人一样自然,只能请一位见过无数仓库的老师傅登场了。
- 前词与后词$w_{k-1}$ 表示已生成的上一词,$w_k$ 是待预测的当前词,模型只依赖最近一个词。
- 分子相识对语料中词对 $w_{k-1}w_k$ 相邻出现的次数,统计“这组搭配出现过多少次”。
- 分母做归一上一词独自出现的总次数,把频次转化为概率。
- 平滑兜底若词对从未出现导致分子为 0,则回退到 unigram 概率,或给分子加 1 做拉普拉斯平滑,避免概率变成 0。
预训练模型
终于,老板重金请来一位见过几百万间厨房仓库的老管家。他不翻手册、不看账本,只消扫一眼箱子里的东西就能脱口而出:“此为樟茶鸭腌料,含花椒与茶叶,需密封避光保存。”这位老管家,就是基于 Transformer 的预训练模型。
预训练模型(如 GPT、T5 系列)在海量“代码 + 自然语言”对上做自监督学习,学会了代码与语言之间的深层映射。针对代码场景的 CodeT5 采用编码器-解码器架构:编码器把代码的理解编码成语义向量,这是“代码理解”;解码器逐词写出描述,这是“代码生成”。相比 n-gram,它能捕捉长距离依赖,还能感知变量名、函数调用图的上下文,真正做到了理解代码意图。
生成阶段,模型按自回归方式逐词决策,整句概率是每个词条件概率的连乘:
老管家虽见多识广,也难免偶尔脱口而出看似漂亮、实则对不上号的话——把“料酒”说成“酱油”。标签写得流畅不等于内容准确,所以验收环节必不可少:机器粗筛加人工校验,双管齐下才能真正放心。
- 位置词 s_t摘要句子中第 t 个词,m 是句子总长度,生成是“逐字进行”的。
- 历史上文 s\<t该词之前所有已生成词的集合,体现“边写边看上文”的自回归特性。
- 连乘号 Π把每个词的选择概率乘起来,得到整句话合理性的总分,避免“局部通顺、整体跑题”。
- 训练目标在训练语料上最大化整句概率的对数似然,让模型输出的词语序列越来越接近真人写作风格。
质量评估
验收标签时,最省事的办法是拿一份“标准答案”来比对字句重合度。假设标准标签是“开盖后冷藏保存”,助理写的却是“放冰箱,盖好”,虽然意思沾边,字面却对不上——这种按“字句重合”打分的方法,就是自动评估指标 BLEU(Bilingual Evaluation Understudy)。
BLEU 最初用于机器翻译,后来成为文本生成领域的通用指标。它统计候选摘要与参考摘要的 n-gram 精确率:1-gram 看单个词是否命中,2-gram 看相邻词对是否命中,3-gram、4-gram 依次递进,越高的阶越能反映句子的流畅度和局部语序。把各阶分数做几何平均,再用简短惩罚因子 BP 压制“只写几个关键词糊弄”的偷懒行为。
BLEU 的完整计算公式为:
然而,字句重合终究不等于语义一致:助理完全可能写出与标准答案毫无重合、但意思更准确的标签。所以 BLEU 只适合当“粗筛漏斗”,真正拍板前还要人工开箱验货,确认标签与实物相符——这正是文档治理中最重要的一环:人机协同校验。
- 各阶精确率 p_n第 n 阶 gram 的精确率,即候选摘要中被参考摘要命中的 gram 数除以候选 gram 总数。
- 对数取平均对 N 个阶数的分数取对数再求平均,等价于几何平均,要求各阶都不能太差。
- 简短惩罚 BP当候选长度短于参考长度时按比例压低总分,防止“抄关键词不写全句”。
- 指数还原外层 exp 把对数平均还原为 0 到 1 之间的分数,越接近 1 字面重合度越高。
实战应用
故事来到最终章。你要把整间仓库几百只箱子全部贴上合格标签,还要立下规矩:以后新入库的箱子必须“先贴标签再上架”。对应到实际工程,就是批量补注释与文档治理——一次性的历史债清理和长期性的流程约束。
实践中,完整的落地路径分四步。第一步扫描代码库,找出所有缺少 docstring 的公共函数;第二步调用预训练模型批量生成候选摘要;第三步用 BLEU 做机器粗筛,对核心模块再走人工抽检;最后把通过校验的摘要合并回代码库,并接入 CI 流水线——以后任何新增代码若缺少注释,流水线会自动拦截并提醒补写。这就是工具链集成的完整闭环,让文档债不再“复利增长”。
推进这类治理项目时,团队常用一个覆盖度指标来衡量效果:
从一只只开箱手写标签,到 AI 批量起草、机器粗筛、人工抽验,再到流水线自动维护——代码摘要生成的完整路径,本质上就是让“沉默的代码”开口介绍自己。愿你接手任何一座“旧仓库”时,都能用这套手艺把它打理得井井有条,让后来者翻开代码就像翻看一本贴满标签的相册。
- 分子已成功生成摘要且通过人工抽检的函数数量,代表“真正合格”的标签数。
- 分母需要文档的函数总数,一般等于公共接口、复杂业务函数与跨模块调用点的总和。
- 百分比换算乘以 100% 把比例转为直观的百分比,便于设定目标(例如首月达到 80%)。
- 辅助指标通常还要跟踪文档错误率与维护成本,防止团队为了刷覆盖率而生产“正确的废话”。
AI 应用场景
遗留系统文档化
阶段:批量文档生成(Batch Annotation)
解决的问题:老系统动辄数千个函数,只有零星注释,新成员入职如坠迷雾。传统做法是让工程师逐个人肉补注释,费用高、周期长、还容易敷衍了事。AI 摘要生成可以把“读代码、写说明”的时间从几周压缩到几小时。
具体案例:某金融科技公司在核心系统迁移前,用 CodeT5 批量扫描全部历史模块,为 5000 多个公共函数生成中文摘要,再按 BLEU 粗筛 + 核心模块人工抽检 10%,最终生成统一格式的文档站。整个补文档周期从预估 3 个月缩短到 1 周,迁移评审会第一次开得如此顺畅。
代码知识库构建
阶段:语义索引与检索增强
解决的问题:代码越来越多,靠翻文件夹找“某个处理超时重试的函数”如同大海捞针。传统关键词搜索搜不到语义相近的代码(比如搜“重试”找不到名为 backoff 的函数)。摘要生成先把每个函数变成一句自然语言描述,再接入向量检索,让“用大白话找代码”成为可能。
具体案例:某大型开源项目维护者给全部模块生成了摘要,并构建内部语义检索工具。新贡献者只需输入“找出校验用户权限的地方”,系统就能返回相关函数及其摘要,新人上手时间从两周降到两天。
代码审查辅助
阶段:变更摘要生成(Summarization for Review)
解决的问题:代码审查时,审查者面对几百行 diff 常常不知从何看起。传统做法是开发者手写 PR 描述,往往啰嗦且遗漏关键改动。AI 对每个变更函数生成摘要,再汇总为 PR 变更说明,帮助审查者优先聚焦高风险改动。
具体案例:某中型互联网公司在 Jenkins 流水线中接入摘要生成插件。每次代码合并请求自动附上“变更了哪些函数、各做了什么、影响哪些调用方”的结构化说明。QA 团队据此快速圈定回归测试范围,线上故障率下降约 30%。
Python 演示
import mathimport refrom collections import Counter def split_words(name): # 把 snake_case / camelCase 拆成单词列表 s = re.sub(r'([a-z0-9])([A-Z])', r'\1_\2', name) return [w for w in re.split(r'[_\W]+', s.lower()) if w] VERB_MAP = { 'get': '获取', 'fetch': '拉取', 'calc': '计算', 'compute': '计算', 'sum': '汇总', 'update': '更新', 'set': '设置', 'create': '创建', 'add': '新增', 'delete': '删除', 'remove': '移除', 'find': '查找'} def generate_summary(func_name, params, has_return): # 规则方法:拆函数名 -> 动词映射 -> 模板拼接 words = split_words(func_name) verb = words[0] if words[0] in VERB_MAP else '处理' obj = '_'.join(words[1:]) if len(words) > 1 else '数据' summary = VERB_MAP.get(verb, verb) + obj if params: summary += ',参数:' + ', '.join(params) if has_return: summary += ',返回结果' return summary def ngrams(tokens, n): # 生成 n-gram 列表,如 2-gram: [('a','b'), ('b','c')] return [tuple(tokens[i:i + n]) for i in range(len(tokens) - n + 1)] def bleu(candidate, reference, max_n=4): # BLEU 评估:n-gram 精确率 + 简短惩罚 c_len, r_len = len(candidate), len(reference) if c_len == 0 or r_len == 0: return 0.0 precisions = [] for n in range(1, max_n + 1): cand_ng = Counter(ngrams(candidate, n)) ref_ng = Counter(ngrams(reference, n)) matched = sum((cand_ng & ref_ng).values()) total = max(sum(cand_ng.values()), 1) precisions.append(matched / total) if min(precisions) == 0: return 0.0 bp = 1.0 if c_len > r_len else math.exp(1 - r_len / c_len) return bp * math.exp(sum(math.log(p) for p in precisions) / max_n) def main(): funcs = [ ('calc_total_price', ['items', 'tax_rate'], True), ('fetch_user_by_id', ['user_id'], True), ('update_stock', ['product_id', 'delta'], False) ] for fname, params, has_ret in funcs: summary = generate_summary(fname, params, has_ret) print(f'{fname}({", ".join(params)}) -> {summary}') # 用 BLEU 对比候选摘要与参考摘要 cand = ['calc', 'total', 'price', 'from', 'items', 'tax'] ref = ['calculate', 'total', 'price', 'from', 'a', 'list'] print('BLEU =', round(bleu(cand, ref), 4)) if __name__ == '__main__': main()
split_words(name)把函数名拆成单词列表,是规则方法“结构分析”的第一步。VERB_MAP = {...}动词映射表,相当于规则方法里的《纸箱辨认手册》。summary = VERB_MAP.get(verb, verb) + obj模板填充的核心逻辑:动词 + 对象拼成一句话。def ngrams(tokens, n)生成任意阶 n-gram,为 BLEU 计算提供基础单元。matched = sum((cand_ng & ref_ng).values())统计候选与参考被命中的 n-gram 总数,对应 BLEU 公式中的分子。bp = 1.0 if c_len > r_len else math.exp(1 - r_len / c_len)实现简短惩罚 BP,防止“只写关键词糊弄”。for fname, params, has_ret in funcs:批量处理入口,对应实战中“扫描代码库逐个函数生成摘要”。
常见误区
误区现在的预训练模型生成摘要那么自然,谁还用规则方法?直接全部交给 CodeT5 不就行了,规则模板早就过时了。
正解规则方法零推理成本、结果完全确定,特别适合给模型结果做兜底和格式约束。比如先让模型自由生成,再用正则模板强制补上参数列表和返回值说明;检索方法在垂直领域还有可解释性优势。实际生产中常把它们做成“模型为主、规则兜底”的混合管道,而不是二选一。
为何常见:因为预训练模型的输出太自然了,让人误以为它永远比规则强,忽略了成本、稳定性和可控性的真实权衡。
误区评估时只盯着 BLEU,分数超过 0.5 就直接合入代码库,反正机器都打过分了。
正解BLEU 只看字面 n-gram 重合,完全不理解语义。候选摘要可以拼凑一堆高频词刷出高分,而一句用词完全不同但语义精准的摘要可能只得零分。正确做法是 BLEU 用于批量粗筛,对核心模块做人肉抽检,以“人机协同”方式把住质量关。
为何常见:BLEU 是一个自动化数字,天然给人“客观、可量化”的信任感,于是很容易被误当成“质量”本身。
误区既然 AI 生成不用花钱,那就给所有函数都补上注释,包括私有函数和 getter,文档越厚越专业。
正解文档维护是有复利成本的。过量的低价值注释不仅增加阅读负担,还会在代码变更时迅速过期失效。业界共识是优先给公共 API、复杂业务逻辑、跨模块接口写摘要;一目了然的函数名本身就是最好的文档。
为何常见:新手做文档治理时容易把“覆盖率”当成唯一目标,认为报告上的数字好看就等于文档质量高。
误区函数名能看懂七八分,给 AI 加个指令把代码“翻译”成中文注释,这不就是摘要生成吗?
正解高质量摘要需要理解代码的意图、边界条件、隐藏副作用,比如“这个函数会修改全局状态”或“在并发下可能抛异常”。这是语义级转写,不是词面级翻译。真正的摘要生成要对“代码干了什么”建模,而不是对“名字怎么念”做机械转换。
为何常见:很多入门示例恰好是“函数名直译”(如 calc_total_price → 计算总价格),容易让人误以为摘要 = 翻译,忽略了更深层的逻辑理解。
面试题
Q1. 代码摘要生成最核心的目标是什么?
- A.把代码翻译成英语
- B.用自然语言描述代码功能← 正确答案
- C.自动修复代码中的错误
- D.压缩代码体积减小依赖
答案:B。代码摘要生成的本质是“给代码写说明”,用自然语言描述功能与用法。A 是翻译不是摘要;C 是代码修复;D 是代码压缩,都与摘要无关。
Q2. 基于规则的方法通常不依赖以下哪一项?
- A.函数名
- B.注释内容
- C.海量预训练语料← 正确答案
- D.控制流结构
答案:C。规则方法靠专家写的模板和启发式规则,分析函数名、注释与控制流即可,不需要海量语料训练。大规模语料是统计语言模型和预训练模型的地盘。
Q3. 检索式方法中,衡量两段代码相似度最常用的指标是?
- A.编辑距离
- B.余弦相似度← 正确答案
- C.马尔可夫链
- D.BLEU 分数
答案:B。检索方法把代码映射成向量后用余弦相似度比较方向一致性。编辑距离针对字符串,马尔可夫链是概率模型,BLEU 用于评估生成文本,都不是代码相似度检索的主流选择。
Q4. bigram 语言模型中,P(w_k | w_{k-1}) 的分母代表什么?
- A.语料中相邻词对出现次数
- B.语料中当前词出现次数
- C.语料中前一个词出现次数← 正确答案
- D.语料中全部单词的数量
答案:C。条件概率的分母是“给定条件”的出现次数,也就是前一个词 w_{k-1} 在语料中出现的总次数;分子才是相邻词对 w_{k-1}w_k 的出现次数。
Q5. 下列哪些属于摘要生成的质量评估手段?
- A.BLEU 指标← 正确答案
- B.n-gram 精确率← 正确答案
- C.人工抽检复核← 正确答案
- D.编译错误数量
答案:ABC。BLEU 及其底层的 n-gram 精确率是自动评估核心,人工抽检是最终质量闸门。编译错误属于代码正确性问题,与摘要文本质量没有直接关系。
Q6. 规则方法生成摘要时,"fetchUserById" 被结构分析拆成的三元组最可能是?
- A.动作=获取,对象=用户,条件=按 ID← 正确答案
- B.动作=用户,对象=获取,条件=无
- C.动作=查找,对象=ID,条件=用户
- D.动作=拉取,对象=ID,条件=无
答案:A。结构分析按“动词 + 名词 + 介词短语”拆解:fetch 是动作(获取/拉取),User 是对象,byId 是条件(按 ID)。C 和 D 把 ID 当成了对象,属于常见拆解错误。
Q7. 统计语言模型生成摘要时,下一个词的选择依据是?
- A.人工预设的规则模板
- B.前面已生成词的词频概率← 正确答案
- C.代码中变量的字符数量
- D.参考摘要的长度限制
答案:B。n-gram 模型根据前面的词计算条件概率 P(w_k | w_{k-1}……),按词频概率挑选下一词。规则模板是规则方法,变量长度和参考长度都不参与概率计算。
Q8. 关于 BLEU 中的简短惩罚 BP,下列说法正确的是?
- A.可以惩罚过短的候选摘要← 正确答案
- B.候选长于参考时值为 1← 正确答案
- C.候选越短惩罚通常越重← 正确答案
- D.候选越短 BP 数值越接近 1
答案:ABC。BP 在候选长度 c 大于参考长度 r 时取 1;当 c ≤ r 时按 e^(1-r/c) 压缩,c 越短该值越小、惩罚越重。D 恰好说反了。
Q9. CodeT5 这类预训练模型生成摘要时,每个词的概率如何计算?
- A.与前面所有已生成词有关← 正确答案
- B.只与第一个词有关
- C.与后面的词有关
- D.与代码长度成正比
答案:A。自回归生成中 P(s_t | s\<t, C) 依赖之前所有已生成词和原始代码,与后面的词无关,也不存在“跟代码长度成正比”这类线性关系。这正体现了 Transformer 建模长距离依赖的优势。
Q10. 在文档治理实战中,以下哪些做法能提高摘要的可维护性?
- A.公共 API 生成摘要并人工复核← 正确答案
- B.用 BLEU 粗筛后抽检核心模块← 正确答案
- C.将流程接入 CI 防止新增漏文档← 正确答案
- D.对每个私有函数强制生成摘要
答案:ABC。公共 API 优先 + 机器粗筛 + 人工抽检 + CI 集成,是文档治理的成熟闭环。D 对所有私有函数强制生成摘要会增加维护噪音,属于“为覆盖率而文档”的典型反模式。