2026年7月9日 周四晚上19:30,报名腾讯会议了解“如何构建自进化的动态知识库(Brain)”(限30人)
免费POC, 零成本试错
FDE知识库

FDE知识库

学习大模型的前沿技术与行业落地应用


收藏

我如何利用 ChromaDB 和 Chainlit 构建基于 Graph-RAG 系统的 LLM 应用程序

发布日期:2025-01-04 23:11:46 浏览次数: 3018
作者:barry的异想世界

微信搜一搜,关注“barry的异想世界”

一个端到端的应用,带有 GUI,并且仅用 3 个脚本将新知识存储在向量数据库中

大型语言模型(LLMs)和知识图谱是处理自然语言的宝贵工具。检索增强生成(RAG)作为一种强大的方法,能够通过上下文知识增强 LLM 的响应。上下文知识通常嵌入并存储在向量数据库中,用于创建上下文以增强提示。然而,这种方式下,知识被映射在一个概念空间中,但并没有真正组织起来。知识图谱捕捉了领域内数据点或实体的信息以及它们之间的关系。数据在知识图谱中被描述为节点以及关系。这比仅仅将单词嵌入向量空间提供了更多的结构。

Graph-RAG 是一种结合了这两者的东西,提供了 RAG 的增强知识,以知识图谱的形式组织,从而使 LLM 的响应更好。

在本文中,我将告诉你我是如何创建一个端到端的应用,将所有这些组合在一起。

简而言之,我使用了

  • • Chainlit[1] 作为前端
  • • ChromaDB[2] 来存储知识为向量
  • • Networkx[3] 来管理图形
  • • Sentence\-transformers[4] (Pytorch)用于生成嵌入。
  • • MistralAI[5] 作为基线 LLM

这些组件的交互如下:

  1. 1. 用户在 Chainlit 界面中写下提示。
  2. 2. 知识图谱 RAG 处理知识的嵌入和存储。
  3. 3. 先前的数据存储在 ChromaDB 中。
  4. 4. 生成的上下文被添加到提示中,并询问 LLM。
  5. 5. Mistral 将生成的答案返回给 Chainlit。

该架构的优势:

  • • 持久性:ChromaDB 确保我们的知识库在会话之间持久存在
  • • 关系意识:图结构捕捉信息片段之间的显式关系
  • • 语义搜索:句子嵌入使得即使措辞不同也能找到相关信息
  • • 用户友好的界面:Chainlit 提供直观的聊天界面以便与系统互动

让我们深入了解每个组件及其如何协同工作,这一切都可以在仅仅 3 个脚本中定义:*`chainlit_app.py`、`rag_implementation.py` 和 `graph_embedding.py*。

我们添加的知识可以通过以下关系图表示:

Chainlit 接口

Chainlit 是一个开源的 Python 库,用于轻松部署具有用户友好界面的聊天机器人。要在本地启动,您需要一个文件,例如“chainlit_app.py”,该文件可以从命令行以“chainlit "chainlit_app.py"”的形式启动。您还可以将其部署到镜像上,以便在 AWS EC2 实例上运行:*

因此,在提议的应用程序中,chainlet 应用程序包含主要启动。理想情况下,图形 RAG 中添加的知识与实际提示解耦,特别是因为我们将这些知识存储在 Chroma 数据库中。在这个例子中,我们简化了这一点,单个脚本首先增强知识和提示。更具体地说,这里我在 initialize_knowledge_base() 中硬编码了一些知识,但这些知识可以从文档中自动读取(这是可以解耦的部分),然后有一个异步函数等待用户输入。

import chainlit as cl
from rag_implementation import MistralRAGSystem

## Initialize RAG system
rag_system = MistralRAGSystem()

## Pre-populate knowledge graph with some initial data
definitialize_knowledge_base():
    knowledge_items = [
        {
            "id""ai_basics",
            "content""Artificial Intelligence is a broad field of computer science focused on creating intelligent machines that can simulate human-like thinking and learning capabilities.",
            "metadata": {"category""introduction""difficulty""beginner"}
        },
        {
            "id""ml_fundamentals",
            "content""Machine Learning is a subset of AI that enables systems to learn and improve from experience without being explicitly programmed, using algorithms that can learn from and make predictions or decisions based on data.",
            "metadata": {"category""core_concept""difficulty""intermediate"}
        }
    ]
    
    for item in knowledge_items:
        rag_system.add_knowledge(item["id"], item["content"], item["metadata"])
    rag_system

## Initialize knowledge base
initialize_knowledge_base()

@cl.on_chat_start
asyncdefstart():
    await cl.Message(content="RAG System with Mistral is ready! How can I help you today?").send()

@cl.on_message
asyncdefmain(message: cl.Message):
    # Check if the message is a knowledge addition command
    if message.content.startswith("/add_knowledge"):
        # Parse the message to extract node_id and content
        parts = message.content.split(maxsplit=3)
        iflen(parts) < 3:
            await cl.Message(content="Usage: /add_knowledge <node_id> <content>").send()
            return
        
        node_id, content = parts[1], parts[2]
        rag_system.add_knowledge(node_id, content)
        await cl.Message(content=f"Added knowledge node: {node_id}").send()
        return

    # Regular query processing
    # Augment the query with relevant context
    augmented_query = rag_system.augment_query(message.content)
    
    # Generate response
    response = rag_system.generate_response(augmented_query)
    
    # Send the response back to the user
    await cl.Message(content=response).send()

Mistral RAG 系统集成

MistralRAGSystem 类作为协调者,将知识图谱与 Mistral LLM 结合。在这个具体实现中,我使用的是在 Huggingface 仓库[6] 上可访问的模型。因此,我们需要从 Huggingface 获取 API 密钥并将其保存到 .env 文件中。

此外,这个类实现了一些 RAG 功能,这些功能在后面的 rag_implementation.py 脚本 中的 KnowledgeGraphRAG 类中进行了描述:

import os
from dotenv import load_dotenv
import requests
from graph_embedding import KnowledgeGraphRAG

classMistralRAGSystem:
    def__init__(self):
        # Load environment variables
        load_dotenv()
        
        # Get Hugging Face API key from environment variable
        self.api_key = os.getenv('MISTRAL_API_KEY')
        ifnotself.api_key:
            raise ValueError("HUGGINGFACE_API_KEY must be set in .env file")
        
        # Default model (corrected name)
        self.model = "mistralai/Mistral-7B-v0.1"
                
        # Initialize Knowledge Graph
        self.knowledge_graph = KnowledgeGraphRAG()

该类的其余部分由主 Chainlit 脚本调用。该脚本几乎添加了知识,查询模型,并返回响应,同时可能还清理了一些输出,以避免响应重复提示:

  def augment_query(self, query: str) -> str:
        """
        Augment the query with relevant context from the knowledge graph
        
        Args:
            query (str): Original user query
        
        Returns:
            str: Augmented query with additional context
        """

        # Retrieve similar nodes
        similar_nodes = self.knowledge_graph.retrieve_similar_nodes(query)
        
        # If similar_nodes is a list, iterate over it directly
        context = "\n".join([str(doc) for doc in similar_nodes])
        
        # Create a structured prompt with context
        augmented_prompt = f"""
        #Context Information:
        #{context}

        Based on the provided context and your extensive knowledge, 
        please answer the following query comprehensively:

        Query: {query}

        Response:
        """

       
        return augmented_prompt
   

    defgenerate_response(self, augmented_query: str) -> str:
        """
        Generate response using Hugging Face API for Mistral model
        
        Args:
            augmented_query (str): Augmented query with context
        
        Returns:
            str: Generated response
        """

        try:
            # Prepare headers with the Hugging Face API key
            headers = {
                'Authorization'f'Bearer {self.api_key}',
                'Content-Type''application/json'
            }
            
            # Prepare payload
            payload = {
                'inputs': augmented_query
            }

            # Hugging Face Inference API endpoint for Mistral model
            url = f'https://api-inference.huggingface.co/models/{self.model}'

            # Make the POST request to generate a response
            response = requests.post(url, json=payload, headers=headers)

            # Check if the request was successful
            if response.status_code == 200:
                #return response.json()[0]['generated_text']
                generated_text = response.json()[0]['generated_text']
                
                
                print("Raw response:", response.json())
                
                start_index = generated_text.find("Response:") + len("Response:")
                response_without_context = generated_text[start_index:].strip()
                
                return response_without_context
            else:
                returnf"Error: {response.status_code} - {response.text}"

        except Exception as e:
            returnf"An error occurred: {str(e)}"

    defadd_knowledge(self, node_id: str, content: str, metadata: dict = None):
        """
        Add knowledge to the graph
        
        Args:
            node_id (str): Unique node identifier
            content (str): Node content
            metadata (dict, optional): Additional metadata
        """

        self.knowledge_graph.add_node(node_id, content, metadata)

知识图谱实现

我们系统的核心是 `KnowledgeGraphRAG` 类,位于 *`graph_embedding.py*` 脚本中,它管理图结构和嵌入。正如我们所说,图关系是通过 Networkx 库管理的,而嵌入则永久保存在 Chroma 数据库中。

Chroma 在底层使用 SqLite,尽管之前的版本是基于 DuckDB。请注意,如果您多次运行此代码,可能会发送一些警告或错误,因为您已经创建了数据库或集合。正如我在开头所说的,理想情况下,我们应该将添加知识和提示系统解耦。

该脚本创建一个数据库,并允许与添加节点和关系相关的调用,这些内容保存在数据库中。

import networkx as nx
import matplotlib.pyplot as plt
from sentence_transformers import SentenceTransformer
import chromadb
from chromadb.config import DEFAULT_TENANT, DEFAULT_DATABASE, Settings
from typing importListDictAny

classKnowledgeGraphRAG:
    def__init__(self, model_name="sentence-transformers/all-MiniLM-L6-v2"):
        # Initialize embedding model
        self.embedding_model = SentenceTransformer(model_name)
        
        # Initialize graph
        self.graph = nx.DiGraph()
      
        self.chroma_client = chromadb.PersistentClient(
             path="test",
             settings=Settings(),
             tenant=DEFAULT_TENANT,
             database=DEFAULT_DATABASE,
)

        self.collection = self.chroma_client.create_collection(name="knowledge_base3")

    defadd_node(self, node_id: str, content: str, metadata: Dict[strAny] = None):
        """
        Add a node to the knowledge graph and embed its content
        
        Args:
            node_id (str): Unique identifier for the node
            content (str): Text content of the node
            metadata (dict, optional): Additional metadata for the node
        """

        # Add to networkx graph
        self.graph.add_node(node_id, content=content, metadata=metadata or {})
        
        # Generate embedding
        embedding = self.embedding_model.encode(content).tolist()
        
        # Ensure metadata is a non-empty dictionary
        metadata = metadata or {}

        # Add to ChromaDB
        self.collection.add(
            ids=[node_id],
            embeddings=[embedding],
            documents=[content],
            metadatas=[metadata]  # Ensure that the metadata is a valid dictionary
        )
        
    defadd_edge(self, source: str, target: str, relationship: str = None):
        """
        Add a directed edge between two nodes
        
        Args:
            source (str): Source node ID
            target (str): Target node ID
            relationship (str, optional): Type of relationship
        """

        self.graph.add_edge(source, target, relationship=relationship)

    defretrieve_similar_nodes(self, query: str, top_k: int = 3):
        """
        Retrieve most similar nodes to a given query.
        
        Args:
            query (str): Search query
            top_k (int): Number of top similar nodes to retrieve.
        
        Returns:
            List of most similar nodes.
        """

        # Generate query embedding
        query_embedding = self.embedding_model.encode(query).tolist()

        # Get the total number of nodes in the collection
        total_nodes = self.collection.count()

        # Adjust top_k if it exceeds the number of available nodes
        top_k = min(top_k, total_nodes)

        # Retrieve from ChromaDB
        results = self.collection.query(
            query_embeddings=[query_embedding],
            n_results=top_k
        )

        # Return the documents (already adjusted for n_results)
        return results.get('documents', [])

## Example usage
defcreate_sample_knowledge_graph():
    kg = KnowledgeGraphRAG()
    #persist_directory="./my_knowledge_base_data2"
    
    # Add some sample nodes about AI
    kg.add_node("ai_intro""人工智能是计算机科学的一个分支")
    kg.add_node("ml_intro""机器学习是 AI 的一个子集,专注于从数据中学习")
    kg.add_node("dl_intro""深度学习使用具有多个层的神经网络")
    
    # Add some relationships
    kg.add_edge("ai_intro""ml_intro""包含")
    kg.add_edge("ml_intro""dl_intro""高级技术")
    
    return kg

## For testing
if __name__ == "__main__":
    kg = create_sample_knowledge_graph()
    kg.visualaze_graph()
    
    # Example retrieval
    results = kg.retrieve_similar_nodes("神经网络")
    print(results)

此外,该类使用 SentenceTransformers 来生成嵌入,并使用 ChromaDB 进行持久存储。这种组合使我们能够维护信息片段之间的语义关系(通过嵌入)和显式关系(通过图结构)。

结论

该实现展示了如何将现代 RAG 技术与持久存储和知识图谱相结合。该系统为构建更复杂的基于知识的应用程序提供了坚实的基础。ChromaDB 用于持久性,Chainlit 用于界面,使其既实用又用户友好。选择 ChromaDB 而非其他永久向量数据库,取决于需求和可用资源。无论如何,我希望我向你展示了,只需 3 个脚本,你就可以拥有一个使用友好前端的端到端应用程序,能够保存新知识,并顺畅运行预先存在的 LLM,而无需微调。

53AI,企业落地大模型首选服务商

产品:场景落地咨询+大模型应用平台+行业解决方案

承诺:免费POC验证,效果达标后再合作。零风险落地应用大模型,已交付160+中大型企业

联系我们

售前咨询
186 6662 7370
预约演示
185 8882 0121

微信扫码

添加专属顾问

回到顶部

加载中...

扫码咨询

扫码登录
登录即表示您同意《53AI网站服务协议》
服务协议

欢迎您使用【53AI 官方网站】(以下简称“本网站”或“我们”)。本《会员服务协议》(以下简称“本协议”)是您(以下简称“会员”或“用户”)与【深圳市博思协创网络科技有限公司】之间关于注册、登录及使用本网站会员服务所订立的法律协议。

在您注册或登录前,请务必审慎阅读、充分理解各条款内容,特别是免除或限制责任的条款、知识产权条款、争议解决条款等。此类条款将以加粗形式提示您注意。 当您通过微信公众号授权、手机验证码验证或其他方式成功登录本网站时,即视为您已完全理解并同意接受本协议的全部内容。

一、 定义

本网站:指由【深圳市博思协创网络科技有限公司】运营的,域名为【53ai.com】的网站及相关移动端页面。

会员服务:指本网站向注册会员提供的知识库文章查阅、内容检索及其他相关增值服务。

知识库内容:指本网站发布的包括但不限于文字、图表、数据、研究报告、行业分析等数字化内容资源。

二、 账号注册与登录

登录方式:本网站支持以下登录方式,您可根据实际情况选择:

微信公众号授权登录:您同意将您的微信OpenID信息授权给本网站,用于创建或关联会员账号。

手机验证码登录:您需提供真实有效的手机号码,并通过短信验证码完成身份验证与登录/注册。

账号安全:您的账号仅限您本人使用,禁止赠与、借用、租用、转让或售卖。因您保管不善导致的账号被盗、密码泄露等损失,由您自行承担。

实名认证:根据相关法律法规要求,我们可能要求您在特定功能下完成实名认证。如您拒绝提供,可能无法使用部分或全部服务。

未成年人保护:若您未满18周岁,请在法定监护人的陪同下阅读本协议,并在征得监护人同意后使用本服务。

三、 服务内容与规范

知识库查阅权限:会员登录后,有权按照其会员等级对应的权限范围,在线浏览、检索本网站知识库中的相关文章及内容。

服务变更:我们有权根据业务发展需要,调整、变更或终止部分服务内容,并将以网站公告、公众号消息等方式提前通知。

禁止行为:您在使用服务时不得实施以下行为:

利用技术手段批量爬取、下载、转存知识库内容;

将知识库内容用于商业目的或未经授权地向第三方传播;

干扰本网站正常运行或侵犯其他用户合法权益;

发布违法违规信息或从事违反公序良俗的活动。

四、 知识产权声明

权利归属:本网站知识库中的排版设计、软件代码等内容的知识产权均归【公司全称】或原权利人所有,受《中华人民共和国著作权法》等法律保护。

有限许可:本网站授予会员一项非独占、不可转让、不可转授权的普通许可,仅限于个人学习、研究之目的在线查阅知识库内容。

侵权追责:未经书面许可,任何单位或个人不得以任何形式复制、转载、摘编、镜像、汇编或以其他方式使用上述内容。一经发现,我们保留追究其法律责任的权利。

五、 个人信息保护

我们重视对您个人信息的保护。关于我们如何收集、使用、存储和保护您的个人信息,请单独阅读 《隐私政策》。

您通过微信公众号授权或手机号验证所提供的信息,我们将严格按照《个人信息保护法》的规定处理,仅用于身份识别、服务提供及安全验证等必要用途。

您可以随时通过网站设置或联系客服行使查阅、更正、删除个人信息及撤回授权同意的权利。

六、 免责声明

内容准确性:知识库内容仅供参考,不构成专业建议。我们不对其完整性、准确性、时效性作任何明示或暗示的保证,您应自行判断并承担使用风险。

不可抗力:因自然灾害、政策法规变化、网络故障、第三方平台接口异常(如微信接口维护、运营商短信通道故障)等不可抗力导致的服务中断或延迟,我们不承担违约责任。

第三方链接:本网站可能包含指向第三方网站的链接,该等网站的内容和服务不受我们控制,请您自行甄别风险。

七、 违约责任

如您违反本协议约定,我们有权视情节采取警告、限制功能、暂停服务、注销账号等措施,并保留要求赔偿损失的权利。

如因您的违约行为导致我们遭受行政处罚、第三方索赔或商誉损失,您应承担全部赔偿责任(包括但不限于罚款、赔偿金、律师费、公证费等)。

八、 法律适用与争议解决

本协议的订立、执行和解释均适用中华人民共和国大陆地区法律。

因本协议产生的或与本协议有关的任何争议,双方应友好协商解决;协商不成的,任何一方均可向【公司所在地】有管辖权的人民法院提起诉讼。

九、 其他

本协议构成双方就本服务达成的完整协议,取代此前任何口头或书面约定。

本协议任一条款被认定为无效或不可执行的,不影响其他条款的效力。

我们对本协议享有最终解释权,并在法律允许的范围内保留随时修改的权利。修改后的协议一经公布即生效,继续使用服务即视为同意修订内容。


已查阅