Skip to main content

🪄 过滤器函数(Filter Function):修改输入和输出

欢迎阅读 Open WebUI 过滤器函数的全面指南!过滤器函数是一个灵活而强大的扩展系统,用于修改发送到大语言模型(Large Language Model,LLM)之前(输入)或从 LLM 返回之后(输出)的数据。无论你是为了更好的上下文而转换输入,还是为了提高可读性而清理输出,过滤器函数都能满足你的需求。

本指南将详细解释什么是过滤器函数、它们如何工作、它们的结构,以及构建你自己的强大且用户友好的过滤器函数所需要知道的一切。让我们深入了解,别担心——我会使用比喻、示例和提示来让一切变得清晰明了!🌟


🌊 什么是 Open WebUI 中的过滤器函数?

想象 Open WebUI 是一个智能净水系统:

  • 用户输入LLM 输出是流动的水。
  • 过滤器函数是在水流到达最终用户之前进行净化、调节和优化的水质处理阶段

过滤器函数位于数据流的中间——像智能检测站一样——你可以在这里决定需要调整什么。

以下是过滤器函数功能的快速总结:

  1. 修改用户输入(Inlet 函数):在数据到达 AI 模型之前调整输入数据。在这里你可以增强清晰度、添加上下文、净化文本或将消息重新格式化以匹配特定要求。
  2. 修改模型输出(Outlet 函数):在 AI 处理之后、显示给用户之前调整 AI 的响应。这可以帮助优化、记录或调整数据,以提供更清晰的用户体验。

**关键概念:**过滤器函数不是独立的模型,而是增强或转换流向来自模型的数据的工具。

过滤器函数就像 AI 工作流中的智能编辑器:你可以在不中断数据流的情况下拦截和优化对话。


🗺️ 过滤器函数的结构:基础框架

让我们从最基础的过滤器函数结构开始。如果一开始某些部分感觉很技术性,别担心——我们会一步一步地详细解释!

🦴 过滤器函数的基本框架

from pydantic import BaseModel
from typing import Optional

class Filter:
# 阀门:过滤器的配置选项 / Valves: Configuration options for the filter
class Valves(BaseModel):
pass

def __init__(self):
# 初始化阀门(过滤器的可选配置)/ Initialize valves (optional configuration for the filter)
self.valves = self.Valves()

def inlet(self, body: dict) -> dict:
# 这里是处理用户输入的地方 / This is where you manipulate user inputs
print(f"inlet called: {body}")
return body

def outlet(self, body: dict) -> None:
# 这里是处理模型输出的地方 / This is where you manipulate model outputs
print(f"outlet called: {body}")

🎯 关键组件解释

1️⃣ Valves 类(可选配置)

把**阀门(Valves)**想象成过滤器函数的智能控制面板。如果你想给用户可配置的选项来调整过滤器函数的行为,就在这里定义它们。

class Valves(BaseModel):
OPTION_NAME: str = "默认值" # Default value

例如: 如果你正在创建一个将响应转换为大写的过滤器函数,你可以通过像 TRANSFORM_UPPERCASE: bool = True/False 这样的阀门让用户配置是否将每个输出完全大写。


2️⃣ inlet 函数(输入预处理)

inlet 函数就像智能预处理器。想象你在使用一个智能助手:在信息进入核心处理(在这里是 LLM)之前,你需要确保信息的格式正确、上下文清晰、内容适当。没有这一步,最终的输出可能会不够准确、缺乏上下文,或者简单地说不够理想。

在 Open WebUI 中,inlet 函数在用户输入发送到模型之前对其进行这种重要的预处理工作。它确保输入对 AI 来说尽可能清晰、有上下文且有帮助。

📥 输入

  • body:从 Open WebUI 发送到模型的原始输入。它采用聊天补全请求的格式(通常是一个包含对话消息、模型设置和其他元数据的字典)。把这个想象成待处理的原始数据。

🚀 你的任务: 修改并返回 body。修改后的 body 版本就是 LLM 要处理的内容,这是你为输入优化质量的机会。

🍳 为什么要使用 inlet
  1. 添加上下文:自动为用户的输入附加关键信息,特别是当他们的文本含糊不清或不完整时。例如,你可以添加"你是一个专业的技术支持专家"或"请帮助用户解决这个编程问题"。

  2. 格式化数据:如果输入需要特定格式,如 JSON 或 Markdown,你可以在发送到模型之前对其进行标准化处理。

  3. 净化输入:删除不必要的字符,清理可能影响处理的符号(如多余的空格或特殊字符),或替换敏感信息。

  4. 优化用户输入:如果你的模型在有特定指导的情况下表现更好,你可以使用 inlet 自动添加这些优化指令!

💡 示例用例:基于数据处理流程
🥗 示例 1:添加专业领域上下文

假设 LLM 是一个编程助手,但用户没有指明具体的编程语言。你可以在将数据发送到模型之前添加这个重要的上下文。

def inlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
# 在对话中添加编程上下文 / Add programming context to the conversation
context_message = {
"role": "system",
"content": "你是一个专业的 Python 编程助手。"
}
# 在聊天历史的开头插入上下文 / Insert context at the beginning of chat history
body.setdefault("messages", []).insert(0, context_message)
return body

📖 效果说明

  • 用户输入"如何处理文件?"时,模型会自动知道要提供 Python 相关的文件处理方法,而不是其他语言的方案。
🔪 示例 2:清理输入(优化格式)

假设用户的输入包含不必要的格式或标记,这可能影响模型的理解。你可以在保留核心内容的同时优化它。

def inlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
# 清理最后一条用户输入 / Clean the last user input
last_message = body["messages"][-1]["content"]
body["messages"][-1]["content"] = last_message.replace("!!!", "").strip()
return body

📖 效果说明

  • 原始输入:"如何解决这个 bug!!!" ➡️ 优化后:"如何解决这个 bug"

注意:用户体验保持不变,但模型收到的是更清晰、更规范的查询。

📊 inlet 如何优化 LLM 的输入:
  • 通过明确模糊查询提高准确性
  • 通过清理干扰信息(如多余符号、HTML 标记等)提升处理效率
  • 通过标准化用户输入确保一致性(如统一 JSON 格式或特定结构)。

💭 inlet 想象成智能预处理器——确保进入模型的每一条信息都经过优化和标准化。输入质量越高,输出效果就越好!


3️⃣ outlet 函数(输出后处理)

outlet 函数就像一个智能后处理器:在 LLM 处理之后优化 AI 的响应。

📤 输入

  • body:包含聊天中的所有当前消息(用户历史 + LLM 回复)。

🚀 你的任务:优化这个 body。你可以进行清理、补充或记录,但要注意每个调整对用户体验的影响。

💡 最佳实践

  • 在出口函数中优先使用日志记录而不是大幅修改(适用于调试或数据分析)。
  • 如果需要复杂的转换处理,建议使用管道函数(Pipe Function)

💡 示例用例:保护敏感信息:

def outlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
for message in body["messages"]:
message["content"] = message["content"].replace("<API_KEY>", "[已隐藏]")
return body

🌟 过滤器函数实战:构建实用示例

让我们通过实际例子来看看如何使用过滤器函数!

📚 示例 #1:为每个用户输入添加专业背景

想让 LLM 始终以技术专家的身份回答问题?你可以在每个用户查询中添加专业背景说明。

class Filter:
def inlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
context_message = {
"role": "system",
"content": "你是一个专业的技术支持专家。"
}
body.setdefault("messages", []).insert(0, context_message)
return body

📚 示例 #2:优化输出格式

需要以特定格式(如 Markdown)呈现输出?使用 outlet 函数!

class Filter:
def outlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
# 为响应添加 Markdown 格式 / Add Markdown formatting to responses
for message in body["messages"]:
if message["role"] == "assistant": # 针对模型响应 / Target model responses
message["content"] = f"**{message['content']}**" # Markdown 强调
return body

🚧 常见疑问解答 🛑

问:过滤器函数与管道函数(Pipe Function)有什么区别?

过滤器函数专注于优化发送到来自模型的数据,不涉及复杂的外部交互。而管道函数:

  • 可以集成外部 API或实现复杂的处理逻辑。
  • 作为独立的"模型"提供服务。

问:可以在 outlet 中进行复杂的后处理吗?

技术上可以,但不推荐

  • 过滤器函数设计用于轻量级的数据优化和日志记录。
  • 复杂的数据转换建议使用管道函数实现。

🎉 总结:为什么要使用过滤器函数?

现在你已经掌握了:

  1. 入口(Inlet)优化用户输入(预处理)。
  2. 出口(Outlet)优化AI 输出(后处理)。
  3. 过滤器函数最适合对数据流进行轻量级的实时优化。
  4. 通过阀门(Valves),你可以让用户动态配置过滤器函数以获得个性化的行为。

🚀 开始实践:开始你的过滤器函数之旅吧!思考一下:什么样的数据优化或上下文增强可以提升你的 Open WebUI 体验?过滤器函数不仅构建起来有趣,使用起来灵活,还能让你的 AI 模型表现更出色!

编码愉快!✨