Skip to main content

外部搜索 (External)

warning

本教程由社区贡献,不属于 Open WebUI 团队官方支持。它仅作为如何针对特定用例自定义 Open WebUI 的演示。想要贡献?请查看贡献教程。

tip

有关 Web 搜索相关的所有环境变量(包括并发设置、结果数量等)的完整列表,请参阅 环境配置文档。

外部 Web 搜索 API​

此选项允许您将 Open WebUI 连接到您自己自托管的 Web 搜索 API 端点。如果您想实现以下目标,这将非常有用:

  • 集成 Open WebUI 原生不支持的搜索引擎。
  • 实现自定义搜索逻辑、过滤或结果处理。
  • 使用私有或内部搜索索引。

Open WebUI 设置​

  1. 导航到 Open WebUI 控制面板。
  2. 转到 设置 选项卡,然后选择 Web 搜索。
  3. 将 启用 Web 搜索 切换到开启位置。
  4. 从下拉菜单中将 Web 搜索引擎 设置为 external。
  5. 在 External Search URL 中填入您自定义搜索 API 端点的完整 URL(例如:http://localhost:8000/search 或 https://my-search-api.example.com/api/search)。
  6. 在 External Search API Key 中填入与您自定义搜索端点身份验证所需的秘密 API 密钥。如果您的端点不需要身份验证,请留空(不建议用于公共端点)。
  7. 点击 保存。

显示外部搜索配置的 Open WebUI 管理面板

API 规范​

Open WebUI 将按如下方式与您的 External Search URL 交互:

  • 方法: POST

  • 请求头:

    • Content-Type: application/json
    • Authorization: Bearer <您的_EXTERNAL_SEARCH_API_KEY>
  • 请求体 (JSON):

    {
    "query": "用户的搜索查询字符串",
    "count": 5 // 请求的最大搜索结果数量
    }
    • query (string): 用户输入的搜索词。
    • count (integer): Open WebUI 期望的建议最大结果数。如果需要,您的 API 可以返回更少的结果。
  • 预期响应体 (JSON): 您的 API 端点 必须 返回一个搜索结果对象的 JSON 数组。每个对象应具有以下结构:

    [
    {
    "link": "搜索结果的 URL",
    "title": "搜索结果页面的标题",
    "snippet": "搜索结果页面的简短描述或片段"
    },
    {
    "link": "...",
    "title": "...",
    "snippet": "..."
    }
    // ... 可能会有更多结果,直到达到请求的数量
    ]
    • link (string): 指向搜索结果的直接 URL。

    • title (string): 网页的标题。

    • snippet (string): 与查询相关的页面内容的描述性文本片段。

      如果发生错误或未找到结果,您的端点理想情况下应返回一个空的 JSON 数组 []。

示例实现 (Python/FastAPI)​

这是一个使用 Python、FastAPI 和 duckduckgo-search 库构建自托管搜索 API 的简单示例。

import uvicorn
from fastapi import FastAPI, Header, Body, HTTPException
from pydantic import BaseModel
from duckduckgo_search import DDGS

EXPECTED_BEARER_TOKEN = "在此处输入您的秘密令牌"

app = FastAPI()

class SearchRequest(BaseModel):
query: str
count: int

class SearchResult(BaseModel):
link: str
title: str | None
snippet: str | None

@app.post("/search")
async def external_search(
search_request: SearchRequest = Body(...),
authorization: str | None = Header(None),
):
expected_auth_header = f"Bearer {EXPECTED_BEARER_TOKEN}"
if authorization != expected_auth_header:
raise HTTPException(status_code=401, detail="Unauthorized")

query, count = search_request.query, search_request.count

results = []
try:
with DDGS() as ddgs:
search_results = ddgs.text(
query, safesearch="moderate", max_results=count, backend="lite"
)

results = [
SearchResult(
link=result["href"],
title=result.get("title"),
snippet=result.get("body"),
)
for result in search_results
]

except Exception as e:
print(f"DuckDuckGo 搜索期间出错: {e}")

return results

if __name__ == "__main__":
uvicorn.run("main:app", host="0.0.0.0", port=8888)