跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客我的书AI学习GitHub 精选镜像AI工具UI配色美学关于
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
PythonAI算法

基于大模型与知识库的 Code Review 实践

一种基于开源大模型结合私有化知识库实现自动化代码审查(Code Review)的方案。针对企业代码安全合规及人工 CR 效率低的问题,该方案通过内网部署 LLM、构建向量数据库检索内部规范文档,并利用 LangChain 框架集成 Gitlab CI 流程。系统支持自定义知识库学习团队规范,将评论精准定位至变更行,在保障数据安全的前提下提升 CR 质量与效率。同时详细阐述了模型选型、知识库构建、Prompt 设计及 Diff 解析等关键技术细节,并提供部署与维护建议。

监控大屏发布于 2025/2/7更新于 2026/10/25103 浏览
基于大模型与知识库的 Code Review 实践

背景

💡 想法源于在一次 Code Review 时,向大语言模型询问哪种写法代码更优雅得来。当时就想能不能让 AI 帮我们辅助做 Code Review?

基于大模型与知识库的 Code Review 实践

痛点

信息安全合规问题:公司内代码直接调 ChatGPT / Claude 会有安全/合规问题,为了使用外部大模型需要对代码脱敏,只提供抽象逻辑,这往往更花时间。

三星引入 ChatGPT 不到 20 天,被曝发生 3 次芯片机密泄露。

低质量代码耗费时间:业务每天至少 10~20 个 MR 需要 CR,虽然提交时 MR 经过单测 + Lint 过滤了一些低级错误,但还有些问题(代码合理性、经验、MR 相关业务逻辑等)需要花费大量时间。可以先经过自动化 CR,再进行人工 CR,可大大提升 CR 效率!

团队 Code Review 规范缺少执行:大部分团队的 Code Review 停留在文档纸面上,成员之间口口相传,并没有一个工具根据规范来严格执行。

介绍

一句话介绍就是:基于开源大模型 + 知识库的 Code Review 实践,类似一个代码评审助手(CR Copilot)。

基于大模型与知识库的 Code Review 实践

特性

符合公司安全规范,所有代码数据不出内网,所有推理过程均在内网完成。

🌈 开箱即用:基于 Gitlab CI,仅 10 几行配置完成接入,即可对 MR 进行 CR。

🔒 数据安全:基于开源大模型做私有化部署,隔离外网访问,确保代码 CR 过程仅在内网环境下完成。

♾ 无调用次数限制:部署在内部平台,只有 GPU 租用成本。

📚 自定义知识库:CR 助手基于提供的飞书文档进行学习,将匹配部分作为上下文,结合代码变更进行 CR,这将大大提升 CR 的准确度,也更符合团队自身的 CR 规范。

🎯 评论到变更行:CR 助手将结果评论到变更代码行上,通过 Gitlab CI 通知,更及时获取 CR 助手给出的评论。

名词解释

名词释义
CR / Code Review越来越多的企业都要求研发团队在代码的开发过程中要进行 CodeReview(简称 CR),在保障代码质量的同时,促进团队成员之间的交流,提高代码水平。
llm / 大规模语言模型大规模语言模型 (Large Language Models,LLMs) 是自然语言处理中使用大量文本数据训练的神经网络模型,可以生成高质量的文本并理解语言。如 GPT、BERT 等。
AIGC利用 NLP、NLG、计算机视觉、语音技术等生成文字、图像、视频等内容。全称是人工智能生成/创作内容(Artificial Intelligence Generated Content);是继 UGC,PGC 后,利用人工智能技术,自动生成内容的生产方式;AIGC 底层技术的发展,驱动围绕不同内容类型(模态)和垂直领域的应用加速涌现。
LLaMA
Meta(Facebook)的大型多模态语言模型。
ChatGLMChatGLM 是一个开源的、支持中英双语的对话语言模型,底座是 GLM 语言模型。
BaichuanBaichuan 2 是百川智能推出的新一代开源大语言模型,采用 2.6 万亿 Tokens 的高质量语料训练。
Prompt一段文本或语句,用于指导机器学习模型生成特定类型、主题或格式的输出。在自然语言处理领域中,Prompt 通常由一个问题或任务描述组成。
langchainLangChain 是一个开源 Python 库,旨在支持使用大型语言模型(LLM)和外部资源开发应用程序。它提供了标准的接口,与其他工具集成,并为常见应用程序提供端到端链。
embedding将任意文本映射到固定维度的向量空间中,相似语义的文本,其向量在空间中的位置会比较接近。在 LLM 应用中常用于相似性的文本搜索。
向量数据库 (Vector stores)存储向量表示的数据库,用于相似性搜索。如 Milvus、Pinecone 等。
Similarity Search在向量数据库中搜索离查询向量最近的向量,用于检索相似项。
知识库存储结构化知识的数据库,LLM 可以利用这些知识增强自己的理解能力。
In-context Learning指不调整模型自身参数,而是在 Prompt 上下文中包含特定问题相关的信息,就可以赋予模型解决新问题能力的一种方式。
Finetune / 微调在预训练模型基础上使用特定数据集进行微调,提升模型在某任务上的性能。

实现思路

流程图

基于大模型与知识库的 Code Review 实践

系统架构

完成一次 CR 流程,需要用到如下技术模块:

基于大模型与知识库的 Code Review 实践

LLMs / 开源大模型选型

CR Copilot 功能的核心在于大语言模型基座,基于不同大模型基座生成的 CR 质量也不尽相同。对于 CR 这个场景,我们需要选型的模型满足以下几个条件:

  1. 理解代码能力强
  2. 对中文支持好
  3. 较强的上下文学习能力

基于大模型与知识库的 Code Review 实践

FlagEval 8 月大模型评测榜单。

模型后面的 -{n}b 指 n*10 亿参数量,比如 13b 就是 130 亿参数,个人试用下来参数量的多少并不能决定效果怎样,根据实际情况来判断。

起初在众多大模型中选择『Llama2-Chinese-13b-Chat』和『chatglm2-6b』、『Baichuan2-13B-Chat』,通过一段时间模型赛马,主观上感觉 Llama2 会更适用于 CR 场景,而 ChatGLM2 更像是文科生,对代码评审没有太多建设性建议,但在中文 AIGC 上会比较有优势!

基于大模型与知识库的 Code Review 实践

两个模型执行过程中的记录。

因大模型合规问题,CR Copilot 会默认使用 ChatGLM2-6B,如有使用 Llama2 模型需求需要向 Meta 申请,通过后可使用。

基于大模型与知识库的 Code Review 实践

Llama 2 要求企业的月活用户数不超过 7 亿。

目前支持的模型可选,仅供参考的评分如下:

  1. chatglm2-6b(默认)
  2. Llama2-Chinese-13b-Chat(推荐)
  3. Baichuan2-13B-Chat

基于大模型与知识库的 Code Review 实践

知识库设计

为什么需要知识库?

大模型基座只包含互联网上的公开数据,对公司内部的框架知识和使用文档并不了解。

举个例子 🌰:公司内有个框架叫 Lynx,让大模型从内部文档中知道『什么是 Lynx?』、『怎么写 Lynx? 』

基于大模型与知识库的 Code Review 实践

一图胜千言。

这里的『强化模式』会使用向量数据库,并将匹配的知识库片段和问题『什么是 Lynx?』生成 Prompt,发送到 LLM 执行。

怎样找到相关度高的知识?

有了知识库后,怎样将我们『搜索的问题/代码』在『知识库』中找到『相关度最高的内容』?

答案是通过三个过程:

  1. Text Embeddings(文本向量化)
  2. Vector Stores(向量存储)
  3. Similarity Search(相似性搜索)

基于大模型与知识库的 Code Review 实践

文本相似度匹配流程图,图源 Langchain-Chatchat。

Text Embeddings(文本向量化)

不同于传统数据库的模糊搜索/匹配关键字,我们需要进行语义/特征匹配。

例如:你搜索『猫』,只能得到带 『猫』 关键字匹配的结果,没办法得到 『布偶』、『蓝白』 等结果,传统数据库认为『布偶』是『布偶』、『猫』是『猫』。要实现关联语义搜索,是通过人工打特征标签,这个过程也被称为特征工程(Feature Engineering)。

基于大模型与知识库的 Code Review 实践

如何才能将文本自动化的方式来提取这些特征?这就要通过 Vector Embedding 向量化实现,目前社区通过 OpenAI 提供的 text-embedding-ada-002 模型生成,这会引起两个问题:

数据安全问题:需要调用 OpenAI 的 API 才能做向量化。

基于大模型与知识库的 Code Review 实践

收费:大概 3000 页/美元。

基于大模型与知识库的 Code Review 实践

我们使用了国产文本相似度计算模型 bge-large-zh,并私有化部署公司内网,一次 embedding 向量化耗时基本在毫秒级。

基于大模型与知识库的 Code Review 实践

Vector Stores(向量存储)

提前将官方文档进行 Vector Embeddings,然后存储在向量数据库里,我们这里选择的向量数据库是 Qdrant,主要考虑到是用 Rust 写的,存储和查询也许会快一些!这里引用一个向量数据库选型的几个维度选择:

向量数据库URLGitHub StarLanguageCloud
chromahttps://github.com/chroma-core/chroma8.5KPython❌
milvushttps://github.com/milvus-io/milvus22.8KGo/Python/C++✅
pineconehttps://www.pinecone.io/❌❌✅
qdranthttps://github.com/qdrant/qdrant12.7KRust✅
typesensehttps://github.com/typesense/typesense14.4KC++❌
weaviatehttps://github.com/weaviate/weaviate7.4KGo✅

数据截止到 2023 年 9 月 10 号

Similarity Search(相似性搜索)

原理是通过比较向量之间的距离来判断它们的相似度。

基于大模型与知识库的 Code Review 实践

那么有了『query 问题的向量』和『数据库里录入的知识库向量』后,这可以直接使用向量数据库提供的 Similarity Search 方式匹配相关内容。

基于大模型与知识库的 Code Review 实践

加载知识库

CR Copilot 知识库分为『内置官方文档知识库』、『自定义知识库』,query 输入是先用完整代码截取前半段 + LLM 生成 summary 总结,然后和知识库做相似上下文,匹配流程如下:

基于大模型与知识库的 Code Review 实践

截取完整代码前半段作为 query 输入,是因为大部分语言前半段都声明了 modules、packages,通过这种方式提高知识库相似匹配度。

官方文档 - 知识库(内置)

避免大家将官方文档重复录入、embedding,CR Copilot 内置了官方文档,目录包含:

内容数据源
React 官方文档https://react.dev/learn
TypeScript 官方文档https://www.typescriptlang.org/docs/
Rspack 官方文档https://www.rspack.dev/zh/guide/introduction.html
Garfishhttps://github.com/web-infra-dev/garfish
公司内 Go / Python / Rust 等编程规范…

并通过一个简单的 CURD 来管理内置知识库。

基于大模型与知识库的 Code Review 实践

自定义知识库 - 飞书文档(自定义)

飞书文档没有格式要求,能看懂正确代码是怎样就行。

这里直接使用 LangChain 提供的 LarkSuite 文档加载类,对有权限的飞书文档进行获取,使用 CharacterTextSplitter / RecursiveCharacterTextSplitter 将文本分割成固定长度的块(chunks),方法有两个主要参数:

chunk_size: 控制每个块的长度。例如设置为 1024,则每个块包含 1024 个字符。

chunk_overlap: 控制相邻两个块之间的重叠长度。例如设置为 128,则每个块会与相邻块重叠 128 个字符。

基于大模型与知识库的 Code Review 实践

Prompt 指令设计

因为大模型有足够多的数据,我们想让大模型按要求执行就需要用到『Prompt 提示词』。

基于大模型与知识库的 Code Review 实践

(图源 Stephen Wolfram)

代码 summary 总结指令

让 LLM 通过文件代码分析当前代码涉及的知识点,用于后续知识库相似度匹配:

prefix = "user: " if model == "chatglm2" else "<s>Human: "   
suffix = "assistant(用中文): let's think step by step." if model == "chatglm2" else "\n</s><s>Assistant(用中文): let's think step by step."
      return f"""{prefix}根据这段 {language} 代码,列出关于这段 {language} 代码用到的工具库、模块包。   {language} 代码:   ```{language}   {source_code}   ```请注意:   - 知识列表中的每一项都不要有类似或者重复的内容   - 列出的内容要和代码密切相关   - 最少列出 3 个,最多不要超过 6 个   - 知识列表中的每一项要具体   - 列出列表,不要对工具库、模块做解释   - 输出中文   {suffix}"""   

其中:

language:当前文件的代码语言(TypeScript、Python、Rust、Golang 等)

source_code:是当前变更文件的完整代码

CR 指令

如果使用的模型(如 LLaMA 2)对中文 Prompt 支持较差,需要在设计 Prompt 时采用『输入英文』『输出中文』的方式,即:

# llama2   
f"""Human: please briefly review the {language}code changes by learning the provided context to do a brief code review feedback and suggestions. if any bug risk and improvement suggestion are welcome(no more than six)   <context>   {context}   </context>      <code_changes>   {diff_code}   </code_changes>\n</s><s>Assistant: """      
# chatglm2   
f"""user: 【指令】请根据所提供的上下文信息来简要审查{language} 变更代码,进行简短的代码审查和建议,变更代码有任何 bug 缺陷和改进建议请指出(不超过 6 条)。   【已知信息】:{context}      【变更代码】:{diff_code}      assistant: """   

其中:

language:当前文件的代码语言(TypeScript、Python、Rust、Golang 等)

context:根据知识库返回的上下文信息

diff_code:是变更的代码(不使用完整代码主要是考虑 LLM max_tokens 最大限制)

评论到变更代码行

为了能计算出变更代码行,写了一个函数,通过解析 diff 来输出变更的行数:

import re      
def parse_diff(input):
       if not input:
           return []
       if not isinstance(input, str) or re.match(r"^\s+$", input):
           return []
          lines = input.split("\n")
       if not lines:
           return []
          result = []
       current_file = None
       current_chunk = None
       deleted_line_counter = 0
       added_line_counter = 0
       current_file_changes = None
          def normal(line):
           nonlocal deleted_line_counter, added_line_counter
           current_chunk["changes"].append({
               "type": "normal",
               "normal": True,
               "ln1": deleted_line_counter,
               "ln2": added_line_counter,
               "content": line
           })
           deleted_line_counter += 1
           added_line_counter += 1
           current_file_changes["old_lines"] -= 1
           current_file_changes["new_lines"] -= 1
          def start(line):
           nonlocal current_file, result
           current_file = {
               "chunks": [],
               "deletions": 0,
               "additions": 0
           }
           result.append(current_file)
          def to_num_of_lines(number):
           return int(number) if number else 1
          def chunk(line, match):
           nonlocal current_file, current_chunk, deleted_line_counter, added_line_counter, current_file_changes
           if not current_file:
               start(line)
           old_start, old_num_lines, new_start, new_num_lines = match.group(1), match.group(2), match.group(
               3), match.group(4)
              deleted_line_counter = int(old_start)
           added_line_counter = int(new_start)
           current_chunk = {
               "content": line,
               "changes": [],
               "old_start": int(old_start),
               "old_lines": to_num_of_lines(old_num_lines),
               "new_start": int(new_start),
               "new_lines": to_num_of_lines(new_num_lines),
           }
           current_file_changes = {
               "old_lines": to_num_of_lines(old_num_lines),
               "new_lines": to_num_of_lines(new_num_lines),
           }
           current_file["chunks"].append(current_chunk)
          def delete(line):
           nonlocal deleted_line_counter
           if not current_chunk:
               return
              current_chunk["changes"].append({
               "type": "del",
               "del": True,
               "ln": deleted_line_counter,
               "content": line
           })
           deleted_line_counter += 1
           current_file["deletions"] += 1
           current_file_changes["old_lines"] -= 1
          def add(line):
           nonlocal added_line_counter
           if not current_chunk:
               return
           current_chunk["changes"].append({
               "type": "add",
               "add": True,
               "ln": added_line_counter,
               "content": line
           })
           added_line_counter += 1
           current_file["additions"] += 1
           current_file_changes["new_lines"] -= 1
          def eof(line):
           if not current_chunk:
               return
           most_recent_change = current_chunk["changes"][-1]
           current_chunk["changes"].append({
               "type": most_recent_change["type"],
               most_recent_change["type"]: True,
               "ln1": most_recent_change["ln1"],
               "ln2": most_recent_change["ln2"],
               "ln": most_recent_change["ln"],
               "content": line
           })
          header_patterns = [
           (re.compile(r"^@@\s+-(\d+),?(\d+)?\s++(\d+),?(\d+)?\s@"), chunk)
       ]
          content_patterns = [
           (re.compile(r"^\ No newline at end of file$"), eof),
           (re.compile(r"^-"), delete),
           (re.compile(r"^+"), add),
           (re.compile(r"^\s+"), normal)
       ]
          def parse_content_line(line):
           nonlocal current_file_changes
           for pattern, handler in content_patterns:
               match = re.search(pattern, line)
               if match:
                   handler(line)
                   break
           if current_file_changes["old_lines"] == 0 and current_file_changes["new_lines"] == 0:
               current_file_changes = None
          def parse_header_line(line):
           for pattern, handler in header_patterns:
               match = re.search(pattern, line)
               if match:
                   handler(line, match)
                   break
          def parse_line(line):
           if current_file_changes:
               parse_content_line(line)
           else:
               parse_header_line(line)
          for line in lines:
           parse_line(line)
          return result   

基于大模型与知识库的 Code Review 实践

这里机器人账号调用 Gitlab API 进行的评论,会默认被 Resolved,这样可以避免 CR Copilot 评论过多造成每个评论要手动点下 Resolved。

部署与维护建议

在实际落地过程中,除了核心算法与 Prompt 设计,系统的稳定性与可维护性同样关键。

硬件资源规划

私有化部署大模型对 GPU 资源有一定要求。对于 6B 参数量的模型,单卡 16GB 显存即可运行量化版本;若追求更高并发或精度,建议使用多卡集群配合 vLLM 等推理加速框架。需预留足够的内存以支撑向量数据库的索引构建。

知识库更新策略

随着公司内部框架迭代,知识库内容需定期更新。建议建立自动化脚本,监听飞书文档或内部 Wiki 的变更,触发增量 Embedding 任务,将新内容同步至向量数据库,避免全量重建带来的延迟。

反馈闭环机制

鼓励开发人员对 CR 助手的评论进行反馈(点赞/点踩)。收集这些反馈数据可用于后续的 Prompt 优化或模型微调(Fine-tuning),使系统逐渐适应团队特定的编码风格。

一点感想

一切皆概率:基于 LLM 的应用最大特点在于『输出不确定性』,在候选词中选概率最高的进行输出,即使像 1+1=? 这样看起来有确定性输出的,LLM 也是基于概率给出的!

开源 LLMs + 领域知识库 + 私有化部署是企业级应用的一种实践方式:

这里 LLMs 指多个大模型组合使用;大模型再强大也必须结合内部的知识库才能发挥作用;

私有化部署好处是打消各行各业对数据安全的担忧!

大模型在 Chat 聊天的产品形态更多是秀肌肉,让各行各业能被触达到;最终的产品形态需要具体场景具体分析!

AI+ 刚刚开始:CR Copilot 只是大模型 + 研发工程化其中一个应用场景,还有一些应用/工具等团队打磨好后再和大家一起分享!

目录

  1. 背景
  2. 痛点
  3. 介绍
  4. 特性
  5. 名词解释
  6. 实现思路
  7. 流程图
  8. 系统架构
  9. LLMs / 开源大模型选型
  10. 知识库设计
  11. 为什么需要知识库?
  12. 怎样找到相关度高的知识?
  13. Text Embeddings(文本向量化)
  14. Vector Stores(向量存储)
  15. Similarity Search(相似性搜索)
  16. 加载知识库
  17. 官方文档 - 知识库(内置)
  18. 自定义知识库 - 飞书文档(自定义)
  19. Prompt 指令设计
  20. 代码 summary 总结指令
  21. CR 指令
  22. llama2
  23. chatglm2
  24. 评论到变更代码行
  25. 部署与维护建议
  26. 硬件资源规划
  27. 知识库更新策略
  28. 反馈闭环机制
  29. 一点感想

更多推荐文章

查看全部
  • 多模态模型入门进阶:MiniGPT-4、Qwen-VL、InternVL 与 DeepSeek-VL 详解
  • Code Llama 7B 快速上手指南
  • AI 产品经理入门指南:核心技能与常见误区解析
  • 字节跳动音视频前端一面面经与深度解析
  • Git 基本使用指南
  • 默认安全治理实践:水平越权检测与前端安全防控
  • C++/Qt 智能指针核心分类、原理与实战避坑
  • Visual C++ 运行库检测工具原型开发 (Python+PyQt)
  • C++ 函数与成员函数声明机制深度剖析与演进
  • Python 爬虫库 urllib 使用详解
  • 位运算实战:判断字符唯一性与查找缺失数字
  • Java 优先队列 PriorityQueue
  • C++ 运算符重载:自定义类型的运算扩展
  • Java 模拟算法实战:LeetCode 经典题解
  • AI 编程工具深度对比:Cursor、Copilot、Trae 与 Claude Code
  • pxcharts-vue:基于 Vue3 的开源多维表格解决方案
  • 基于 Unity 和 AI 零代码制作小游戏“飞翔的牛马”
  • C/C++依赖管理:Conan 深度解析与实战
  • PostgreSQL 物理复制与逻辑复制详解
  • Windows 下通过 WSL 安装 OpenClaw 并配置飞书与百炼模型

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • RSA密钥对生成器

    生成新的随机RSA私钥和公钥pem证书。 在线工具,RSA密钥对生成器在线工具,online

  • Mermaid 预览与可视化编辑

    基于 Mermaid.js 实时预览流程图、时序图等图表,支持源码编辑与即时渲染。 在线工具,Mermaid 预览与可视化编辑在线工具,online

  • 随机西班牙地址生成器

    随机生成西班牙地址(支持马德里、加泰罗尼亚、安达卢西亚、瓦伦西亚筛选),支持数量快捷选择、显示全部与下载。 在线工具,随机西班牙地址生成器在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • curl 转代码

    解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online