大模型从入门到精通——基于智谱AI和LangChain实现RAG应用(一)

news2024/9/26 21:55:29

基于智谱AI和LangChain实现RAG应用(一)

1. 使用 LangChain 调用智谱 GLM

1.1 自定义chatglm

#!/usr/bin/env python
# -*- encoding: utf-8 -*-

from typing import Any, List, Mapping, Optional, Dict
from langchain_core.callbacks.manager import CallbackManagerForLLMRun
from langchain_core.language_models.llms import LLM
from zhipuai import ZhipuAI

import os

# 继承自 langchain.llms.base.LLM
class ZhipuAILLM(LLM):
    # 默认选用 glm-4
    model: str = "glm-4"
    # 温度系数
    temperature: float = 0.1
    # API_Key
    api_key: str = None
    
    def _call(self, prompt : str, stop: Optional[List[str]] = None,
                run_manager: Optional[CallbackManagerForLLMRun] = None,
                **kwargs: Any):
        client = ZhipuAI(
            api_key = self.api_key
        )

        def gen_glm_params(prompt):
            '''
            构造 GLM 模型请求参数 messages

            请求参数:
                prompt: 对应的用户提示词
            '''
            messages = [{"role": "user", "content": prompt}]
            return messages
        
        messages = gen_glm_params(prompt)
        response = client.chat.completions.create(
            model = self.model,
            messages = messages,
            temperature = self.temperature
        )

        if len(response.choices) > 0:
            return response.choices[0].message.content
        return "generate answer error"


    # 首先定义一个返回默认参数的方法
    @property
    def _default_params(self) -> Dict[str, Any]:
        """获取调用API的默认参数。"""
        normal_params = {
            "temperature": self.temperature,
            }
        # print(type(self.model_kwargs))
        return {**normal_params}

    @property
    def _llm_type(self) -> str:
        return "Zhipu"

    @property
    def _identifying_params(self) -> Mapping[str, Any]:
        """Get the identifying parameters."""
        return {**{"model": self.model}, **self._default_params}
    

定义了一个名为 ZhipuAILLM 的类,它继承自 LLM(这是 LangChain 框架中的一个基类,用于表示语言模型)。该类封装了与智谱AI(ZhipuAI)进行交互的逻辑,主要用于调用智谱AI的 GLM 模型进行文本生成任务。以下是代码的详细解释:

1. 头部注释
#!/usr/bin/env python
# -*- encoding: utf-8 -*-
  • #!/usr/bin/env python:这是 Unix/Linux 脚本的 Shebang,表示这个脚本应该用 python 解释器来运行。
  • # -*- encoding: utf-8 -*-:声明文件使用 UTF-8 编码,确保代码可以处理多语言文本(如中文)。
2. 导入模块
from typing import Any, List, Mapping, Optional, Dict
from langchain_core.callbacks.manager import CallbackManagerForLLMRun
from langchain_core.language_models.llms import LLM
from zhipuai import ZhipuAI

import os
  • typing 模块:提供类型提示(Type Hints)的支持,提升代码的可读性和安全性。
  • langchain_core.callbacks.manager.CallbackManagerForLLMRun:用于管理和追踪语言模型运行时的回调函数。
  • langchain_core.language_models.llms.LLM:LangChain 框架中的 LLM 基类,ZhipuAILLM 继承自这个类。
  • zhipuai.ZhipuAI:智谱AI的客户端,用于与智谱AI的服务进行交互。
3. 定义 ZhipuAILLM
class ZhipuAILLM(LLM):
    model: str = "glm-4"
    temperature: float = 0.1
    api_key: str = None
  • model: 默认模型设为 "glm-4",这代表使用 GLM-4 模型进行推理。
  • temperature: 温度系数,控制生成文本的随机性。较低的值(如 0.1)会使生成的文本更确定性。
  • api_key: 用于身份验证的 API 密钥,必须在实例化时提供。
4. 定义 _call 方法
def _call(self, prompt: str, stop: Optional[List[str]] = None,
          run_manager: Optional[CallbackManagerForLLMRun] = None,
          **kwargs: Any):
    client = ZhipuAI(api_key=self.api_key)

    def gen_glm_params(prompt):
        messages = [{"role": "user", "content": prompt}]
        return messages

    messages = gen_glm_params(prompt)
    response = client.chat.completions.create(
        model=self.model,
        messages=messages,
        temperature=self.temperature
    )

    if len(response.choices) > 0:
        return response.choices[0].message.content
    return "generate answer error"
  • _call 方法:这个方法定义了当你调用语言模型时实际发生的操作。

    • prompt: 用户提供的输入文本。
    • stop: 可选参数,用于指定生成文本的停止条件。
    • run_manager: 可选参数,用于管理模型运行时的回调。
    • **kwargs: 允许传递其他可选参数。
  • client = ZhipuAI(api_key=self.api_key): 创建一个智谱AI的客户端实例。

  • gen_glm_params(prompt):内部函数,用于生成请求参数 messages,其中包含用户的输入提示。

  • messages:构造的请求参数列表。

  • response = client.chat.completions.create(...):向智谱AI发送请求,使用指定模型和参数生成文本。

  • if len(response.choices) > 0:检查生成的响应中是否有内容,如果有,返回生成的文本内容;否则,返回错误信息。

5. 定义 _default_params 属性
@property
def _default_params(self) -> Dict[str, Any]:
    normal_params = {
        "temperature": self.temperature,
    }
    return {**normal_params}
  • _default_params:返回默认的模型参数,例如温度(temperature)。这用于在没有明确指定参数时,提供一些默认值。
6. 定义 _llm_type 属性
@property
def _llm_type(self) -> str:
    return "Zhipu"
  • _llm_type:返回模型的类型标识符,在这里是 "Zhipu",表示这是一个智谱AI的模型。
7. 定义 _identifying_params 属性
@property
def _identifying_params(self) -> Mapping[str, Any]:
    return {**{"model": self.model}, **self._default_params}

_identifying_params:返回一个字典,包含标识模型实例的所有参数,如模型名称和默认参数。这个属性可以用来唯一标识该语言模型实例。

这个类封装了对智谱AI的 GLM 模型的调用,可以用于集成在 LangChain 框架中,执行文本生成任务。主要功能包括:

  • 设置模型类型和参数(如温度系数)。
  • 生成请求参数并与智谱AI的服务进行交互。
  • 返回生成的文本或错误信息。

1.2 接入 langchain

当前涉及到构建相关知识库,参考链接:

大模型入门到精通——使用Embedding API及搭建本地知识库(一)

大模型入门到精通——使用Embedding API及搭建本地知识库(二)

定义ZhipuAIEmbeddings如下:


from __future__ import annotations

import logging
from typing import Dict, List, Any

from langchain.embeddings.base import Embeddings
from langchain.pydantic_v1 import BaseModel, root_validator

logger = logging.getLogger(__name__)

class ZhipuAIEmbeddings(BaseModel, Embeddings):
    """`Zhipuai Embeddings` embedding models."""

    client: Any
    """`zhipuai.ZhipuAI"""

    @root_validator()
    def validate_environment(cls, values: Dict) -> Dict:
        """
        实例化ZhipuAI为values["client"]

        Args:

            values (Dict): 包含配置信息的字典,必须包含 client 的字段.
        Returns:

            values (Dict): 包含配置信息的字典。如果环境中有zhipuai库,则将返回实例化的ZhipuAI类;否则将报错 'ModuleNotFoundError: No module named 'zhipuai''.
        """
        from zhipuai import ZhipuAI
        _ = load_dotenv(find_dotenv())
        api_key = os.environ["API_key"]
        values["client"] = ZhipuAI(api_key=api_key)
        return values
    
    def embed_query(self, text: str) -> List[float]:
        """
        生成输入文本的 embedding.

        Args:
            texts (str): 要生成 embedding 的文本.

        Return:
            embeddings (List[float]): 输入文本的 embedding,一个浮点数值列表.
        """
        embeddings = self.client.embeddings.create(
            model="embedding-2",
            input=text
        )
        return embeddings.data[0].embedding
    
    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        """
        生成输入文本列表的 embedding.
        Args:
            texts (List[str]): 要生成 embedding 的文本列表.

        Returns:
            List[List[float]]: 输入列表中每个文档的 embedding 列表。每个 embedding 都表示为一个浮点值列表。
        """
        return [self.embed_query(text) for text in texts]
    
    
    async def aembed_documents(self, texts: List[str]) -> List[List[float]]:
        """Asynchronous Embed search docs."""
        raise NotImplementedError("Please use `embed_documents`. Official does not support asynchronous requests")

    async def aembed_query(self, text: str) -> List[float]:
        """Asynchronous Embed query text."""
        raise NotImplementedError("Please use `aembed_query`. Official does not support asynchronous requests")
    
def vectorize_text(embeddings_model,chunks):
   
    return embeddings_model.embed_documents(chunks)

from dotenv import find_dotenv, load_dotenv
import os

# 读取本地/项目的环境变量。

# find_dotenv()寻找并定位.env文件的路径
# load_dotenv()读取该.env文件,并将其中的环境变量加载到当前的运行环境中
# 如果你设置的是全局的环境变量,这行代码则没有任何作用。
_ = load_dotenv(find_dotenv())

# 获取环境变量 API_KEY
api_key = os.environ["API_key"] #填写控制台中获取的 APIKey 信息

1. 实例化 ZhipuAILLM 类,并传入参数创建一个模型对象 zhipuai_model
zhipuai_model = ZhipuAILLM(model="glm-4", temperature=0.1, api_key=api_key)

参数解释:

  1. model="glm-4":

    • 指定了使用的模型版本为 "glm-4"。这个参数告诉 ZhipuAILLM 类使用 GLM-4 模型进行推理和生成文本。
    • 你还可以指定其他模型版本(如 "glm-4-0520"),如果模型版本支持不同的特性或更新,这样的配置可以灵活切换不同的模型。
  2. temperature=0.1:

    • 设置生成文本的温度系数(temperature)。温度系数控制生成文本的随机性:
      • 较低的值(如 0.1)意味着生成的文本更具有确定性,输出更加集中于模型认为最可能的结果。
      • 较高的值会增加生成内容的多样性和创造性,但也可能导致结果不太一致。
  3. api_key=api_key:

    • api_key 智谱AI API 密钥
2. 调用如下
zhipuai_model("你好,请你自我介绍一下!")
zhipuai_model("请介绍一下百度网站")

在这里插入图片描述

2. 构建检索问答链

2.1 加载向量数据库

  • 配置系统路径以导入模块。
  • 从环境变量中读取智谱AI API 密钥。
  • 定义用于生成文本嵌入的对象。
  • 设置向量数据库的保存路径。
  • 加载并实例化向量数据库,用于存储和检索嵌入向量。
## 加载向量数据库
import sys
sys.path.append("./data_base/vector_db/chroma") # 将父目录放入系统路径中
# 使用智谱 Embedding API,注意,需要将上一章实现的封装代码下载到本地
from langchain.vectorstores.chroma import Chroma
from dotenv import load_dotenv, find_dotenv
import os

_ = load_dotenv(find_dotenv())    # read local .env file
zhipuai_api_key = os.environ['API_key']
# 定义 Embeddings
embedding = ZhipuAIEmbeddings()

# 向量数据库持久化路径
persist_directory = './data_base/vector_db/chroma'

# 加载数据库
vectordb = Chroma(
    persist_directory=persist_directory,  # 允许我们将persist_directory目录保存到磁盘上
    embedding_function=embedding
)


print(f"向量库中存储的数量:{vectordb._collection.count()}")

question = "什么是prompt engineering?"
docs = vectordb.similarity_search(question,k=3)
print(f"检索到的内容数:{len(docs)}")

for i, doc in enumerate(docs):
    print(f"检索到的第{i}个内容: \n {doc.page_content}", end="\n-----------------------------------------------------\n")

在这里插入图片描述

2.2 创建LLM

import os 
OPENAI_API_KEY = os.environ["API_key"]

zhipuai_model = ZhipuAILLM(model = "glm-4", temperature = 0.1, api_key = api_key)  
zhipuai_model.invoke("请你介绍一下自己")

2.3 构建检索问答链

1. 提示模版定义

通过插入特定的上下文和问题来生成提示,适用于自然语言处理模型。它确保模型生成的回答简洁明确,并在回答结束时添加

from langchain.prompts import PromptTemplate

template = """使用以下上下文来回答最后的问题。如果你不知道答案,就说你不知道,不要试图编造答
案。最多使用三句话。尽量使答案简明扼要。总是在回答的最后说“谢谢你的提问!”。
{context}
问题: {question}
"""

QA_CHAIN_PROMPT = PromptTemplate(input_variables=["context","question"],
                                 template=template)
2. 构建检索问答链
  1. 问题输入: 用户提出一个问题。
  2. 文档检索: 使用向量数据库检索与问题相关的文档或上下文。
  3. 答案生成: 智谱AI模型根据检索到的上下文生成简明的答案,遵循提供的提示模板。
  4. 返回结果: 返回生成的答案和用于生成答案的源文档(如果启用了 return_source_documents)。

RetrievalQA.from_chain_type 构建检索问答链

from langchain.chains import RetrievalQA

qa_chain = RetrievalQA.from_chain_type(zhipuai_model,
                                       retriever=vectordb.as_retriever(),
                                       return_source_documents=True,
                                       chain_type_kwargs={"prompt":QA_CHAIN_PROMPT})

3. 问答链测试
  • 定义问题

question_1 = "什么是南瓜书?"
question_2 = "王阳明是谁?"


1. 大模型+知识库
  • 打印回答1
result = qa_chain({"query": question_1})
print("大模型+知识库后回答 question_1 的结果:")
print(result["result"])
  • 打印回答2
result = qa_chain({"query": question_2})
print("大模型+知识库后回答 question_2 的结果:")
print(result["result"])

在这里插入图片描述

2. 大模型回复
  • 打印回答1
prompt_template = """请回答下列问题:
                            {}""".format(question_1)

### 基于大模型的问答
zhipuai_model.predict(prompt_template)

  • 打印回答2
prompt_template = """请回答下列问题:
                            {}""".format(question_2)

### 基于大模型的问答
zhipuai_model.predict(prompt_template)

在这里插入图片描述

2.4 添加记忆功能

question = "为什么这门课需要教这方面的知识?"
result = qa({"question": question})
print(result['answer'])

在这里插入图片描述

实现一个对话式的检索问答链,其中结合了智谱AI模型、向量数据库和会话记忆来处理连续的问题。

1. 导入必要的模块
from langchain.chains import ConversationalRetrievalChain
from langchain.memory import ConversationBufferMemory
  • ConversationalRetrievalChain: 用于创建一个支持多轮对话的检索问答链。与标准的检索问答链不同,它能够保持上下文,并在多轮对话中使用之前的对话历史。
  • ConversationBufferMemory: 提供了会话记忆功能,能够保存对话的历史记录,从而在对话过程中引用之前的内容。
2. 创建会话记忆 memory
memory = ConversationBufferMemory(
    memory_key="chat_history",
    return_messages=True
)
  • memory_key="chat_history": 定义用于存储对话历史的键名,与后续提示模板中的变量名保持一致,以便在生成答案时能够引用这些历史记录。
  • return_messages=True: 指定返回的对话历史记录将以消息列表的形式返回,而不是作为一个单一的字符串。这对于在多轮对话中保留消息的顺序和内容非常有用。
3. 创建检索器 retriever
retriever = vectordb.as_retriever()
  • vectordb.as_retriever(): 使用之前加载的向量数据库 vectordb 生成一个检索器对象。这个检索器负责从数据库中检索与当前问题相关的内容。
4. 创建对话检索问答链 qa
qa = ConversationalRetrievalChain.from_llm(
    zhipuai_model,
    retriever=retriever,
    memory=memory
)
  • ConversationalRetrievalChain.from_llm: 这是一个工厂方法,用于创建一个对话式检索问答链实例。
    • zhipuai_model: 使用的语言模型对象(之前实例化的 ZhipuAILLM)。
    • retriever=retriever: 使用的检索器对象,用于从向量数据库中检索相关信息。
    • memory=memory: 会话记忆对象,保存并管理对话的历史记录,使得模型能够在多轮对话中使用上下文信息生成更连贯的回答。
5. 处理第一个问题
question = "我可以学习到关于提示工程的知识吗?"
result = qa({"question": question})
print(result['answer'])
  • question: 第一个问题,询问关于“提示工程”的知识。
  • qa({"question": question}): 将问题传递给问答链进行处理。问答链会通过以下步骤生成答案:
    1. 检索与问题相关的文档或内容。
    2. 使用模型生成一个基于检索内容的回答。
    3. 利用会话记忆引用之前的对话(如果有)。
  • print(result['answer']): 输出模型生成的答案。
6. 处理第二个问题
question = "为什么这门课需要教这方面的知识?"
result = qa({"question": question})
print(result['answer'])
  • question: 第二个问题,询问为什么课程需要教授“提示工程”相关的知识。
  • 由于对话记忆功能的存在,模型能够引用之前的对话上下文来生成更准确和连贯的回答。

参考

https://datawhalechina.github.io/llm-universe/#/C4/2.构建检索问答链?id=_2-创建一个-llm

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2077279.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

统一身份认证服务(CAS)系统实现SSO认识

一、前言 CAS(Central Authentication Service)即中央认证服务,是 Yale 大学发起的一个企业级开源项目,旨在为 Web 应用系统提供一种可靠的 SSO 解决方案,它是一个企业级的开源单点认证登录解决方案,采用ja…

netty编程之UDP

写在前面 源码 。 UDP,user datagram protocol,是internet协议簇中无连接的传输协议,因为无连接所以相比于TCP需要维护更少的信息以及网络交互,所以具有更高的效率。本文看下netty是如何实现的,和TCP方式差别不大,下面…

【宝马中国-注册/登录安全分析报告】

前言 由于网站注册入口容易被黑客攻击,存在如下安全问题: 暴力破解密码,造成用户信息泄露短信盗刷的安全问题,影响业务及导致用户投诉带来经济损失,尤其是后付费客户,风险巨大,造成亏损无底洞…

Java使用EasyExcel导出图片(原比例大小)到Excel中

EasyExcel导出图片 又开始写Excel导出的需求了,哈哈哈…… 目前的需求是将图表分析对的饼图和折线图,也就是一张完整的图片单独导出到Excel中 为了方便客户在业务报告时,可以使用数据分析图片,从而更清晰准确地展示数据趋势 因…

【C++学习笔记】数据类型与运算符(一)

目录 一、常量与变量 1.1 常量 字面常量 符号常量 1.2 变量 1.3 标识符命名规范 二、数据类型 2.1 整型 2.2 实型(浮点型) 2.3 字符型 2.4 字符串 2.5 布尔型 三、cin控制台输入 3.1 输入代码 3.2 解决输入中文乱码 四、运算符 4.1 算术…

OpenCV杂项图像变换(1)自适应阈值处理函数adaptiveThreshold()的使用

操作系统:ubuntu22.04 OpenCV版本:OpenCV4.9 IDE:Visual Studio Code 编程语言:C11 算法描述 函数对数组应用自适应阈值。 该函数根据以下公式将灰度图像转换为二值图像: 对于 THRESH_BINARY: t e x t d s t ( x , y ) { maxV…

# NLP-transformer学习:(5)Bert 实战

NLP-transformer学习:(5)模型训练和预测 基于 NLP-transformer学习:(2,3,4),这里对transformer 更近一步,学习尝试使用其中的bert 文章目录 NLP-transformer学习:&#x…

在 Debian 上安装 IntelliJ IDEA 笔记

在 Debian💩 上安装 IntelliJ IDEA 💡 笔记 下载安装 JDK17安装 IntelliJ IDEA Community添加创建桌面启动项(快捷方式) 参考资料 下载 两个包已经下好了,一个JDK17,一个IntelliJ IDEA Community 使用 wge…

【Liunx入门】Liunx软件包管理器

文章目录 前言一、什么是软件包二、网络相关指令三、Ubuntu包管理软件apt1.查看软件包2.sudo权限3.软件安装4.卸载软件5.软件更新6.升级软件包 总结 前言 Linux软件包管理器是Linux系统中用于安装、升级和卸载软件包的工具。它们提供了一个方便的方式来管理软件包,…

c++习题25-大整数加法

目录 一,题目 二,思路 三,代码 一,题目 描述 求两个不超过200位的非负整数的和。 输入 有两行,每行是一个不超过200位的非负整数,可能有多余的前导0。 输出 一行,即相加后的结果。结果里不…

Physics of Language Models学习小结

1.概述 Physics of Language Models 参考:https://zhuanlan.zhihu.com/p/711391378 这是一系列论文和一个新的LLM研究方向,官网的概述如下。 苹果掉落,盒子移动,但重力和惯性等普遍规律对技术进步至关重要。虽然GPT-5或LLaMA-…

Threejs学习-三维坐标系、相机控件

坐标系: Three.js 使用的是右手坐标系,x 轴朝右,y 轴朝上,z 轴朝向自己。 相机控件轨道控制器 相机控件OrbitControls 通过相机控件OrbitControls实现旋转缩放预览效果。 // 设置相机控件轨道控制器OrbitControls const contr…

fastjson漏洞分析与复现

一、基础知识 Fastjson介绍: fastjson是阿里巴巴开源的JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。即fastjson的主要功能就是将Java Bean序列化成JSON字…

IDEA插件支持API调试、接口用例支持一键同步API变更,MeterSphere开源持续测试工具v3.2.0版本发布

2024年8月26日,MeterSphere开源持续测试工具正式发布v3.2.0版本。 在这一版本中,接口测试方面,MeterSphere API Debugger插件支持API调试,接口用例支持一键同步API变更;测试管理方面,在“测试用例”模块中…

牛客笔试训练

牛客.过桥 在函数 public static int n;public static int[]arrnew int[2001];public static int bfs(){int left1;int right1;int ret0;while(left<right){ret;int rright;for(int ileft;i<right;i){rMath.max(r,arr[i]i);if(r>n){return ret;}}leftright1;rightr;}…

网络原理 TCP与UDP协议

博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 关注博主带你了解更多数据结构知识 1.应用层 之前编写完了基本的 java socket &#xff0c;要知道&#xff0c;我们之前所写的所有代码都在应⽤层&#xff0c;都是为了 完成某项…

关键点检测——HRNet源码解析篇

&#x1f34a;作者简介&#xff1a;秃头小苏&#xff0c;致力于用最通俗的语言描述问题 &#x1f34a;专栏推荐&#xff1a;深度学习网络原理与实战 &#x1f34a;近期目标&#xff1a;写好专栏的每一篇文章 &#x1f34a;支持小苏&#xff1a;点赞&#x1f44d;&#x1f3fc;、…

linux下部署数据库总结

数据库 数据库主要分为两大类&#xff1a;关系型数据库与 NoSQL 数据库 关系型数据库&#xff0c;是建立在关系模型基础上的数据库&#xff0c;其借助于集合代数等数学概念和方法来处理数据库 中的数据主流的 MySQL、Oracle、MS SQL Server 和 DB2 都属于这类传统数据库。 NoSQ…

JVM理论篇(一)

一、类加载子系统 1.1 类加载子系统作用 类加载子系统负责从文件系统或者网络中加载Class文件&#xff0c;Class文件在文件开头有特定的文件标识。(CAFEBABE)ClassLoader只负责class文件的加载&#xff0c;至于它是否可以运行&#xff0c;则由Execution Engine 执行引擎决定。…

Spire.PDF for .NET【文档操作】演示:创建标记的 PDF 文档

带标签的 PDF&#xff08;也称为 PDF/UA&#xff09;是一种包含底层标签树&#xff08;类似于 HTML&#xff09;的 PDF&#xff0c;用于定义文档的结构。这些标签可以帮助屏幕阅读器浏览整个文档而不会丢失任何信息。本文介绍如何使用Spire.PDF for .NET在 C# 和 VB.NET 中从头…