☰
Scira 开源 AI 搜索引擎:用 Vercel AI SDK 搭一套可复现的检索问答链路
2026/10/1 7:17:31 网站建设 项目流程

1. Scira 开源 AI 搜索引擎到底解决了什么问题

Scira 是一个用 Vercel AI SDK 搭起来的开源 AI 搜索引擎,核心能力是把「用户提问 → 模型判断要不要搜 → 调用搜索工具 → 聚合结果 → 流式返回带引用的答案」这条链路完整跑通。它适合谁?适合想自己搭一套检索问答系统、又不想从零写工具编排的开发者,也适合想研究 Vercel AI SDK 流式工具调用(tool calling + streaming)怎么落地的人。

我第一次看 Scira 的代码时,最直观的感受是:它没有把「搜索」当成一个黑盒 API,而是把搜索拆成了多个可插拔的工具——网页搜索、学术论文、社交平台、视频、航班、电影等。模型根据问题自己决定调哪个工具,这就是典型的 agentic search 结构。excerpt 里提到它目前主要绑定 xAI 的 Grok,但因为底层是 Vercel AI SDK,换成 DeepSeek 这类兼容 OpenAI 协议的服务其实改动很小。

这里有个关键点:Vercel AI SDK 的streamText支持tools参数,工具执行完会把结果回灌给模型,模型再生成最终答案。Scira 的「引用来源」就是工具返回的结构化数据里带的 URL,前端渲染时把它们列出来。理解这一点,你就能明白为什么它「可复现」——整条链路没有私有魔法,全是标准接口。

我实测下来,本地跑通 Scira 的最小结构需要三样东西:一个能流式输出的模型服务、一组搜索工具的实现、一个把两者串起来的路由。下面我会按这个顺序拆,重点放在你能直接复制粘贴的部分。如果你只是想先看看模型对话效果,可以先用模型对话页面验证接口通不通,再回来搭工具链。

需要提前说明的是,Scira 的搜索工具本身依赖外部搜索 API(比如 Tavily、Exa 之类),这些需要你自己申请 key。模型服务这块,我用 TaoToken 做统一入口,因为它兼容 OpenAI 协议,Vercel AI SDK 里换个 baseURL 就能接。这样你就不用为了换模型去改一堆代码。

2. 用 TaoToken 做模型入口的前置准备

在动手改 Scira 之前,先把模型入口理顺。Vercel AI SDK 默认走 OpenAI 的https://api.openai.com/v1,我们要做的是把它指向自己的兼容端点。TaoToken 的 API 地址是https://taotoken.net/api,注意这里不带任何查询参数,直接作为 baseURL 用。

第一步是拿 Key。打开 API Keys 页面(https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api_keys&utm_campaign=rewrite),创建一个新 key,复制出来。这个 key 后面会写进.env.local,格式是sk-开头的一串字符。别把它提交到 git,Scira 的.gitignore默认已经忽略了.env.local,但你自己新建文件时留意一下。

第二步是确认模型 ID。Vercel AI SDK 里调用模型时用的是模型标识符,比如gpt-4o-mini、deepseek-chat这类。你可以在模型对话页面(https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_content=model_chat&utm_campaign=rewrite)里先手动发一条消息,确认这个模型 ID 能正常返回,再写进代码。这一步能帮你排除掉「模型名写错」这种低级但高频的问题。

第三步是理解 Scira 的模型配置位置。Scira 通常在lib/ai/providers.ts或类似文件里用createOpenAI创建 provider 实例。你要改的就是这个实例的baseURL和apiKey。如果你用的是@ai-sdk/openai包,写法是:

import { createOpenAI } from '@ai-sdk/openai'; export const myProvider = createOpenAI({ baseURL: process.env.OPENAI_BASE_URL, apiKey: process.env.OPENAI_API_KEY, });

然后把OPENAI_BASE_URL=https://taotoken.net/api和OPENAI_API_KEY=sk-你的key写进.env.local。这样 Scira 里所有通过这个 provider 发起的请求都会走 TaoToken。如果你后面想接 Claude Code 那类编码场景,可以另外看 Coding Plan(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite),但那是另一条线,本文聚焦搜索链路。

这里有个容易踩的坑:有些教程会让你把 baseURL 写成带/v1的完整路径。Vercel AI SDK 的 OpenAI provider 内部会自己拼/chat/completions,所以你只需要给到/api这一层。多写或少写/v1都可能导致 404。我建议你先用 curl 测一下端点,确认返回结构再改代码。

3. 可复制的环境变量与路由配置片段

这一节是全文最核心的部分,给你能直接落地的配置。先看环境变量,在项目根目录建.env.local:

# 模型入口 OPENAI_BASE_URL=https://taotoken.net/api OPENAI_API_KEY=sk-你的key OPENAI_MODEL=deepseek-chat # 搜索工具(以 Tavily 为例,按你实际申请的服务填) TAVILY_API_KEY=tvly-你的key # 应用自身 NEXT_PUBLIC_APP_URL=http://localhost:3000

注意OPENAI_MODEL这个变量,Scira 有些版本是硬编码模型名的,你需要找到调用处把它替换成process.env.OPENAI_MODEL。如果懒得改,直接把硬编码那行的字符串换成你的模型 ID 也行。

接下来是路由配置。Scira 的问答接口一般在app/api/search/route.ts或app/api/chat/route.ts。核心逻辑是用streamText把模型和工具串起来。下面是一个精简但可运行的版本:

import { streamText } from 'ai'; import { myProvider } from '@/lib/ai/providers'; import { webSearchTool } from '@/lib/tools/web-search'; export const maxDuration = 60; export async function POST(req: Request) { const { messages } = await req.json(); const result = streamText({ model: myProvider(process.env.OPENAI_MODEL!), messages, tools: { webSearch: webSearchTool, }, maxSteps: 5, }); return result.toDataStreamResponse(); }

这里几个参数值得说清楚。tools里注册的工具,模型会在需要时自动调用;maxSteps: 5限制最多几轮「模型思考 → 调工具 → 再思考」,防止无限循环;toDataStreamResponse()是 Vercel AI SDK 提供的流式响应封装,前端用useChat就能接。

工具本身的实现长这样:

import { tool } from 'ai'; import { z } from 'zod'; export const webSearchTool = tool({ description: '搜索网页获取实时信息,当问题涉及最新事件或需要外部资料时使用', parameters: z.object({ query: z.string().describe('搜索关键词'), }), execute: async ({ query }) => { const res = await fetch('https://api.tavily.com/search', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ api_key: process.env.TAVILY_API_KEY, query, max_results: 5, }), }); const data = await res.json(); return data.results.map((r: any) => ({ title: r.title, url: r.url, content: r.content, })); }, });

工具返回的数组里带url,这就是前端渲染引用来源的数据源。Scira 前端会把toolInvocations里的结果提取出来展示。你只要保证工具返回结构里有 URL 字段,引用就能显示。

如果你用的是 Cline MCP 或类似工具链,配置逻辑是一样的三件套:Base URL 填https://taotoken.net/api,Key 填你的sk-,Model ID 填你验证过的模型名。Codex 的auth.json也是同样三个字段,别漏了 Model ID,否则会报模型不存在。

4. 验证一次从提问到引用返回的完整请求

配置写完,启动npm run dev,打开http://localhost:3000。现在做一次完整验证:在输入框里问一个需要实时信息的问题,比如「最近有什么新的开源 AI 搜索项目」。

预期行为是这样的:前端先显示模型正在思考,然后你会看到它触发了一次webSearch工具调用(界面上可能显示「正在搜索…」),接着流式吐出答案,答案末尾或侧边列出几条带链接的来源。打开浏览器开发者工具的 Network 面板,找到那个流式请求,Response 里应该能看到tool-invocations和text-delta交替出现的数据块。

如果你想用命令行验证,可以直接 curl 你的路由:

curl -X POST http://localhost:3000/api/search \ -H "Content-Type: application/json" \ -d '{"messages":[{"role":"user","content":"介绍一下 Vercel AI SDK 的 tool calling"}]}'

返回的是一串 SSE 格式的流,你会看到类似0:"..."的文本增量和9:{...}的工具调用记录。如果只看到文本没有工具调用,说明模型判断这个问题不需要搜索,换个明确需要实时信息的问题再试。

成功的关键标志有三个:一是模型确实调用了工具(不是直接编答案),二是工具返回的数据被模型引用进了回答,三是前端能渲染出可点击的来源链接。三个都满足,说明你的检索问答链路通了。

我试过把maxSteps设成 1,结果模型调完工具就没机会生成最终答案了,返回的是工具原始数据。所以这个值至少给 2,给 5 比较稳妥。另外maxDuration在 Vercel 部署时要注意,免费版有执行时长限制,本地开发无所谓。

5. 本篇常见报错与排查对照

跑这条链路,报错基本集中在几个地方。下面按真实错误信息对照排查。

401 Unauthorized / invalid api key:最常见。先检查.env.local里的OPENAI_API_KEY有没有多余空格或换行,再确认 baseURL 是不是https://taotoken.net/api而不是带/v1的版本。如果 key 本身没问题,去 API Keys 页面确认这个 key 没有被删除或过期。改完环境变量一定要重启 dev server,Next.js 不会热加载.env.local。

local proxy failed / fetch failed:这个通常出现在工具执行阶段,不是模型阶段。检查你的搜索 API key 是否有效,以及execute函数里的 fetch 地址能不能通。如果你在容器里跑,注意容器网络是否能访问外网。这个错误和模型入口无关,别去改 baseURL。

reading 'choices' / Cannot read properties of undefined:说明返回结构不是预期的 OpenAI 格式。可能是 baseURL 指错了端点,或者模型 ID 不存在导致服务端返回了错误对象。先用 curl 直接打https://taotoken.net/api/chat/completions看返回,确认结构里有choices字段再回来查代码。

OAuth / authentication_error:如果你在 Claude Code 或类似工具里看到这个,通常是认证方式没配对。这类工具要用 API Key 模式而不是 OAuth 模式,配置里找ANTHROPIC_BASE_URL或对应字段,填https://taotoken.net/api,Key 填sk-开头的那串。具体接入方式可以看接入文档(https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite),里面有各客户端的字段对照。

模型不调用工具,直接编答案:不是报错但很常见。检查工具的description写得够不够明确,模型靠这段描述判断何时调用。把「搜索网页」改成「当问题涉及最新事件、实时数据或需要外部资料时,搜索网页获取信息」,触发率会明显提高。

引用来源不显示:前端拿不到 URL。检查工具返回的数组里每个对象是否有url字段,以及前端提取逻辑是否匹配这个字段名。字段名对不上,数据在但渲染不出来。

排查顺序建议从模型入口开始:先用模型对话页面确认 key 和模型 ID 可用,再查工具,最后查前端渲染。这样能把问题范围快速缩小到一层。

6. 把这条链路用起来

链路跑通之后,你可以按自己的需求替换工具。Scira 原版有学术、社交、视频等多个工具,你完全可以只保留网页搜索,或者加一个查数据库的工具。Vercel AI SDK 的tool函数是通用的,只要execute返回结构化数据,模型就能用。

如果你打算长期跑编码类或 agent 类任务,可以了解下 Coding Plan(https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding_plan&utm_campaign=rewrite),它和搜索链路是互补的。日常调试模型输出,用模型对话页面最快。所有接入相关的字段和示例,接入文档里都有,遇到配置问题先翻那里。

最后留一个实用技巧:把maxSteps和工具的description当成两个调优旋钮。前者控制搜索深度,后者控制搜索触发率。大部分「答得不好」的问题,调这两个比换模型更有效。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询