Press "Enter" to skip to content

面向文档的代理 使用向量数据库、LLMs、Langchain、FastAPI和Docker的旅程

利用ChromaDB、Langchain和ChatGPT:从大型文档数据库中增强响应和引用来源

介绍

面向文档的代理正开始在商业领域获得关注。公司越来越多地利用这些工具来利用内部文档,增强业务流程。一份最近的麦肯锡报告 [1] 强调了这一趋势,指出生成式人工智能每年可能为全球经济增加2.6-4.4万亿美元,并自动化当前工作活动的70%。该研究确定了客户服务、销售和市场营销以及软件开发作为将受到转变影响的主要行业。大部分变革源于公司内部支撑这些领域的信息可以通过使用文档导向代理等解决方案更容易地为员工和客户所访问。

尽管目前的技术已经取得了一些进展,但仍然面临一些挑战。即使考虑到具有10万令牌限制的新型大型语言模型 (LLMs),这些模型仍然具有有限的上下文窗口。虽然10万个令牌似乎是一个很大的数字,但当我们看到支撑客户服务部门的数据库规模时,它只是一个微小的数字。另一个经常出现的问题是模型输出的不准确性。在本文中,我们将提供一步一步构建一个可以处理任意大小文档并提供可验证答案的文档导向代理的指南。

我们使用向量数据库ChromaDB来增强我们的模型上下文长度能力,并使用Langchain来促进我们架构中不同组件之间的集成。作为我们的LLM,我们使用OpenAI的ChatGPT。由于我们想要为我们的应用提供服务,我们使用FastAPI为用户创建交互端点与我们的代理进行交互。最后,我们的应用使用Docker进行容器化,这使我们能够轻松地在任何环境中部署它。

图1:AI代理每天都在变得更加智能(图片来源)

代码如往常一样可以在我的Github上找到。

向量数据库:语义搜索应用的核心关键

向量数据库是释放生成式人工智能潜力的关键。这些类型的数据库被优化用于处理向量嵌入-包含原始数据丰富语义信息的数据表示。与传统的标量数据库不同,后者在处理向量嵌入的复杂性上存在问题,而向量数据库对这些嵌入进行索引,将其与其源内容关联起来,并支持高级功能,如语义信息检索和AI应用的长期记忆。

向量数据库与向量索引(如Facebook的AI相似性搜索 (FAISS))并不相同-我们在本系列的先前文章中已经介绍过 [2]。它们允许数据插入、删除和更新,存储关联的元数据,并支持实时数据更新而无需进行完全重新索引-这是一个耗时且计算成本高昂的过程。

与精确匹配不同,向量数据库使用相似性度量来寻找最接近查询的向量。它们使用近似最近邻 (ANN) 搜索算法进行优化搜索。这些算法可以压缩原始向量,加速查询过程。此外,余弦相似度、欧氏距离和点积等相似度度量可以比较并识别与查询最相关的结果。

图2简洁地说明了向量数据库中的相似性搜索过程。从原始文档的摄入开始 (i),数据被分成可管理的块 (ii),并转换为向量嵌入 (iii)。这些嵌入被索引以便快速检索 (iv),并计算块向量与用户查询之间的相似性度量 (v)。最终,输出与原始查询一致的最相关数据块 (vi) ,为用户提供对应的见解。

图2:相似性搜索过程:i) 原始文档的摄入,ii) 划分成块,iii) 嵌入的创建,iv) 索引,v) 相似性度量计算和最后,vi) 输出的块(图片来自作者)

构建一个面向文档的代理

我们首先在服务器启动时加载所有必要的模型和数据。

我们从预定义的目录中加载数据,并将其处理成可管理的块。这些块的大小设计得足够小,以便在从相似性搜索过程中获得结果后将它们传递给LLM。这个过程利用了DirectoryLoader将文档加载到内存中,并利用RecursiveCharacterTextSplitter将它们拆分成可管理的块。它以字符级别进行拆分,具有默认的块大小为1000个字符和块重叠为20个字符。块重叠确保块之间存在上下文连续性,最大限度地减少了在块边界丢失有意义上下文的风险。

def load_docs(directory: str):    """    从给定目录加载文档。    """    loader = DirectoryLoader(directory)    documents = loader.load()    return documentsdef split_docs(documents, chunk_size=1000, chunk_overlap=20):    """    将文档分成块。    """    text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size, chunk_overlap=chunk_overlap)    docs = text_splitter.split_documents(documents)    return docs

接下来,我们使用SentenceTransformerEmbeddings方法从这些块生成向量嵌入,并将它们索引到ChromaDB,我们的向量数据库中。这些嵌入被存储在数据库中,并作为我们的可搜索数据。数据库不在内存中存储;请注意我们将其持久化在磁盘上,这减少了我们的内存开销。然后,我们加载聊天模型,具体来说是OpenAI的gpt-3.5-turbo,它作为我们的LLM。

@app.on_event("startup")async def startup_event():    """    服务器启动时加载所有必要的模型和数据。    """    app.directory = '/app/content/'    app.documents = load_docs(app.directory)    app.docs = split_docs(app.documents)    app.embeddings = SentenceTransformerEmbeddings(model_name="all-MiniLM-L6-v2")    app.persist_directory = "chroma_db"    app.vectordb = Chroma.from_documents(        documents=app.docs,        embedding=app.embeddings,        persist_directory=app.persist_directory    )    app.vectordb.persist()    app.model_name = "gpt-3.5-turbo"    app.llm = ChatOpenAI(model_name=app.model_name)    app.db = Chroma.from_documents(app.docs, app.embeddings)    app.chain = load_qa_chain(app.llm, chain_type="stuff", verbose=True)

最后,“/query/{question}”端点接收用户查询。它在数据库上运行相似性搜索,使用问题作为输入。如果存在匹配的文档,则将它们输入到LLM中生成答案。答案和来源(原始文档及其元数据)将被返回,以确保提供的信息易于验证。

@app.get("/query/{question}")async def query_chain(question: str):    """    使用给定的问题查询模型并返回答案。    """    matching_docs_score = app.db.similarity_search_with_score(question)    if len(matching_docs_score) == 0:        raise HTTPException(status_code=404, detail="未找到匹配的文档")    matching_docs = [doc for doc, score in matching_docs_score]    answer = app.chain.run(input_documents=matching_docs, question=question)    # 准备来源    sources = [{        "content": doc.page_content,        "metadata": doc.metadata,        "score": score    } for doc, score in matching_docs_score]    return {"answer": answer, "sources": sources}

我们使用Docker将应用程序容器化,这确保了无论部署平台如何,都能保持隔离和环境一致性。以下是我们的Dockerfile设置的详细信息:

FROM python:3.9-busterWORKDIR /appCOPY . /appRUN pip install - no-cache-dir -r requirements.txtEXPOSE 1010CMD ["uvicorn", "main:app", " - host", "0.0.0.0", " - port", "1010"]

应用程序在Python 3.9环境中运行,我们需要从requirements.txt文件安装所有必要的依赖项:

langchain==0.0.221uvicorn==0.22.0fastapi==0.99.1unstructured==0.7.12sentence-transformers==2.2.2chromadb==0.3.26openai==0.27.8python-dotenv==1.0.0

然后通过Uvicorn在端口1010上提供应用程序。

请注意,我们需要配置环境变量。我们的应用程序需要ChatOpenAI模型的OPENAI_API_KEY。对于像API密钥这样的敏感信息,最佳做法是将其存储为环境变量,而不是硬编码到应用程序中。我们使用python-dotenv包从项目根目录的.env文件中加载环境变量。在生产环境中,我们希望使用更安全的方法,例如Docker secrets或安全的保险库服务。

实验:理解面向文档的代理的有效性

实验的主要目标是评估我们的面向文档的代理在为用户查询提供全面准确的响应方面的有效性。

我们使用一系列VoAGI文章作为我们的知识库。这些文章涵盖了各种人工智能和机器学习主题,并在我们的Chroma向量数据库中进行了摄取和索引。所选文章包括:

  1. “Whisper JAX vs PyTorch:揭示GPU上的ASR性能真相”
  2. “测试支持1162种语言的大规模多语言语音(MMS)模型”
  3. “利用猎鹰40B模型,最强大的开源LLM”
  4. “OpenAI的函数调用在语言学习模型中的力量:全面指南”

这些文章被分成可管理的块,转换为向量嵌入,并在我们的数据库中进行了索引,从而构成了代理的知识基础。

用户查询通过调用我们应用程序的API端点来执行,该端点使用FastAPI实现,并通过Docker部署。我们在实验中使用的查询是:“Falcon-40b是什么,我可以用它进行商业用途吗?”。

curl --location 'http://0.0.0.0:1010/query/What is Falcon-40b and can I use it for commercial use'

作为对我们查询的响应,LLM解释了Falcon-40b是什么,并确认它可以用于商业用途。这些信息由四个不同的源块支持,所有这些源块均来自文章:“利用猎鹰40B模型,最强大的开源LLM”。正如我们上面所看到的,每个源块也被添加到响应中,以便用户可以验证支持LLM答案的原始文本。这些块还根据它们与查询的相关性进行了评分,这为我们提供了对该部分对代理整体答案的重要性的额外视角。

{    "answer": "Falcon-40B是由技术创新研究所(TII)开发的最先进的语言模型。它是基于Transformer的模型,在各种语言理解任务上表现良好。Falcon-40B的重要性在于,根据TII的公告,它现在可以免费用于商业和研究用途。这意味着开发人员和研究人员可以根据自己的特定需求访问和修改模型,而无需支付任何版税。然而,需要注意的是,尽管Falcon-40B可以用于商业用途,但它仍然是在网络数据上进行训练的,可能存在潜在的偏见和在线流行的刻板印象。因此,在生产环境中使用Falcon-40B时,应采取适当的缓解策略。",    "sources": [        {            "content": "这就是Falcon-40B的重要性所在。上周末,技术创新研究所(TII)宣布Falcon-40B现在可以免费用于商业和研究用途,没有版税的限制。因此,它打破了专有模型的障碍,为开发人员和研究人员提供了免费访问最先进的语言模型的机会,他们可以根据自己的特定需求使用和修改。\n\n此外,Falcon-40B模型现在是OpenLLM排行榜上表现最好的模型,超过了LLaMA、StableLM、RedPajama和MPT等模型。该排行榜旨在跟踪、排名和评估各种LLM和聊天机器人的性能,提供明确、公正的能力度量标准。图1:Falcon-40B在OpenLLM排行榜上占据主导地位(图片来源)\n\n代码如常在我的Github上可用。Falcon LLM是如何开发的?",            "metadata": {                "source": "/app/content/Harnessing the Falcon 40B Model, the Most Powerful Open-Source LLM.txt"            },            "score": 1.045290231704712        },        {            "content": "Falcon-40B中的解码器块采用并行的注意力/MLP(多层感知器)设计,并具有两层归一化。这种结构在模型的扩展性和计算速度方面具有优势。注意力和MLP层的并行化提高了模型同时处理大量数据的能力,从而减少了训练时间。此外,两层归一化的实现有助于稳定学习过程,并减轻与内部协变量转移相关的问题,从而实现了更强大和可靠的模型。使用Falcon-40B-Instruct实现聊天功能\n\n我们正在使用Falcon-40B-Instruct,这是Falcon-40B的新变体。它基本上是相同的模型,但在Baize的混合上进行了微调。Baize是一个使用LoRA进行训练的开源聊天模型的低秩适应。Baize使用100,000个ChatGPT与自己对话以及Alpaca的数据来改善其性能。",            "metadata": {                "source": "/app/content/Harnessing the Falcon 40B Model, the Most Powerful Open-Source LLM.txt"            },            "score": 1.319214940071106        },        {            "content": "Falcon开发的核心差异之一是训练数据的质量。Falcon的预训练数据大小约为五万亿个标记,来自公共网络爬行、研究论文和社交媒体对话。由于LLM对其训练数据特别敏感,团队建立了一个定制的数据流水线,使用广泛的过滤和去重技术从预训练数据中提取高质量的数据。\n\n该模型本身在AWS上使用384个GPU进行了两个月的训练。结果是一个超越了GPT-3的LLM,仅需75%的训练计算预算和五分之一的推断时间计算。",            "metadata": {                "source": "/app/content/Harnessing the Falcon 40B Model, the Most Powerful Open-Source LLM.txt"            },            "score": 1.3254718780517578        },        {            "content": "Falcon-40B主要以英语为中心,但还包括德语、西班牙语、法语、意大利语、葡萄牙语、波兰语、荷兰语、罗马尼亚语、捷克语和瑞典语的语言能力。请注意,与在网络数据上训练的任何模型一样,它存在反映在线偏见和刻板印象的潜在风险。因此,请在使用Falcon-40B进行生产环境中时充分评估这些风险,并实施适当的缓解策略。模型架构和目标\n\n作为基于Transformer的模型家族的一员,Falcon-40B遵循因果语言建模任务,其目标是预测标记序列中的下一个标记。其架构基本上是在GPT-3 [1]的设计原则基础上进行的一些重要调整。",            "metadata": {                "source": "/app/content/Harnessing the Falcon 40B Model, the Most Powerful Open-Source LLM.txt"            },            "score": 1.3283030986785889        }    ]}

结论

在本文中,我们构建了一个解决AI系统中处理大规模文档挑战的解决方案,利用向量数据库和一套开源工具。我们的方法使用ChromaDB和Langchain与OpenAI的ChatGPT来构建一个功能强大的面向文档的代理。

我们的方法使代理能够通过搜索和处理大规模数据库中的文本块来回答复杂的查询 —— 在我们的案例中,是一系列关于各种AI主题的VoAGI文章。除了代理的答案,我们还返回了用于支持LLM主张的原始文档的文本块以及它们与用户查询的相似度得分。这是一个重要的特性,因为这些代理有时会提供不准确的信息。

大型语言模型编年史:航行自然语言处理的前沿

本文属于“大型语言模型编年史:航行自然语言处理的前沿”,这是一系列新的每周文章,将探索如何利用大模型的强大能力进行各种自然语言处理任务。通过深入研究这些尖端技术,我们旨在赋予开发人员、研究人员和爱好者利用自然语言处理的潜力并开启新的可能性。

目前已发布的文章:

  1. 使用ChatGPT总结最新的Spotify发布
  2. 使用FAISS和Sentence Transformers以闪电般的推理速度对数百万个文档进行语义搜索
  3. 利用Whisper、WhisperX和PyAnnotate解锁音频数据的力量:高级转录和语音分段
  4. Whisper JAX与PyTorch对比:揭示在GPU上进行ASR性能的真相
  5. 高效企业级语音识别的Vosk评估和实施指南
  6. 测试支持1162种语言的大规模多语言语音(MMS)模型
  7. 利用Falcon 40B模型,最强大的开源LLM
  8. 语言学习模型中OpenAI的函数调用的威力:全面指南

参考资料

[1] https://www.mckinsey.com/capabilities/mckinsey-digital/our-insights/the-economic-potential-of-generative-ai-the-next-productivity-frontier#introduction

[2] 使用FAISS和Sentence Transformers以闪电般的推理速度对数百万个文档进行语义搜索

保持联系:LinkedIn

Leave a Reply

Your email address will not be published. Required fields are marked *