大模型应用开发

大模型概述

大模型的能力

涌现能力:随着训练数据规模增大能力迅速提升,超过随机水平

  1. 上下文学习
  2. 指令微调:泛化能力很强,微调后可以在未见过的任务上表现良好
  3. 逐步推理:LLM有“思维链”推理机制,可以逐步推理解决复杂任务

大基座模型

借助于无标注数据训练,可以用于大量下游任务;多个应用可以依赖于极少的几个大模型统一建设

支持对话作为统一入口

可以对话交互

常见大模型

闭源模型

  1. GPT:OPENAI
    ** decoder-only**
    • 通过语言建模将世界知识压缩到仅解码器的 Transformer 模型中
    • CHATGPT目前知识更新到23年4月
    • GPT-4扩展到多模态信号。用红队评估来加强安全性,并使用了一个可预测扩展方式评估能力(用稍小的模型来评估GPT模型)
  2. Claude
    • 具有长上下文的能力,大概支持200K token
    • 最多支持生产4000个token
    • 更好地生成 JSON、XML、YAML、代码和 Markdown 格式的正确输出
  3. PaLM:GOOGLE
    • 开发了许多特定领域的微调版本模型
    • 混合了百种语言,能够学习到每种语言的细微差别
    • 最有缩放比例: 数据和模型大小大致按照 1:1 的比例缩放,可以达到最佳性能
  4. 文心一言
    • 基于飞桨框架进行训练
  5. 星火大模型
    • 比ChatGPT更懂中文

开源

  1. LLaMA:Meta

    • decoder-only
    • 仅使用公开可用的数据集来训练最先进的模型
    • 大规模的数据过滤和清洗技术,减少噪声和偏见
    • 一些改进:
      * Pre-normalization:对每个子层进行归一化,防止梯度爆炸和消失
      * SwiGLU 激活函数:增加网络的表达能力和非线性
      * RoPE 位置编码:在网络的每一层添加了位置编码
  2. GLM:Tsinghua

    • 支持2048的上下文长度(ChatGLM 3.2 万字符)
    • 支持中英文两种语言
    • 使用了INT4和P-Tuning微调算法,能够在7G显存条件下进行微调
    • 在这里插入图片描述
  3. 通义千问:阿里巴巴

    • 阿里产品体系以及广泛的应用场景使得通义千问更具可落地性和市场可接受程度。
  4. Baichuan:百川智能

    • 开源了预训练模型和对齐模型,预训练模型是面向开发者的“基座”,而对齐模型则面向广大需要对话功能的普通用户
    • Baichuan2-192K 大模型,上下文窗口长度高达 192 K

LangChain

  1. 目的:构建基于大型语言模型的端到端应用程序或工作流程。为各种大型语言模型应用提供通用接口,从而简化应用程序的开发流程。
  2. 核心板块:
    • 模型输入/输出(Model I/O):与语言模型交互的接口
    • 数据连接(Data connection):与特定应用程序的数据进行交互的接口
    • 链(Chains):将组件组合实现端到端应用。
    • 记忆(Memory):用于链的多次运行之间持久化应用程序状态;
    • 代理(Agents):扩展模型的推理能力。用于复杂的应用的调用序列;
    • 回调(Callbacks):扩展模型的推理能力。用于复杂的应用的调用序列

调用

Prompt/Completion

输入给LLM的文本或问题,接收到的输出是Completion

Temperature:0~1

  1. 用于控制LLM生成文本的随机性与创造性:接近0随机性低,接近1随机性高
  2. 基于不同应用场景需求来设置该参数

System Prompt

  1. 并不在训练时起作用,而是在使用的时候固定影响模型回复,且重要性较高
  2. 一般一个对话中仅有一个
{
    "system prompt":"你是一个幽默风趣的个人知识库助手,可以根据给定的知识库内容回答用户的提问,注意,你的回答风格应是幽默风趣的",
    "user prompt":"我今天有什么事务?"
}

大模型调用

百度文心一言

两层认证

首先需要获取密钥API Key、Secret Key,然后基于密钥获取access_token,利用access_token进行调用

使用Langchain进行调用

需要自定义一个LLM类

定义一个继承自 LLM 类的自定义 LLM 类:

GLM智谱AI+清华

参数说明

  1. prompt (list): 按照 {“role”: “user”, “content”: “你好”} 的键值对形式进行传参; 总长度超过模型最长输入限制后会自动截断,需按时间由旧到新排序。
  2. temperature (float): 采样温度,控制输出的随机性,必须为正数取值范围是:(0.0,1.0],值越小,输出会更加稳定。
  3. top_p (float): 用温度取样的另一种方法,称为核取样。例如:0.1 意味着模型解码器只考虑从前 10% 的概率的候选集中取 tokens。

调用智谱 AI Embedding API

官方的 SDK 返回的结果是字典的格式,可以直接传入键获得值。

基于Langchain封装智谱AI embedding

要实现自定义 Embeddings,需要定义一个自定义类继承自 LangChain 的 Embeddings 基类,然后定义三个函数:

  1. _embed 方法,其接受一个字符串,并返回一个存放 Embeddings 的 List[float],即模型的核心调用;
  2. embed_query 方法,用于对单个字符串(query)进行 embedding。
  3. embed_documents 方法,用于对字符串列表(documents)进行 embedding。
    按照教程来定义一个Embedding模型类继承自Langchain的base类在进行调用就好了

Langchain详解

I/O

用户原始输入与模型和示例进行组合,然后输入给大语言模型,再根据大语言模型的返回结果进行输出或者结构化处理。
L

数据连接

  • 大预言模型的知识来源于其训练数据集,因此缺乏很多最新知识和个性化专业知识
  • LangChain 数据连接(Data connection)模块通过以下方式提供组件来加载、转换、存储和查询数据
    在这里插入图片描述

  • 对于复杂的需求,可能需要将多个大型语言模型进行链式组合,或与其他组件进行链式调用
  • 链允许将多个组件组合在一起
import warnings
warnings.filterwarnings('ignore')

from langchain.chat_models import ChatOpenAI 
from langchain.prompts import ChatPromptTemplate  
from langchain.chains import LLMChain  

# 这里我们将参数temperature设置为0.0,从而减少生成答案的随机性。
# 如果你想要每次得到不一样的有新意的答案,可以尝试调整该参数。
llm = ChatOpenAI(temperature=0.0)  

#初始化提示模版
prompt = ChatPromptTemplate.from_template("描述制造{product}的一个公司的最佳名称是什么?")

#将大语言模型(LLM)和提示(Prompt)组合成链
chain = LLMChain(llm=llm, prompt=prompt)

#运行大语言模型链
product = "大号床单套装"
chain.run(product)

SequentialChain 是简单顺序链的更复杂形式,允许多个输入/输出。

记忆(Meomory)

  • LLM训练好之后参数固定,用户的输入不会影响大模型参数,因此模型输出完毕后,它便会“遗忘”之前用户的输入和它的输出
  • 为了使得模型“有记忆”,使用Memory组件在这里插入图片描述

Agent

语言模型仅依赖预训练数据,与外界“断开”。Agent可以使得它具备计算和获取外界知识的能力。
在这里插入图片描述

回调(Callback)

  1. 可以记录整个流程运行情况,例如Agent模块记录调用Tool的次数以及每次调用返回值
  2. CallbackHandler 用于记录每个应用场景(如 Agent、LLchain 或 Tool )的日志
  3. CallbackManager则封装和管理所有的 CallbackHandler

可以在构造函数或者请求中传入回调

大模型开发

要素

核心点不是对模型的优化,因为大部分是直接调用模型API来实现,因此更多是一个工程问题

核心要点

  1. Prompt Engineering替代子模型的训练调优:用一个通用大模型 + 若干业务 Prompt 来解决任务
  2. 通用架构:特定数据库+ Prompt + 通用大模型(基于langchain)

重要流程:

  1. 搭建整体架构:模型、输入输出
  2. 搭建数据库:将非结构化数据以向量形式存储
  3. prompt engneering
  4. 验证迭代
  5. 搭建前后端

本项目原理

基于本地知识库的大模型开发应用原理(使用Langchain框架)

项目流程:

本地文档 -> 读取文本 -> 文本分割 -> 文本向量化(向量化的文本及其索引会存入数据库) -> question向量化 -> 在文本向量中匹配出与问句向量最相似的 top k个 -> 匹配出的文本作为上下文和问题一起添加到 prompt中 -> 提交给 LLM生成回答。

核心技术

包括 LLM API 调用、向量数据库、检索问答链

最终代码结构

-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层:将不同API进行封装,隐藏API调用差异
  • 数据层:包括个人知识库的源数据和embedding
  • 数据库层:存放向量数据库文件
  • 应用层:基于LangChain的检索问答链,有历史记录或者无历史记录
  • 服务层:通过 Gradio 搭建前端界面与 FastAPI 进行封装,支持多样化的项目调用。

构建项目数据库

加载文档

利用langchain.document_loaders库可以加载pdf、md、mp4文档(使用whisper)

文档分割

代表性分割方法:RecursiveCharacterTextSplitter(): 按字符串分割文本,递归地尝试按不同的分隔符进行分割文本

* RecursiveCharacterTextSplitter 递归字符文本分割
RecursiveCharacterTextSplitter 将按不同的字符递归地分割(按照这个优先级["\n\n", "\n", " ", ""]),
    这样就能尽量把所有和语义相关的内容尽可能长时间地保留在同一位置
RecursiveCharacterTextSplitter需要关注的是4个参数:

* separators - 分隔符字符串数组
* chunk_size - 每个文档的字符数量限制
* chunk_overlap - 两份文档重叠区域的长度:可以保持上下文信息
* length_function - 长度计算函数

文档向量化

  1. Embedding:将文本转化为实数向量
  2. 度量文本相似度的方法:
    • 计算两个向量之间的点积:计算简单,丢失了方向信息。
    • 计算两个向量之间的余弦相似度

向量数据库

构建方法

  1. 可用于高校存储和检索向量数据的数据库习题,主要关注向量数据的相似性
  2. Chroma 轻量级且数据存储在内存中,这使得它非常容易启动和开始使用。
vectordb = Chroma.from_documents(
    documents=split_docs[:100], # 为了速度,只选择了前 100 个切分的 doc 进行生成。
    embedding=embedding,
    persist_directory=persist_directory  # 允许我们将persist_directory目录保存到磁盘上
)
vectordb.persist()	# 持久化向量数据库,以便我们在未来的课程中使用。

通过向量数据库检索

相似度检索
sim_docs = vectordb.similarity_search(question,k=3)
MMR检索

核心思想是在已经选择了一个相关性高的文档之后,再选择一个与已选文档相关性较低但是信息丰富的文档。

构造检索问答链

通过传入语言模型和向量数据库创建一个检索器,使用我呢提查询调用

# 导入检索式问答链
from langchain.chains import RetrievalQA
# 声明一个检索式问答链
qa_chain = RetrievalQA.from_chain_type(
    llm,
    retriever=vectordb.as_retriever()
)
结合prompt进行提问

定义了一个提示模板,包含一些关于如何使用下面的上下文片段的说明,然后有一个上下文变量的占位符。

from langchain.prompts import PromptTemplate

# Build prompt
template = """使用以下上下文片段来回答最后的问题。如果你不知道答案,只需说不知道,不要试图编造答案。答案最多使用三个句子。尽量简明扼要地回答。在回答的最后一定要说"感谢您的提问!"
{context}
问题:{question}
有用的回答:"""
QA_CHAIN_PROMPT = PromptTemplate.from_template(template)

更多文档处理方法如下:
在这里插入图片描述

构建整个项目数据库

  1. 加载知识库里的文档pdf,md,txt
  2. 将文档切片并使用Embedding模型向量化保存到数据库中
  3. 使数据库持久化

Prompt设计

设计技巧

使用分割符表示输入不同部分

选择用 ```,“”",< >, ,: 等做分隔符,只要能明确起到隔断作用即可。
使用分割符可以避免提示词注入:即用户输入的文本可能包含预设prompt冲突的内容

使用结构化输出

照某种格式组织的内容,例如JSON、HTML

prompt = f"""
请生成包括书名、作者和类别的三本虚构的、非真实存在的中文书籍清单,\
并以 JSON 格式提供,其中包含以下键:book_id、title、author、genre。
"""
response = get_completion(prompt)
print(response)

要求模型检查是否满足条件

我们可以告诉模型先检查这些假设,如果不满足,则会指 出并停止执行后续的完整流程

提供少量示例

少样本提示:在模型执行任务之前先给几个满足要求和期望的输出

prompt = f"""
您的任务是以一致的风格回答问题(注意:文言文和白话的区别)。
<学生>: 请教我何为耐心。
<圣贤>: 天生我材必有用,千金散尽还复来。
<学生>: 请教我何为坚持。
<圣贤>: 故不积跬步,无以至千里;不积小流,无以成江海。骑骥一跃,不能十步;驽马十驾,功在不舍。
<学生>: 请教我何为孝顺。
"""
response = get_completion(prompt)
print(response)

给模型时间思考

  1. 指定完成任务所需步骤123
  2. 让模型在下结论之前找出一个自己的解法:先自己做一遍在判断对不对
  3. 模型可能出现幻觉问题

基于问答助手的prompt构建

  1. 加载数据库->根据相似性检验
  2. 构建一个prompt template,创建基于template的检索链
from langchain.chains import RetrievalQA

qa_chain = RetrievalQA.from_chain_type(llm,
                                       retriever=vectordb.as_retriever(),
                                       return_source_documents=True,
                                       chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})# 加上我们的本地知识,就可以帮助 LLM 做出更好的回答
                                      

添加历史对话功能

使用 ConversationBufferMemory ,它保存聊天消息历史记录的列表,这些历史记录将在回答问题时与问题一起传递给聊天机器人,从而将它们添加到上下文中。

原理

将新问题放在之前对话的语境中进行检索,可以处理依赖历史信息的查询。并保留所有信 息在对话记忆中,方便追踪。
在这里插入图片描述

验证迭代

在遇到一些棘手的例子无法通过Prompt或者算法解决时,需要手动将这些添加到测试集合之中,并且对这些小样本集性能进行评估
在这里插入图片描述

根据回答进行评估并更改Prompt

  1. 去冗余
  2. 让模型分点作答
  3. 表明知识来源
  4. 构造思维链:可以让模型对得出的答案进行反思,消除幻觉问题
  5. 添加指令解析:可以避免用户提出的问题被忽略(Agent机制:增加一个LLM来解析指令,然后提问在送入大模型,最后将大模型的输出与解析的指令在送入大模型得到最终答案)

评估方法

人工量化得分

多维度评分

  1. 回答一致性
  2. 知识正确性
  3. 回答正确性
  4. 逻辑性
  5. 通顺性
  6. 智能型

自动评估

构造客观选择题ABCD

让模型选择一个答案,但还是可能输出不止一个文字,这里可以设计一个函数进行解析

计算答案相似度BLEU
  1. 大致思想是主题相似度,相似度越高越好
  2. 它的总体思想就是准确率,假如给定标准译文reference,神经网络生成的句子是candidate,句子长度为n,candidate中有m个单词出现在reference,m/n就是bleu的1-gram的计算公式。
  3. BLEU-1衡量的是单词级别的准确性,更高阶的bleu可以衡量句子的流畅性。
使用大模型评估

将一个模型输出给另一个大模型,同时给它评分规则和知识片段。
这里尽量使用比当前模型性能更好的模型来评分

前后端搭建

项目代码封装以接口形式未部署层提供核心功能(最终版)

LLM封装

由于需要调用不同的大模型,这里首先定义一个自定义的大模型基类,在此基础上对不同大模型区别于基类调用的地方进行重写

数据库构建

  1. 创建一个向量库构建函数,这个函数里面定义一个具有统一接口处理不同格式数据的函数
  2. 定义加载已有数据库的函数

检索问答链

  1. 定义一个LLM映射函数,可以针对传入model参数的不同映射到不同的LLM对象,实现对不同API来源的LLM的切换
  2. 定义两种检索问答链,普通检索的和加入历史问答的

Gradio

搭建前端界面

可以让你从 Python 中通过友好的 Web 界面演示机器学习模型。在

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值