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/searchhttps://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)