为网站添加 AI 搜索功能:语义搜索与 RAG 实现指南

一个典型的痛点:某文档站有 400 多篇教程,用户搜索「怎么改页面标题」什么都搜不到,因为页面里写的是「修改 title 标签」。关键词搜索按字面匹配,用户必须用词精确才能命中,而真实用户的表达千奇百怪。AI 语义搜索把「文本」编码成「向量」,在语义空间里找最近邻——即使措辞完全不同,也能返回意思相近的内容。下面从原理、实现到选型,给出可落地的方案。

语义搜索 vs 关键词搜索

特性 关键词搜索 AI 语义搜索
匹配方式 字面匹配 语义理解
拼写错误 不支持 自动纠错
同义词 需手动配置 自动理解
自然语言 不支持 完全支持
冷启动 无需训练 需嵌入模型
搜索质量 ⭐⭐ ⭐⭐⭐⭐

需要说明:语义搜索不是要替代全文检索,实践中两者经常搭配成「混合检索」——先用 BM25 拿到关键词命中的结果,再和向量检索结果做加权融合,召回率会明显好于单独用任何一种。

技术架构

三个核心组件,缺一不可:

  1. 嵌入模型:把文本变成 1536 维(text-embedding-3-small)左右的向量,文本越相似向量越接近;
  2. 向量数据库:存向量、建索引、做最近邻查询;
  3. LLM 生成(可选):把检索结果组织成自然语言回答,即 RAG。

这里容易被忽略的是**分块(chunking)**策略。页面太长直接整篇嵌入,向量会被「稀释」;建议按段落或 500-1000 字符切块,块之间留 50-100 字符重叠,并写入标题、URL 等元数据,检索时才不丢上下文。

实现方案

方案一:基于向量数据库的语义搜索(推荐)

用 OpenAI 嵌入 + Chroma,代码很短,适合先跑通概念:

from openai import OpenAI
import chromadb

client = OpenAI()
chroma_client = chromadb.PersistentClient(path="./chroma_db")
collection = chroma_client.get_or_create_collection("website_content")

# 1. 索引文档
def index_content(docs):
    for i, doc in enumerate(docs):
        response = client.embeddings.create(
            model="text-embedding-3-small",
            input=doc["text"]
        )
        collection.add(
            embeddings=[response.data[0].embedding],
            documents=[doc["text"]],
            metadatas=[{"title": doc["title"], "url": doc["url"]}],
            ids=[f"doc_{i}"]
        )

# 2. 搜索
def search(query, n_results=5):
    response = client.embeddings.create(
        model="text-embedding-3-small",
        input=query
    )
    results = collection.query(
        query_embeddings=[response.data[0].embedding],
        n_results=n_results
    )
    return results

几个工程要点:嵌入接口有 QPS 限制,批量索引时要做并发控制;数据更新时用 upsert(相同 id 覆盖)而不是重复 add,避免向量库里堆满旧版本。

方案二:RAG 搜索(检索 + 生成)

在语义搜索之上,让 LLM 基于检索到的内容作答,并「引用来源」避免幻觉:

def rag_search(query):
    # 1. 检索相关内容
    context_docs = search(query)
    context = "\n\n".join(context_docs["documents"][0])
    
    # 2. 生成回答
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=[
            {"role": "system", "content": f"基于以下内容回答用户问题。如果内容不足以回答,请如实告知。\n\n相关内容:\n{context}"},
            {"role": "user", "content": query}
        ]
    )
    return response.choices[0].message.content

RAG 的关键是把「来源」一起返回,让回答旁列出对应的原文链接,用户能点进去核实——这也是企业知识库问答最常见的做法,接入思路可参考网站 AI 聊天机器人。

前端集成

// 搜索前端组件
class AISearch {
    constructor(inputEl, resultEl) {
        this.input = inputEl;
        this.results = resultEl;
        this.debounceTimer = null;
        
        this.input.addEventListener('input', (e) => {
            clearTimeout(this.debounceTimer);
            this.debounceTimer = setTimeout(() => {
                this.search(e.target.value);
            }, 300);
        });
    }
    
    async search(query) {
        if (query.length < 2) return;
        
        const response = await fetch('/api/search', {
            method: 'POST',
            headers: { 'Content-Type': 'application/json' },
            body: JSON.stringify({ query })
        });
        
        const data = await response.json();
        this.renderResults(data);
    }
    
    renderResults(data) {
        this.results.innerHTML = data.map(item => `
            <a href="${item.url}" class="search-result">
                <h4>${item.title}</h4>
                <p>${item.excerpt}</p>
            </a>
        `).join('');
    }
}

前端做了 300ms 防抖,避免每次击键都请求一次;实际部署时建议后端再加一层缓存(相同 query 结果缓存 5-10 分钟),把成本压下来。

向量数据库选择

数据库 类型 托管选项 免费额度
Chroma 嵌入式 自托管 完全免费
Pinecone 托管服务 SaaS 有免费层
Weaviate 自托管/云 SaaS/自托管 有免费层
Qdrant 自托管/云 SaaS/自托管 有免费层
pgvector PostgreSQL 扩展 自托管 完全免费

选型建议:小站先用 Chroma 或 pgvector,零成本起步;数据量到百万级向量、需要 SLA 和弹性,再考虑 Pinecone/Qdrant 的托管版。如果网站已经在用 PostgreSQL,直接加 pgvector 扩展最省事,不用引入新组件。

成本估算

以 text-embedding-3-small 为例,100 万 token 约 $0.02,一个 500 页、每页 2000 字的站点,全量索引成本不到 1 美元;检索阶段的嵌入费用几乎可以忽略,大头其实是 RAG 场景下的 LLM 生成 token。整体下来,一个中小站点的语义搜索月成本通常控制在几美元以内。

上线后怎么衡量效果

搜得准不准,不能靠感觉。建议上线前先准备 50-100 条真实用户问题作为测试集,统计「前 3 条结果里有没有正确答案」的命中率,作为迭代的基线;上线后用三个指标持续跟踪:零结果率(用户搜索后一条结果都没有的比例)、搜索结果点击率、以及「搜索后是否立刻发起新搜索」的比例——后者越低说明结果越对路。每周跑一次测试集,模型或分块策略每次改动后都对比基线,语义搜索才会越用越准。

16IDC 观察

AI 语义搜索让网站的内容价值被更充分地发现:对文档、博客、知识库这类内容密集型站点,语义搜索的用户满意度通常比传统搜索高 40%-60%,因为用户不用再「猜关键词」。建议从 Chroma 或 pgvector 开始,先跑通「索引 + 检索」,再加 RAG 和混合检索逐步优化。更多AI 相关应用可参考本站相关文章。

参考:OpenAI Embeddings 文档 https://platform.openai.com/docs/guides/embeddings;Chroma 官方文档 https://docs.trychroma.com/