02-用LangChain开发Q&A助手 | 豆包MarsCode AI刷题

236 阅读2分钟

本文记录了在学习02_文档QA系统的环境配置、知识点和重点

环境配置

  • MarsCode中给定的部分包已经deprecated,需要换成新包
# from langchain.document_loaders import PyPDFLoader
# from langchain.document_loaders import Docx2txtLoader
# from langchain.document_loaders import TextLoader
from langchain_community.document_loaders import PyPDFLoader
from langchain_community.document_loaders import Docx2txtLoader
from langchain_community.document_loaders import TextLoader
# from langchain.pydantic_v1 import BaseModel
from pydantic import BaseModel
  • 环境变量配置(使用doubao大模型)
os.environ["OPENAI_API_KEY"] = 'xxx' # 模型api_key
os.environ["OPENAI_BASE_URL"] = 'xxx' # 调用服务器base_url
os.environ["EMBEDDING_MODELEND"] = 'xxx' # 嵌入模型的endpoint

项目框架

image.png

  1. 加载文档:分别使用PyPDFLoader、Docx2txtLoader、TextLoader加载pdf、docx、txt格式的文件,读取其中的文本内容,以list格式存在documents中
  2. 文档切割:将文本按照chunk_size、chunk_overlap进行划分
  3. 转向量存储:文本转向量,存储到向量数据库,这一步用到embedding模型
  4. 设计RetrievalQA链,包括LLM(负责Answer),retriever(负责从vector DB中找相关嵌入片,随问题一起传入LLM)

重点

  • 为什么在分割文本块时要设置overlap:
  1. 保留上下文信息
  2. 减少边界重点信息的丢失
  • retriever如何提取和提问最相关的嵌入片(向量之间如何比较)
  1. 比较向量的方式主要有两种:欧式距离余弦相似度
  2. 欧式距离:两个向量在多维空间之间的直线距离,即两个向量在各个维度差的平方和的平方根。适合需要关注实际距离的比较场景。
  3. 余弦相似度:更关注向量的方向,而不是它们的大小。即使两个向量的长度不同,只要它们的方向相似,余弦相似度也会很高。适合于文本处理等需要关注语义的场景,比如判断两个文本的相似度
  • 如何用doubao-embedding模型进行向量分析
  1. 创建一个新的模型推理点
  2. 选择Doubao-embedding|text-240715模型
  3. 将模型endpoint配置到环境变量中
os.environ["EMBEDDING_MODELEND"] = 'xxx'
  1. 通过将chunk_documents通过embedding-model转化为向量集,存储到Qdrant DB
vectorstore = Qdrant.from_documents(
    documents=chunked_documents,  # 以分块的文档
    embedding=DoubaoEmbeddings(
        model=os.environ["EMBEDDING_MODELEND"],
    ),  # 用Doubao的Embedding Model做嵌入
    location=":memory:",  # in-memory 存储
    collection_name="my_documents",
)  # 指定collection_name
  1. 要创建一个新类DoubaoEmbeddings,指明调用模型的key和base_url,以及query方法
class DoubaoEmbeddings(BaseModel, Embeddings):
    client: Ark = None
    api_key: str = ""
    model: str

    def __init__(self, **data: Any):
        super().__init__(**data)
        if self.api_key == "":
            self.api_key = os.environ["OPENAI_API_KEY"]
        self.client = Ark(
            base_url=os.environ["OPENAI_BASE_URL"],
            api_key=self.api_key
        )

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

    def embed_documents(self, texts: List[str]) -> List[List[float]]:
        return [self.embed_query(text) for text in texts]

    class Config:
        arbitrary_types_allowed = True