大模型agent开发之基于知识库的聊天机器人

1. 文本知识库的加载和分割

实现一个智能文档助手,基于已有知识库给向ai发起提问使ai能够基于知识库回答更加准确的答案,首先需要加载对应的文档,文档类型可以是docx,xlsx,md等格式。并且对文档进行分割,将其分割成一块一块的Document类型并转成list类型方便后续处理。

    def getFile(self):
        print(f"Attempting to load document: {self.doc}")
        doc = self.doc
        loaders = {
            "docx": Docx2txtLoader,
            "pdf": PyPDFLoader,
            "excel": UnstructuredExcelLoader
        }
        file_extension = doc.split(".")[-1]
        loader_class = loaders.get(file_extension)

        if loader_class:
            try:
                print(f"Using loader: {loader_class.__name__}")
                loader = loader_class(doc)
                text = loader.load()
                print("Loaded text:", text)

                # 处理返回的 text 是 list 但内容是 Document 类型的情况
                if isinstance(text, list):
                    processed_text = []
                    for t in text:
                        if isinstance(t, Document):
                            processed_text.append(t)
                        else:
                            print(f"Unknown object type in list: {type(t)}")
                    return processed_text
                elif isinstance(text, str):
                    return [text]
                else:
                    raise ValueError("Loaded content is neither string nor list of strings.")
            except Exception as e:
                print(f"Error loading {file_extension} file: {e}")
                print(f"Document path: {doc}")
                return None
        else:
            print(f"Unsupported file extension: {file_extension}")
            return None

2. 文档向量化存储

将上述切割好的文档保存在类实例‘splitText’中选择‘all-MiniLM-L6-v2’文本嵌入模型,这是一种轻量级小模型。根据该模型对列表中的每个文本块进行向量化处理,然后通过Chroma向量化数据库保存生成的向量。

    # 向量化与向量存储
    def embeddingAndVectorDB(self):
        # 确保 self.splitText 不为空
        if not self.splitText or len(self.splitText) == 0:
            raise ValueError("Document list is empty. Please provide valid documents.")

        # 使用本地的预训练模型,如 'all-MiniLM-L6-v2'
        embedding_model = LocalEmbedding('sentence-transformers/all-MiniLM-L6-v2')
        page_texts = []
        for t in self.splitText:
            page_texts.append(t.page_content)
        print(f"page: {page_texts}")
        # 生成嵌入
        embeddings = embedding_model.embed_documents(page_texts)
        if not embeddings or len(embeddings) != len(page_texts):
            raise ValueError("Mismatch between document count and embedding count.")

        # 打印调试信息
        print(f"Documents: {self.splitText}")
        print(f"Embeddings: {embeddings}")

        # 使用 Chroma 存储这些向量
        db = Chroma.from_texts(
            texts=page_texts,  # 文档列表
            embedding=embedding_model  # 传入自定义的嵌入模型
        )

        return db

 3. 索引并使用自然语言找出相关文本块

在本模块中首先获取到向量数据库并与传入的问题一起根据余弦相似度算法计算出评分最高的文本块,并将文本块返回。

    # 提问并找到相关文本块(在向量存储时使用最大边际相似性和相似性打分)
    def askAndFindFiles(self, question):
        db = self.embeddingAndVectorDB()
        print(f"Vector DB created: {db}")  # 确保数据库创建成功
        retriever = db.as_retriever(search_type="similarity_score_threshold",
                                    search_kwargs={"score_threshold": 0.1, "k": 1})
        context = retriever.invoke(input=question)
        print(f"Retrieved documents: {context}")  # 确保检索到内容
        return context

4. 开始和文件聊天

首先需要传入知识库文本地址,然后引用获取问题的接口,该接口回将与问题相关的文本块返回来,然后将文本块拼接好传入到本地大模型中作为提示词。

# 和文本机器人聊天
def chatWithyl(question):
    _content = ""
    context = chat_yl.askAndFindFiles(question)
    for i in context:
        _content += i.page_content
    msgs = chat_yl.prompts.format_messages(context=_content, question=question)
    print(msgs)
    response = llm(msgs)
    print(f"answer: {response}")

最后运行向大模型提出某一领域问题,即可得到相关的答案。

posted @ 2024-10-21 20:09  我刀呢?  阅读(8)  评论(0编辑  收藏  举报