feat(search): 网络搜索新增 DeepSeek 官方来源

不单独配置凭据,直接复用当前激活的 LLM 配置(base_url/api_key/model)。

这个来源与 ddgs/brave/tavily 性质不同:DeepSeek 没有可直接调用的搜索接口,
搜索只存在于其 Anthropic 兼容 messages 接口内部,以 web_search_20250305
服务端工具的形式由 DeepSeek 服务端执行。由此带来几个必须让用户知道的差异,
已在设置页写明:

- 仅支持 DeepSeek 官方端点 + anthropic 协议。实测其 OpenAI 协议端点会直接以
  "unknown variant, expected `function`" 拒绝一切服务端工具,web_search_options
  之类的顶层字段则被静默忽略,没有可用的替代写法。
- 每次搜索额外消耗一次模型调用。
- 搜索请求由 DeepSeek 服务端发出,不经过搜索出口代理,也不计入流量留痕。
- 返回结果只有标题与链接,没有摘要(DeepSeek 只给 encrypted_content),需要正文
  时仍由 WebFetch 抓取。

上述条件不做程序校验,仅在界面说明,由用户自行确认——配置不满足时搜索会在实际
调用时报错,与其它来源填错 Key 的反馈路径一致,可用「测试搜索」按钮实跑验证。

依赖 norma v0.3.8。
This commit is contained in:
Autumn-27 committed 2026-09-12 07:13:46 -04:00
1 parent abf701e03c
commit e4c744a318
11 files changed
+133 -47

No files matched your search

+23 -2
View File
@@ -398,8 +398,9 @@ export default function SystemSettingsPage() {
<b>web_search</b>(仅返回标题/链接/摘要,不抓取正文;抓取由 WebFetch 负责)。网络搜索<b>不走</b>
记录代理,独立于流量捕获。
<br />
来源可选 <b>DuckDuckGo(ddgs)</b>(无需 Key)、<b>Brave(免费版)</b>(需填写 Brave API Key)或{" "}
<b>Tavily</b>(需填写 Tavily API Key)。总开关关闭时,各 Agent 的网络搜索开关不可用。
来源可选 <b>DuckDuckGo(ddgs)</b>(无需 Key)、<b>Brave(免费版)</b>(需填写 Brave API Key)、{" "}
<b>Tavily</b>(需填写 Tavily API Key)或 <b>DeepSeek</b>(复用当前 LLM 配置)。总开关关闭时,各
Agent 的网络搜索开关不可用。
</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-4">
@@ -436,11 +437,31 @@ export default function SystemSettingsPage() {
<SelectItem value="ddgs">DuckDuckGo(ddgs · 免费无 Key)</SelectItem>
<SelectItem value="brave-free">Brave(免费版 · 需 Key)</SelectItem>
<SelectItem value="tavily">Tavily(需 Key)</SelectItem>
<SelectItem value="deepseek">DeepSeek(官方)</SelectItem>
</SelectContent>
</Select>
</div>
)}
{webSearch && backend === "deepseek" && (
<div className="border-border/60 bg-muted/30 flex flex-col gap-2 rounded-md border p-3">
<p className="text-sm font-medium">DeepSeek 官方联网搜索</p>
<p className="text-muted-foreground text-xs leading-relaxed">
该来源直接复用<b>当前激活的 LLM 配置</b>。因此它
<b>仅支持 DeepSeek 官方模型</b>,且该配置<b>必须使用 anthropic 协议</b>
——DeepSeek 的 OpenAI 协议端点不支持服务端搜索。切换 LLM 配置后此来源可能失效。
</p>
<p className="text-muted-foreground text-xs leading-relaxed">
与其它来源不同,搜索由 <b>DeepSeek 服务端执行</b>:每次搜索会额外消耗一次模型调用(产生 Token
费用),搜索请求<b>不经过上面的出口代理</b>,也<b>不计入流量留痕</b>;返回结果<b>只有标题和链接</b>
(无摘要),需要正文时由 WebFetch 抓取。
</p>
<p className="text-muted-foreground text-xs leading-relaxed">
是否满足上述条件由你自行确认,系统不做拦截;可用下方「测试搜索」按钮实际跑一次来验证。
</p>
</div>
)}
{webSearch && backend === "brave-free" && (
<div className="flex flex-col gap-2">
<Label htmlFor="brave-key" className="text-sm font-normal text-muted-foreground">
+1 -1
View File
@@ -889,7 +889,7 @@ export interface Settings {
// Web search. brave_key_set / tavily_key_set reflect whether a key is stored
// (the values are never returned). On PUT, send the corresponding field to set/clear.
web_search_enabled: boolean;
web_search_backend: string; // "ddgs" | "brave-free" | "tavily"
web_search_backend: string; // "ddgs" | "brave-free" | "tavily" | "deepseek"
brave_key_set: boolean;
tavily_key_set: boolean;
// write-only: only sent on PUT to store/clear the key.