目录
介绍
学习目标
目录
创建Python环境
使用FastApi开发后端
摄入的代码
QNA类代码
FastAPI应用程序的代码
用反射设计前端
前端目录
最终应用程序的步骤
步骤1:在前端目录中克隆聊天模板存储库
步骤2:运行以下命令将目录初始化为反射应用
步骤3:测试应用程序,使用从前端目录内部的以下命令
主聊天组件的代码
编辑状态.py文件
编写file_upload.py文件的内容
测试和部署
结论
关键要点
常见问题
首页 科技周边 人工智能 带有Langchain的边缘设备上的自托管抹布应用

带有Langchain的边缘设备上的自托管抹布应用

Apr 14, 2025 am 10:35 AM

介绍

在我们在Raspberry Pi上构建RAG应用程序的系列文章的第二部分中,我们将在第一部分奠定的基础上扩展,在该基础上我们创建并测试了核心管道。在第一部分中,我们创建了核心管道并对其进行了测试,以确保一切按预期工作。现在,我们将通过构建FastApi应用程序来服务我们的破布管道并创建反射应用程序,从而为用户提供一种简单且交互式的方式来访问它,从而进一步迈出一步。这部分将指导您设置FastApi后端,用Reflex设计前端,并在Raspberry Pi上启动并运行所有内容。最后,您将拥有一个完整的工作应用程序,该应用程序已准备好现实使用。

学习目标

  • 设置FastApi后端,以与现有的RAG管道集成并有效地查询。
  • 使用Reflex设计一个用户友好的界面,以与FastApi后端和RAG管道进行交互。
  • 创建和测试用于查询和文档摄入的API端点,从而确保使用FastAPI平稳操作。
  • 在Raspberry Pi上部署和测试完整的应用程序,以确保后端和前端组件同时无缝函数。
  • 了解FastApi和Reflex之间的集成,以获得凝聚力的RAG应用体验。
  • 实施和故障排除FastApi和Reflex组件,以在Raspberry Pi上提供完全操作的抹布应用。

如果您错过了上一版,请务必在此处查看:带有Langchain和Ollama的边缘设备上的自托管破布应用程序 - 第一部分

目录

  • 创建Python环境
  • 使用FastApi开发后端
  • 用反射设计前端
  • 测试和部署
  • 常见问题

本文作为数据科学博客马拉松的一部分发表

创建Python环境

在创建应用程序开始之前,我们需要设置环境。创建环境并安装以下依赖关系:

深石 
boto3 == 1.34.144 
Botocore == 1.34.144 
fastapi == 0.110.3 
Gunicorn == 22.0.0 
httpx == 0.27.0 
HuggingFace-Hub == 0.23.4 
Langchain == 0.2.6 
Langchain-Community == 0.2.6 
兰链核== 0.2.11 
Langchain-验证== 0.0.62 
Langchain-Text-Splitters == 0.2.2 
langsmith == 0.1.83 
棉花糖== 3.21.3 
numpy == 1.26.4 
熊猫== 2.2.2 
pydantic == 2.8.2 
pydantic_core == 2.20.1 
pymupdf == 1.24.7 
pymupdfb == 1.24.6 
python-dotenv == 1.0.1 
pytz == 2024.1 
pyyaml == 6.0.1 
反射== 0.5.6 
请求== 2.32.3
反射== 0.5.6
Reflex-hosting-cli == 0.1.13

安装了所需的软件包后,我们需要在设备中放置所需的型号。我们将使用Ollama来做到这一点。请按照本文第1部分的步骤下载语言和嵌入模型。最后,为后端和前端应用程序创建两个目录。

一旦使用Ollama拉动了模型,我们就准备构建最终应用程序。

使用FastApi开发后端

在本文的第1部分中,我们建立了具有摄入和QNA模块的抹布管道。我们已经使用一些文档对两个管道进行了测试,并且它们正常工作。现在,我们需要用FastAPI包装管道来创建易于使用的API。这将有助于我们将其与任何前端应用程序集成在一起,例如简化,链条,Gradio,Reflex,React,Angular等。让我们首先构建应用程序的结构。遵循结构是完全可选的,但是如果您遵循其他结构来创建应用程序,请确保检查依赖关系导入。

以下是我们将遵循的树结构:

后端
├ -  app.py
├ - ─txt
└ -  src
    ├─Config.py
    ├─doc_loader
    │││─-base_loader.py
    │├├前__init__.py
    PDF_LOADER.PY
    ├─摄取
    ├ -  __init__.py
    └─QNA.PY

让我们从config.py开始。该文件将包含应用程序的所有可配置选项,例如Ollama URL,LLM名称和嵌入式模型名称。以下是一个示例:

 lanking_model_name =“ phi3”
embeddings_model_name =“ nomic-embed-text”
Ollama_url =“ http:// localhost:11434”

base_loader.py文件包含由孩子Document Loader继承的父文档加载程序类。在此应用程序中,我们仅使用PDF文件,因此Child PDFLoader类将是
创建将继承基本负载类。

以下是base_loader.py和pdf_loader.py的内容:

 #base_loader.py
来自ABC Import ABC,AbstractMethod

班级加载工(ABC):
    def __init __(self,file_path:str) - >无:
        self.file_path = file_path

    @AbstractMethod
    异步def load_document(self):
        经过


#pdf_loader.py
导入操作系统

来自.base_loader导入基本负载器
来自langchain.schema导入文档
来自langchain.document_loaders.pdf导入pymupdfloader
来自langchain.text_splitter导入tarnextsplitter


PDFLOADER类(基本负载器):
    def __init __(self,file_path:str) - >无:
        super().__ INT __(file_path)

    异步def load_document(self):
        self.file_name = os.path.basename(self.file_path)
        loader = pymupdfloader(file_path = self.file_path)

        text_splitter = partinextsplitter(
            saparator =“ \ n”,
            chunk_size = 1000,
            chunk_overlap = 200,
        )
        页面=等待loader.aload()
        total_pages = len(页)
        块= []
        对于IDX,枚举(页)中的页面:
            chunks.append(
                文档(
                    page_content = pag.page_content,
                    元数据= dict(
                        {
                            “ file_name”:self.file_name,
                            “ page_no”:str(idx 1),
                            “ total_pages”:str(total_pages),
                        }
                    ),
                )
            )

        final_chunks = text_splitter.split_documents(块)
        返回final_chunks

我们已经在文章的第1部分中讨论了PDF_LOADER的工作。

接下来,让我们构建摄入类。这与我们在本文第1部分中构建的那个相同。

摄入的代码

导入操作系统
导入config作为CFG

来自Pinecone Import Pinecone
来自langchain.Vectorstores.Deeplake Import Deeplake
来自langchain.embeddings.ollama进口Ollamaembeddings
来自.doc_loader导入pdfloader

类摄入:
    “”“记录摄入管道。”“”
    def __init __(自我):
        尝试:
            self.embeddings = ollamaembeddings(
                型号= cfg.embeddings_model_name,
                base_url = cfg.ollama_url,
                show_progress = true,
            )
            self.vector_store = deeplake(
                dataset_path =“ data/text_vectorstore”,
                嵌入= self.embeddings,
                num_workers = 4,
                冗长= false,
            )
        除例外为E:
            提高RuntimeError(F“无法初始化摄入系统。错误:{e}”)

    异步def create_and_add_embeddings(
        自己,
        文件:str,,
    ):
        尝试:
            loader = pdfloader(
                file_path =文件,
            )

            块=等待loader.load_document()
            size =等待self.vector_store.aadd_documents(documents =块)
            返回Len(尺寸)
        除(valueerror,runtimeerror,keyError,typeError)作为e:
            提高异常(f“错误:{e}”)

现在,我们已经设置了摄入类,我们将继续创建QNA类。这也与我们在本文第1部分中创建的那个相同。

QNA类代码

导入操作系统
导入config作为CFG

来自Pinecone Import Pinecone
来自langchain.Vectorstores.Deeplake Import Deeplake
来自langchain.embeddings.ollama进口Ollamaembeddings
来自langchain_community.llms.ollama import ollama
来自.doc_loader导入pdfloader

QNA类:
    “”“记录摄入管道。”“”
    def __init __(自我):
        尝试:
            self.embeddings = ollamaembeddings(
                型号= cfg.embeddings_model_name,
                base_url = cfg.ollama_url,
                show_progress = true,
            )
            self.model = ollama(
                型号= cfg.language_model_name,
                base_url = cfg.ollama_url,
                详细= true,
                温度= 0.2,
            )
            self.vector_store = deeplake(
                dataset_path =“ data/text_vectorstore”,
                嵌入= self.embeddings,
                num_workers = 4,
                冗长= false,
            )
            self.triever = self.vector_store.as_retriever(
                search_type =“相似性”,
                search_kwargs = {
                    “ K”:10,
                },,
            )
        除例外为E:
            提高RuntimeError(F“无法初始化摄入系统。错误:{e}”)

    def create_rag_chain(self):
        尝试:
            system_prompt =“”“”
            ”“”
            提示= chatprompttemplate.from_messages(
                [
                    (“系统”,system_prompt),
                    (“人类”,“ {input}”),
                这是给出的
            )
            Question_answer_chain = create_stuff_documents_chain(self.model,提示)
            rag_chain = create_retrieval_chain(self.triever,Question_answer_chain)

            返回rag_chain
        除例外为E:
            提高RuntimeError(F“无法创建检索链。错误:{e}”)

这样,我们已经完成了创建RAG应用程序的代码功能。现在,让我们用fastapi包装该应用程序。

FastAPI应用程序的代码

导入系统
导入操作系统
导入紫外线

从SRC进口QNA摄入
来自FastAPI Import FastApi,请求,文件,uploadfile
来自fastapi.Respons import streamResponse

app = fastapi()

摄入=摄入()
chatbot = qna()
rag_chain = chatbot.create_rag_chain()


@app.get(“/”)
def hello():
    返回{“消息”:“在服务器8089中运行的API}


@app.post(“/query”)
异步def ask_query(请求:请求):
    data =等待请求.json()
    问题= data.get(“问题”)

    异步def event_generator():
        对于rag_chain.pick中的块(“答案”)。
            产生块

    返回streamingresponse(event_generator(),媒体_type =“ text/plain”)


@app.post(“/ingest”)
异步def ingest_document(文件:uploadfile = file(...)):
    尝试:
        os.makedirs(“文件”,equent_ok = true)
        file_location = f“ files/{file.filename}”
        使用file_object的打开(file_location,“ wb”):
            file_object.write(file.file.read())

        size =等待摄入.create_and_add_embeddings(file = file_location)
        返回{“消息”:f“摄入文件!文档计数:{size}”}
    除例外为E:
        返回{“消息”:f“发生错误:{e}”}


如果__name__ ==“ __ -main __”:
    尝试:
        uvicorn.run(app,host =“ 0.0.0.0”,端口= 8089)
    除了键盘间断为E:
        打印(“应用程序停止!”)

让我们通过每个端点分解应用程序:

  • 首先,我们初始化FastApi应用程序,摄入和QNA对象。然后,我们使用QNA类的create_rag_chain方法创建一个抹布链。
  • 我们的第一个终点是一个简单的获取方法。这将有助于我们知道该应用是否健康。将其视为“ Hello World”终点。
  • 第二个是查询端点。这是一种帖子方法,将用于运行链条。它采用一个请求参数,我们从中提取用户的查询。然后,我们创建了一种异步方法,该方法在链条函数呼叫周围充当异步包装器。我们需要这样做,以允许FastApi处理LLM的流函数调用,以在聊天界面中获得类似ChatGpt的体验。然后,我们将异步方法与StreamResponse类包装并返回。
  • 第三端点是摄入端点。这也是一种帖子方法,将整个文件作为输入作为字节。我们将此文件存储在本地目录中,然后使用摄入类的create_and_add_embeddings方法摄入。

最后,我们使用主机和端口使用Uvicorn软件包运行该应用程序。要测试应用程序,只需使用以下命令运行应用程序:

 python app.py

带有Langchain的边缘设备上的自托管抹布应用

使用Postman,失眠或Bruno等API测试IDE测试应用程序。您也可以使用Thunder Client Extension进行相同的操作。

测试摄入端点:

带有Langchain的边缘设备上的自托管抹布应用

测试查询端点:

带有Langchain的边缘设备上的自托管抹布应用

用反射设计前端

我们已经成功创建了一个用于后端的FastApi应用程序。是时候建立我们的前端了。您可以为此选择任何前端库,但是对于本文,我们将使用Reflex构建前端。 Reflex是一个仅使用Python的前端库,纯粹是使用Python构建Web应用程序的。它通过用于计算器,图像生成和聊天机器人等常见应用程序的模板证明了我们。我们将使用聊天机器人应用模板作为用户界面的启动。我们的最终应用程序将具有以下结构,因此让我们在此处参考。

前端目录

我们将拥有一个前端目录:

前端
├ - 资产
│└└前favicon.ico
├ - 文档
│└ -  emo.gif
├ - 聊天
组件
││││站
│││├站file_upload.py
││├ -  __init__.py
││││─..poting_icon.py
│││├站
Navbar.py
│├├前__init__.py
Chat.py
sate.py
├ - ─txt
├─-rxConfig.py
└ - 上传_files

最终应用程序的步骤

按照步骤准备最终应用程序的接地。

步骤1:在前端目录中克隆聊天模板存储库

git克隆https://github.com/reflex-dev/reflex-chat.git。

步骤2:运行以下命令将目录初始化为反射应用

Reflex Init

带有Langchain的边缘设备上的自托管抹布应用

这将设置Reflex应用程序,并准备好运行和开发。

步骤3:测试应用程序,使用从前端目录内部的以下命令

反射运行

带有Langchain的边缘设备上的自托管抹布应用

让我们开始修改组件。首先,让我们修改chat.py文件。

以下是相同的代码:

导入反射为Rx
来自reflex_demo.com import incort loading_icon
来自reflex_demo.State Import QA,状态

messages_style = dict(dict)(
    display =“ inline-block”,
    填充=“ 0 10px”,
    border_radius =“ 8px”,
    max_width = [“ 30em”,“ 30em”,“ 50em”,“ 50em”,“ 50em”,“ 50em”],
)


DEF消息(QA:QA) - > rx.component:
    “”“一个问题/答案消息。

    args:
        QA:问题/答案对。

    返回:
        显示问题/答案对的组件。
    ”“”
    返回rx.box(
        rx.box(
            rx.markdown(
                QA.问题,
                background_color = rx.color(“淡紫色”,4),,
                color = rx.color(“淡紫色”,12),
                ** Message_Style,
            ),
            text_align =“ right”,
            margin_top =“ 1em”,
        ),
        rx.box(
            rx.markdown(
                QA.ANSWER,
                background_color = rx.Color(“ Accent”,4),,
                color = rx.Color(“ Accent”,12),
                ** Message_Style,
            ),
            text_align =“左”,
            padding_top =“ 1em”,
        ),
        宽度=“ 100%”,
    )


def chat() - > rx.component:
    “”“列出单个对话中的所有消息。”“”
    返回rx.vstack(
        rx.box(rx.foreach(state.chats [state.current_chat],消息),width =“ 100%”),
        py =“ 8”,
        flex =“ 1”,
        宽度=“ 100%”,
        max_width =“ 50em”,
        padding_x =“ 4px”,
        align_self =“中心”,
        溢出=“隐藏”,
        padding_bottom =“ 5em”,
    )


def Action_bar() - > rx.component:
    ”“”“动作栏发送新信息。”“”
    返回rx.center(
        rx.vstack(
            rx.chakra.form(
                rx.chakra.form_control(
                    rx.hstack(
                        rx。输入(
                            rx.input.slot(
                                rx.tooltip(
                                    rx.icon(“ info”,size = 18),
                                    content =“输入一个问题以获取答复。”,,
                                )
                            ),
                            占位符=“键入某物...”,
                            ,,,,
                            width = [“ 15em”,“ 20em”,“ 45em”,“ 50EM”,“ 50EM”,“ 50EM”],
                        ),
                        rx.button(
                            rx.cond(
                                state.processing,
                                loading_icon(高度=“ 1em”),
                                rx.text(“ send”,font_family =“ ubuntu”),
                            ),
                            type =“提交”,
                        ),
                        align_items =“中心”,
                    ),
                    is_disabled = state.processing,
                ),
                on_submit = state.process_question,
                reset_on_submit = true,
            ),
            rx.text(
                “反射可能会返回事实不正确或误导性响应。使用酌处权。”,
                text_align =“中心”,
                font_size =“。75EM”,
                color = rx.Color(“淡紫色”,10),
                font_family =“ ubuntu”,
            ),
            rx.logo(margin_top =“  -  1em”,margin_bottom =“  -  1em”),
            align_items =“中心”,
        ),
        位置=“粘性”,
        底部=“ 0”,
        左=“ 0”,
        padding_y =“ 16px”,
        backdrop_filter =“自动”,
        backdrop_blur =“ lg”,
        border_top = f“ 1px solid {rx.color('mauve',3)}”,
        background_color = rx.color(“淡紫色”,2),
        align_items =“ stract”,
        宽度=“ 100%”,
    )

这些变化是从模板中本地存在的最小化。

接下来,我们将编辑chat.py应用程序。这是主要的聊天组件。

主聊天组件的代码

以下是它的代码:

导入反射为Rx
来自reflex_demo.com.ponents导入聊天,navbar,upload_form
来自reflex_demo.State Extiment State


@rx.page(路由=“/chat”,title =“ rag chatbot”)
def chat_interface() - > rx.component:
    返回rx.chakra.vstack(
        navbar(),
        chat.chat(),
        chat.action_bar(),
        background_color = rx.color(“淡紫色”,1),
        color = rx.color(“淡紫色”,12),
        min_height =“ 100VH”,
        align_items =“ stract”,
        间距=“ 0”,
    )


@rx.page(route =“/”,title =“ rag chatbot”)
def index() - > rx.component:
    返回rx.chakra.vstack(
        navbar(),
        upload_form(),
        background_color = rx.color(“淡紫色”,1),
        color = rx.color(“淡紫色”,12),
        min_height =“ 100VH”,
        align_items =“ stract”,
        间距=“ 0”,
    )


#将状态和页面添加到应用程序。
app = rx.app(
    主题= rx.theme(
        外观=“黑暗”,
        accent_color =“玉”,
    ),
    stylesheets = [“ https://fonts.googleapis.com/css2?family=ubuntu&display=swap”],
    样式= {
        “ font_family”:“ ubuntu”,
    },,
)
app.add_page(索引)
app.add_page(chan_interface)

这是聊天接口的代码。我们仅将字体系列添加到应用程序配置中,其余代码是相同的。

接下来,让我们编辑state.py文件。这是前端将呼叫API端点以进行响应的地方。

编辑状态.py文件

导入请求
导入反射为Rx


QA类(RX.BASE):
    问题:str
    答案:str


default_chats = {
    “ intros”:[],
}


班级状态(rx.state):
    聊天:dict [str,list [qa]] = default_chats
    current_chat =“ intros”
    URL:str =“ http:// localhost:8089/query”
    问题:str
    处理:bool = false
    new_chat_name:str =“”

    def create_chat(self):
        “”“创建新聊天。”“”
        #将新聊天添加到聊天列表中。
        self.current_chat = self.new_chat_name
        self.chats [self.new_chat_name] = []

    Def Delete_chat(self):
        “”“删除当前聊天。”“”
        del self.chats [self.current_chat]
        如果len(self.chats)== 0:
            self.chats = default_chats
        self.current_chat = list(self.chats.keys())[0]

    def set_chat(self,chat_name:str):
        “”“设置当前聊天的名称。

        args:
            chat_name:聊天的名称。
        ”“”
        self.current_chat = chat_name

    @rx.var
    def chat_titles(self) - > list [str]:
        “”“获取聊天标题的列表。

        返回:
            聊天名称列表。
        ”“”
        返回列表(self.chats.keys())

    异步def process_question(self,form_data:dict [str,str]):
        #从表格中获取问题
        问题= form_data [“问题”]

        #检查问题是否为空
        如果问题==“”:
            返回

        型号= self.openai_process_question

        在模型中的价值异步(问题):
            产量值

    异步def openai_process_question(自我,问题:str):
        “”“从API获取响应。

        args:
            form_data:一个带有当前问题的dict。
        ”“”
        #将问题添加到问题列表中。
        QA = QA(问题=问题,答案=“”)
        self.chats [self.current_chat] .append(QA)
        有效载荷= {“问题”:问题}

        #清除输入并开始处理。
        self.processing = true
        屈服

        响应= requests.post(self.url,json =有效载荷,流= true)

        #流式传输结果,在每个单词之后产生。
        for Answers_text in enthys.iter_content(chunk_size = 512):
            #确保答案_text在串联之前不是没有
            答案_text = wherme_text.decode()
            如果答案_text不是没有:
                self.Chats [self.current_chat] [ -  1] .answer = answers_text
            别的:
                答案_text =“”
                self.Chats [self.current_chat] [ -  1] .answer = answers_text
            self.chats = self.chats
            屈服

        #切换处理标志。
        self.processing = false

在此文件中,我们为查询端点定义了URL。我们还修改了OpenAI_Process_Question方法,以将邮政请求发送到查询端点并获取流媒体
响应,将显示在聊天接口中。

编写file_upload.py文件的内容

最后,让我们编写file_upload.py文件的内容。此组件将在开头显示,这将使我们可以上传文件以进行摄入。

导入反射为Rx
导入操作系统
进口时间

导入请求


类uploadexample(rx.state):
    上传:bool = false
    摄入:bool = false
    进度:int = 0
    total_bytes:int = 0
    ingestion_url =“ http://127.0.0.1:8089/ingest”

    async def handle_upload(self,files:list [rx.uploadfile]):
        self.ingesting = true
        屈服
        用于文件中的文件:
            file_bytes =等待file.read()
            file_name = file.filename
            文件= {
                “文件”:(OS.Path.BasEname(file_name),file_bytes,“ multipart/form-data”)
            }
            响应= requests.post(self.ingestion_url,files = files)
            self.ingesting = false
            屈服
            如果响应。STATUS_CODE== 200:
                #屈服rx.redirect(“/chat”)
                self.show_redirect_popup()

    def handle_upload_progress(自我,进度:dict):
        self.uploading = true
        self.progress = rough(进度[“进度”] * 100)
        如果self.progress> = 100:
            self.uploading = false

    def cancel_upload(self):
        self.uploading = false
        返回rx.cancel_upload(“ upload3”)


def upload_form():
    返回rx.vstack(
        rx.upload(
            rx.Flex(
                rx.text(
                    “在这里拖放文件或单击以选择文件”,
                    font_family =“ ubuntu”,
                ),
                rx.icon(“上传”,大小= 30),
                方向=“列”,
                align =“中心”,
            ),
            ,,,,
            border =“ 1px固体RGB(233,233,233,0.4)”,
            margin =“ 5em 0 10px 0”,
            Background_Color =“ RGB(107,99,246)”,
            border_radius =“ 8px”,
            填充=“ 1em”,
        ),
        rx.vstack(rx.foreach(rx.selected_files(“ upload3”),rx.text)),),),),
        rx.cond(
            〜uploadexample。
            rx.button(
                “上传”,
                on_click = uploadexample.handle_upload(
                    rx.upload_files(
                        上传_,
                        on_upload_progress = uploadexample.handle_upload_progress,
                    ),
                ),
            ),
            rx.Flex(
                rx.spinner(size =“ 3”,加载= uploadexample.ingesting),
                rx.button(
                    “取消”,
                    on_click = uploadexample.cancel_upload,
                ),
                align =“中心”,
                间距=“ 3”,
            ),
        ),
        rx.alert_dialog.root(
            rx.alert_dialog.trigger(
                rx.button(“继续聊天”,color_scheme =“ green”),
            ),
            rx.alert_dialog.content(
                rx.alert_dialog.title(“重定向聊天接口?”),),
                rx.alert_dialog.Description(
                    “您将被重定向到聊天界面。”
                    尺寸=“ 2”,
                ),
                rx.Flex(
                    rx.alert_dialog.cancel(
                        rx.button(
                            “取消”,
                            变体=“软”,
                            color_scheme =“灰色”,
                        ),
                    ),
                    rx.alert_dialog.Action(
                        rx.button(
                            “继续”,
                            color_scheme =“绿色”,
                            变体=“固体”,
                            on_click = rx.redirect(“/chat”),
                        ),
                    ),
                    间距=“ 3”,
                    margin_top =“ 16px”,
                    Justify =“ End”,
                ),
                样式= {“ max_width”:450},
            ),
        ),
        align =“中心”,
    )

此组件将允许我们上传文件并将其摄入矢量存储。它使用我们的FastApi应用程序的摄入端点上传和摄入文件。摄入后,用户可以简单地移动
到聊天界面询问查询。

这样,我们已经完成了为我们的应用程序构建前端。现在,我们需要使用一些文档来测试应用程序。

测试和部署

现在,让我们在某些手册或文档上测试应用程序。要使用该应用程序,我们需要单独运行后端应用程序和Reflex应用程序。使用该目录运行后端应用
以下命令:

 python app.py

等待FastApi开始运行。然后在另一个终端实例中使用以下命令运行前端应用:

反射运行

应用程序正在启动和运行,到达以下URL访问Reflex应用程序。最初,我们将在文件上传页面中。上传文件,然后按“上传”按钮。

带有Langchain的边缘设备上的自托管抹布应用

该文件将上传并摄入。这将需要一段时间,具体取决于文档的大小和
设备规格。完成后,单击“继续聊天”按钮以移至聊天接口。编写您的查询,然后按发送。

结论

在Thistwo Parteries中,您现在您在Raspberry Pi上构建了一个完整且功能上功能的RAG应用程序,从创建核心管道到用FastApi后端包装并开发基于反射的前端。借助这些工具,您的破布管道是可访问且交互式的,可通过用户友好的Web界面提供实时查询处理。通过掌握这些步骤,您在紧凑,高效的平台上构建和部署端到端应用程序方面获得了宝贵的经验。这种设置为在Raspberry Pi(例如Raspberry Pi)上部署AI驱动应用程序的无数可能性打开了大门,这使得最先进的技术更容易访问和实用。

关键要点

  • 提供了有关设置开发环境的详细指南,包括使用Ollama安装必要的依赖项和模型,以确保该应用程序已准备好最终构建。
  • 本文解释了如何将RAG管道包裹在FastAPI应用程序中,包括设置查询模型和摄入文档的终点,使该管道可以通过Web API访问。
  • RAG应用程序的前端是使用Reflex(仅Python的前端库Reflex构建的。本文演示了如何修改聊天应用程序模板以创建用于与RAG管道进行交互的用户友好界面。
  • 本文指南将FastAPI后端与反射前端集成在一起,并在Raspberry Pi上部署完整的应用程序,以确保无缝操作和用户可访问性。
  • 提供了使用Postman或Thunder Client等工具来测试摄入和查询端点的实用步骤,同时运行和测试反射前端,以确保整个应用程序按预期功能。

常见问题

问题1:如何使自己可以从世界任何地方访问该应用程序而不会损害安全性?

答:有一个名为TailScale的平台,允许您的设备连接到私人安全网络,仅可访问您。您可以将Raspberry Pi和其他设备添加到尾部设备中,并连接到VPN以访问您的应用程序。

Q2:我的摄入和QNA的应用非常慢。

答:由于覆盆子PI的硬件规格较低,这是限制。这篇文章只是有关如何使用Raspberry Pi和Ollama构建RAG应用程序的主题教程。

本文所示的媒体不由Analytics Vidhya拥有,并由作者酌情使用。

以上是带有Langchain的边缘设备上的自托管抹布应用的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

AI投资者停滞不前? 3条购买,建造或与人工智能供应商合作的战略途径 AI投资者停滞不前? 3条购买,建造或与人工智能供应商合作的战略途径 Jul 02, 2025 am 11:13 AM

投资蓬勃发展,但仅资本还不够。随着估值的上升和独特性的衰落,以AI为中心的风险投资的投资者必须做出关键决定:购买,建立或合作伙伴才能获得优势?这是评估每个选项和PR的方法

AGI和AI超级智能将严重击中人类天花板的假设障碍 AGI和AI超级智能将严重击中人类天花板的假设障碍 Jul 04, 2025 am 11:10 AM

让我们来谈谈。 对创新AI突破的分析是我正在进行的AI中正在进行的福布斯列覆盖的一部分,包括识别和解释各种有影响力的AI复杂性(请参阅此处的链接)。 前往Agi和

Kimi K2:最强大的开源代理模型 Kimi K2:最强大的开源代理模型 Jul 12, 2025 am 09:16 AM

还记得今年早些时候破坏了Genai行业的大量开源中国模型吗?尽管DeepSeek占据了大多数头条新闻,但Kimi K1.5是列表中的重要名字之一。模型很酷。

未来预测从AI到AGI的道路上的大规模情报爆炸 未来预测从AI到AGI的道路上的大规模情报爆炸 Jul 02, 2025 am 11:19 AM

让我们来谈谈。 对创新AI突破的分析是我正在进行的AI中正在进行的福布斯列覆盖的一部分,包括识别和解释各种有影响力的AI复杂性(请参阅此处的链接)。对于那些读者

Grok 4 vs Claude 4:哪个更好? Grok 4 vs Claude 4:哪个更好? Jul 12, 2025 am 09:37 AM

到2025年中期,AI“军备竞赛”正在加热,XAI和Anthropic都发布了他们的旗舰车型Grok 4和Claude 4。这两种模型处于设计理念和部署平台的相反端,但他们却在

推理模型的思想链可能无法长期解决 推理模型的思想链可能无法长期解决 Jul 02, 2025 am 11:18 AM

例如,如果您向模型提出一个问题,例如:“(x)人在(x)公司做什么?”您可能会看到一个看起来像这样的推理链,假设系统知道如何检索必要的信息:找到有关CO的详细信息

这家初创公司在印度建立了一家医院来测试其AI软件 这家初创公司在印度建立了一家医院来测试其AI软件 Jul 02, 2025 am 11:14 AM

临床试验是药物开发中的巨大瓶颈,Kim和Reddy认为他们在PI Health建立的AI-Spainite软件可以通过扩大潜在符合条件的患者的库来更快,更便宜。但是

参议院杀死了特朗普的预算法案中的10年州AI禁令 参议院杀死了特朗普的预算法案中的10年州AI禁令 Jul 02, 2025 am 11:16 AM

参议院星期二早上以99-1投票,杀死了暂停,在倡导团体,立法者和成千上万的美国人中的最后一分钟的骚动中,他们将其视为危险的过度。他们没有保持安静。参议院倾听。国家保持

See all articles