我们将开发以大语言模型为功能核心、通过大语言模型的强大理解能力和生成能力、结合特殊的数据或业务逻辑来提供独特功能的应用称为大模型开发。开发大模型相关应用,其技术核心点虽然在大语言模型上,但一般通过调用 API 或开源模型来实现核心的理解与生成,通过 Prompt Enginnering 来实现大语言模型的控制,因此,虽然大模型是深度学习领域的集大成之作,大模型开发却更多是一个工程问题。
在大模型开发中,我们一般不会去大幅度改动模型,而是将大模型作为一个调用工具,通过 Prompt Engineering、数据工程、业务逻辑分解等手段来充分发挥大模型能力,适配应用任务,而不会将精力聚焦在优化模型本身上。因此,作为大模型开发的初学者,我们并不需要深研大模型内部原理,而更需要掌握使用大模型的实践技巧。
大模型开发要素
同时,在评估思路上,大模型开发与传统 AI 开发也有了质的差异。传统 AI 开发需要首先构造训练集、测试集、验证集,通过在训练集上训练模型、在测试集上调优模型、在验证集上最终验证模型效果来实现性能的评估。然而,大模型开发更敏捷、灵活,我们一般不会在初期显式地确定训练集、验证集,由于不再需要训练子模型,我们不再构造训练集,而是直接从实际业务需求出发构造小批量验证集,设计合理 Prompt 来满足验证集效果。然后,我们将不断从业务逻辑中收集当下 Prompt 的 Bad Case,并将 Bad Case 加入到验证集中,针对性优化 Prompt,最后实现较好的泛化效果。
在本章中,我们将简述大模型开发的一般流程,并结合项目实际需求,逐步分析完成项目开发的工作和步骤。
结合上述分析,我们一般可以将大模型开发分解为以下几个流程:
以下我们将结合本实践项目与上文的整体流程介绍,简要分析本项目开发流程如下:
本项目实现原理如下图所示(图片来源 ),过程包括加载本地文档 -> 读取文本 -> 文本分割 -> 文本向量化 -> question向量化 -> 在文本向量中匹配出与问句向量最相似的 top k个 -> 匹配出的文本作为上下文和问题一起添加到 prompt中 -> 提交给 LLM生成回答。
用户常用文档格式有 pdf、txt、doc 等,首先使用工具读取文本,通常使用 langchain 的文档加载器模块可以方便的将用户提供的文档加载进来,也可以使用一些 python 比较成熟的包进行读取。
由于目前大模型使用 token 的限制,我们需要对读取的文本进行切分,将较长的文本切分为较小的文本,这时一段文本就是一个单位的知识。
使用文本嵌入(Embeddings)对分割后的文档进行向量化,使语义相似的文本片段具有接近的向量表示。然后,存入向量数据库,这个流程正是创建 索引(index)
的过程。
向量数据库对各文档片段进行索引,支持快速检索。这样,当用户提出问题时,可以先将问题转换为向量,在数据库中快速找到语义最相关的文档片段。然后将这些文档片段与问题一起传递给语言模型,生成回答。
Langchain 集成了超过 30 个不同的向量存储库。我们选择 Chroma 向量库是因为它轻量级且数据存储在内存中,这使得它非常容易启动和开始使用。
将用户知识库内容经过 embedding 存入向量知识库,然后用户每一次提问也会经过 embedding,利用向量相关性算法(例如余弦算法)找到最匹配的几个知识库片段,将这些知识库片段作为上下文,与用户问题一起作为 prompt 提交给 LLM 回答。
整个流程将确保项目从规划、开发、测试到上线和维护都能够顺利进行,为用户提供高质量的基于个人知识库的问答助手。
经过上文分析,本项目为搭建一个基于大模型的个人知识库助手,基于 LangChain 框架搭建,核心技术包括 LLM API 调用、向量数据库、检索问答链等。项目整体架构如下:
如上,本项目从底向上依次分为 LLM 层、数据层、数据库层、应用层与服务层:
① LLM 层 主要基于四种流行 LLM API 进行了 LLM 调用封装,支持用户以统一的入口、方式来访问不同的模型,支持随时进行模型的切换;
② 数据层 主要包括个人知识库的源数据以及 Embedding API,源数据经过 Embedding 处理可以被向量数据库使用;
③ 数据库层 主要为基于个人知识库源数据搭建的向量数据库,在本项目中我们选择了 Chroma;
④ 应用层 为核心功能的最顶层封装,我们基于 LangChain 提供的检索问答链基类进行了进一步封装,从而支持不同模型切换以及便捷实现基于数据库的检索问答;
⑤ 最顶层为 服务层,我们分别实现了 Gradio 搭建 Demo 与 FastAPI 组建 API 两种方式来支持本项目的服务访问。
本项目的完整代码存放于 project 目录下,实现了项目的全部功能及封装,代码结构如下:
-project
-readme.md 项目说明
-requirements.txt 使用依赖包的版本
-llm LLM调用封装
-self_llm.py 自定义 LLM 基类
-wenxin_llm.py 自定义百度文心 LLM
-spark_llm.py 自定义讯飞星火 LLM
-zhipuai_llm.py 自定义智谱AI LLM
-call_llm.py 将各个 LLM 的原生接口封装在一起
-test.ipynb 使用示例
-embedding embedding调用封装
-zhipuai_embedding.py 自定义智谱AI embedding
-call_embedding.py 调用 embedding 模型
-data 源数据路径
-database 数据库层封装
-create_db.py 处理源数据及初始化数据库封装
-qa_chain 应用层封装
-qa_chain.py 封装检索问答链,返回一个检索问答链对象
-chat_qa_chian.py:封装对话检索链,返回一个带有历史记录的对话检索链对象
-get_vectordb.py 返回向量数据库对象
-model_to_llm.py 调用模型
-test.ipynb 使用示例
-serve 服务层封装
-run_gradio.py 启动 Gradio 界面
-api.py 封装 FastAPI
-run_api.sh 启动 API
-test.ipynb 使用示例
LLM 层主要功能为将国内外四种知名 LLM API(OpenAI-ChatGPT、百度文心、讯飞星火、智谱GLM)进行封装,隐藏不同 API 的调用差异,实现在同一个对象或函数中通过不同的 model 参数来使用不同来源的 LLM。
在 LLM 层,我们首先构建了一个 Self_LLM 基类,基类定义了所有 API 的一些共同参数(如 API_Key,temperature 等);然后我们在该基类基础上继承实现了上述四种 LLM API 的自定义 LLM。同时,我们也将四种 LLM 的原生 API 封装在了统一的 get_completion 函数中。
在上一章,我们已详细介绍了每一种 LLM 的调用方式、封装方式,项目代码中的 LLM 层封装就是上一章讲解的代码实践。
数据层主要包括个人知识库的源数据(包括 pdf、txt、md 等)和 Embedding 对象。源数据需要经过 Embedding 处理才能进入向量数据库,我们在数据层自定义了智谱提供的 Embedding API 的封装,支持上层以统一方式调用智谱 Embedding 或 OpenAI Embedding。
在上一章,我们也已详细介绍了 Embedding API 的调用及封装方式。
数据库层主要存放了向量数据库文件。同时,我们在该层实现了源数据处理、创建向量数据库的方法。
我们将在第四章详细介绍向量数据库、源数据处理方法以及构建向量数据库的具体实现。
应用层封装了整个项目的全部核心功能。我们基于 LangChain 提供的检索问答链,在 LLM 层、数据库层的基础上,实现了本项目检索问答链的封装。自定义的检索问答链除具备基本的检索问答功能外,也支持通过 model 参数来灵活切换使用的 LLM。我们实现了两个检索问答链,分别是有历史记录的 Chat_QA_Chain 和没有历史记录的 QA_Chain。
我们将在第五章讲解 Prompt 的构造与检索问答链的构建细节。
服务层主要是基于应用层的核心功能封装,实现了 Demo 的搭建或 API 的封装。在本项目中,我们分别实现了通过 Gradio 搭建前端界面与 FastAPI 进行封装,支持多样化的项目调用。
我们将在第六章详细介绍如何使用 Gradio 以及 FastAPI 来实现服务层的设计。
优秀不够,你是否无可替代
软件测试交流QQ群:721256703,期待你的加入!!
欢迎关注我的微信公众号:软件测试君
参与评论
手机查看
返回顶部