使用Gradio构建AI前端 - RAG召回测试

使用Gradio构建AI前端 - RAG召回测试

一、摘要

构建AI应用的前端方案有很多,这里介绍一个开源前端库---Gradio,通过它可以使用简短的代码就可以快速的实现简单的AI应用前端。这里我们选择的场景为做RAG召回测试,通过调用先前封装好的LangChain代码,来快速的搭建这个前端页面。

二、AI项目前端方案的对比

可以做AI的前端方案很多,这里主要介绍比较热门的三个方案:

  • Gradio 是一款开源的 Python 库,核心定位是快速构建机器学习 / 深度学习模型的交互式 Web 演示界面,无需前端开发经验,一行代码即可将模型(或任意 Python 函数)转化为可通过浏览器访问的交互页面,方便开发者、研究者快速展示、测试和分享模型。
  • Streamlit 是一款开源的 Python 库,主打快速构建数据科学 / 机器学习领域的交互式 Web 应用,无需前端开发经验,以 "脚本即应用" 为核心理念 ------ 普通的 Python 脚本只需添加少量 Streamlit 语法,就能一键转化为可交互的 Web 应用,是数据分析师、算法工程师快速落地可视化 / 分析工具的首选。
  • Vue(读音 /vjuː/,类似 view)是一款渐进式 JavaScript 框架,核心聚焦于前端视图层(UI)开发,由尤雨溪开发并开源,是目前最主流的前端框架之一(与 React、Angular 并称)。
    相对三种方案,Gradio是直接被设计成AI的前端的,Streamlit适合做数据科学的前端。而Vue是一个更专业的前端框架。
    这里我们介绍的就是Gradio。所以我们使用Gradio构建了一个RAG(检索增强生成)召回测试系统界面,主要功能是通过调用LC_RAG_02_RecallTest.py中的recall函数实现相似度检索,用户可以输入查询文本并设置返回结果数量,系统会展示检索到的最相似文档。

三、环境介绍

这里基于我另外一篇笔记:
https://www.cnblogs.com/aspnetx/p/19173914

在这个笔记中,介绍了如何使用python构建RAG系统,使用的是LangChain1.0的库。

整个项目可以在以下仓库中找到:
https://github.com/microsoftbi/Langchain_DEMO/tree/main/RAG

我会用到在其中的一个文件中封装好的做RAG召回测试的代码,来构建前端应用,借此展示Gradio环境中如何快速的搭建前端页面。

本文创建的代码文件名为:LC_RAG_07b_Gradio.py

调用先前召回测试的代码文件为:LC_RAG_02_RecallTest.py

四、主要功能模块

1. 召回测试函数 run_recall_test

  • 功能:调用LC_RAG_02_RecallTest.py文件中封装好的recall函数执行检索并捕获输出结果。
Python 复制代码
def run_recall_test(query, top_k):
    """运行召回测试并返回结果"""
    try:
        # 调用recall函数,但需要捕获其输出
        import io
        from contextlib import redirect_stdout
        
        # 创建一个字符串IO对象来捕获输出
        f = io.StringIO()
        with redirect_stdout(f):
            recall(
                query=query,
                top_k=top_k,
                vectorstore_dir="./RAG/chroma_db",
                embedding_model="text-embedding-v4"
            )
        
        # 获取捕获的输出
        output = f.getvalue()
        return output
    except Exception as e:
        return f"错误: {str(e)}"
  • 实现要点:
    • 使用io.StringIO()创建字符串缓冲区
    • 通过redirect_stdout上下文管理器捕获recall函数的打印输出
    • 调用recall函数时指定参数:查询文本、返回数量、向量存储目录和嵌入模型
      因为在先前封装好的代码中并没有返回值,而是直接通过print来输出结果,所以这里需要调用相关的包来读取这些输出。

2. Gradio界面构建

首先需要确保Gradio的库已经被安装:

复制代码
pip install gradio 

然后在代码中引入这个库。

复制代码
import gradio as gr 

随后使用gr.Blocks创建结构化界面,在其下再通过gr.Row()以及gr.Column(),就可以往这个框架下分割出来不同的行和列来堆放需要的组件。

顺便说一下,Gradid有两种方式的布局,一个是interface, 通过绑定的函数自动生成界面,另一个就是Block,通过行列的方式自己组织界面。这里用到的就是Blocks方式。

以下是几种常用的设置前端界面的方法:

(1)页面标题与说明

直接做markdown格式的输出:

python 复制代码
gr.Markdown("# RAG召回测试系统")
gr.Markdown("使用Gradio构建的RAG召回测试界面,调用LC_RAG_02_RecallTest.py实现相似度检索")

(2)输入区域(左侧)

也就是在gr.Row()的第一个gr.Column()

Python 复制代码
        with gr.Column(scale=1):
            gr.Markdown("## 查询设置")
            
            # 查询文本输入
            query_input = gr.Textbox(
                label="查询文本",
                placeholder="请输入您要检索的问题或关键词",
                lines=3,
                info="例如: '什么是未成年?' 或 '哪些节假日应该安排休假?'"
            )
            
            # Top-K设置
            top_k_slider = gr.Slider(
                label="Top-K检索数量",
                minimum=1,
                maximum=10,
                value=5,
                step=1,
                info="设置返回的最相似文档数量"
            )
            
            # 提交按钮
            submit_btn = gr.Button(
                "执行召回测试",
                variant="primary",
                size="lg"
            )
            
            # 重置按钮
            clear_btn = gr.Button("重置", variant="secondary")

这段代码包括创建以下界面:

  • 查询文本输入框:gr.Textbox,支持多行输入
  • Top-K设置滑块:gr.Slider,范围1-10,默认值5
  • 操作按钮:"执行召回测试"(主按钮)和"重置"(次要按钮)

可以看到通过gr.对应的方法,就可以创建不同的组件。

(3)输出区域(右侧)

gr.Row()的第二个gr.Column()

Python 复制代码
        # 右侧:输出区域
        with gr.Column(scale=2):
            gr.Markdown("## 召回结果")
            
            # 结果输出
            result_output = gr.Textbox(
                label="相似度检索结果",
                lines=20,
                interactive=False,
                placeholder="召回结果将显示在这里..."
            )
            
            # 状态信息
            status_info = gr.Markdown("状态: 就绪")
  • 结果输出框:gr.Textbox,展示检索结果
  • 状态信息:gr.Markdown,显示系统当前状态

3. 按钮事件

这里主要是调用前面定义的方法:run_recall_test

然后下面封装了一个响应按钮的方法:

Python 复制代码
# 按钮事件
def on_submit(query, top_k):
    if not query:
        return "请输入查询文本", "状态: 错误 - 查询文本不能为空"
        
    status_info.value = "状态: 正在执行召回测试..."
    result = run_recall_test(query, top_k)
    return result, "状态: 测试完成"

最后挂载按钮的click方法:

复制代码
# 绑定事件
submit_btn.click(
    fn=lambda query, top_k: on_submit(query, top_k),
    inputs=[query_input, top_k_slider],
    outputs=[result_output, status_info]

需要留意的是这里的事件响应的方法跟其它编程语言的会有些不同。

5. 应用启动

python 复制代码
demo.launch(
    server_name="0.0.0.0",  # 允许外部访问
    server_port=7860,       # 端口号
    share=False,            # 不生成公共链接
    debug=False             # 非调试模式
)

指定端口号和其它信息,直接运行这个代码就可以在浏览器里访问了。

以下是代码所构建的界面。

可以看到相比用Vue来封装,代码量就少了很多,尤其是不需要创建,构建项目,以及为前端去专门写API。

所以对于快速的开发来说,Gradio是非常合适的。但是对于企业级的专业开发,还是建议选择Vue。

还有一种建议就是,通过Gradio来做快速的原型开发,然后用Vue来做生产开发。
以下是代码的全部内容,点击展开。

Python 复制代码
import os
import gradio as gr
from dotenv import load_dotenv
from LC_RAG_02_RecallTest import recall

# 加载环境变量
load_dotenv()

def run_recall_test(query, top_k):
    """运行召回测试并返回结果"""
    try:
        # 调用recall函数,但需要捕获其输出
        import io
        from contextlib import redirect_stdout
        
        # 创建一个字符串IO对象来捕获输出
        f = io.StringIO()
        with redirect_stdout(f):
            recall(
                query=query,
                top_k=top_k,
                vectorstore_dir="./RAG/chroma_db",
                embedding_model="text-embedding-v4"
            )
        
        # 获取捕获的输出
        output = f.getvalue()
        return output
    except Exception as e:
        return f"错误: {str(e)}"

# 创建界面
with gr.Blocks(title="RAG召回测试系统", theme=gr.themes.Soft()) as demo:
    # 页面标题
    gr.Markdown("# RAG召回测试系统")
    gr.Markdown("使用Gradio构建的RAG召回测试界面,调用LC_RAG_02_RecallTest.py实现相似度检索")
    
    with gr.Row():
        # 左侧:输入区域
        with gr.Column(scale=1):
            gr.Markdown("## 查询设置")
            
            # 查询文本输入
            query_input = gr.Textbox(
                label="查询文本",
                placeholder="请输入您要检索的问题或关键词",
                lines=3,
                info="例如: '什么是未成年?' 或 '哪些节假日应该安排休假?'"
            )
            
            # Top-K设置
            top_k_slider = gr.Slider(
                label="Top-K检索数量",
                minimum=1,
                maximum=10,
                value=5,
                step=1,
                info="设置返回的最相似文档数量"
            )
            
            # 提交按钮
            submit_btn = gr.Button(
                "执行召回测试",
                variant="primary",
                size="lg"
            )
            
            # 重置按钮
            clear_btn = gr.Button("重置", variant="secondary")
        
        # 右侧:输出区域
        with gr.Column(scale=2):
            gr.Markdown("## 召回结果")
            
            # 结果输出
            result_output = gr.Textbox(
                label="相似度检索结果",
                lines=20,
                interactive=False,
                placeholder="召回结果将显示在这里..."
            )
            
            # 状态信息
            status_info = gr.Markdown("状态: 就绪")
    
    # 按钮事件
    def on_submit(query, top_k):
        if not query:
            return "请输入查询文本", "状态: 错误 - 查询文本不能为空"
        
        status_info.value = "状态: 正在执行召回测试..."
        result = run_recall_test(query, top_k)
        return result, "状态: 测试完成"
    
    def on_clear():
        return "", 5, "", "状态: 已重置"
    
    # 绑定事件
    submit_btn.click(
        fn=lambda query, top_k: on_submit(query, top_k),
        inputs=[query_input, top_k_slider],
        outputs=[result_output, status_info]
    )
    
    clear_btn.click(
        fn=on_clear,
        inputs=[],
        outputs=[query_input, top_k_slider, result_output, status_info]
    )
    
    # 示例查询
    gr.Markdown("## 示例查询")
    with gr.Row():
        example1 = gr.Button("什么是未成年?")
        example2 = gr.Button("哪些节假日应该安排休假?")
        example3 = gr.Button("足球比赛的基本规则是什么?")
    
    def set_example(example_text):
        return example_text, 5, "", "状态: 就绪"
    
    example1.click(fn=lambda: set_example("什么是未成年?"), inputs=[], outputs=[query_input, top_k_slider, result_output, status_info])
    example2.click(fn=lambda: set_example("哪些节假日应该安排休假?"), inputs=[], outputs=[query_input, top_k_slider, result_output, status_info])
    example3.click(fn=lambda: set_example("足球比赛的基本规则是什么?"), inputs=[], outputs=[query_input, top_k_slider, result_output, status_info])

# 启动应用
if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=False,
        debug=False
    )
相关推荐
schinber9 小时前
大模型领域常见的核心名词解释
大模型·大模型名词
程序员柒叔10 小时前
Langfuse 项目概览
大模型·llm·prompt·可观测性·llm评估
攻城狮7号17 小时前
Anthropic开源Skills项目,打响了智能体标准化的第一枪
人工智能·大模型·skills·anthropic开源·ai技能
南方者18 小时前
大模型推理中 IRQ 中断优化:从机制解析到性能调优实践
大模型·irq
AI人工智能+18 小时前
大模型如何革新银行流水信息抽取
大模型·ocr·文本信息抽取
程序员柒叔19 小时前
Dify 工作流组件开发指南
大模型·word·workflow·工作流·dify
plmm烟酒僧19 小时前
使用 OpenVINO 本地部署 DeepSeek-R1 量化大模型(第二章:前端交互与后端服务)
前端·人工智能·大模型·intel·openvino·端侧部署·deepseek
大数据追光猿19 小时前
【Agent】高可用智能 Agent:记忆机制设计与性能优化实战
人工智能·python·langchain·大模型·agent
一代明君Kevin学长19 小时前
RAG中的上下文压缩(Contextual Compression)
人工智能·python·深度学习·ai·大模型·检索增强·rag