Claude 用第三方模型没有联网搜索怎么办?四种解决方案完整配置

共计 12152 个字符,预计需要花费 31 分钟才能阅读完成。

介绍

Claude Code(含桌面版)自带的 Web Search 联网搜索功能,在接入第三方模型或 API 中转后经常会失效——要么报错,要么搜出来是空的,最坑的是模型假装搜到了、实际在编内容。原因不在客户端设置,而在上游服务商有没有实现这个工具web_search 是 Anthropic 定义的”服务器端工具”,搜索由厂商自己的基础设施执行,纯做协议转换的中转商没有搜索后端,这个工具就永远跑不起来。

好在这个问题有成熟解法。本文给出四种经过实测的方案:

  1. DeepSeek 官方通道——零安装,官方原生支持,代价是只能用 DeepSeek 模型
  2. Firecrawl 官方 MCP + Skills——独立于模型厂商的抓取服务,任意模型下可用
  3. 自建 MiMo 搜索 MCP——把 MiMo 的联网搜索包装成自己的 MCP server
  4. 项目内 CLI 脚本——不依赖 MCP,任何能跑 Node 的环境都能用

四种方案可以叠加使用,文末有对比表和选择建议。

Claude 用第三方模型没有联网搜索怎么办?四种解决方案完整配置

先搞懂原理:为什么第三方模型搜不了

Claude 的 web_search(工具 ID web_search_20250305)是一个服务器端工具:模型只能”请求搜索”,真正执行搜索、把结果注入对话的是上游厂商的服务器。所以:

  • 服务商自己实现了这个工具(有自己的搜索后端)→ 原生可用
  • 纯协议中转(只把 Anthropic 格式翻译成 OpenAI 格式转发)→ 工具声明被透传或丢弃,没人执行

这解释了另外两个常见疑问:

  • 为什么 WebFetch 还能用? WebFetch 是客户端工具——由 Claude Code 自己抓取网页、转成文本再交给模型,不依赖上游做任何事,所以在中转下照样能跑。只有 WebSearch 会挂。
  • 为什么换客户端设置没用? 上游格式、模型映射、effort 这类的调整都不解决——这是上游能力问题,不是配置问题。

三种失败表现(从明显到隐蔽)

表现 说明
显式报错 中转把服务器工具转成普通函数时描述字段为 null,上游直接返回 400
静默空结果 只回显你的查询词、没有任何结果块,也不报错
假装搜到了(最坑) HTTP 200 一切正常,模型用散文写一段”搜索结果”——实际全是编的

判断标准:真结果一定带 URL / 来源链接。 没有来源的”搜索结果”都是编的。另一个实用提醒:搜索能力只取决于当前生效的那个 provider——换 provider 后要重新测,别从单次失败下结论说”这台机器用不了搜索”。

方案一:DeepSeek 官方通道(零安装)

DeepSeek 官方 API 原生实现了 Claude Code 的 Web Search。官方文档原话:

The DeepSeek API natively supports the Web Search feature in Claude Code. When using Claude Code, if the model determines that your question requires a web search, it will invoke the Web Search tool and perform the search through the API provided by DeepSeek.

配置:把 Claude Code / 桌面版的 API 端点切到 DeepSeek 官方即可:

export ANTHROPIC_BASE_URL=https://api.deepseek.com/anthropic
export ANTHROPIC_AUTH_TOKEN=<你的 DeepSeek API Key>

(模型映射等完整环境变量见 DeepSeek 官方文档。如果用 CC Switch 这类切换器,选 DeepSeek 官方那条 profile 即可。)

优点

  • 零安装、零维护,模型自己决定什么时候搜,体验和官方完全一致
  • 搜索结果会带来源链接,可直接核对

缺点

  • 锁定 DeepSeek 模型——想要别的模型就用不了这条路
  • 搜索会产生额外 token 费用:搜索内容要经模型总结一遍,官方文档明确提示

适合:就用 DeepSeek 模型、图省事的人。

方案二:Firecrawl 官方 MCP + Skills

Firecrawl 是一个独立的网页抓取服务,通过 MCP 接入 Claude 后,与当前用什么模型完全无关——任意 provider 下都能用。能力面也最宽:搜索、抓单页、整站爬取、定时监控、文档解析等。

2.1 接入 MCP

在终端执行(user scope = 所有项目可用):

claude mcp add --transport http -s user firecrawl https://mcp.firecrawl.dev/v2/mcp-oauth --header "x-firecrawl-api-key: fc-你的key"

API key 在 firecrawl.dev 后台创建。

为什么用 API key 而不是 OAuth 登录? 实测 OAuth 方式存下来的凭据只有 accessToken、没有 refreshToken,token 过期后无法自动续期,接口直接 401。API key 不过期,一劳永逸。

2.2 安装 CLI + Skills(可选但推荐)

官方一条命令装齐 CLI 和技能包:

npx -y firecrawl-cli@latest init --all --browser

只想装给 Claude Code、且已有 key 的话,可以限定范围跳过浏览器授权:

npx -y firecrawl-cli@latest init --agent claude-code --skip-auth

装完会有 28 个 skill(12 核心 + 16 工作流)。MCP 和 Skill 是两回事:

MCP Skill
本质 连接协议,把工具接进会话 一份说明书,教模型怎么用工具
加载 每次会话常驻(占上下文) 相关时才读进来(不占常驻)
能力 25 个工具:search / scrape / crawl / monitor / parse 等 使用策略 + 成品模板(调研、SEO 审计等)

2.3 重载机制(关键)

MCP 和 skills 都是会话启动时加载的,装完必须:

托盘退出 Claude → 重开 → 开新会话

只关窗口不行(主进程还活着);旧会话继续用也可能不生效,别赌。

2.4 三个坑

  • 别用 && 串命令claude mcp remove ... && claude mcp add ... 里前一条失败(比如本来就 remove 过了),后一条会被静默跳过,看起来像”配置没生效”——分开跑。
  • 限流 3 请求/分钟:这是分钟级请求数上限,短时间并发几个调用就会打满,之后所有调用连续 429。MCP 侧只回一句光秃秃的 Request failed with status code 429、不带原因,用 CLI 排查:
    firecrawl --status    # 看剩余配额
    firecrawl doctor      # 10 项健康检查
    
  • 别用 claude mcp get firecrawl 查状态——它会把 API key 明文打印出来进对话记录。查连通性用 claude mcp list

计费:credit 制,搜索 2 credits/次(按官方要求提交反馈可退 1);抓页面按量计费、单页消耗很低。个人使用免费额度基本够。

适合:任何 provider 环境;需要抓全文、整站、定时监控、文档解析这些”深度取网页”的场景。

方案三:自建 MiMo 搜索 MCP

MiMo 有联网搜索能力(OpenAI 端点下的 web_search 工具),但走标准客户端调用不了。解法是自己写一个小 MCP server 直调它的 API。

3.1 服务端代码

~/.claude/mcp-servers/mimo-search/index.js

import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import Database from "better-sqlite3";
import { homedir } from "os";
import { join } from "path";

function getMimoApiKey() {
  // 优先环境变量
  if (process.env.MIMO_API_KEY) return process.env.MIMO_API_KEY;

  // 否则从 cc-switch 数据库读(改成本地数据库或其他来源均可)
  const dbPath = join(homedir(), ".cc-switch", "cc-switch.db");
  const db = new Database(dbPath, { readonly: true });
  const row = db
    .prepare(
      "SELECT settings_config FROM providers WHERE id = '<你的 MiMo provider id>'"
    )
    .get();
  db.close();

  if (!row?.settings_config) throw new Error("MiMo provider not found in cc-switch DB");
  const cfg = JSON.parse(row.settings_config);
  const key = cfg?.env?.ANTHROPIC_AUTH_TOKEN;
  if (!key) throw new Error("ANTHROPIC_AUTH_TOKEN not found in MiMo provider config");
  return key;
}

const MIMO_API_KEY = getMimoApiKey();

const server = new McpServer({
  name: "mimo-search",
  version: "1.0.0",
});

server.tool(
  "mimo-web-search",
  "Search the web using MiMo's web search capability. Returns real-time web results with URLs.",
  {
    query: z.string().describe("The search query"),
    max_results: z.number().optional().default(5).describe("Max number of results (1-10)"),
    force_search: z.boolean().optional().default(true).describe("Force search even if model thinks it can answer"),
  },
  async ({ query, max_results, force_search }) => {
    const body = {
      model: "mimo-v2.5-pro",
      messages: [{ role: "user", content: query }],
      tools: [
        {
          type: "web_search",
          max_keyword: 3,
          force_search,
          limit: max_results,
        },
      ],
      max_completion_tokens: 4096,
      temperature: 1.0,
      top_p: 0.95,
      stream: false,
      thinking: { type: "disabled" },
    };

    try {
      const resp = await fetch("https://api.xiaomimimo.com/v1/chat/completions", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          "api-key": MIMO_API_KEY,
        },
        body: JSON.stringify(body),
      });

      if (!resp.ok) {
        const errText = await resp.text();
        return {
          content: [{ type: "text", text: `MiMo API error ${resp.status}: ${errText}` }],
          isError: true,
        };
      }

      const data = await resp.json();
      const choice = data.choices?.[0];
      const text = choice?.message?.content || "(no content)";

      const citations = (choice?.message?.annotations || [])
        .filter((a) => a.type === "url_citation")
        .map((a) => {
          const parts = [`- [${a.title || a.url}](${a.url})`];
          if (a.publish_time) parts.push(`  published: ${a.publish_time.slice(0, 10)}`);
          if (a.summary) parts.push(`  ${a.summary.trim()}`);
          return parts.join("n");
        });

      let result = text;
      if (citations.length > 0) {
        result = `## Summarynn${text}nn## Sourcesnn${citations.join("n")}`;
      }

      return { content: [{ type: "text", text: result }] };
    } catch (err) {
      return {
        content: [{ type: "text", text: `Request failed: ${err.message}` }],
        isError: true,
      };
    }
  }
);

const transport = new StdioServerTransport();
await server.connect(transport);

package.json

{
  "name": "mimo-search-mcp",
  "version": "1.0.0",
  "type": "module",
  "dependencies": {
    "@modelcontextprotocol/sdk": "^1.12.0",
    "better-sqlite3": "^13.0.3"
  }
}

3.2 注册与安装

注册到 Claude 桌面版配置(路径:AppData/Roaming/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "mimo-search": {
      "command": "node",
      "args": ["<mimo-search 目录的绝对路径>/index.js"]
    }
  }
}

然后在目录里 npm install 装依赖。设置 MIMO_API_KEY 环境变量可以跳过数据库那段(代码里第一优先级就是它),比读 cc-switch DB 干净得多。

3.3 实现要点(踩过的坑)

  • 搜索结果引用在 choices[0].message.annotationstype: url_citation,含 url / title / publish_time / summary 字段),不在 tool_calls——最初按 tool_calls 解析导致引用全丢,看起来像”搜不到”。
  • 空 annotations = 搜索后端没返回结果,此时模型的散文总结是编的,不要采信。
  • 新版 SDK 只发 ESM:如果报”找不到 CJS 导出文件”,把代码写成 import + package.json"type": "module" 即可,不需要降级 SDK。
  • key 在服务启动时读一次并缓存,换了 key 要托盘退出重开 App 才生效。
  • 支持联网的是 mimo-v2.5-promimo-v2.5,计费约 ¥16/1000 次搜索 + token 费。

3.4 能力边界(实测)

  • :按主题/关键词搜到页面,返回 AI 整理好的综述 + Sources(标题链接、发布日期、摘要)。查”某商家什么背景””某技术是什么”这类资料性问题很顺手。
  • 不能:站点级列表查询(”某站最新 N 篇文章”)、页面实时内容、site: 语法(会被当普通关键词)。
  • 注意:索引以中文互联网内容为主,部分境外站点(如维基百科、Reddit)收录不全;价格等时效数据不可直接采信(综述可能混入旧数据),要用官网或 Firecrawl 核实。

适合:想要”一搜就有整理好的答案”、不需要自己翻源的场景。

3.5 懒人版:把提示词丢给 AI

不想一步步手装的话,把下面这段直接发给你的 AI(Claude Code 这类能执行命令的工具都可以),它会按上面的规格把服务建好、依赖装好、配置注册好:

帮我搭一个 MiMo 联网搜索的 MCP server,直接动手,做完告诉我结果:

1. 在 ~/.claude/mcp-servers/mimo-search/ 下创建 Node 项目:
   - package.json:type 为 module(ESM),依赖 @modelcontextprotocol/sdk 和 better-sqlite3
   - index.js:用 SDK 的 McpServer + StdioServerTransport 起一个 stdio server
2. 工具定义:名称 mimo-web-search,参数 query(必填)、max_results(可选,默认 5)、
   force_search(可选,默认 true)
3. 工具实现:
   - POST https://api.xiaomimimo.com/v1/chat/completions,header 带 api-key
   - body:model 用 mimo-v2.5-pro;messages 放 query;
     tools 为 [{ type: "web_search", max_keyword: 3, force_search, limit: max_results }];
     thinking 设 disabled;其余参数用合理默认
   - 来源引用在 choices[0].message.annotations 数组里(type 为 url_citation,
     字段有 url / title / publish_time / summary),不在 tool_calls 里;
     输出格式为 "## Summary"(正文)+ "## Sources"(每行 - [标题](url) + published 日期 + 摘要)
   - API key 优先读环境变量 MIMO_API_KEY,没有就报清晰的错误提示
4. npm install 装依赖
5. 注册进 Claude Desktop 配置:AppData/Roaming/Claude/claude_desktop_config.json
   的 mcpServers 下加一条,command 为 node、args 为 index.js 的绝对路径
6. 做完告诉我:怎么让配置生效(托盘退出重开 + 开新会话)、怎么验证

我的 MiMo API key:<粘贴你的 key;或先设好 MIMO_API_KEY 环境变量,让第 3 步直接读它>

装完记得:托盘退出重开 Claude → 开新会话,然后说一句”用 mimo-web-search 搜一下 XXX”验证。

方案四:项目内 CLI 脚本(不依赖 MCP)

如果你使用的工具支持执行命令但不支持 MCP(或想在脚本流水线里直接调用搜索),可以把同样的逻辑抽成一个 CLI 脚本——两个环境都能用,规则里只写脚本版就不会出现”规则写了但这端跑不了”的问题。

tools/mimo-search.js

#!/usr/bin/env node
/**
 * MiMo 联网搜索 CLI —— 任意能跑 Node 的环境通用。
 *
 * 用法: node tools/mimo-search.js "查询内容" [max_results]
 *
 * 返回:AI 整理好的综述(不是原始结果列表)。适合查商家背景/线路/机房这类
 * 稳定性信息;**价格等时效数据不可直接采信**(综述可能混入旧价),用 firecrawl 或官网核实。
 *
 * API key 来源:环境变量 MIMO_API_KEY,否则读 cc-switch DB。
 */
const { execFileSync } = require('child_process');
const path = require('path');

const query = process.argv[2];
const maxResults = Number(process.argv[3]) || 5;
if (!query) {
  console.error('用法: node tools/mimo-search.js "查询内容" [max_results]');
  process.exit(1);
}

function getMimoApiKey() {
  if (process.env.MIMO_API_KEY) return process.env.MIMO_API_KEY;
  // 从 cc-switch DB 读(借用 MiMo MCP 目录下的 better-sqlite3;
  // 只用环境变量的话这段不会执行,无需该依赖)
  const mcpDir = path.join(process.env.USERPROFILE || process.env.HOME, '.claude', 'mcp-servers', 'mimo-search');
  const out = execFileSync('node', ['-e', `
    const Database = require(${JSON.stringify(path.join(mcpDir, 'node_modules', 'better-sqlite3'))});
    const { homedir } = require('os');
    const { join } = require('path');
    const db = new Database(join(homedir(), '.cc-switch', 'cc-switch.db'), { readonly: true });
    const row = db.prepare("SELECT settings_config FROM providers WHERE id = '<你的 MiMo provider id>'").get();
    db.close();
    if (!row?.settings_config) throw new Error('MiMo provider not found in cc-switch DB');
    const cfg = JSON.parse(row.settings_config);
    const key = cfg?.env?.ANTHROPIC_AUTH_TOKEN;
    if (!key) throw new Error('ANTHROPIC_AUTH_TOKEN not found');
    process.stdout.write(key);
  `], { encoding: 'utf8' });
  return out.trim();
}

(async () => {
  const apiKey = getMimoApiKey();
  const body = {
    model: 'mimo-v2.5-pro',
    messages: [{ role: 'user', content: query }],
    tools: [{ type: 'web_search', max_keyword: 3, force_search: true, limit: maxResults }],
    max_completion_tokens: 4096,
    temperature: 1.0,
    top_p: 0.95,
    stream: false,
    thinking: { type: 'disabled' },
  };
  const resp = await fetch('https://api.xiaomimimo.com/v1/chat/completions', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json', 'api-key': apiKey },
    body: JSON.stringify(body),
  });
  if (!resp.ok) {
    console.error(`MiMo API error ${resp.status}: ${(await resp.text()).slice(0, 300)}`);
    process.exit(1);
  }
  const data = await resp.json();
  const choice = data.choices?.[0];
  const text = choice?.message?.content || '(no content)';

  // 从 annotations 提 url_citation,输出「标题链接 + 发布日期 + 摘要」
  const citations = (choice?.message?.annotations || [])
    .filter((a) => a.type === 'url_citation')
    .map((a) => {
      const parts = [`- [${a.title || a.url}](${a.url})`];
      if (a.publish_time) parts.push(`  published: ${a.publish_time.slice(0, 10)}`);
      if (a.summary) parts.push(`  ${a.summary.trim()}`);
      return parts.join('n');
    });

  if (citations.length > 0) {
    console.log(`## Summarynn${text}nn## Sourcesnn${citations.join('n')}`);
  } else {
    console.log(text);
  }
})().catch((e) => { console.error('[x]', e.message); process.exit(1); });

用法:

node tools/mimo-search.js "商家名 是什么背景" 5

两个说明:

  • 最省事的 key 配置是设一个 MIMO_API_KEY 环境变量——脚本第一优先级就是它,设了就完全不碰数据库那段。
  • 用数据库方案的话,<你的 MiMo provider id> 替换成自己的:在 cc-switch 的 provider 列表里找到 MiMo 那条的 id,或安全地查一下 DB(只查 id/name,别查含 key 的字段):
    SELECT id, name FROM providers;
    

优点:不依赖 MCP 支持,任何能跑 Node 的环境(另一个 AI 工具、CI、定时脚本)都能用;也不占会话上下文(MCP 工具定义是每会话常驻的)。

缺点:需要手动调用(或在规则里写明),不像 MCP 那样被模型自动调度。

懒人版:把提示词丢给 AI

同样可以不自己动手——把下面这段发给你的 AI,它会写好脚本并跑一次真实查询给你验证:

帮我加一个 MiMo 联网搜索的 CLI 脚本,直接动手,做完跑一次给我看:

1. 在当前项目建 tools/mimo-search.js(Node,用全局 fetch 即可,无需第三方依赖)
2. 用法:node tools/mimo-search.js "查询内容" [条数],条数默认 5;
   没有查询词时打印用法并以退出码 1 结束
3. 实现:
   - POST https://api.xiaomimimo.com/v1/chat/completions,header 带 api-key
   - body:model 用 mimo-v2.5-pro;messages 放查询词;
     tools 为 [{ type: "web_search", max_keyword: 3, force_search: true, limit: 条数 }];
     thinking 设 disabled;其余参数用合理默认
   - API key 读环境变量 MIMO_API_KEY,没设就报清晰的错误提示
   - 来源引用在 choices[0].message.annotations 里(type 为 url_citation,
     字段有 url / title / publish_time / summary);
     有引用时输出 "## Summary"(正文)+ "## Sources"(每行 - [标题](url) + published 日期 + 摘要),
     没有引用时只输出正文
4. 写完用一条真实查询跑通验证(例如 node tools/mimo-search.js "小米 最新消息" 3)

我的 MiMo API key 放在环境变量 MIMO_API_KEY 里(还没设的话告诉我)。

四方案对比

方案一 DeepSeek 官方 方案二 Firecrawl 方案三 MiMo MCP 方案四 CLI 脚本
安装成本 零(换个 provider) 装 MCP + 可选 skills 自己建 MCP server 存一个 js 文件
对模型的要求 只能用 DeepSeek 模型 任意模型 任意模型(需支持 MCP) 任意环境(能跑 Node)
搜索方式 模型原生调用 工具调用 工具调用 手动/脚本调用
返回形态 模型总结 + 来源 原始结果 / 全文 AI 综述 + 来源 AI 综述 + 来源
费用 额外 token 费 credits(有免费额度) ~¥16/1000 次 同左(同一个 API)
特色能力 体验原生 抓全文 / 整站 / 监控 / 解析文档 中文资料综述 可脚本化 / 不占上下文

怎么选

  • 只用 DeepSeek 模型 → 方案一,什么都不用装,体验最好
  • 任意模型 + 需要”深度取网页”(抓全文、爬站、监控、解析文档)→ 方案二,功能最全且与模型解耦
  • 想要”一搜就给整理好的答案”、偏资料性查询 → 方案三
  • 工具不支持 MCP,或要在脚本/流水线里搜索 → 方案四
  • 推荐组合:方案一(日常原生搜索)+ 方案二(深度抓取)互补——一个负责快、一个负责全;MiMo 系(方案三/四)作为中文资料的补充

小结

  • 第三方模型下 Web Search 失效的根因:web_search服务器端工具,只有自带搜索后端的服务商(如 DeepSeek 官方)能执行;纯中转没有后端,必然失败——要么报错、要么空结果、要么模型编造(没有来源链接的”搜索结果”都是编的
  • 四个解法各有取舍:换 provider(零安装但锁模型)、外挂 Firecrawl(最全但按量计费)、自建 MiMo MCP(中文综述顺手)、CLI 脚本(不依赖 MCP、可脚本化)
  • 装完 MCP / skill 记得托盘退出重开 + 开新会话才生效;排查限流和健康状态用 CLI,别用会打印 key 的 claude mcp get
  • 搜索能力只取决于当前生效的 provider——换 provider 后重新测,别从单次失败下结论
正文完
 0
admin
版权声明:本站原创文章,由 admin 于2026-09-18发表,共计12152字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
原来频道被人恶意举报…… 新电报频道 | 加入电报群