🪄 过滤器功能:修改输入和输出
欢迎来到 Open WebUI 中过滤器的全面指南!过滤器是一个灵活且强大的插件系统,用于在数据发送到大型语言模型(LLM)之前(输入)或从 LLM 返回之后(输出)对其进行修改。无论你是为了更好的上下文而转换输入,还是为了提高可读性而清理输出,过滤器功能都能让你轻松实现。
本指南将详细介绍什么是过滤器、它们的工作原理、结构以及你需要知道的一切,以便构建强大且用户友好的过滤器。让我们开始吧,不用担心——我会用比喻、示例和提示来让一切清晰明了!🌟
🌊 Open WebUI 中的过滤器是什么?
想象一下 Open WebUI 就像一条水流通过管道:
- 用户输入和LLM 输出是水。
- 过滤器则是水处理阶段,在水到达最终目的地之前对 其进行清洁、修改和调整。
过滤器就像流程中的检查点,在这里你可以决定需要进行哪些调整。
以下是过滤器的主要功能简要总结:
- 修改用户输入(入口函数):在数据到达 AI 模型之前对其进行调整。这包括增强清晰度、添加上下文、清理文本或重新格式化消息以符合特定要求。
- 修改模型输出(出口函数):在数据经过处理后,但在展示给用户之前对其进行调整。这可以帮助改进、记录或适应数据,从而提供更干净的用户体验。
关键概念:过滤器不是独立的模型,而是增强或转换数据的工具,这些数据在进入和离开模型时都会被处理。
过滤器就像是 AI 工作流中的翻译或编辑:你可以在不中断流程的情况下拦截并更改对话内容。
🗺️ 过滤器功能的结构:骨架
让我们从最简单的过滤器功能表示开始。如果某些部分一开始感觉技术性较强,别担心——我们会逐步分解所有内容!
🦴 基础骨架
from pydantic import BaseModel
from typing import Optional
class Filter:
# 阀门:过滤器的配置选项
class Valves(BaseModel):
pass
def __init__(self):
# 初始化阀门(过滤器的可选配置)
self.valves = self.Valves()
def inlet(self, body: dict) -> dict:
# 在这里处理用户输入
print(f"inlet called: {body}")
return body
def outlet(self, body: dict) -> None:
# 在这里处理模型输出
print(f"outlet called: {body}")
🎯 关键组件解释
1️⃣ Valves
类(可选设置)
可以把阀门想象成过滤器的旋钮和滑块。如果你想为用户提供可配置的选项来调整过滤器的行为,那么可以在这里定义这些选项。
class Valves(BaseModel):
OPTION_NAME: str = "默认值"
例如:
如果你正在创建一个将响应转换为大写的过滤器,可以通过类似 TRANSFORM_UPPERCASE: bool = True/False
的阀门让用户配置是否将每个输出完全大写。
2️⃣ inlet
函数(输入预处理)
inlet
函数就像是烹饪前准备食材。想象一下你是一位厨师:在食材进入食谱(这里的 LLM)之前,你可能会洗菜、切洋葱或调味肉。没有这个步骤,你的最终菜肴可能会缺乏风味、含有未清洗的食材,或者根本无法达到预期效果。
在 Open WebUI 中,inlet
函数对用户输入进行重要的准备工作,确保输入尽可能清晰、有上下文并且易于 AI 处理。
📥 输入:
body
:来自 Open WebUI 的原始输入,通常是一个包含对话消息、模型设置和其他元数据的字典。可以将其视为你的食谱原料。
🚀 任务:
修改并返回 body
。经过修改后的 body
是 LLM 处理的内容,因此这是你为输入带来清晰度、结构和上下文的机会。
🍳 为什么使用 inlet
?
-
添加上下文:自动向用户的输入中附加关键信息,特别是在他们的文本模糊或不完整时。例如,你可能会添加“你是一个友好的助手”或“帮助用户排查软件错误”。
-
格式化数据:如果输入需要特定格式,如 JSON 或 Markdown,你可以在发送给模型之前进行转换。
-
清理输入:删除不需要的字符,去除可能有害或令人困惑的符号(如过多的空格或表情符号),或替换敏感信息。
-
简化用户输入:如果模型的输出可以通过额外指导得到改善,你可以使用
inlet
自动注入澄清说明!
💡 示例用例:基于食材准备
🥗 示例 1:添加系统上下文
假设 LLM 是一位为意大利烹饪准备菜肴的厨师,但用户没有提到“这是为意大利烹饪”。你可以通过在发送数据之前附加此上下文来确保信息清晰。
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:清理输入(移除 奇怪字符)
假设用户输入看起来很混乱或包含不必要的符号,如 !!!
,使得对话效率低下或难以让模型解析。你可以清理它,同时保留核心内容。
def inlet(self, body: dict, __user__: Optional[dict] = None) -> dict:
# 清理最后一条用户输入(来自 'messages' 列表末尾)
last_message = body["messages"][-1]["content"]
body["messages"][-1]["content"] = last_message.replace("!!!", "").strip()
return body
📖 会发生什么?
- 之前:
"如何调试这个问题!!!"
➡️ 发送到模型时变为"如何调试这个问题"
注意:用户感受相同,但模型处理的是更干净、更易理解的查询。
📊 如何通过 inlet
优化输入以供 LLM 使用:
- 提高准确性,通过澄清模棱两可的查询。
- 使 AI 更加高效,通过移除不必要的噪音,如表情符号、HTML 标签或多余的标点符号。
- 确保一致性,通过将用户输入格式化为符合模型预期模式或模式(如特定用途的 JSON)。
💭 把 inlet
想象成厨房里的副厨**——确保送入模型的所有东西(你的 AI “配方”)都已准备好、清洁并调味至完美。输入越好,输出越佳!
3️⃣ outlet
函数(输出后处理)
outlet
函数就像一位校对员:在数据由 LLM 处理之后(或在此期间)对其进行整理或做出最终修改。
📤 输入:
body
:包含当前所有消息的字典(用户历史 + LLM 回复)。
🚀 任务:修改这个 body
。你可以清理、追加或记录更改,但要注意每次调整对用户体验的影响。
💡 最佳实践:
- 记录优先于直接编辑(例如,用于调试或分析)。
- 如果需要大量修改(如格式化输出),考虑使用管道功能。
💡 示例用例:剥离你不希望用户看到的敏感 API 响应:
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
for message in body["messages"]:
if message["role"] == "assistant": # 目标模型回复
message["content"] = f"**{message['content']}**" # 使用 Markdown 突出显示
return body
🚧 可能的困惑:常见问题解答 🛑
Q: 过滤器与管道功能有何不同?
过滤器用于修改进入和离开模型的数据,但并不显著与这些阶段之外的逻辑交互。而管道:
- 可以集成外部 API或显著改变后端处理操作的方式。
- 将自定义逻辑作为全新的“模型”暴露出来。
Q: 是否可以在 outlet
中进行大量后处理?
当然可以,但这不是最佳实践:
- 过滤器旨在进行轻量级的更改或应用日志记录。
- 如果需要大量修改,考虑使用管道功能。
🎉 总结:为什么要构建过滤器功能?
到现在为止,你已经了解到:
- 入口处理用户输入(预处理)。
- 出口调整AI 输出