本文将会介绍什么是Open
WebUI中的Pipelines,并给出一些简单的例子,最后演示如何结合Pipelines来制作大模型解数学题的Web界面。
在文章NLP(一百零三)大模型应用利器之Open
WebUI入门 中,笔者介绍了大模型应用方面一个很好用的工具,即Open WebUI
。本文将会在此基础上,介绍Open WebUI
的一个重要特性,即Pipelines(管道,或者流水线),它允许开发者来定制使用大模型的流程。
Open WebUI中的Pipelines
介绍
Pipelines为Open WebUI
带来了模块化、定制化的工作流程,这对于任何支持Open
API的UI客户端都是支持的。只需几行代码,它就能帮助你轻松地扩展功能,集成独特的逻辑,创建动态工作流程。
常见的Pipeline有以下几种:
Function Calling Pipeline : 轻松处理function
calls,使用定制化逻辑来提升你的应用;
Custom RAG Pipeline : 执行复杂的RAG
pipelines满足你的需求;
Rate Limit Filter : 控制流程中的请求,避免超出rate
limits;
Toxic Message
Filter :执行过滤器,用于高效地检测和处理有毒的消息;
其它
如需使用Pipelines 服务,我们只需要执行下面的Docker命令即可:
1 docker run -p 9099:9099 --add-host=host.docker.internal:host-gateway -v pipelines:/app/pipelines --name pipelines --restart always ghcr.io/open-webui/pipelines:main
例子
使用open-webui serve
命令启动Open WebUI
,在该应用界面中配置Pipelines连接,如下图:
配置Pipelines连接
以添加Wikipedia Pipeline
为例,我们来演示如何在Open WebUI
使用Pipelines.
在Settings -> Admin Panel -》 Pipelines汇总,选择来自Github
URL的pipeline,并点击下载按钮,并保存,如下图:
添加Wikipedia Pipeline
在新对话(New
Chat)中,选择Wikipedia Pipeline
进行对话,以输入"Mistral
AI"为例,结果如下图:
使用Wikipedia Pipeline
Pipelines实战
接下来,我们来自己实现一个定制化的Pipeline,即使用大模型来数学题。
在文章NLP(一百)大模型数学能力测评 中,笔者介绍了如何使用大模型微调数学解题数据,并使用训练后的模型来解答数学题。其中,使用大模型来解答数学题的流程是这样的:
用户输入数学题目
大模型给出思考和解答过程,并生成Python代码
执行Python代码,得到运行结果
使用运行结果,进行回答总结
我们以QWen-2-72B-Instruct
为例,在笔者构建的数学习题数据集上进行微调,训练后的模型在GSM8K 数据集上的准确率为93.03%,在MATH 数据集上的准确率为68.54%,比训练前的两个指标有所提升,如下图:
pipelines_4.png
笔者在Github的llm_math_solver
项目中,进行了一系列模型微调,结果如下表:
QWen1.5-32B
79.68%
43.58%
2402
Yi-1.5-34B
83.47%
52.76%
3480
Yi-1.5-34B-Chat
85.67%
57.22%
3479
QWen-2-72B-Instruct
93.03%
68.54%
3469
在MATH 数据集上,微调后的QWen-2-72B-Instruct
模型准确率达到了惊人的68.54%。与之进行对比,GPT-4o-0513
模型的准确率为76.6%,DeepSeek-Coder-V2-Instruct
模型(236B)的准确率为75.7%。
我们将以微调后的QWen-2-72B-Instruct
模型来创建大模型解数学题的Web界面。
使用Pipelines构建大模型解数学题的Web界面
首先,使用vLLM部署微调后的QWen-2-72B-Instruct
模型,新模型为QWen-2-72B-Instruct-math
模型。
我们创建Math Solver Pipeline
,其中上传的Pipeline实现的Python脚本如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 import osimport reimport jsonimport requestsimport subprocessfrom typing import List , Union , Generator, Iteratorfrom schemas import OpenAIChatMessagefrom pydantic import BaseModelfrom openai import OpenAIfrom random import choices os.environ["OPENAI_BASE_URL" ] = "http://localhost:50080/v1" os.environ["OPENAI_API_KEY" ] = "token-abc123" client = OpenAI() execution_desc = ["运行以上代码,输出会是: " , "现在将上面的代码复制到Python环境中运行,运行结果为:" , "执行上述Python代码,运行结果将是:" , "上面的Python代码执行结果为:" , "运行上述代码,我们可以得到题目要求的答案。输出结果将是:" ]class Pipeline : class Valves (BaseModel ): pass def __init__ (self ): self.name = "Math Solver Pipeline" pass async def on_startup (self ): print (f"on_startup:{__name__} " ) pass async def on_shutdown (self ): print (f"on_shutdown:{__name__} " ) pass def pipe ( self, user_message: str , model_id: str , messages: List [dict ], body: dict ) -> Union [str , Generator, Iterator]: print (f"pipe:{__name__} " ) print (f"user_message: {user_message} " ) query = user_message messages = [{"role" : "system" ,"content" : "你是一个数学解题大师,请解决下面的数学题,给出思考过程,必要时需要给出解题过程中的Python代码。正确答案的数值用\\boxed{}包围起来,最终的答案以因此开头,不要讲多余的废话。" }] messages.append({"role" : "user" , "content" : f"题目:{query} " }) result = client.chat.completions.create(messages=messages, model="Qwen2-72B-Instruct-math" , temperature=0.2 , stream=True ) reply_message = "" for chunk in result: if hasattr (chunk, "choices" ) and chunk.choices[0 ].delta.content: reply_message += chunk.choices[0 ].delta.content if '```python' in reply_message and '\n```' in reply_message: messages.append({"role" : "assistant" , "content" : '```' .join(reply_message.split('```' )[:-1 ]) + '```' }) python_code_string = re.findall(r'```python\n(.*?)\n```' , reply_message, re.S)[0 ] python_file_path = 'temp.py' with open (python_file_path, 'w' ) as f: f.write(python_code_string) python_code_run = subprocess.run(['python3' , python_file_path], stdout=subprocess.PIPE, timeout=10 ) if python_code_run.returncode: raise RuntimeError("生成的Python代码无法运行!" ) python_code_execution = python_code_run.stdout.decode('utf-8' ) os.remove(python_file_path) code_reply_str = choices(execution_desc, k=1 )[0 ] code_reply = f"\n{code_reply_str} ```{python_code_execution.strip()} ```\n" reply_message += code_reply messages.append({"role" : "user" , "content" : code_reply}) result = client.chat.completions.create(messages=messages, model="Qwen2-72B-Instruct-math" , temperature=0.2 , stream=True ) final_reply = "" for chunk in result: if hasattr (chunk, "choices" ) and chunk.choices[0 ].delta.content: reply_message += chunk.choices[0 ].delta.content final_reply += chunk.choices[0 ].delta.content return reply_message.replace('```python' , '\n```python' ) else : return reply_message
创建完该Pipeline后,我们就能在Open WebUI
界面中使用该流程进行对话了。
示例对话如下图:
有兴趣的读者,可以尝试在DeepSeek
V2产品中解决上面的数学题。这样你就能发现,微调后的QWen-2-72B-Instruct-math
模型的在这些题目上的表现不输给DeepSeek
V2 Coder模型。
总结
本文介绍了什么是Open
WebUI中的Pipelines,并给出一些简单的例子,最后演示如何结合Pipelines来制作大模型解数学题的Web界面。
关于对QWen-2-72B-Instruct
模型的数学能力微调,以及创建解数学题的Pipeline方面的资料,可参考Github项目:
https://github.com/percent4/llm_math_solver .
参考文献
Getting Started with OpenWebUI Pipelines:
https://ikasten.io/2024/06/03/getting-started-with-openwebui-pipelines/
Pipelines: UI-Agnostic OpenAI API Plugin Framework:
https://docs.openwebui.com/pipelines/
Qwen2-72B-Instruct:
https://huggingface.co/Qwen/Qwen2-72B-Instruct
DeepSeek-Coder-V2: Breaking the Barrier of Closed-Source Models in
Code Intelligence: https://github.com/deepseek-ai/DeepSeek-Coder-V2
Welcome to LLM Math Solver:
https://github.com/percent4/llm_math_solver