十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

AI搜索技术拆解:从Perplexity到RAG实现

AI搜索技术拆解:从Perplexity到RAG实现 Perplexity Search 这类 AI 搜索产品登上各类 AI 产品关注榜背后不只是产品包装做得好更多是整个搜索交互范式发生了变化。用户输入问题后系统先通过搜索引擎拿到一批候选网页再让大模型基于这些网页摘要生成一段带引用编号的答案。和传统搜索返回蓝色链接不同AI 搜索直接给出结论、证据来源和继续追问的入口使用者不再需要一个个点开链接自己拼信息。这篇文章适合产品经理、后端开发者和正在做大模型应用的人。产品侧关心它为什么好用、引用怎么做、如何评估开发侧更关心 RAG 管线、搜索 API、LLM 调用、参数取舍和排错。下面先从产品逻辑入手再落到可运行的工程实现最后给出衡量标准、常见坑和生产化建议。示例用简化的 Python 服务演示实际落地时可根据团队技术栈替换。1. Perplexity Search 走红背后的技术逻辑AI 搜索到底解决了什么1.1 传统搜索的痛点索引到了信息但把筛选工作留给了用户传统搜索引擎本质上是一个索引系统。它先抓取海量网页建立倒排索引再根据用户 query 返回相关链接。这套机制对“我知道要找一个网站”“我想了解某个词的标准定义”这类任务效率很高但对“基于多个来源做综合判断”的任务用户要连续搜索多次、打开多个页面、自己对比信息整个过程非常耗时。更麻烦的是长尾问题。比如要比较两家 AI 翻译产品的价格、隐私策略、支持语言传统搜索会返回几十个页面用户要把价格区间和功能差异手动整理出来。另一个问题是多轮上下文你在传统搜索里搜了第一轮第二轮换关键词前面语境基本丢失只能靠用户自己继续拼。AI 搜索要解决的问题就是把“信息检索”和“信息综合”合并成一步同时用引用让结果可回查。Perplexity Search 真正切中的不是“聊天框里多了搜索按钮”而是把传统搜索引擎留给用户的整理工作接管过来让用户从“逐页浏览判断”变成“先看答案再通过来源验证”。1.2 AI 搜索的新交互答案、引用与追问Perplexity 类产品的页面形态通常包含四个部分顶部是答案区块答案中穿插引用编号底部或右侧是来源列表包含标题、域名和链接再往下是推荐追问引导用户继续深入同时用户可以在同一个对话里不断追问系统会记住上下文。这种形态的关键词不是“生成”而是“可验证”。大模型回答问题非常流畅但流畅不等于正确。引用列表给了用户一条验证路径如果回答中引用了某个网站用户可以直接点击源去核对。这也倒逼系统在构造 prompt 时只把检索到的真实内容交给模型而不是让模型凭记忆发挥。这种交互从“用户自己浏览链接做判断”变成“系统先综合、用户再验证”正是 AI 搜索让人感觉更直接的原因。它也没有丢掉传统搜索的长处网页标题、域名、摘要仍然保留只是从主菜变成了验证依据。1.3 为什么关注度会上升检索和生成终于可以被工程化组合热度上升不是单点原因。从技术侧看最近几代大模型在指令跟随和长上下文上进步明显模型能够按照“只使用检索资料回答并标注引用”这类约束生成内容检索成本也降下来了普通开发者可以拿到搜索 API 或开源检索组件。从产品侧看AI 搜索把“聊天”和“搜索”两个过去分开的入口合并。用户既可以得到对话式回答又保留了信息来源比纯聊天窗口更适合做知识获取入口。再加上 API 可以嵌入编程助手、客服系统、办公软件形成新的集成场景开发者关注度自然上升。需要说明的是各种 AI 产品指数榜的统计口径并不统一有的偏网站访问、有的偏开发者讨论、有的偏应用下载。某一时段排名冲到前面只能说明市场关注度在快速提高不能完全等同于市场份额。研究这类产品时真正值得关注的是背后的交互模型和技术链路有没有解决实际问题。2. 理解 AI 搜索的底层链路检索、增强、生成、溯源2.1 查询理解与多轮改写AI 搜索和传统搜索一样第一步不是直接检索而是先理解 query。用户真正想问的往往和输入的文字不完全一样。比如用户输入“它和谷歌搜索比有什么优势”搜索系统需要知道“它”指代什么用户输入“最近 RAG 有哪些新进展”“最近”要结合当前时间解释成日期范围。在工程上常见做法是先用一个小模型或一段精简 prompt 对 query 做改写和意图识别。改写结果会传给搜索引擎而不是直接拿来生成答案。这个步骤虽然很小但直接影响检索质量。QUERY_REWRITE_PROMPT 你是搜索查询改写助手。请把用户问题改写成适合搜索引擎的关键词查询。 要求保留核心实体补充省略的指代不添加编造条件。 只输出改写后的查询文本。 用户问题{question} 改写结果这里要注意改写不是无中生有。比如用户问“它收费吗”如果上下文里没有明确过对象系统应该直接返回原始问题而不是猜一个实体进去。多轮改写只有在对话历史明确时才有意义。2.2 实时检索从模型记忆到网络证据查询改写完成后进入检索层。检索层一般调用搜索 API拿到标题、URL、摘要和发布时间。选择搜索服务时至少关心四件事结果相关性、内容更新速度、请求限制和返回字段是否包含摘要。只给链接不给摘要的接口会增加后续构建 prompt 的成本。AI 搜索里的“实时”有两层含义一是索引要包含足够新的网页二是查询时要显式传递时间上下文让搜索 API 优先返回近期内容。如果模型本身的训练数据有截止日期实时检索就是弥补时效性的关键。检索结果通常要限制数量。常见做法是取前 5 到 10 条再按相关度和域名质量重排。返回条数太多生成阶段容易超长也容易引入噪音。2.3 RAG把外部证据注入生成流程RAG 是这套链路的标准名词全称 Retrieval-Augmented Generation。它把外部知识注入 prompt让模型在生成时“有据可依”。在 AI 搜索场景中外部知识来自搜索 API在私有知识库场景中外部知识来自向量检索或关键词检索。两类场景的流程非常相似召回候选内容、整理成上下文、交给模型生成、再后处理校验。很多刚接触大模型的人以为只需要把问题丢给模型让模型用训练时学过的知识回答。这在简单常识问题上可以但一旦涉及新闻事件、产品文档、内部资料模型就会幻觉。RAG 的价值不是让模型“更聪明”而是让模型“有当下可查的依据”。完整的 AI 搜索链路可以概括成query 改写、内容召回、结果重排、上下文构造、LLM 生成、引用校验、结果返回。其中任何一环出问题最终答案都会偏离事实。2.4 引用溯源把信任做进界面和数据结构引用是 AI 搜索和纯聊天机器人最明显的区别。没有引用模型给出再流畅的回答用户也无法判断内容真假有引用用户至少可以把答案拆回来源逐一验证。从数据结构上看引用要贯穿到 result 对象每条引用必须对应一个真实 URL而不是让模型嘴上说“根据某网站”。实现层面有两种做法。第一种是让模型在回答文本里输出[1][2]编号服务端再把编号映射成 link第二种是让模型输出结构化 JSON包含 answer 和 citations 数组。第二种更稳。无论哪种生成后都要做校验防止模型编造编号或漏标来源。注意引用编号的价值是让链接指向真实来源不是让回答看起来专业。一个不能点击、不能验证的来源列表没有信任价值。3. 动手实现一个 Perplexity 风格的 AI 搜索最小应用3.1 学习环境的技术选型与依赖这里做一个最小应用学习阶段关键在于把链路跑通不追求高并发。选择 Python 3.10 FastAPI requests openai 就够。如果你所在团队用 Java也可以把后面的实现换成 Spring AI 或 WebClient逻辑完全一致。pip install fastapi uvicorn[standard] requests openai pydantic需要准备两个外部服务一个 LLM 接口一个搜索接口。学习环境用任何 OpenAI 兼容的服务都可以搜索服务也可以用测试额度。不要在生产还依赖学习期的临时 key。3.2 项目结构按职责拆层方便后续排查ai-search-demo/ ├── app.py # FastAPI 入口 ├── search.py # 检索层 ├── prompt.py # 提示词构造 ├── llm.py # 模型调用 ├── config.py # 环境变量读取 └── requirements.txt把层拆开是为了排查方便。回答问题后如果发现答案质量差先看是检索层没召回好内容还是模型把内容用错了。如果所有逻辑写在一个文件里定位问题只能从头读到尾。3.3 检索层代码先拿回候选网页和摘要search.py 的核心是统一搜索 API 的返回结构。不同搜索服务返回字段不一样统一成 title、url、snippet 三个字段后prompt 层只依赖这套结构。# search.py import os import requests from typing import List, Dict SEARCH_ENDPOINT os.getenv(SEARCH_ENDPOINT, ) SEARCH_API_KEY os.getenv(SEARCH_API_KEY, ) def search_web(query: str, top_k: int 5) - List[Dict[str, str]]: if not SEARCH_ENDPOINT: raise RuntimeError(SEARCH_ENDPOINT 未配置请先设置搜索服务地址) params { q: query, count: top_k, } headers { Authorization: fBearer {SEARCH_API_KEY}, } resp requests.get(SEARCH_ENDPOINT, paramsparams, headersheaders, timeout5) resp.raise_for_status() items resp.json().get(items, []) results [] for item in items[:top_k]: results.append({ title: item.get(title, ), url: item.get(link) or item.get(url, ), snippet: item.get(snippet) or item.get(description, ), }) return results这段代码把搜索 API 的返回结果统一成三个字段。搜索服务不同字段名会有差异落地前要读官方文档确认。注意加了 timeout避免检索服务慢拖垮整个接口。3.4 生成层代码把检索结果带入模型并保留引用prompt.py 负责构造上下文。关键约束有三条只使用资料、回答中标注编号、资料不足时明确说明。# prompt.py from typing import List, Dict def build_prompt(question: str, results: List[Dict[str, str]]) - str: context_lines [] for i, item in enumerate(results, start1): context_lines.append( f[{i}] 标题{item[title]}\n f 来源{item[url]}\n f 摘要{item[snippet]} ) context \n\n.join(context_lines) return f请基于以下检索资料回答用户问题。 规则 1. 只使用资料中出现的信息不要凭模型记忆补充。 2. 回答中需要引用资料时在句尾使用[N]标注。 3. 如果资料不足以回答明确说明“根据现有资料无法回答”。 4. 回答控制在 300 字以内。 检索资料 {context} 用户问题 {question} 回答 llm.py 负责调用模型。任何兼容 OpenAI Chat Completions 接口的服务都可以接进来。# llm.py import os from openai import OpenAI client OpenAI( api_keyos.getenv(LLM_API_KEY, ), base_urlos.getenv(LLM_BASE_URL, None), ) def generate_answer(prompt: str, temperature: float 0.2) - str: resp client.chat.completions.create( modelos.getenv(LLM_MODEL, gpt-4o-mini), messages[{role: user, content: prompt}], temperaturetemperature, ) return resp.choices[0].message.content注意 temperature 不建议调太高AI 搜索需要稳定性和可验证性太高的随机性会让同样的问题每次返回不同结论。最后用 FastAPI 把链路串起来。# app.py from fastapi import FastAPI from pydantic import BaseModel from search import search_web from prompt import build_prompt from llm import generate_answer app FastAPI() class Query(BaseModel): q: str top_k: int 5 app.post(/api/search) def ai_search(query: Query): results search_web(query.q, query.top_k) prompt build_prompt(query.q, results) answer generate_answer(prompt) return { answer: answer, sources: results, }回答文本里的[1]可以在前端通过 sources 数组映射成可点击链接。这个最小闭环已经具备 AI 搜索的核心形态。3.5 参数说明与默认值选择参数含义常见默认值调大影响调小影响推荐场景top_k传给模型的结果条数5信息更全但噪音和成本上升上下文更短但可能漏关键信息通用问题取 5垂直小语料取 3snippet_max_chars每条摘要最大长度300上下文更长、更贵信息不足长文档场景适当加大temperature采样温度0.2更发散但可能偏离资料更稳定但偏保守AI 搜索用 0.1 到 0.3max_tokens生成最大 token 数500回答更长可能被截断看答案预期长度调整search_count搜索返回原始条数10覆盖更多但重排耗时召回不完整先取 10 再过滤到 5调参不是一劳永逸。同一个参数在不同 query 下表现不同建议准备 20 到 50 条测试 query每次只改一个参数对比效果。4. 运行验证如何判断搜索结果不是编出来的4.1 准备测试用例与预期行为只测“能返回结果”不够。建议准备四类用例时效性问题、知识截止问题、多跳比较问题、明显不可答问题。时效性问题例如“某大会最近发布了什么新功能”预期是答案中包含近期信息。知识截止问题例如模型训练后发生的事件预期是模型能借助检索回答而不是复述旧知识。多跳比较问题例如“A 产品定价和 B 产品定价谁更适合小团队”预期是模型综合多个来源比较。明显不可答问题例如“某内部系统接口文档在哪”预期是模型明确说资料不足而不是编一个 URL。启动服务并请求uvicorn app:app --reload --port 8000curl -X POST http://127.0.0.1:8000/api/search \ -H Content-Type: application/json \ -d {q: RAG 检索增强生成和传统搜索的区别, top_k: 5}这里演示的是通过命令验证。真实环境还要准备自动化测试集把常见 query 的预期行为固化下来。4.2 验证引用真实性和答案一致性回答返回后检查三件事。第一来源是否真实存在逐个打开引用 URL。第二答案是否真的来自摘要把模型输出里的关键句与检索摘要比对。第三编号是否一致答案里写了[2]但第二条来源不是它说的内容说明引用映射有问题。正常输出示例{ answer: RAG 的核心是把检索到的外部资料注入 prompt让模型基于资料生成回答[1][2]。, sources: [ { title: Retrieval-Augmented Generation 介绍, url: https://example.com/rag-intro, snippet: RAG 通过检索外部知识来增强大模型生成的准确性。 }, { title: RAG 与传统搜索的差异, url: https://example.com/rag-vs-search, snippet: 传统搜索返回链接RAG 直接生成基于证据的回答。 } ] }注意不要只检查接口返回 HTTP 200。AI 搜索应用即使返回成功也可能包含伪造引用和幻觉内容验证必须覆盖输出本身。如果检索服务没有返回摘要模型仍然生成了很具体的数字或结论就要怀疑模型是不是用了自己的记忆。4.3 学习环境与生产环境的差异维度学习环境生产环境检索服务测试 key、单文档稳定 API、限流、重试、降级模型服务OpenAI 兼容接口即可并发、超时、鉴权、敏感信息过滤缓存不缓存
返回列表