🔥 30分钟搭建AI搜索引擎:Cursor+v0.dev+Bolt.new实战教程

891 阅读6分钟

整合多款AI工具,从构思到上线完整实践 |

image.png

本文介绍如何快速实现一个AI搜索引擎,包含意图识别、搜索聚合、智能分析等功能。最重要的是 - 从开发到部署全程免费。 访问地址: ai.chatgptnb.com/

目录

前言

最近AI搜索引擎特别火,但很多同学觉得实现起来很复杂。其实不然,本文将教你用最简单的方式实现一个AI搜索引擎。而且整个项目完全免费,非常适合快速验证想法。

技术栈

  • Next.js 14
  • 豆包大模型 API (5亿免费token)
  • Serp API (新用户100条免费额度)
  • Tailwind CSS
  • TypeScript

快速开始

首先使用 Bolt.new 搭建一个前端项目框架。虽然 Bolt 每天有使用次数限制,但搭建一个基础项目绰绰有余。如果对生成的UI不满意,还可以用 v0.dev 重新生成更好看的页面样式。

调试好基础页面后,我们把项目导入到 Cursor 编辑器中完成具体逻辑。这里有个小技巧 - 可以用临时邮箱(www.linshiyouxiang.net)注册 Cursor,免费使用 Claude 3.5 等模型。如果用了 v0.dev 生成新页面,直接让 Cursor 帮你适配到现有项目中就行。

实现思路

整个搜索引擎的实现分为前后端两大部分。让我们先从用户交互开始:

一、前端交互实现

image.png

前端采用对话式交互,一次完整的搜索分析流程如下:

// 1. 处理搜索请求
async function handleSearch(query: string) {
  addMessage('user', query);
  const stream = await startSearch(query);
  
  for await (const event of stream) {
    switch (event.type) {
      case 'intent':
        updateIntent(event.content);
        break;
      case 'search':
        displayResults(event.results);
        break;
      case 'topics':
        showRelatedTopics(event.topics);
        break;
      case 'analysis':
        streamAnalysis(event.content);
        break;
    }
  }
}

// 2. 渲染消息内容
function ChatMessage({ message, isLoading }) {
  return (
    <div className="message">
      {/* 意图识别 */}
      {message.intent && <IntentView intent={message.intent} />}
      
      {/* 搜索结果 */}
      {message.results && <SearchResults results={message.results} />}
      
      {/* 相关主题 */}
      {message.topics && <TopicList topics={message.topics} />}
      
      {/* 分析结果 */}
      {message.analysis && <AnalysisView content={message.analysis} />}
    </div>
  );
}

整个交互流程:

  1. 输入问题 → 分析意图
  2. 获取意图 → 检索网页
  3. 整理结果 → 生成主题
  4. 综合信息 → 输出分析

💡 采用流式响应实现实时反馈,提升用户体验

这样的实现既保证了交互流畅,又让用户清晰地了解每步进展。

二、后端功能实现

后端主要实现四个核心功能:

  1. 意图识别
  2. 搜索聚合
  3. 智能分析
  4. API 路由

让我们一步步来看具体实现。

1. 意图识别

最简单的方式是直接用豆包大模型:

async analyzeIntent(query: string): Promise<IntentAnalysis> {
  const completion = await this.openai.chat.completions.create({
    messages: [
      {
        role: 'system',
        content: `你是一位金融分析专家。请分析用户查询,并返回以下JSON格式结果:
{
  "description": "用一句话描述用户意图",
  "needsSearch": true/false (是否需要检索最新市场信息),
  "searchKeywords": "优化后的检索关键词",
  "type": "查询类型(market:市场行情, general:普通咨询, calculation:计算类, historical:历史数据, definition:概念解释)"
}`
      },
      {
        role: 'user',
        content: query
      }
    ],
    model: 'ep-20240820165714-ckvrz',
    temperature: 0.3,
    max_tokens: 150
  });

  try {
    const result = JSON.parse(completion.choices[0]?.message?.content || '{}');
    return {
      description: result.description || '正在分析市场数据...',
      needsSearch: result.needsSearch ?? true,
      searchKeywords: result.searchKeywords || query,
      type: result.type || 'market'
    };
  } catch (error) {
    console.error('Intent parsing error:', error);
    return {
      description: '正在分析市场数据...',
      needsSearch: true,
      searchKeywords: query,
      type: 'market'
    };
  }
}

这段代码不仅能分析用户意图,还能:

  1. 判断是否需要检索最新信息
  2. 优化搜索关键词
  3. 识别查询类型(市场行情/普通咨询/计算类等)
  4. 包含错误处理机制
2. 搜索实现

有了意图后,就能构造更精准的搜索:

async retrieve(query: string): Promise<SearchResult[]> {
  const cacheKey = `search:${query}`;
  if (this.cache.has(cacheKey)) {
    return this.cache.get(cacheKey);
  }

  try {
    const searchParams: any = {
      api_key: this.serpapiKey,
      engine: 'google',
      hl: 'zh-cn',
      gl: 'cn',
      q: query,
      num: 10
    };

    const response = await axios.get('https://serpapi.com/search.json', {
      params: searchParams,
      timeout: 15000
    });

    const results = response.data;
    const searchResult: SearchResult[] = [];

    // 处理普通搜索结果
    if (results.organic_results) {
      results.organic_results.forEach((result: any) => {
        searchResult.push({
          title: result.title,
          link: result.link,
          snippet: result.snippet,
          source: result.source || new URL(result.link).hostname,
          date: result.date || new Date().toLocaleDateString(),
          type: 'market'
        });
      });
    }

    // 添加缓存
    this.cache.set(cacheKey, searchResult);
    setTimeout(() => this.cache.delete(cacheKey), this.cacheTimeout);
    
    return searchResult;

  } catch (error) {
    console.error('搜索错误:', error);
    throw new Error(error instanceof Error ? error.message : '搜索服务出现错误');
  }
}

🔍 这里选择了 Serp API 是因为它提供新用户免费 100 条搜索额度,足够测试和小规模使用。而且它能提供主流搜索引擎的实时爬虫数据,对于快速验证想法来说非常合适。如果额度用完了,换个手机号重新注册就好。

3. 智能分析

除了基础搜索,我们还需要智能分析功能:

// 1. 生成相关研究主题
async generateRelatedTopics(context: SearchContext): Promise<string[]> {
  const completion = await this.llm.complete({
    system: '你是金融研究专家,请基于搜索内容生成5个相关主题',
    user: this.buildPrompt(context),
    config: {
      temperature: 0.8,
      maxTokens: 200
    }
  });

  return this.parseTopics(completion.content);
}

// 2. 流式分析响应
async streamAnalysis(context: SearchContext): Promise<ReadableStream> {
  const stream = await this.llm.streamComplete({
    system: '你是金融分析专家,请深入分析用户问题',
    user: this.buildPrompt(context),
    config: {
      temperature: 0.7
    }
  });

  return this.transformToReadable(stream);
}

// 3. 构建分析上下文
interface SearchContext {
  query: string;
  results: SearchResult[];
  messages: Message[];
  intent: IntentAnalysis;
}

private buildPrompt(context: SearchContext): string {
  const { query, results, intent } = context;
  return `
用户问题: ${query}
查询意图: ${intent.description}
搜索结果: ${this.formatResults(results)}
  `.trim();
}
4. API 实现

最后是完整的 API 路由处理:

export async function search(request: Request) {
  // 1. 初始化流式响应
  const { stream, writer } = initializeStream();
  
  try {
    const { query, messages } = await parseRequest(request);
    const searchService = initializeService();

    // 2. 分析意图
    await streamStep(writer, 'intent', async () => {
      const intent = await searchService.analyzeIntent(query);
      return intent.description;
    });

    // 3. 执行搜索
    await streamStep(writer, 'search', async () => {
      const results = await searchService.retrieve(intent.searchKeywords);
      return results;
    });

    // 4. 生成相关主题
    await streamStep(writer, 'topics', async () => {
      const topics = await searchService.generateRelatedTopics({
        query, results, messages, intent
      });
      return topics;
    });

    // 5. 流式分析
    await streamAnalysis(writer, async () => {
      const analysisStream = await searchService.streamAnalysis({
        query, results, messages, intent
      });
      return analysisStream;
    });

    return buildResponse(stream);
    
  } catch (error) {
    return handleError(error, writer, stream);
  }
}

这样的实现有以下优点:

  1. 代码结构清晰,职责分明
  2. 使用 TypeScript 类型保证类型安全
  3. 支持流式响应提升体验
  4. 完善的错误处理机制
  5. 易于扩展和护

💡 实际项目中建议添加日志记录、性能监控、限流等生产级特性。

关于技术实现

我们使用 OpenAI 的 npm 包但实际调用豆包 API,因为豆包的接口与 OpenAI 完全兼容,这样既能享受到 OpenAI 包的完善类型提示和工具函数,又能用上国内更快更便宜的大模型服务。只需要修改 baseURL 指向豆包的服务地址即可。

部署上线

推荐使用 Netlify 进行部署。通过部署十几个项目的实践来看,Netlify 在国内的访问速度比 Vercel 快很多。

开发工具推荐

为了加快开发速度,这里推荐几个好用的工具:

总结

通过这个简单的实现,我们看到搭建一个 AI 搜索引擎并不复杂,而且完全不需要成本。关键是:

  1. 选择合适的免费工具和服务
  2. 合理设计搜索流程
  3. 注意用户体验细节

如果对实现细节感兴趣,可以在评论区交流。

进阶优化

这个实现还比较基础,要做成生产级产品还需要考虑以下优化:

  1. RAG检索增强
class RAGSearch {
  constructor() {
    this.vectorDB = new VectorStore();
    this.embedder = new Embedder();
  }
  
  async search(query: string) {
    // 1. 文本向量化
    const vector = await this.embedder.encode(query);
    
    // 2. 相似度检索
    const similar = await this.vectorDB.search(vector);
    
    // 3. 混合排序
    return this.hybridRank([
      ...similar,           // 向量检索结果
      ...this.keywordSearch(query), // 关键词搜索
      ...this.recentDocs(query)     // 实时文档
    ]);
  }
}
  1. 知识库集成
  • 行业研报库:整合主流金融研究机构报告
  • 专业词典:金融术语解释和专业知识
  • 历史数据:市场历史行情和交易数据
  • 实时资讯:新闻、公告、研报等实时信息
  1. 多模型协作
  • 意图识别模型
  • 检索排序模型
  • 分析总结模型
  • 问答对话模型
  1. 性能优化
  • 分布式缓存
  • 异步并行
  • 增量更新
  • 预计算

💡 这些优化可以根据实际需求逐步实现,先用最简单的方案验证想法。