抛砖引玉,作者对大模型 LLMs 认知有限,有不当之处望咱们纠正!
布景
想法源于在一次 Code Review 时,向 Claude 问询哪种写法代码更优雅得来。其时就想能不能让 AI 帮咱们辅助做 Code Review?
痛点
-
信息安全合规问题:公司内代码直接调 ChatGPT / Claude 会有安全/合规问题,为了运用 ChatGPT / Claude 需求对代码脱敏,只供给抽象逻辑,这往往更花时刻。
- 三星引进ChatGPT不到 20 天,被曝发生3次芯片机密泄露
- 低质量代码消耗时刻:达人事务每天至少 10~20 个 MR 需求 CR,尽管提交时 MR 经过 单测 + Lint 过滤了一些低级过错,但还有些问题(代码合理性、经历、MR 相关事务逻辑等)需求花费很多时刻,最后能够先经过主动化 CR,再进行人工 CR,可大大进步 CR 功率!
- 团队 Code Review 规范缺少履行:大部分团队的 Code Review 停留在文档纸面上,成员之间口口相传,并没有一个东西依据规范来严格履行。
介绍
一句话介绍就是:依据开源大模型 + 常识库的 Code Review 实践,类似一个代码评定帮手(CR Copilot)。
特性
契合公司安全规范,所有代码数据不出内网,所有推理进程均在内网完结
- 开箱即用:依据 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)的大型多模态言语模型。 |
ChatGLM | ChatGLM 是一个开源的、支撑中英双语的对话言语模型,底座是 GLM 言语模型。 |
Baichuan | Baichuan 2 是百川智能推出的新一代开源大言语模型,采用 2.6 万亿 Tokens 的高质量语料练习。 |
Prompt | 一段文本或句子,用于辅导机器学习模型生成特定类型、主题或格局的输出。在自然言语处理领域中,Prompt 一般由一个问题或任务描绘组成,例如“给我写一篇有关人工智能的文章”、“翻译这个英文句子到法语”等等。在图画识别领域中,Prompt 则能够是一个图片描绘、标签或分类信息。 |
langchain | LangChain 是一个开源Python 库,由 Harrison Chase 开发,旨在支撑运用大型言语模型(LLM)和外部资源(如数据源或言语处理系统)开发运用程序。它供给了标准的接口,与其他东西集成,并为常见运用程序供给端到端链 。 |
embedding | 将恣意文本映射到固定维度的向量空间中,类似语义的文本,其向量在空间中的位置会比较挨近。在 LLM 运用中常用于类似性的文本查找。 |
向量数据库 (Vector stores) | 存储向量表明的数据库,用于类似性查找。如Milvus、Pinecone等。 |
Similarity Search | 在向量数据库中查找离查询向量最近的向量,用于检索类似项。 |
常识库 | 存储结构化常识的数据库,LLM能够利用这些常识增强自己的理解才干。 |
In-context Learning | In-Context Learning 是机器学习领域的一个概念,指不调整模型本身参数,而是在 Prompt 上下文中包括特定问题相关的信息,就能够赋予模型解决新问题才干的一种方法。 |
Finetune / 微调 | 在预练习模型基础上运用特定数据集进行微调,进步模型在某任务上的功能。 |
完成思路
流程图
系统架构
完结一次 CR 流程,需求用到如下技能模块:
LLMs / 开源大模型选型
CR Copilot 功能的中心在于大言语模型基座,依据不同大模型基座生成的 CR 质量也不尽相同。关于 CR 这个场景,咱们需求选型的模型满足以下几个条件:
- 理解代码
- 对中文支撑好
- 较强的上下文学习才干
FlagEval 8 月大模型评测榜单(https://flageval.baai.ac.cn/#/trending)
模型后面的
-{n}b
指n*10
亿参数量,比方 13b 就是 130 亿参数,个人试用下来参数量的多少并不能决定作用怎样,依据实际情况来判断。
起先在众多大模型中挑选『Llama2-Chinese-13b-Chat』和『chatglm2-6b』、『Baichuan2-13B-Chat』,经过一段时刻模型赛马,主观上感觉 Llama2、Baichuan2 会更适用于 CR 场景,而 ChatGLM2 更像是文科生,对代码评定没有太多建设性主张,但在中文 AIGC 上会比较有优势!
两个模型履行进程中的记载
因大模型合规问题,CR Copilot 会默认运用 ChatGLM2-6B,如有运用 Llama2 模型需求需求向 Meta 请求,经过后可运用。
Llama 2 要求企业的月活用户数不超越 7 亿
常识库规划
为什么需求常识库?
大模型基座只包括互联网上的公开数据,对公司内部的结构常识和运用文档并不了解。
举个例子:公司内有个结构叫 Lynx,让大模型从内部文档中知道『什么是 Lynx?』、『怎样写 Lynx?』
一图胜千言
这儿的『强化形式』会运用向量数据库,并将匹配的常识库片段和问题『什么是 Lynx?』生成 Prompt,发送到 LLM 履行。
怎样找到相关度高的常识?
有了常识库后,怎样将咱们『查找的问题/代码』在『常识库』中找到『相关度最高的内容』?
答案是经过三个进程:
- Text Embeddings(文本向量化)
- Vector Stores(向量存储)
- Similarity Search(类似性查找)
文本类似度匹配流程图,图源 Langchain-Chatchat
Text Embeddings(文本向量化)
不同于传统数据库的含糊查找/匹配关键字,咱们需求进行语义/特征匹配。
例如:你查找『猫』,只能得到带 『猫』 关键字匹配的成果,没办法得到 『布偶』、『蓝白』 等成果,传统数据库以为『布偶』是『布偶』、『猫』是『猫』。要完成相关语义查找,是经过人工打特征标签,这个进程也被称为特征工程(Feature Engineering)。
怎么才干将文本主动化的方法来提取这些特征?这就要经过 Vector Embedding 向量化完成,现在社区经过 OpenAI 供给的 text-embedding-ada-002 模型生成,这会引起两个问题:
- 数据安全问题:需求调用 OpenAI 的 API 才干做向量化
- 收费:大概 3000页/美元
咱们运用了国产文本类似度计算模型 bge-large-zh,并私有化布置公司内网,一次 embedding 向量化耗时基本在毫秒级。
Vector Stores(向量存储)
提早将官方文档进行 Vector Embeddings,然后存储在向量数据库里,咱们这儿挑选的向量数据库是 Qdrant,主要考虑到是用 Rust 写的,存储和查询也许会快一些!这儿引证一个向量数据库选型的几个维度挑选:
向量数据库 | URL | GitHub** **Star | Language | Cloud |
---|---|---|---|---|
chroma | github.com/chroma-core… | 8.5K | Python | ❌ |
milvus | github.com/milvus-io/m… | 22.8K | Go/Python/C++ | ✅ |
pinecone | www.pinecone.io/ | ❌ | ❌ | ✅ |
qdrant | github.com/qdrant/qdra… | 12.7K | Rust | ✅ |
typesense | github.com/typesense/t… | 14.4K | C++ | ❌ |
weaviate | github.com/weaviate/we… | 7.4K | Go | ✅ |
数据截止到2023年9月10号
Similarity Search(类似性查找)
原理是经过比较向量之间的间隔来判断它们的类似度
那么有了『query 问题的向量』和『数据库里录入的常识库向量』后,这能够直接运用向量数据库供给的 Similarity Search 方法匹配相关内容。
加载常识库
CR Copilot 常识库分为『内置官方文档常识库』、『自定义常识库』,query 输入是先用完好代码截取前半段 + LLM 生成 summary 总结,然后和常识库做类似上下文,匹配流程如下:
截取完好代码前半段作为 query 输入,是由于大部分言语前半段都声明晰 modules、packages,经过这种方法进步常识库类似匹配度。
官方文档-常识库(内置)
防止咱们将官方文档重复录入、embedding,CR Copilot 内置了官方文档,目录包括:
内容 | 数据源 |
---|---|
React 官方文档 | react.dev/learn |
TypeScript 官方文档 | www.typescriptlang.org/docs/ |
Rspack 官方文档 | www.rspack.dev/zh/guide/in… |
Garfish | github.com/web-infra-d… |
公司内 Go / Python / Rust 等编程规范 | … |
并经过一个简单的 CURD 来管理内置常识库
自定义常识库-飞书文档(自定义)
飞书文档没有格局要求,能看懂正确代码是怎样就行
这儿直接运用 LangChain 供给的 LarkSuite 文档加载类,对有权限的飞书文档进行获取,运用 CharacterTextSplitter / RecursiveCharacterTextSplitter 将文本分割成固定长度的块(chunks),方法有两个主要参数:
-
chunk_size
: 操控每个块的长度。例如设置为 1024,则每个块包括 1024 个字符。 -
chunk_overlap
: 操控相邻两个块之间的重叠长度。例如设置为 128,则每个块会与相邻块重叠 128 个字符。
Prompt 指令规划
由于大模型有足够多的数据,咱们想让大模型按要求履行就需求用到『Prompt 提示词』。
(图源 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 来输出改变的行数:
def parse_last_diff(git_diff):
diff_list = git_diff.split("\n")[::-1]
last_line_first_char = diff_list[1][0] if len(diff_list) > 1 else None
lastOldLineCount = ""
lastNewLineCount = ""
for item in diff_list:
match = re.search(r"^@@ \-\d+,\d+ \+\d+,\d+ @@", item)
if match:
lastOldLineCount, lastNewLineCount = re.sub(
r"@@ \-(\d+),(\d+) \+(\d+),(\d+) @@.*",
lambda match: str(int(match.group(1)) + int(match.group(2)))
+ ","
+ str(int(match.group(3)) + int(match.group(4))),
item,
).split(",")
break
if not lastOldLineCount.isdigit() or not lastNewLineCount.isdigit():
return {
"lastOldLine": -1,
"lastNewLine": -1,
}
last_old_line = -1 if last_line_first_char == "+" else int(lastOldLineCount) - 1
last_new_line = -1 if last_line_first_char == "-" else int(lastNewLineCount) - 1
return {
"lastOldLine": last_old_line,
"lastNewLine": last_new_line,
}
这儿机器人账号调用 Gitlab API 进行的评论,会默认被 Resolved,这样能够防止 CR Copilot 评论过多造成每个评论要手动点下 Resolved
一点感想
- 一切皆概率:依据 LLM 的运用最大特色在于『输出不确定性』,在候选词中选概率最高的进行输出,即便像 1+1=? 这样看起来有确定性输出的,LLM 也是依据概率给出的!
-
开源 LLMs + 领域常识库 + 私有化布置是企业级运用的一种实践方法::
- 这儿 LLMs 指多个大模型组合运用;大模型再强壮也有必要结合内部的常识库才干发挥作用;
- 私有化布置优点是打消各行各业对数据安全的担忧!
- 大模型在 Chat 聊天的产品形状更多是秀肌肉,让各行各业能被触达到;最终的产品形状需求详细场景详细剖析!
- AI+ 刚刚开始:CR Copilot 仅仅达人 LLMs + 研制工程化其间一个运用场景,还有一些运用/东西等达人团队打磨好后再和咱们一起共享!
参加咱们
最后,假如您对 LLMs+、前端 React、后端 Golang 等领域感兴趣,欢迎参加咱们,用最适合的技能服务好事务,和事务一起生长!job.toutiao.com/s/ieD4KuyR