Qwen3-Reranker-0.6B进阶使用:Gradio WebUI界面定制化教程
Qwen3-Reranker-0.6B进阶使用:Gradio WebUI界面定制化教程
1. 引言
1.1 从能用,到好用
你已经成功部署了Qwen3-Reranker-0.6B模型,通过简单的测试脚本验证了它的基础功能。现在,你可能正面临一个新的问题:每次都要修改代码、运行脚本,才能测试不同的查询和文档,这个过程既繁琐又不够直观。
想象一下这样的场景:产品经理想看看模型对不同类型问题的排序效果,运营同学想批量测试一批商品描述的匹配度,或者你自己想快速对比几种不同提示词的效果。如果每次都要打开终端、修改代码、运行脚本,效率实在太低了。
这就是为什么我们需要一个可视化、可交互的Web界面。今天,我要带你做的,就是把那个基础的测试脚本,变成一个功能完整、界面友好、可以分享给团队使用的Web应用。我们不仅能让它“跑起来”,还要让它“用起来爽”。
1.2 为什么选择Gradio?
你可能会问:市面上有那么多Web框架,为什么偏偏选Gradio?
答案很简单:快。Gradio的核心优势就是“快速原型开发”。它不需要你懂前端HTML/CSS/JavaScript,不需要复杂的路由配置,甚至不需要搭建完整的后端服务。你只需要用Python写一个处理函数,Gradio就能自动生成一个完整的Web界面。
对于模型调试和演示来说,这简直是神器。你可以在几分钟内搭建一个界面,实时看到模型的输出,快速迭代你的提示词和参数。而且,Gradio生成的界面足够美观,可以直接分享链接给同事测试,或者集成到你的产品演示中。
1.3 本教程能带给你什么
通过这篇教程,你将学会:
- 从零搭建一个完整的Gradio WebUI,用于Qwen3-Reranker模型调用
- 深度定制界面布局和交互逻辑,让它更符合你的使用习惯
- 优化体验,添加文件上传、批量处理、结果导出等实用功能
- 部署分享,让团队其他成员也能轻松使用你的工具
我们不会停留在“Hello World”级别的简单示例,而是会构建一个真正有实用价值的重排序工具。准备好了吗?让我们开始吧。
2. 基础WebUI搭建:让你的模型“可视化”
2.1 环境准备与依赖安装
首先,确保你已经按照之前的教程部署好了Qwen3-Reranker-0.6B环境。如果还没有,可以快速回顾一下核心步骤:
# 进入项目目录
cd Qwen3-Reranker
# 确保必要的Python包已安装
pip install gradio
Gradio的安装非常简单,一行命令就能搞定。如果你需要更丰富的界面组件,也可以安装完整版:
pip install "gradio[all]"
不过对于我们的重排序应用,基础版就足够了。
2.2 创建第一个Gradio应用
让我们从一个最简单的版本开始。创建一个新文件 webui_basic.py:
import gradio as gr
from transformers import AutoModelForCausalLM, AutoTokenizer
import torch
# 加载模型和分词器(这里简化处理,实际使用时需要根据你的部署方式调整)
def load_model():
"""加载Qwen3-Reranker模型"""
model_path = "Qwen/Qwen3-Reranker-0.6B"
tokenizer = AutoTokenizer.from_pretrained(model_path, trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
model_path,
torch_dtype=torch.float16,
device_map="auto",
trust_remote_code=True
)
return model, tokenizer
# 初始化模型(在实际应用中,你可能希望延迟加载或使用单例)
# model, tokenizer = load_model()
def rerank_single_pair(query, document):
"""对单个查询-文档对进行重排序"""
# 这里先返回一个模拟结果,后续会替换为真实的模型调用
if not query or not document:
return "请输入查询和文档内容"
# 模拟计算相关性得分(0-1之间)
# 在实际实现中,这里应该调用你的模型推理代码
score = 0.85 # 模拟得分
return f"查询: {query}\n文档: {document}\n相关性得分: {score:.3f}"
# 创建Gradio界面
with gr.Blocks(title="Qwen3-Reranker 基础演示") as demo:
gr.Markdown("# 🎯 Qwen3-Reranker-0.6B 语义重排序工具")
gr.Markdown("输入查询语句和待排序的文档,获取相关性评分")
with gr.Row():
with gr.Column(scale=1):
query_input = gr.Textbox(
label="📝 查询语句",
placeholder="例如:什么是机器学习?",
lines=3
)
document_input = gr.Textbox(
label="📄 文档内容",
placeholder="请输入需要评估的文档内容...",
lines=8
)
submit_btn = gr.Button("🚀 开始评估", variant="primary")
with gr.Column(scale=1):
output = gr.Textbox(
label="📊 评估结果",
lines=12,
interactive=False
)
# 绑定点击事件
submit_btn.click(
fn=rerank_single_pair,
inputs=[query_input, document_input],
outputs=output
)
# 启动应用
if __name__ == "__main__":
demo.launch(
server_name="0.0.0.0",
server_port=7860,
share=False # 设置为True可以生成临时公网链接
)
运行这个脚本:
python webui_basic.py
然后在浏览器中打开 http://localhost:7860,你就能看到第一个版本的Web界面了。虽然功能还很基础,但我们已经有了一个可交互的起点。
2.3 集成真实的模型推理
现在,让我们把模拟函数替换为真实的模型调用。根据你的实际部署方式(可能是直接加载模型,也可能是调用API服务),调整 rerank_single_pair 函数:
def rerank_single_pair(query, document):
"""对单个查询-文档对进行重排序(真实模型版本)"""
if not query or not document:
return "错误:请输入查询和文档内容"
try:
# 假设你有一个已经初始化的model和tokenizer
# 实际代码需要根据你的模型加载方式调整
# 构造输入文本(根据Qwen3-Reranker的格式要求)
input_text = f"query: {query}\ndocument: {document}"
# 编码输入
inputs = tokenizer(input_text, return_tensors="pt").to(model.device)
# 模型推理
with torch.no_grad():
outputs = model(**inputs)
# 获取相关性得分(这里需要根据实际模型输出调整)
# Qwen3-Reranker通常输出一个分数或概率
logits = outputs.logits
# 简化处理:取最后一个token的某个维度的值作为分数
score = torch.softmax(logits[:, -1, :], dim=-1)[0, 1].item()
# 格式化输出
result = f"""## 评估结果
**查询语句**: {query}
**文档内容**: {document[:200]}... # 只显示前200字符
**相关性得分**: {score:.4f}
**解读**:
- 得分范围: 0.0 ~ 1.0
- 得分越高,表示相关性越强
- 当前得分: {'高相关性' if score > 0.7 else '中等相关性' if score > 0.4 else '低相关性'}"""
return result
except Exception as e:
return f"推理出错: {str(e)}"
重要提示:上面的代码是一个示例框架,实际的模型调用方式需要根据Qwen3-Reranker的具体接口和你的部署环境来调整。关键是要理解Gradio如何与你的模型服务交互。
3. 界面深度定制:打造专业级工具
3.1 多文档批量处理界面
在实际应用中,我们经常需要同时评估多个文档。让我们升级界面,支持批量输入:
def create_advanced_interface():
"""创建高级版界面,支持批量处理"""
with gr.Blocks(title="Qwen3-Reranker 高级版", theme=gr.themes.Soft()) as demo:
gr.Markdown("""
# 🔍 Qwen3-Reranker-0.6B 语义重排序系统
*轻量级 · 高性能 · 多文档批量处理*
""")
# 标签页布局
with gr.Tabs():
# 标签页1:单文档评估
with gr.TabItem("📝 单文档评估"):
with gr.Row():
with gr.Column():
single_query = gr.Textbox(
label="查询语句",
placeholder="输入你的查询问题...",
lines=2
)
single_doc = gr.Textbox(
label="文档内容",
placeholder="输入待评估的文档...",
lines=10
)
single_btn = gr.Button("评估单文档", variant="primary")
with gr.Column():
single_output = gr.Textbox(
label="评估结果",
lines=15,
show_copy_button=True
)
single_btn.click(
fn=rerank_single_pair,
inputs=[single_query, single_doc],
outputs=single_output
)
# 标签页2:多文档批量评估
with gr.TabItem("📚 多文档批量评估"):
with gr.Row():
with gr.Column(scale=2):
batch_query = gr.Textbox(
label="查询语句",
placeholder="输入查询问题...",
lines=2
)
batch_docs = gr.Textbox(
label="文档列表(每行一个)",
placeholder="文档1内容...\n文档2内容...\n文档3内容...",
lines=12
)
with gr.Row():
clear_btn = gr.Button("清空", variant="secondary")
batch_btn = gr.Button("批量评估", variant="primary")
with gr.Column(scale=3):
batch_output = gr.Dataframe(
label="批量评估结果",
headers=["文档ID", "内容摘要", "相关性得分", "排序"],
datatype=["str", "str", "number", "number"],
row_count=10,
col_count=(4, "fixed"),
interactive=False
)
gr.Markdown("**结果说明**: 表格按得分从高到低排序,得分越高表示相关性越强")
# 批量处理函数
def batch_rerank(query, docs_text):
"""批量处理多个文档"""
if not query or not docs_text:
return []
docs = [d.strip() for d in docs_text.split('\n') if d.strip()]
results = []
# 这里应该调用批量推理接口
# 为了演示,我们生成模拟数据
import random
for i, doc in enumerate(docs[:10]): # 限制前10个
score = random.uniform(0.3, 0.95) # 模拟得分
summary = doc[:50] + "..." if len(doc) > 50 else doc
results.append([f"文档{i+1}", summary, round(score, 4), i+1])
# 按得分排序
results.sort(key=lambda x: x[2], reverse=True)
# 更新排序序号
for i, row in enumerate(results):
row[3] = i + 1
return results
batch_btn.click(
fn=batch_rerank,
inputs=[batch_query, batch_docs],
outputs=batch_output
)
clear_btn.click(
fn=lambda: ("", ""),
inputs=[],
outputs=[batch_query, batch_docs]
)
# 标签页3:文件上传处理
with gr.TabItem("📁 文件上传处理"):
gr.Markdown("支持上传文本文件,每行作为一个文档进行处理")
with gr.Row():
with gr.Column():
file_query = gr.Textbox(
label="查询语句",
placeholder="输入查询问题...",
lines=2
)
file_upload = gr.File(
label="上传文档文件",
file_types=[".txt", ".csv"],
file_count="single"
)
file_btn = gr.Button("处理文件", variant="primary")
with gr.Column():
file_preview = gr.Textbox(
label="文件内容预览",
lines=8,
interactive=False
)
file_output = gr.File(label="下载结果文件")
def process_file(query, file):
"""处理上传的文件"""
if file is None:
return "请先上传文件", None
try:
# 读取文件内容
with open(file.name, 'r', encoding='utf-8') as f:
content = f.read()
# 预览前500字符
preview = content[:500] + ("..." if len(content) > 500 else "")
# 这里应该调用模型处理
# 生成结果文件(示例)
import tempfile
import csv
temp_file = tempfile.NamedTemporaryFile(
mode='w',
suffix='.csv',
delete=False,
encoding='utf-8'
)
writer = csv.writer(temp_file)
writer.writerow(["文档ID", "内容摘要", "相关性得分"])
# 模拟处理每行
lines = content.split('\n')
for i, line in enumerate(lines[:20]): # 限制前20行
if line.strip():
# 模拟得分
score = 0.5 + (i % 10) * 0.05
summary = line[:30] + "..." if len(line) > 30 else line
writer.writerow([f"行{i+1}", summary, f"{score:.4f}"])
temp_file.close()
return preview, temp_file.name
except Exception as e:
return f"文件处理出错: {str(e)}", None
file_btn.click(
fn=process_file,
inputs=[file_query, file_upload],
outputs=[file_preview, file_output]
)
# 添加一些说明
with gr.Accordion("📖 使用说明", open=False):
gr.Markdown("""
### 功能说明
1. **单文档评估**:适合精细分析单个文档的相关性
2. **多文档批量评估**:适合从多个候选文档中找出最相关的
3. **文件上传处理**:适合处理大量文档,支持结果导出
### 使用技巧
- 查询语句要具体明确,避免模糊表述
- 文档内容尽量完整,包含关键信息
- 批量处理时,建议每次不超过50个文档
- 结果得分范围:0.0(不相关)~ 1.0(高度相关)
""")
return demo
这个高级版本包含了:
- 标签页布局:三种不同的使用模式
- 数据表格:以结构化方式展示批量结果
- 文件上传:支持从文件读取文档
- 结果导出:可以下载处理后的CSV文件
- 交互控件:清空按钮、文件预览等
3.2 添加参数调节面板
不同的应用场景可能需要不同的处理参数。让我们添加一个参数调节面板:
def create_interface_with_params():
"""创建带参数调节的界面"""
with gr.Blocks(title="Qwen3-Reranker 参数调节版", theme=gr.themes.Monochrome()) as demo:
gr.Markdown("# ⚙️ Qwen3-Reranker 参数调节版")
with gr.Row():
# 左侧:输入区域
with gr.Column(scale=2):
query = gr.Textbox(label="查询语句", lines=3)
document = gr.Textbox(label="文档内容", lines=10)
# 中间:参数调节区域
with gr.Column(scale=1):
with gr.Group():
gr.Markdown("### 模型参数")
temperature = gr.Slider(
minimum=0.0,
maximum=2.0,
value=0.7,
step=0.1,
label="Temperature",
info="控制随机性,值越高输出越多样"
)
top_p = gr.Slider(
minimum=0.0,
maximum=1.0,
value=0.9,
step=0.05,
label="Top-p",
info="核采样参数,控制候选词范围"
)
max_length = gr.Slider(
minimum=10,
maximum=1000,
value=512,
step=10,
label="最大长度",
info="生成文本的最大长度"
)
batch_size = gr.Slider(
minimum=1,
maximum=32,
value=4,
step=1,
label="批处理大小",
info="同时处理的文档数量"
)
with gr.Group():
gr.Markdown("### 显示选项")
show_details = gr.Checkbox(
label="显示详细推理过程",
value=False
)
format_output = gr.Radio(
choices=["纯文本", "Markdown", "JSON"],
value="Markdown",
label="输出格式"
)
# 右侧:输出区域
with gr.Column(scale=2):
output = gr.Textbox(label="评估结果", lines=15)
with gr.Row():
submit_btn = gr.Button("开始评估", variant="primary")
reset_btn = gr.Button("重置参数", variant="secondary")
# 带参数的评估函数
def rerank_with_params(query, document, temp, top_p_val, max_len, batch_size_val, show_details_val, format_val):
"""带参数的重排序函数"""
if not query or not document:
return "请输入查询和文档内容"
# 这里应该调用带参数的模型接口
# 模拟结果
score = 0.82
# 根据格式选项格式化输出
if format_val == "纯文本":
result = f"查询: {query}\n文档: {document[:100]}...\n得分: {score:.3f}"
if show_details_val:
result += f"\n\n参数设置:\n- Temperature: {temp}\n- Top-p: {top_p_val}\n- 最大长度: {max_len}"
elif format_val == "Markdown":
result = f"""## 评估结果
**查询**: {query}
**文档摘要**: {document[:100]}...
**相关性得分**: **{score:.3f}**
**参数配置**:
- Temperature: `{temp}`
- Top-p: `{top_p_val}`
- 最大长度: `{max_len}`
- 批处理大小: `{batch_size_val}`"""
else: # JSON格式
import json
result_data = {
"query": query,
"document_preview": document[:100] + "...",
"score": round(score, 3),
"parameters": {
"temperature": temp,
"top_p": top_p_val,
"max_length": max_len,
"batch_size": batch_size_val
}
}
result = json.dumps(result_data, indent=2, ensure_ascii=False)
return result
# 绑定事件
submit_btn.click(
fn=rerank_with_params,
inputs=[query, document, temperature, top_p, max_length, batch_size, show_details, format_output],
outputs=output
)
# 重置参数函数
def reset_params():
return [0.7, 0.9, 512, 4, False, "Markdown"]
reset_btn.click(
fn=reset_params,
inputs=[],
outputs=[temperature, top_p, max_length, batch_size, show_details, format_output]
)
return demo
3.3 添加历史记录和对比功能
对于调试和优化来说,能够对比不同查询或参数的结果非常有用:
def create_interface_with_history():
"""创建带历史记录功能的界面"""
# 用于存储历史记录的全局变量(在实际应用中应该使用数据库)
history = []
with gr.Blocks(title="Qwen3-Reranker 历史记录版") as demo:
gr.Markdown("# 📊 Qwen3-Reranker 历史记录与对比")
with gr.Row():
# 输入区域
with gr.Column():
current_query = gr.Textbox(label="当前查询", lines=2)
current_doc = gr.Textbox(label="当前文档", lines=6)
current_btn = gr.Button("评估并保存", variant="primary")
# 历史记录区域
with gr.Column():
history_display = gr.Dataframe(
label="历史记录",
headers=["时间", "查询摘要", "文档摘要", "得分"],
datatype=["str", "str", "str", "number"],
row_count=5,
interactive=False
)
with gr.Row():
clear_history_btn = gr.Button("清空历史", variant="secondary")
compare_btn = gr.Button("对比选中项", variant="primary")
# 输出和对比区域
current_output = gr.Textbox(label="当前结果", lines=8)
comparison_output = gr.Textbox(label="对比结果", lines=10, visible=False)
# 评估并保存到历史
def evaluate_and_save(query, doc):
if not query or not doc:
return "请输入内容", []
# 模拟评估
score = 0.75
# 保存到历史
import datetime
timestamp = datetime.datetime.now().strftime("%H:%M:%S")
history.append({
"time": timestamp,
"query": query[:30] + "..." if len(query) > 30 else query,
"doc": doc[:50] + "..." if len(doc) > 50 else doc,
"score": score
})
# 只保留最近10条
if len(history) > 10:
history.pop(0)
# 更新历史显示
history_list = [
[h["time"], h["query"], h["doc"], h["score"]]
for h in history
]
result = f"评估完成!得分: {score:.3f}\n已保存到历史记录。"
return result, history_list
# 对比历史记录
def compare_history():
if len(history) < 2:
return gr.Textbox(visible=False), "需要至少2条记录才能对比"
# 获取得分最高的两条记录
sorted_history = sorted(history, key=lambda x: x["score"], reverse=True)
best = sorted_history[0]
second = sorted_history[1] if len(sorted_history) > 1 else best
comparison = f"""## 历史记录对比分析
### 最佳匹配
**时间**: {best['time']}
**查询**: {best['query']}
**文档**: {best['doc']}
**得分**: {best['score']:.3f}
### 次佳匹配
**时间**: {second['time']}
**查询**: {second['query']}
**文档**: {second['doc']}
**得分**: {second['score']:.3f}
### 分析
- 最佳匹配得分比次佳高 {best['score'] - second['score']:.3f}
- 平均得分: {(best['score'] + second['score']) / 2:.3f}
- 建议: 尝试结合两者的查询特点,优化搜索效果"""
return gr.Textbox(visible=True), comparison
# 清空历史
def clear_history():
history.clear()
return []
# 绑定事件
current_btn.click(
fn=evaluate_and_save,
inputs=[current_query, current_doc],
outputs=[current_output, history_display]
)
compare_btn.click(
fn=compare_history,
inputs=[],
outputs=[comparison_output, comparison_output]
)
clear_history_btn.click(
fn=clear_history,
inputs=[],
outputs=history_display
)
return demo
4. 部署与优化:让工具真正可用
4.1 完整的生产级应用
现在,让我们把所有功能整合到一个完整的应用中:
# webui_complete.py
import gradio as gr
import argparse
import logging
from typing import List, Tuple
import json
# 设置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
class QwenRerankerWebUI:
"""Qwen3-Reranker WebUI 主类"""
def __init__(self, model_path: str = None):
"""
初始化WebUI
Args:
model_path: 模型路径,如果为None则使用模拟模式
"""
self.model_path = model_path
self.history = []
self.setup_model()
def setup_model(self):
"""设置模型(这里简化处理,实际需要加载模型)"""
if self.model_path:
logger.info(f"正在加载模型: {self.model_path}")
# 实际应该在这里加载模型
# self.model, self.tokenizer = load_model(self.model_path)
self.use_real_model = True
else:
logger.info("使用模拟模式(不加载真实模型)")
self.use_real_model = False
def rerank(self, query: str, document: str, **kwargs) -> float:
"""
重排序核心函数
Args:
query: 查询语句
document: 文档内容
**kwargs: 其他参数
Returns:
相关性得分
"""
if self.use_real_model:
# 调用真实模型
# score = self.model.predict(query, document)
# return score
pass
# 模拟模式:返回一个基于文本长度的模拟得分
# 这只是为了演示,实际应该使用模型推理
query_len = len(query)
doc_len = len(document)
if query_len == 0 or doc_len == 0:
return 0.0
# 简单的模拟逻辑
import random
base_score = 0.5
length_factor = min(doc_len / 1000, 1.0) * 0.3
random_factor = random.random() * 0.2
return min(base_score + length_factor + random_factor, 0.99)
def create_interface(self):
"""创建完整的Web界面"""
with gr.Blocks(
title="Qwen3-Reranker-0.6B 语义重排序系统",
theme=gr.themes.Soft(),
css="""
.gradio-container {
max-width: 1200px !important;
margin: 0 auto !important;
}
.result-box {
border: 1px solid #e0e0e0;
border-radius: 8px;
padding: 15px;
margin: 10px 0;
background: #f8f9fa;
}
.score-high { color: #28a745; font-weight: bold; }
.score-medium { color: #ffc107; font-weight: bold; }
.score-low { color: #dc3545; font-weight: bold; }
"""
) as demo:
# 标题和描述
gr.Markdown("""
# 🔍 Qwen3-Reranker-0.6B 语义重排序系统
*基于通义千问轻量级重排序模型 · 支持多文档批量处理 · 提供可视化分析*
""")
# 主标签页
with gr.Tabs():
# 快速评估标签页
with gr.TabItem("⚡ 快速评估"):
self.create_quick_eval_tab()
# 批量处理标签页
with gr.TabItem("📊 批量处理"):
self.create_batch_tab()
# 高级设置标签页
with gr.TabItem("⚙️ 高级设置"):
self.create_advanced_tab()
# 历史分析标签页
with gr.TabItem("📈 历史分析"):
self.create_history_tab()
# 页脚
gr.Markdown("---")
with gr.Row():
gr.Markdown("""
**使用提示**:
- 查询语句要具体明确
- 文档内容尽量完整
- 批量处理建议不超过50个文档
- 得分范围: 0.0 (不相关) ~ 1.0 (高度相关)
""")
gr.Markdown("""
**版本信息**:
- 模型: Qwen3-Reranker-0.6B
- 界面版本: 1.0.0
- 最后更新: 2024年
""")
return demo
def create_quick_eval_tab(self):
"""创建快速评估标签页"""
with gr.Row():
with gr.Column(scale=2):
query = gr.Textbox(
label="查询语句",
placeholder="请输入你的查询问题...",
lines=3,
elem_id="query-input"
)
document = gr.Textbox(
label="文档内容",
placeholder="请输入需要评估的文档内容...",
lines=10,
elem_id="doc-input"
)
with gr.Row():
submit_btn = gr.Button("开始评估", variant="primary", size="lg")
clear_btn = gr.Button("清空输入", variant="secondary")
with gr.Column(scale=3):
with gr.Group():
output_score = gr.Number(
label="相关性得分",
value=0.0,
precision=4,
elem_id="score-output"
)
score_bar = gr.Slider(
minimum=0,
maximum=100,
value=0,
interactive=False,
label="得分可视化",
elem_id="score-bar"
)
score_text = gr.Markdown("", elem_id="score-text")
with gr.Accordion("📋 详细结果", open=False):
detail_output = gr.Textbox(
lines=8,
show_copy_button=True,
elem_id="detail-output"
)
# 评估函数
def evaluate_single(query_text, doc_text):
if not query_text or not doc_text:
return 0.0, 0, "请先输入查询和文档内容", ""
try:
# 调用重排序函数
score = self.rerank(query_text, doc_text)
score_percent = int(score * 100)
# 生成评估文本
if score > 0.7:
level = "高相关性"
level_class = "score-high"
elif score > 0.4:
level = "中等相关性"
level_class = "score-medium"
else:
level = "低相关性"
level_class = "score-low"
score_html = f"<span class='{level_class}'>{level}</span> (得分: {score:.4f})"
# 详细结果
detail = f"""## 评估详情
**查询语句**: {query_text}
**文档长度**: {len(doc_text)} 字符
**相关性分析**:
- 得分: {score:.4f}
- 等级: {level}
- 解读: {'建议采用此文档' if score > 0.7 else '可考虑此文档' if score > 0.4 else '不建议采用此文档'}
**处理状态**: ✅ 评估完成"""
return score, score_percent, score_html, detail
except Exception as e:
logger.error(f"评估出错: {e}")
return 0.0, 0, f"评估出错: {str(e)}", ""
# 清空函数
def clear_inputs():
return "", "", 0.0, 0, "", ""
# 绑定事件
submit_btn.click(
fn=evaluate_single,
inputs=[query, document],
outputs=[output_score, score_bar, score_text, detail_output]
)
clear_btn.click(
fn=clear_inputs,
inputs=[],
outputs=[query, document, output_score, score_bar, score_text, detail_output]
)
def create_batch_tab(self):
"""创建批量处理标签页"""
with gr.Row():
with gr.Column():
batch_query = gr.Textbox(
label="查询语句",
placeholder="输入查询问题...",
lines=2
)
batch_docs = gr.Textbox(
label="文档列表(每行一个文档)",
placeholder="文档1内容...\n文档2内容...\n文档3内容...",
lines=12
)
with gr.Row():
batch_size = gr.Slider(
minimum=1,
maximum=20,
value=5,
step=1,
label="每次处理数量"
)
batch_btn = gr.Button("批量评估", variant="primary")
with gr.Column():
batch_results = gr.Dataframe(
label="评估结果",
headers=["序号", "文档摘要", "得分", "等级"],
datatype=["number", "str", "number", "str"],
row_count=10,
interactive=False
)
with gr.Row():
export_json = gr.Button("导出JSON", variant="secondary")
export_csv = gr.Button("导出CSV", variant="secondary")
export_file = gr.File(label="下载文件", visible=False)
# 批量处理函数
def process_batch(query_text, docs_text, size):
if not query_text or not docs_text:
return [], None
docs = [d.strip() for d in docs_text.split('\n') if d.strip()]
results = []
# 分批处理
for i in range(0, min(len(docs), 50), size): # 最多处理50个
batch = docs[i:i+size]
for j, doc in enumerate(batch):
score = self.rerank(query_text, doc)
# 确定等级
if score > 0.7:
level = "高"
elif score > 0.4:
level = "中"
else:
level = "低"
summary = doc[:40] + "..." if len(doc) > 40 else doc
results.append([i+j+1, summary, round(score, 4), level])
# 按得分排序
results.sort(key=lambda x: x[2], reverse=True)
# 生成导出文件
import tempfile
import csv
# JSON导出
json_data = {
"query": query_text,
"total_docs": len(docs),
"processed": len(results),
"results": [
{
"rank": idx + 1,
"score": result[2],
"level": result[3],
"preview": result[1]
}
for idx, result in enumerate(results)
]
}
json_file = tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False, encoding='utf-8')
json.dump(json_data, json_file, indent=2, ensure_ascii=False)
json_file.close()
return results, json_file.name
# 导出函数
def export_to_csv(results_data):
if not results_data:
return None
import tempfile
import csv
csv_file = tempfile.NamedTemporaryFile(mode='w', suffix='.csv', delete=False, encoding='utf-8')
writer = csv.writer(csv_file)
writer.writerow(["排名", "文档摘要", "得分", "等级"])
for row in results_data:
writer.writerow(row)
csv_file.close()
return csv_file.name
# 绑定事件
batch_btn.click(
fn=process_batch,
inputs=[batch_query, batch_docs, batch_size],
outputs=[batch_results, export_file]
)
export_json.click(
fn=lambda x: x,
inputs=[export_file],
outputs=export_file
)
export_csv.click(
fn=export_to_csv,
inputs=[batch_results],
outputs=export_file
)
def create_advanced_tab(self):
"""创建高级设置标签页"""
with gr.Row():
with gr.Column():
gr.Markdown("### 模型参数设置")
temperature = gr.Slider(0.0, 2.0, 0.7, step=0.1, label="Temperature")
top_p = gr.Slider(0.0, 1.0, 0.9, step=0.05, label="Top-p")
max_tokens = gr.Slider(1, 1000, 512, step=1, label="最大Token数")
gr.Markdown("### 处理设置")
enable_cache = gr.Checkbox(True, label="启用结果缓存")
timeout = gr.Slider(1, 60, 30, step=1, label="超时时间(秒)")
retry_times = gr.Slider(0, 5, 2, step=1, label="重试次数")
with gr.Column():
gr.Markdown("### 界面设置")
theme_select = gr.Radio(
["默认", "深色", "浅色"],
value="默认",
label="主题颜色"
)
language_select = gr.Radio(
["中文", "英文"],
value="中文",
label="界面语言"
)
auto_save = gr.Checkbox(True, label="自动保存设置")
gr.Markdown("### 系统信息")
with gr.Group():
model_status = gr.Markdown("**模型状态**: 模拟模式")
memory_usage = gr.Markdown("**内存使用**: --")
last_update = gr.Markdown("**最后更新**: --")
save_btn = gr.Button("保存设置", variant="primary")
# 保存设置函数
def save_settings(temp, top_p_val, max_tokens_val, cache, timeout_val, retry, theme, lang, auto_save_val):
settings = {
"temperature": temp,
"top_p": top_p_val,
"max_tokens": max_tokens_val,
"enable_cache": cache,
"timeout": timeout_val,
"retry_times": retry,
"theme": theme,
"language": lang,
"auto_save": auto_save_val
}
# 这里应该保存到配置文件
logger.info(f"保存设置: {settings}")
return "✅ 设置已保存!部分设置需要刷新页面生效。"
save_btn.click(
fn=save_settings,
inputs=[temperature, top_p, max_tokens, enable_cache, timeout, retry_times, theme_select, language_select, auto_save],
outputs=gr.Markdown()
)
def create_history_tab(self):
"""创建历史分析标签页"""
with gr.Row():
with gr.Column():
history_table = gr.Dataframe(
label="评估历史",
headers=["时间", "查询", "得分", "操作"],
datatype=["str", "str", "number", "str"],
row_count=10,
interactive=False
)
with gr.Row():
refresh_btn = gr.Button("刷新历史", variant="secondary")
clear_all_btn = gr.Button("清空历史", variant="stop")
with gr.Column():
stats_plot = gr.Plot(label="得分分布")
trend_plot = gr.Plot(label="趋势分析")
# 模拟历史数据
def get_history():
import datetime
import random
history_data = []
now = datetime.datetime.now()
for i in range(10):
time = (now - datetime.timedelta(minutes=i*5)).strftime("%H:%M")
query = f"查询示例 {i+1}"
score = round(random.uniform(0.3, 0.95), 3)
action = "查看详情"
history_data.append([time, query, score, action])
return history_data
# 更新图表
def update_plots():
import matplotlib.pyplot as plt
import numpy as np
# 得分分布图
fig1, ax1 = plt.subplots(figsize=(6, 4))
scores = np.random.randn(100) * 0.2 + 0.6
scores = np.clip(scores, 0, 1)
ax1.hist(scores, bins=20, alpha=0.7, color='skyblue', edgecolor='black')
ax1.set_xlabel('得分')
ax1.set_ylabel('频次')
ax1.set_title('得分分布直方图')
ax1.grid(True, alpha=0.3)
# 趋势图
fig2, ax2 = plt.subplots(figsize=(6, 4))
x = range(10)
y = [0.5 + 0.1 * np.sin(i/2) + 0.05 * i for i in x]
ax2.plot(x, y, marker='o', linestyle='-', color='orange')
ax2.set_xlabel('评估次数')
ax2.set_ylabel('平均得分')
ax2.set_title('得分趋势图')
ax2.grid(True, alpha=0.3)
ax2.set_ylim(0, 1)
return fig1, fig2
# 绑定事件
refresh_btn.click(
fn=get_history,
inputs=[],
outputs=history_table
)
refresh_btn.click(
fn=update_plots,
inputs=[],
outputs=[stats_plot, trend_plot]
)
clear_all_btn.click(
fn=lambda: [],
inputs=[],
outputs=history_table
)
def main():
"""主函数"""
parser = argparse.ArgumentParser(description="Qwen3-Reranker WebUI")
parser.add_argument("--model-path", type=str, help="模型路径")
parser.add_argument("--port", type=int, default=7860, help="服务端口")
parser.add_argument("--share", action="store_true", help="生成公网链接")
args = parser.parse_args()
# 创建WebUI实例
webui = QwenRerankerWebUI(model_path=args.model_path)
# 创建界面
demo = webui.create_interface()
# 启动服务
demo.launch(
server_name="0.0.0.0",
server_port=args.port,
share=args.share,
favicon_path=None
)
if __name__ == "__main__":
main()
4.2 部署和运行
保存上面的代码为 webui_complete.py,然后运行:
# 基本运行
python webui_complete.py
# 指定端口
python webui_complete.py --port 8080
# 生成公网链接(需要gradio账号)
python webui_complete.py --share
# 指定模型路径(如果你有真实模型)
python webui_complete.py --model-path /path/to/your/model
访问 http://localhost:7860 就能看到完整的Web界面了。
4.3 性能优化建议
在实际生产环境中,你还需要考虑以下优化:
- 模型加载优化:
# 使用缓存,避免重复加载
from functools import lru_cache
@lru_cache(maxsize=1)
def get_model():
"""获取模型单例"""
return load_model()
- 异步处理:
import asyncio
from concurrent.futures import ThreadPoolExecutor
executor = ThreadPoolExecutor(max_workers=4)
async def async_rerank(query, document):
"""异步重排序"""
loop = asyncio.get_event_loop()
return await loop.run_in_executor(executor, rerank_sync, query, document)
- 批处理优化:
def batch_rerank(query, documents):
"""批量重排序,减少模型调用次数"""
# 将多个文档合并为一批处理
batch_inputs = prepare_batch(query, documents)
batch_scores = model.predict_batch(batch_inputs)
return batch_scores
- 结果缓存:
from cachetools import TTLCache
cache = TTLCache(maxsize=1000, ttl=300) # 缓存1000个结果,5分钟过期
def cached_rerank(query, document):
"""带缓存的重排序"""
cache_key = f"{query}_{document}"
if cache_key in cache:
return cache[cache_key]
score = rerank(query, document)
cache[cache_key] = score
return score
5. 总结
5.1 核心收获
通过这篇教程,我们完成了一个完整的Qwen3-Reranker-0.6B WebUI工具的开发。从最基础的单文档评估,到功能丰富的批量处理、参数调节、历史分析,我们一步步构建了一个真正可用的生产级工具。
关键的技术要点包括:
- Gradio基础使用:掌握了Blocks、Tabs、Row、Column等布局组件,以及各种输入输出组件的使用方法
- 界面设计原则:学会了如何设计直观、易用的用户界面,包括合理的布局、清晰的标签、友好的交互
- 功能模块化:将复杂功能拆分为独立的标签页和组件,提高代码的可维护性
- 实际工程考虑:考虑了文件上传、结果导出、历史记录、参数调节等实际需求
5.2 进阶建议
现在你已经有了一个可用的WebUI,接下来可以考虑:
- 集成真实模型:将模拟评分替换为真实的Qwen3-Reranker模型调用
- 添加用户认证:如果需要对外提供服务,可以添加简单的登录验证
- 数据库集成:使用SQLite或MySQL存储历史记录和用户数据
- API接口:为WebUI添加REST API,方便其他系统集成
- 容器化部署:使用Docker打包整个应用,方便部署和迁移
5.3 最后的思考
工具的价值在于使用。一个好的WebUI不仅仅是技术的展示,更是用户体验的体现。通过这个项目,你不仅学会了Gradio的使用,更重要的是掌握了如何从用户角度思考,设计出真正好用的工具。
记住,技术是为业务服务的。无论你的模型多么强大,如果用户无法方便地使用它,那么它的价值就无法充分发挥。希望这个教程能帮助你更好地展示和应用Qwen3-Reranker的能力。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。
更多推荐




所有评论(0)