一、 大模型是怎样工作的?
通俗原理
其实,它只是根据上文,猜下一个词(的概率)……
训练:
-
大模型阅读了人类说过的所有的话。这就是 「机器学习」
-
训练过程会把不同 token 同时出现的概率存入 「神经网络」文件。保存的数据就是「参数」,也叫「权重」
推理:
-
我们给推理程序若干 token,程序会加载大模型权重,算出概率最高的下一个 token 是什么
-
用生成的 token,再加上上文,就能继续生成下一个 token。以此类推,生成更多文字
Token 是什么?
-
可能是一个英文单词,也可能是半个,三分之一个
-
可能是一个中文词,或者一个汉字,也可能是半个汉字,甚至三分之一个汉字
-
大模型在开训前,需要先训练一个 tokenizer 模型。它能把所有的文本,切成 token
架构:
-
这套生成机制的内核叫「Transformer 架构」
-
Transformer 是目前人工智能领域最广泛流行的架构,被用在各个领域
-
Transformer 仍是主流,但并不是最先进的
目前只有 transformer 被证明了符合 scaling-law。
大模型应用技术架构
纯 Prompt
Agent + Function Calling
RAG(Retrieval-Augmented Generation)
-
Embeddings:把文字转换为更易于相似度计算的编码。这种编码叫向量
-
向量数据库:把向量存起来,方便查找
-
向量搜索:根据输入向量,找到最相似的向量
Fine-tuning(精调/微调)
面对一个需求,如何开始,如何选择技术方案?
二、Prompt工程
大模型只接受一种输入,那就是 prompt
主要要求:指令具体、信息丰富、减少歧义
Prompt 的典型构成
- 角色:给 AI 定义一个最匹配任务的角色,比如:「你是一位软件工程师」「你是一位小学老师」
大模型对 prompt 开头和结尾的内容更敏感,先定义角色,其实就是在开头把问题域收窄,减少歧义。
-
指示:对任务进行描述
-
上下文:给出与任务相关的其它背景信息(尤其在多轮交互中)
-
例子:必要时给出举例,学术中称为 Few-Shot Learning 或 In-Context Learning;这对对输出正确性有很大帮助
-
输入:任务的输入信息;在提示词中明确的标识出输入
-
输出:输出的风格、格式描述,引导只输出想要的信息,以及方便后继模块自动解析模型的输出结果,比如(JSON、XML)
思维链(Chain of Thoughts, CoT)
- 论文地址:arxiv.org/abs/2205.11…
- 发现 prompt 以「Let’s think step by step」开头,AI 就会把问题分解成多个步骤,然后逐步解决,使得输出的结果更加准确。它是偶然被「发现」的(OpenAI 的人在训练时没想过会这样)
自洽性(Self-Consistency)
一种对抗「幻觉」的手段。就像我们做数学题,要多次验算一样。
-
同样 prompt 跑多次(把 temperature 设大,比如 0.9;或每次用不同的 temperature)
-
通过投票选出最终结果
思维树(Tree-of-thought, ToT)
-
在思维链的每一步,采样多个分支
-
拓扑展开成一棵思维树
-
判断每个分支的任务完成度,以便进行启发式搜索
-
设计搜索算法
-
判断叶子节点的任务完成的正确性
- 最简单的是:直接大白话问一次 (IO)
- 进阶一点是:思维链,让一步步思考(CoT)
- 再进一步是:思维链问多次,出结果后选举——少数服从多数(CoT-SC)
- 思维树=思维链问多次+链里每一步的逐步选举(ToT)
prompt示例整理
和人一样,更多例子、更好的例子、多次验算,都能提升正确率。
-
github.com/linexjlin/G… - 泄露出来的高级 GPTs 的 prompt
三、RAG
LLM 固有的局限性
-
LLM 的知识不是实时的
-
LLM 可能不知道你私有的领域/业务知识
RAG 系统的基本搭建流程
搭建过程:
-
文档加载,并按一定条件切割成片段
-
将切割的文本片段灌入检索引擎
-
封装检索接口
-
构建调用流程:Query -> 检索 -> Prompt -> LLM -> 回复
ES检索(关键词拆分后入库)
将文本灌入检索引擎
import os, time
from elasticsearch import Elasticsearch, helpers
# 1. 创建Elasticsearch连接
es = Elasticsearch(
hosts=[ELASTICSEARCH_BASE_URL], # 服务地址与端口
http_auth=(ELASTICSEARCH_NAME, ELASTICSEARCH_PASSWORD), # 用户名,密码
)
# 2. 定义索引名称
index_name = "teacher_demo_index"
# 3. 创建索引
es.indices.create(index=index_name)
# 4. 灌库指令
actions = [
{
"_index": index_name,
"_source": {
"keywords": to_keywords(para),
"text": para
}
}
for para in paragraphs
]
# 6. 文本灌库
helpers.bulk(es, actions)
# 灌库是异步的
time.sleep(2)
实现关键字检索
def search(query_string, top_n=3):
# ES 的查询语言
search_query = {
"match": {
"keywords": to_keywords(query_string)
}
}
res = es.search(index=index_name, query=search_query, size=top_n)
return [hit["_source"]["text"] for hit in res["hits"]["hits"]]
向量检索
文本向量(Text Embeddings)
- 将文本转成一组 𝑁 维浮点数,即文本向量又叫 Embeddings。
- 向量之间可以计算距离,距离远近对应语义相似度大小。
向量数据库
专门为向量检索设计的中间件。
-
FAISS: Meta 开源的向量检索引擎 github.com/facebookres…
-
Pinecone: 商用向量数据库,只有云服务 www.pinecone.io/
-
Milvus: 开源向量数据库,同时有云服务 milvus.io/
-
Weaviate: 开源向量数据库,同时有云服务 weaviate.io/
-
Qdrant: 开源向量数据库,同时有云服务 qdrant.tech/
-
PGVector: Postgres 的开源向量检索引擎 github.com/pgvector/pg…
-
RediSearch: Redis 的开源向量检索引擎 github.com/RediSearch/…
-
ElasticSearch 也支持向量检索 www.elastic.co/enterprise-…
几个关键概念
- 向量数据库的意义:快速的检索。
- 向量数据库本身不生成向量:向量是由 Embedding 模型产生的。
- 向量数据库与传统的关系型数据库是互补的:不是替代关系,在实际应用中根据实际需求经常同时使用。
思考优化的点
一、 文本分割的粒度:
- 粒度太大可能导致检索不精准,粒度太小可能导致信息不全面。
- 问题的答案可能跨越两个片段
改进:
- 按一定粒度,部分重叠式的切割文本,使上下文更完整。
- 单文本块多向量:
- 首先将文本分割为长度300-500 token的文本块,这些文本块被用于向量检索。但是在构建向量时,我们不是利用这个文本块得到一个向量,而是将文本块拆分为一个个句子,得到每个句子的向量表示,如果其中一个句子的向量表示和用户的query向量相似度足够高,整个文本块就会被检索回来
- 补充标题信息: 针对 Markdown 这种有明显章节结构的文档,按章节进行文本分割,并在文本开头补充对应章节的标题信息。
二、检索后排序 有时,最合适的答案不一定排在检索的最前面
方案:
- 检索时过招回一部分文本。
- 通过一个排序模型对 query 和 document 重新打分排序。
- 混合检索(Hybrid Search) 传统的关键字检索(稀疏表示)与向量检索(稠密表示)各有优劣。
举个具体例子,比如文档中包含很长的专有名词,关键字检索往往更精准而向量检索容易引入概念混淆。
# 背景说明:在医学中“小细胞肺癌”和“非小细胞肺癌”是两种不同的癌症
query = "非小细胞肺癌的患者"
documents = [
"玛丽患有肺癌,癌细胞已转移",
"刘某肺癌I期",
"张某经诊断为非小细胞肺癌III期",
"小细胞肺癌是肺癌的一种"
]
query_vec = get_embeddings([query])[0]
doc_vecs = get_embeddings(documents)
print("Cosine distance:")
for vec in doc_vecs:
print(cos_sim(query_vec, vec))
return [hit["_source"]["text"] for hit in res["hits"]["hits"]]
结果:
Cosine distance:
0.8915268056308027
0.8895478505819983
0.9039165614288258
0.9131441645902685]
所以,有时候我们需要结合不同的检索算法,来达到比单一检索算法更优的效果。这就是混合检索。
混合检索的核心是,综合文档 𝑑 在不同检索算法下的排序名次(rank),为其生成最终排序。
一个最常用的算法叫 Reciprocal Rank Fusion(RRF)
该方法的优势在于不利用相关分数,而仅靠排名计算
其中 𝐴 表示所有使用的检索算法的集合,𝑟𝑎𝑛𝑘𝑎(𝑑) 表示使用算法 𝑎 检索时,文档 𝑑 的排序,𝑘 是个常数。
很多向量数据库都支持混合检索,比如 Weaviate、Pinecone 等。也可以根据上述原理自己实现。
- RAG-Fusion
RAG-Fusion 就是利用了 RRF 的原理来提升检索的准确性。
- PDF 文档中的表格怎么处理
总结
RAG 的流程
离线步骤
- 文档加载:将文档加载到系统中。
- 文档切分:按一定条件切割成片段。
- 向量化:将切割的文本片段灌入检索引擎。
- 灌入向量数据库:将向量存入向量数据库。
在线步骤
- 获得用户问题:获取用户输入的问题。
- 用户问题向量化:将用户问题转换为向量。
- 检索向量数据库:从向量数据库中检索与问题相关的文档。
- 将检索结果和用户问题填入 Prompt 模版:将检索结果和用户问题一起输入大模型。 用最终获得的 Prompt 调用 LLM:由 LLM 生成回复。
希望这篇文章能给你带来一些启发和帮助。
如果你觉得有用,别忘了点赞、分享给更多的朋友哦!
欢迎关注公众号「编程复盘与思考随笔」
看更多走心好文请下面公众号关注:
关注后台私信【搞钱】送0基础搞钱方法手把手教程,一起搞钱!
点亮【关注、赞和在看】,让钱和爱都流向你。
欢迎加入我的2024年VIP群,大家一起成长。若想进一步了解,请选择以下通道详询!(备注来意:【发财】)