Files
agent-park/docs/plans/2026-01-25-ai-search-system-design.md
T

11 KiB
Raw Blame History

AI 智能搜索系统设计文档

日期: 2026-01-25 作者: Claude Code 状态: 设计阶段

概述

为项目列表添加 AI 语义搜索功能,用户可通过自然语言描述需求,系统通过向量相似度匹配返回相关项目,而非传统的关键词模糊搜索。

核心目标

  • 支持自然语言查询(如"帮我找做图像生成的项目")
  • 基于向量相似度的语义匹配
  • 完全在 n8n 中实现 AI 逻辑,Next.js 应用保持纯净
  • 利用现有 Neon 数据库的 pgvector 扩展

架构设计

整体架构

前端(Next.js
    ↓
API 代理(/api/search/ai
    ↓
n8n 工作流(AI 逻辑)
    ↓
Neon 数据库(pgvector

核心组件

数据层(Neon + pgvector

  • Project 表添加 embedding 字段存储向量
  • HNSW 索引加速相似度搜索
  • 向量维度:1536OpenAI text-embedding-3-small

服务层(n8n 工作流)

  • 向量化工作流:定时扫描未向量化项目,调用 OpenAI API 生成向量
  • AI 搜索工作流:接收查询 → 生成向量 → 相似度搜索 → 返回结果

前端层(Next.js

  • 搜索框增加 AI 模式切换按钮
  • 显示相似度评分和匹配原因

数据库设计

Schema 修改

model Project {
  // ... 现有字段

  // 新增:向量嵌入字段
  embedding          vector(1536)?   // pgvector 类型
  embeddingUpdatedAt DateTime?       // 向量化更新时间
}

迁移 SQL

-- 启用 pgvector 扩展
CREATE EXTENSION IF NOT EXISTS vector;

-- 添加向量列
ALTER TABLE "Project" ADD COLUMN "embedding" vector(1536);
ALTER TABLE "Project" ADD COLUMN "embeddingUpdatedAt" TIMESTAMP;

-- 创建 HNSW 索引(余弦距离)
CREATE INDEX idx_project_embedding_cosine
ON "Project" USING hnsw ("embedding" vector_cosine_ops)
WITH (m = 16, ef_construction = 64);

-- 复合索引(查找未向量化项目)
CREATE INDEX idx_project_embedding_null
ON "Project" ("id")
WHERE "embedding" IS NULL;

向量化内容策略

字段权重分配:

  • 名称(40%):name + nameEn
  • 描述(40%):description + descriptionEn
  • 标签(15%):tags(逗号连接)
  • 详细内容(5%):content + contentEn(截取前 500 字)

示例输入文本:

AI Video Generator
一个基于人工智能的视频生成工具,可以自动从文本生成高质量视频...
人工智能, 视频生成, AIGC
详细功能介绍...

n8n 工作流设计

工作流 1:定时向量化

触发器Cron 表达式(每 5 分钟)

*/5 * * * *

流程

触发器
  ↓
查询未向量化项目(LIMIT 20)
  ↓
批量处理(每批 5 个)
  ↓
  构造文本内容(合并字段)
  ↓
  调用 OpenAI Embeddings API
  ↓
  更新数据库 embedding 字段
  ↓
  等待 1 秒(控制速率)
  ↓
下一批

PostgreSQL 查询

SELECT id, name, "nameEn", description, "descriptionEn",
       content, "contentEn"
FROM "Project"
WHERE "embedding" IS NULL
  AND "status" = 'ACTIVE'
LIMIT 20

错误处理

  • API 限流:指数退避重试(1s → 2s → 4s)
  • 最多重试 3 次
  • 失败记录日志

工作流 2AI 搜索

触发器Webhook/webhook/ai-search

流程

Webhook 接收查询
  ↓
接收参数:{ query, locale, limit, filters }
  ↓
调用 OpenAI Embeddings API(生成查询向量)
  ↓
PostgreSQL 向量相似度搜索
  ↓
应用过滤条件(tags, status)
  ↓
格式化结果(添加相似度评分)
  ↓
返回 JSON 响应

PostgreSQL 查询

SELECT
  id, name, "nameEn", slug, description, "descriptionEn",
  1 - (embedding <=> '{{ query_vector }}'::vector) as similarity
FROM "Project"
WHERE "embedding" IS NOT NULL
  AND "status" = 'ACTIVE'
ORDER BY embedding <=> '{{ query_vector }}'::vector
LIMIT {{ limit || 20 }}

响应格式

{
  "results": [
    {
      "project": { /* 项目数据 */ },
      "similarity": 0.89,
      "matchReason": "项目名称和描述与图像生成高度相关"
    }
  ],
  "total": 42,
  "searchTime": 156
}

Next.js API 设计

路由配置

文件src/app/api/search/ai/route.ts

import { NextResponse } from 'next/server'

const N8N_WEBHOOK_URL = process.env.N8N_AI_SEARCH_WEBHOOK

export async function POST(request: Request) {
  try {
    const body = await request.json()

    // 转发到 n8n 工作流
    const n8nResponse = await fetch(N8N_WEBHOOK_URL, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(body)
    })

    const results = await n8nResponse.json()

    return NextResponse.json(results)

  } catch (error) {
    return NextResponse.json(
      { error: 'Search failed' },
      { status: 500 }
    )
  }
}

请求格式

{
  "query": "帮我找做图像生成的AI工具",
  "locale": "zh",
  "limit": 20,
  "filters": {
    "tags": ["AIGC"],
    "status": "ACTIVE"
  }
}

前端交互设计

UI 组件修改

文件src/components/search/SearchBar.tsx

功能

  • 添加 AI 模式切换按钮(Sparkles 图标)
  • AI 模式时按钮高亮(金色背景)
  • 不同模式的占位符提示
  • 加载状态优化

关键代码

<button
  onClick={() => setAiMode(!aiMode)}
  className={`
    px-3 py-2 border-2 transition-all
    ${aiMode
      ? 'bg-yellow-400 border-yellow-500 text-black'
      : 'bg-white border-gray-300 text-gray-600'
    }
  `}
  title="AI 语义搜索"
>
  <Sparkles className="w-5 h-5" />
</button>

AI 搜索结果展示

文件src/components/search/AISearchResults.tsx

功能

  • 显示相似度指示条(左侧彩色条)
  • 相似度评分(0-100%
  • 匹配原因说明(可选)
  • 颜色编码:绿色(>0.8)、黄色(>0.6)、红色(<0.6

搜索模式对比

特性 传统搜索 AI 搜索
占位符 "搜索项目名称..." "描述你想要的项目..."
匹配方式 关键词模糊匹配 向量语义相似度
返回速度 极快(<100ms 较快(1-3s
结果增强 相似度评分 + 匹配原因
提示信息 "💡 试试:'帮我找能生成视频的 AI 工具'"

环境变量配置

Next.js 应用(.env.local

# Neon 数据库(已有)
DATABASE_URL=postgres://...

# n8n Webhook
N8N_AI_SEARCH_WEBHOOK=https://your-n8n-instance.com/webhook/ai-search
N8N_WEBHOOK_API_KEY=your-webhook-key  # 可选,用于安全验证

n8n 工作流

# OpenAI API(用于 Embeddings
OPENAI_API_KEY=sk-...

# Neon 数据库(与 Next.js 共享)
NEON_DATABASE_URL=postgres://...

错误处理与优化

错误处理策略

n8n 工作流

  • API 限流:指数退避重试
  • API Key 无效:发送告警
  • 数据库查询失败:返回友好错误信息
  • 向量未就绪:提示用户稍后重试

前端

  • 10 秒超时限制
  • 超时或错误时自动降级到传统搜索
  • Toast 消息提示用户

性能优化

数据库查询

  • 只返回必要字段(不返回 content)
  • 使用 HNSW 索引
  • 设置查询超时(5s

缓存策略(可选)

  • Redis 缓存常见查询结果(5 分钟 TTL)
  • 内存缓存热门查询

监控指标

  • 平均搜索响应时间
  • API 调用次数/成本
  • 向量化完成率
  • 错误率

成本估算

OpenAI Embeddings API

定价

  • text-embedding-3-small$0.00002 / 1K tokens

估算

  • 单个项目(500 tokens):$0.00001
  • 1000 个项目:$0.01
  • 单次搜索(10 tokens):$0.0000002
  • 1000 次搜索:$0.0002

月度预算:$5 可处理 50 万个项目或 2500 万次搜索

Neon 免费套餐

限制

  • 存储:0.5GB
  • 计算:300 小时/月

向量存储

  • 单个项目(1536 维):3KB(半精度)
  • 1000 个项目:3MB
  • 10,000 个项目:30MB

结论:免费套餐完全够用(可支持 5,000-10,000 个项目)


测试计划

单元测试

// src/__tests__/search.test.ts
describe('AI Search', () => {
  it('should handle empty query', async () => {
    const response = await fetch('/api/search/ai', {
      method: 'POST',
      body: JSON.stringify({ query: '' })
    })
    expect(response.status).toBe(400)
  })

  it('should fallback to traditional search on error', async () => {
    // 测试错误降级逻辑
  })
})

E2E 测试

// tests/e2e/ai-search.spec.ts
test('AI 搜索功能', async ({ page }) => {
  await page.goto('/zh/projects')
  await page.click('[data-testid="ai-mode-toggle"]')
  await page.fill('input[name="search"]', '视频生成工具')
  await page.press('input[name="search"]', 'Enter')
  await expect(page.locator('.ai-search-results')).toBeVisible()
})

集成测试

  • 测试 n8n 工作流端到端
  • 验证向量搜索结果准确性
  • 测试错误场景(API 限流、数据库连接失败)

部署清单

数据库准备

  • 运行数据库迁移
  • 验证 pgvector 扩展已启用
  • 检查 HNSW 索引创建成功

n8n 配置

  • 创建向量化工作流

    • 配置 Cron 触发器(每 5 分钟)
    • 配置 PostgreSQL 节点
    • 配置 OpenAI Embeddings 节点
    • 添加错误处理和重试逻辑
  • 创建 AI 搜索工作流

    • 配置 Webhook 触发器
    • 配置 OpenAI Embeddings 节点
    • 配置 PostgreSQL 向量查询
    • 配置结果格式化
  • 测试工作流

    • 手动触发向量化流程
    • 测试 Webhook 搜索
    • 验证错误处理

Next.js 部署

  • 添加环境变量(N8N_WEBHOOK_URL
  • 创建 API 路由(/api/search/ai
  • 更新 SearchBar 组件
  • 创建 AISearchResults 组件
  • 本地测试完整流程
  • 部署到 Vercel

验证步骤

  1. 向量化测试

    -- 检查已向量化项目数
    SELECT COUNT(*) FROM "Project" WHERE embedding IS NOT NULL;
    
  2. 搜索测试

    • 输入自然语言查询
    • 验证返回结果相关性
    • 检查相似度评分
  3. 性能测试

    • 测量平均响应时间
    • 验证并发处理能力

后续优化方向

  1. 混合搜索:结合关键词搜索和向量搜索,提升准确率
  2. 查询缓存Redis 缓存热门查询结果
  3. A/B 测试:对比传统搜索和 AI 搜索的用户体验
  4. 多模态搜索:支持图片、语音输入
  5. 个性化排序:基于用户历史行为优化结果
  6. 自动标签建议AI 分析项目内容推荐标签

参考资料