ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

从零构建AI工具垂直搜索引擎:架构、索引与语义检索实践

从零构建AI工具垂直搜索引擎:架构、索引与语义检索实践

1. 这个项目是怎么来的

一直想找个好用的 AI 工具导航站,试了一圈发现大多数要么是人工整理的静态列表,要么就是搜索结果又大又杂。搜“AI 写作”出来一堆八竿子打不着的 SaaS 产品,搜“本地知识库”又混进不少纯数据库项目。后来我干脆自己动手,做了一个垂直搜索引擎,专门搜索 AI 工具,把范围死死锁在“AI 工具”这个大品类里。做的时候想的很清楚:不做第二个人工分类导航站,而是做成一个真正能搜的引擎,让用户输入一个模糊需求,比如“帮我总结 PDF 的工具”“能跑私人知识库的开源方案”,引擎通过关键词匹配加语义相似度把最相关的工具排出来。

整个项目从零开始,边界也比一开始预想的复杂得多。最大的痛点是没有任何现成数据,不像通用搜索引擎有全网网页可以爬,我的信息源只有 AI 工具自身的官网、介绍页、文档,以及各类工具榜单的汇总页面。而“AI 工具”这个垂直池子本身有个难题:概念边界模糊。大模型应用层工具、开源模型框架、数据集平台、Agent 编排平台、提示词优化服务,全都挤在“AI 工具”这四个字底下,垂直不等于简单,反而对分类和过滤的要求更高。

这篇文章我会把整体架构、数据爬取、索引设计、语义检索混排以及我在实际开发中踩过的坑完整写一遍,希望能够帮到同样想折腾垂直搜索的人。适合的读者是对搜索系统有一定了解、想快速搭一个垂直领域搜索原型,或者对 RAG 落地细节感兴趣的个人开发者。

2. 垂直搜索的整体架构与设计思路

2.1 为什么做垂直搜索而不做通用搜索

垂直搜索这个词听起来像在蹭“垂直领域”概念,但做下来我觉得它和技术架构强相关。通用搜索引擎的核心是覆盖全量网页、处理海量去重、处理各类异构页面结构,这需要大量算力和存储。而垂直搜索的目标完全不同:它只针对一个细小的领域,希望搜出来的每一页都尽量是高质量、强相关的。我做的这个 AI 工具搜索,更像一个带搜索能力的结构化工具库。

这个策略在数据环节上有一个很直接的收益:我可以只抓固定的几十个站点、几百个榜单页面,然后抽取出能放进数据库里的结构化字段,而不是处理无限膨胀的网页快照。比如一款 AI 翻译工具,我只需要记录工具名、官网地址、标签、一句话简介、核心功能描述、开源状态、权限模式、价格模式、上架时间,以及从页面里截取的一段介绍原文。这些字段数据量不大,但搜索体验的保障程度要高得多。

从用户体验看,垂直搜索结果通常带有“全局性”之外的额外价值。通用搜索里搜“AI 视频生成”,前面几条基本是媒体文章和榜单,不会直接给工具卡片;我的垂直搜索就会直接把能用的视频生成工具列出来,每个后面都带着官网、价格模式、开源与否、支持能力等信息,这种“即看即用”的体验才是做垂直搜索的初衷。

2.2 数据层与检索层的边界划分

架构上我把项目拆成了数据层、索引层、检索层、服务层四块,走最直观的“爬取-清洗-入库-索引导出-查询召回-排序展示”的流水线。

  • 数据层:负责信息源管理、页面爬取、HTML 内容抽取、字段识别、去重合并、快照存储。
  • 索引层:负责把数据转换出倒排索引,同时生成向量索引,并为每个文档计算各种元数据标签。
  • 检索层:接收查询词,做分词、同义映射、召回候选、文本得分和向量得分融合、规则排序。
  • 服务层:提供 HTTP 接口和前端页面,接收搜索请求返回 JSON 结果,同时记录点击行为,用于后续调权。

数据层和索引层的边界必须清晰。我一开始偷懒,把索引构建逻辑和爬取解析放在同一个脚本里,结果每次数据一更新就要全量重建索引,导致搜着搜着新数据不生效。后来改成数据层把清洗后的 JSON 快照落盘,索引层单独从快照构建,两边通过文件版本号关联,才把这个解耦问题彻底解决。

检索层是核心体验只在一处,就是召回和排序。垂直搜索领域里用户输入往往很模糊,比如“AI PPT”“数字人”“SaaS AI”,如果只靠字面匹配那效果很糟糕。所以检索层必须能同时跑两套检索:一是基于倒排索引的文本检索,保证精确的控制力和可控性;二是基于 Embedding 的向量检索,负责泛化和语义相似。融合阶段再结合标签权重和人工规则做最终排序。

2.3 为什么最终选了轻量索引方案

一开始我想用一套完整的企业级检索引擎,因为索引能力确实很成熟,各种分词器、过滤器、聚合查询都很好用。但跑起来后发现我的数据量连百万级都没到,只有两三万条工具的元数据,为了这点数据再引入一个独立索引服务,运维成本反而盖过了收益。于是我决定自己写一个轻量索引模块,把分词、倒排、排序逻辑全部控制在代码里。

轻量索引有个很大的好处:构建逻辑透明。搜索里出现任何“莫名其妙的排序”,我都能直接打开索引定义看到底是哪个字段权重出了问题,而不是在一个庞大配置文件里翻半天。对于个人项目来说,这种可解释性太重要了,因为它大大降低了调试成本。同时构建过程只要几秒,完全可以在启动时全量加载到内存,连缓存层都不太需要一个复杂的淘汰算法。

轻量方案也有明显短板,最突出的就是并发能力和分布式扩展。但个人项目场景下,查询并发不大,也没有多机房需要,这个短板基本可以被忽略。而且后续即使数据增长到百万级,只要索引模块支持增量构建,性能依然可控。

3. 信息源与数据爬取:效果的关键在源头

3.1 信息源划分与采集策略

数据从哪来找就好比做饭选食材,食材不新鲜,厨师再厉害也白搭。我把信息源分成三类:

  • 工具官网和文档站点:网站结构相对清晰,内容权威性最强,是描述工具能力的一手来源。
  • AI 工具导航站和榜单页:汇总了大量工具名称和直达链接,信息密度高,是发现长尾工具的主要来源。
  • 社交媒体和技术社区讨论帖:主要用来挖掘一些刚发布的、还没有被导航站收录的新工具,同时可以补全功能和场景关键词。

采集策略上,官网和导航站以“增量爬取”为主,每天跑一次,只处理页面变化或新增链接;社交媒体和讨论帖则用“定期定向抓取+人工复核”的方式,因为这里噪音大、虚假信息多,直接把它作为核心数据源会让索引质量崩掉。综合下来,官网和导航站的采集占比达到 80%。如果爬取频率过高,很容易被源站反爬,而且很多工具的页面更新频率远低于日更,所以一天一轮已经完全够用。

实际开发里基于 Python 的爬虫框架是最趁手的,天然支持异步并发、去重、断点重试。采集流程是:从种子列表里加载导航站链接,用选择器对列表页做抽取,提取出每一行的工具名和 URL,然后进入详情页解析逻辑;详情页优先级高的字段包括工具名、官网链接、简介、标签、价格模式、适用场景、开发者信息、开源协议、最近更新日期等。每轮采集结束后,新的记录会先落到临时区,经过清洗和超链接去重,能入库的才标记为正式文档。

3.2 页面解析和目标字段识别

页面解析最大的问题是同一套选择器不适用于不同站点,每个站的 HTML 结构不过是一个通用结构的变体。与其对每个网站写一套规则,我选择了一条更划算的路径:用“基础字段模板” + “站点自适配规则”的方式。每个站点可以配置独立的标题选择器、正文选择器、标签选择器,没有配置的网站则回到默认解析逻辑,从 meta 描述、og:title、H1 标题和正文段落里做启发式提取。

启发式提取有个经验数据:从 HTML 里直接选.description或.summary这类 class 名的段落,命中率在 40% 左右;从<meta name="description">里取描述时,命中率能有 60% 以上。最终我把 meta 描述设为一阶数据源,正文首段设为二阶数据源,OL 列表常用句式比如“Features”后面紧跟的段落按权重子段截断,这样大部分情况下都能拿到干净的一段工具介绍。

不需要的内容也要过滤,最关键的是去掉三类无意义文本:Cookie 提示、功能通用套话、以及来源广告区块。有一个典型的坑是,不少官网的 hero 区域文案看起来像是工具介绍,其实是空话营销文案,比如“赋能全场景”“驱动下一代”,这样的介绍一旦进入索引,用户搜“PDF 转 Word”时这种工具很容易干扰排序。所以我加了一套“低信息量句式过滤”,先把这类句子在入库前剔除,后续检索精确度会显著改善。

3.3 数据清洗与去重策略

爬取结果清洗处理的对象主要是字符串、URL、HTML 实体,要为索引提供标准输入。URL 去重不只是简单去重,因为同一工具经常有多个 URL 表达方式,比如https://abc.com、https://www.abc.com/、https://abc.com/index.html都可能指向同一个工具,我把 URL 做归一化处理:去掉协议和参数部分,保留路径,再判断主体是否相同。这一步能去掉大概 30% 的重复数据,默认页面保留根域名的那个版本。

去重之后还要做文本块级别去重,两个不同工具的官网有时会引用同一个开源项目的 README 片段,这种跨文档重复会导致搜索结果里反复出现高度相似的段落。我用“文本指纹 + 最长公共子串”的思路写了一个相似度过滤器,超过一定阈值的文本就只保留最早入库的那份,后续版本作为补充快照但不参与索引。

清洗环节里非常重要的一步是“字段冲突检测”。一个工具绑定了多个标签,但标签之间如果语义冲突,比如同时标了“本地部署”和“云端 SaaS”,那很可能是抓错了网站或误判了版本。对这种字段,我不做自动修正,而是打一个置信度标记,让索引排序时降权,低置信度记录在搜索结果里也会排在更靠后,相当于用排序来表达不确定。

3.4 原始快照与增量更新的权衡

完整数据的可信度离不开快照机制。快照在个人项目里经常被忽略,直到某天官网改版,爬虫解析出的结果全变成了错误文本,这时候如果没有上一版快照,就几乎没法做版本对比回滚。我在数据层里建立了快照版本管理,每一轮爬取会生成一个新的 JSON 文件,里面记录工具 ID 对应的字段 hash 和内容指纹。索引构建时如果发现某个工具的内容 hash 没变,就直接复用上一轮的索引条目,避免重复计算。

更新周期我做了分级而不是一刀切:高权重导航站每 6 小时爬一轮;普通官网每 24 小时爬一轮;活跃度极低的站点放到每周一次。分级更新有个额外好处,就是对源站的压力分散了很多,不容易触发风控。而且增量更新里旧记录被替换后,锚文本和引用关系可能变化,所以索引层必须支持文档级更新操作,而不是重建全量索引。

4. 索引构建与分类体系

4.1 分类体系的设计与字段映射

AI 工具的分类不能太细也不能太粗,太细会导致用户搜一个概念时对应工具太少,太粗则会让结果失去精准度。最终我把 AI 工具分成 20 个大类,再在每类下设若干子类。比如“文本生成”下有“文章写作”“营销文案”“剧本创作”等子类;“图像生成”下有“文生图”“图生图”“图片编辑”等子类;“音频处理”下有“语音合成”“音乐生成”“唱歌翻唱”等子类。

这个分类体系不只是给前端展示用,更关键的是参与索引权重:一个工具如果在分类和查询意图都匹配时,它的排序分会有显著加成。为了避免人工分类的成本太高,我在入库阶段就写了一个基于关键词规则库的自动分类器。规则库是“关键词或句式 -> 分类”的映射集合,比如出现“text to image”“stable diffusion”“diffusion model”等关键词,就自动归为“图像生成/文生图”。规则分类准确率在 78% 左右,剩下分类置信度较低的记录进入人工复核队列,每周集中清一次,保证库内数据质量。

字段映射上,工具型搜索最有用的是“结构化的能力字段”,我把文本描述、功能列表、技术标签、模型类型拆成多个独立字段,这样检索时能精确限定范围。比如用户输入“开源 本地部署 语音合成”,我会先把 query 解析为“开源”和“本地部署”两个硬性条件,然后只在“语音合成”分类内部进行候选过滤,这样结果就不会混入视频理解类工具。

4.2 倒排索引的实现与分词策略

轻量索引里倒排索引是最核心的数据结构,我直接用 Python 的字典实现,键是词项,值是一个列表,列表中每个元素保存文档 ID、词频、命中位置。构建逻辑很简单,对每个文档做分词,去掉停用词,剩余词按 token 进行词频统计和位置记录。内存占用控制在合理的量级,两万条工具体量下,索引构建耗时大概在 3 秒左右,完全能满足个人场景。

分词策略上中文直接用了常见的中文分词库,因为工具名和功能介绍里大量出现中英文混合句式,比如 “AI 文生视频平台”、“Text-to-Video AI generator”,“AI”、“文生视频”需要分别切出来,又比如 “RAG”、“LLM”、“Agent”这类 AI 术语必须在词典里单独登记,否则会被切成没意义的单字。我给分词模块额外维护了一个领域词典,把所有跟 AI 工具强相关的专有名词加进去,同时把量词、冠词、部分副词加入停用词表,降低噪音对排序的干扰。

英文分词相对简单,按空格和标点切分后做小写化和词干还原,但小型项目里我也做了一层特殊处理:保留部分短语。比如“text-to-video”这个连字符短语,直接按 token 切开会导致检索“text to video”时匹配不上,所以我在倒排里同时保留未分词的原始短语和分词后的 token,召回阶段二者都参与,最后在合并阶段让短语命中权重更高。

4.3 向量索引的构建与 Embedding 基础设施

倒排索引保证精确性,但解决不了“用户问法跟工具描述措辞不一样”的问题。比如用户搜“给老照片补全颜色”,而工具描述写的是“AI 图像修复与增强”,字面上没有任何重合词,倒排索引怎么都召回不了。这时候就要靠语义向量索引。

向量索引的基础是 Embedding 模型。我给每个文档生成的是 768 维的向量,来源是把“标题 + 摘要 + 标签 + 分类路径 + 关键功能描述”整体编码。纯描述文本直接塞进模型容易丢失结构化信息,因此我在拼接文本时用了模板:

工具名:{name} 类型:{category} 标签:{tags} 简介:{summary} 功能:{functions} 适用场景:{scenarios}

这样编码出来的向量卡在“工具是什么、能做什么”的语义空间里,效果要明显好于只编码一个摘要。向量索引我直接存在一个本地向量数据库里,在个人项目规模下性能完全够用,查询耗时在几十毫秒量级。

向量召回默认取 top 50 候选,再配合文本检索结果做融合。这样做的好处是语义模型漏召回的话,文本召回的强规则还能兜底,不会出现“搜得到就是排得乱”的问题。

4.4 倒排与向量的召回融合和评分公式

召回融合是整个检索质量的关键,一步之差体验会差很多。我先把文本检索召回的结果记作 A 集合,向量检索召回的结果记作 B 集合,然后按文档 ID 做合并,得分公式大体是:

final_score = 0.6 * text_score + 0.35 * vector_score + 0.05 * meta_score

text_score是倒排索引里基于 BM25 变体计算出的文本相关度,vector_score是余弦相似度归一化后的得分,meta_score是标签匹配度、分类匹配度、时效性和置信度的综合加权值。经验上 0.6 / 0.35 / 0.05 这个比例对 AI 工具场景比较合适,因为工具搜索用户更多时候是带着明确功能词过来的,字面匹配仍然要承担主要责任。

但融合公式必须基于推荐召回情况动态调整。比如查询“开源的模型托管平台”,文本几乎没命中,全靠向量语义泛化,向量得分占比就需要自动上调。所以我在融合层加了一个“recall 分布感知”逻辑:如果 A 集合为空或得分整体偏低,就把向量的权重拉到 0.7 以上。这比固定权重要稳定得多。

meta_score里我特别重视“新鲜度”,新上架的 AI 工具往往更符合用户预期,而两三年前的旧工具即使内容描述相似,用户点击意愿也偏低。新鲜度得分是按天衰减的,公式为1 / (1 + age_days / 90),效果是上线 90 天的工具新鲜度得分降到一半,180 天的降到三分之一,以此递减。

5. 搜索实现与实际调整

5.1 查询解析:从原始输入到检索条件

搜索框里输入的词不直接进倒排索引,必须先做一次查询解析。这一层处理四件事:分词、同义词扩展、意图识别、参数提取。

分词与索引侧保持一致,这里有个细节,倒排索引里的 token 和查询分词必须用完全相同的词典和分析逻辑,否则索引里是“文生视频”,查询却是“文生 视频”,导致召回不了。同义词扩展对整个系统特别重要,我建了一个同义 / 近义词表,把“图像生成”“文生图”“图片生成”“text-to-image”映射为一个等价概念组。用户无论用哪种说法,都会被扩展到概念组内所有表达去召回。

意图识别决定要不要触发分类过滤。比如用户搜“PDF 总结工具”,意图里“PDF 总结”是功能属性,“工具”是类目词,这时候系统应该进入“文档处理”分类过滤;如果搜“最火的视频生成模型”,就没有明确工具类目,需要更偏向语义召回和热度排序。我用一个轻量规则加分类模型的方式做意图识别,规则主要依赖预设意图短语,分类模型则用少量标注数据训练一个文本分类器,整体准确率在 85% 左右。

参数提取里最重要的就是硬性过滤条件,比如开源、免费、本地部署、API 可用,这些条件用户一般直接用自然语言表达,比如“免费开源的本地知识库”。我通过规则匹配把“免费”“开源”“本地”提取成三个过滤条件,过滤条件在召回后生效,确保结果里不出现非免费或非开源的工具。

5.2 文本召回和向量召回的候选集处理

文本召回时我不会对全部字段一律平等,而是在构建倒排索引时给字段设了不同的 boost。标题字段 boost 3.0,标签字段 boost 2.5,描述字段 boost 1.0。搜索“AI 写作助手”时,标题里包含“写作助手”的工具得分会显著高于只在描述段里出现了该词的工具,这也符合用户对名称精确度感知的期望。

召回数量控制上文本召回默认取 top 100,向量召回取 top 50,最后合并去重。这里有个教训:不是召回越多越好。召回太多以后面排序阶段靠弱信号做判断时,相关性低的文档容易混进来,而且计算成本也会上升。经过一轮调参以后,150 个候选是我的推荐值,再高就是噪音。

合并阶段要做的一个重要处理是去重归一化。同一个工具可能同时出现在 A 和 B 集合里,合并时保留得分较高路径的得分,再从 meta_score 里取交集系数加成,最后真正参与排序的只有 150 条以内的记录,响应时间一般控制在 150 毫秒以内。

5.3 排序细节:当语义分数和文本分数打架时

排序里最常见的碰撞场景是:语义分数很高的结果与用户搜的字面词根本不匹配。比如搜“AI 声音复刻”,向量检索召回了几个语义相关的变声工具,但标题里完全没有“复刻”两个字。这样的结果如果排在前面,用户会困惑,因为他以为系统没识别出他的关键词。

针对这个问题,我的处理方式是做一个字面相关性惩罚,当text_score低于阈值时直接将该文档的融合得分打一个惩罚系数。惩罚项的强势程度可以根据搜索场景调整:“工具搜索”偏严格,“灵感探索”偏宽松。还有一种解决思路是干脆把这类文档放到第二屏以后,确保第一屏的精准性,我觉得这个对 AI 工具词典类型的产品更友好。

另一个排序细节就是去掉空头结果。有些模块没了模型信息,但介绍写得很高大上,用户点进官网却发现插件已经停更。这类结果排序上要降权,我通过字段完整性做一个降权惩罚,缺失模型或价格信息的记录,得分统一乘 0.8。不然的话,那些维护得好的工具体验会长期被没维护的空壳工具压制。

5.4 搜索质量调优的闭环方法

单靠调参数不会让搜索质量自动变好,必须建立评测闭环。我设计了一百多条由真实用户搜索习惯改编的测试 query 集,按主题分布在各个 AI 工具分类里,每次调整代码后都会跑一遍回归测试。每条 query 人工标了 2 到 5 条最佳期望结果,输出时检查“期望结果是否在前十”“无关结果占比”“结果类型分布多样性”。

启动回归测试后,我把搜索日志里的点击行为也接进来:点击量高而排序靠后的记录,大概率说明当前融合权重不合理,我会看这些记录是在文本分偏低还是向量分偏低,再做针对性调整。比如“视频脚本生成”query 下用户反复点击某条,但该条排序在第 8 位以后,我就会检查它是不是被某些低质长尾工具挤到后面了,必要时把分类得分权重换掉。

调优这块我得泼一盆冷水:很多人上来就想着让模型来学习排序,但在数据量只有两万条、还没有大量用户交互日志的时候,学习排序是不现实的。我能做的就是不断的规则迭代、评测回归、点击反馈校准三件套,这反而是垂直搜索产品最可靠的进阶路径。

6. 部署落地与爬坑实录

6.1 服务部署与索引加载细节

整个搜索服务用 Python 实现,基于轻量 Web 框架对外提供 RESTful API。进程启动时会做三件事:加载数据快照、构建或加载倒排索引、把向量索引映射到内存。这三步大约耗时 4 到 6 秒,所以线上服务的健康检查必须在全部对象加载完成后再返回 ready,否则一重启接口就报错。

缓存层我用了两层:本地缓存做热点搜索和常用搜索词的返回结果,缓存时间设成 10 分钟,用户对工具新鲜度感知不强,10 分钟内返回旧结果完全没问题。第二层是对象级缓存,对同一个工具详情接口做缓存,避免重复拼接 HTML 片段。要注意的是,索引更新后一定要主动清掉这两层缓存,否则会出现“索引更新了但搜出来还是旧数据”的幽灵问题。

日志体系我记录了三个核心点:请求日志、召回日志、点击日志。请求日志记录 query 和响应耗时;召回日志记录每个候选集的得分明细,是调优时最宝贵的数据;点击日志记录返回结果里用户点了哪些位置,为后续排序调整提供事实依据。特别提醒,召回日志一定要留,不然你会发现在线上完全没法复现某个 query 的排序之所以差,因为分数细节已经丢了。

6.2 爬虫反爬处理和异常兼容

个人项目做爬虫最怕的不是编码问题,而是被反爬机制识别后整个 IP 段被封。我的策略是用时间去换安全,控制抓取频率,每台源主机之间随机延时 2 到 6 秒,单站点并发不超过 2。这不是性能最优解,但对小型项目来说,稳定性远比速度重要。

很多站点做了页面版本切换,部分页面已经变成 JavaScript 动态渲染,直接 HTTP 请求拿到的 HTML 里没有正文内容。我针对这些站点做了叠加判断:目标字段为空或字段长度低于 10 个字符时,就标记为“低置信度页面”,不进入索引,留待后续用浏览器渲染方案补抓。这个逻辑帮我避免了一大批劣质数据进入索引后污染搜索结果。

还有一种异常情况是同一个工具官网有多个子域名页面,分别记录了不同的功能介绍。我通过站点级合并逻辑判断,同根域名下的子页面只保留信息最丰富、文本长度最合适的那个版本,避免分裂成多个重复索引记录,能大幅提升“某个知名工具”的搜索准确率。

6.3 索引性能瓶颈和数据膨胀

数据从几万条涨到十几万条之间,性能上会有一个明显的拐点。我的轻量索引刚开始构建只要 3 秒,后来文档数涨到 30 万之后,构建时间飙到了 20 秒以上,内存占用也翻了好几倍。这让我不得不提前做了两步优化。

第一步是减少参与索引的文档数量。数据层里有很多低置信度或低质量文档,本就不应该进入索引,我把这一级过滤前置到了入库阶段,索引规模直接减少了约四成。第二步是给倒排索引加“文档频率截断”,高频无区分度的词,比如“AI”本身,在索引里保留词项但不参与评分,低于最低文档频率的词则被视为罕见词,只有精确匹配才能触发该词的相关性贡献。

如果后续数据量继续上涨,我计划把索引模块从内存全量加载改成按分片加载,或者直接迁移到嵌入式引擎,但我始终不会放弃可解释性,因为在小团队里可调试性就是最大的长期收益。

6.4 最常见的问题排查速查表

在这类搜索项目里,我发现很多看起来“很玄”的问题,根因其实都集中在几个固定环节。整理成表格放在这,排查时先对号入座,再去看代码,会快很多:

现象可能原因排查方向
搜“AI 写作”完全没有结果查询分词和索引分词词典不一致对比两侧分词结果,统一词典版本
搜“免费开源”返回很多商业工具查询解析里的硬性过滤条件没生效检查意图识别阶段是否识别出条件词
结果排序和点击偏好不一致向量权重偏低,语义结果被文本结果压制调高 vector_score 权重或动态权重逻辑
新工具入库后搜不到索引更新后缓存没清检查缓存清理逻辑和新文档状态
同一工具多个页面都在结果里URL 归一化没覆盖到所有页面加强根域归一化和站点合并逻辑
语义召回明明是该工具但就是没召回向量拼接模板里缺少关键字段检查文档向量拼接是否包含标签和功能描述

这张表基本上覆盖了我开发过程中遇到的最常见问题。尤其是第一条分词不一致,可以说是我调整最久的一个点,因为两边只要一改词典,就一定要同步更新,否则就会出现某几个词“薛定谔的可搜到”状态。

7. 还可以延展的功能和方向

这个项目目前已经能稳定提供搜索服务,但我心里一直留了几个开发优先级比较高的延展方向。

第一是加入用户反馈闭环。搜索页上增加“结果是否有用”的按钮,或者隐藏的点赞点踩行为,把用户反馈转化为训练数据。长期来看,这种信号比点击日志更干净,因为点击有误导性,用户可能是误点,而主动反馈的意图明确得多。

第二是支持以图搜工具、以例搜工具。用户有时没办法用语言描述他想要的是什么,比如他手头有一张图片风格的示意图,想让 AI 工具做出同样的效果,这时候如果支持图搜,就能按视觉特征召回相关工具。这个方向对数据集要求更高,但会显著降低搜索门槛。

第三是引入工具之间的关联推荐。搜索“Stable Diffusion”时,可以联动推荐“LoRA 训练工具”“提示词管理器”“模型托管平台”,这其实是在搜索之外构建一个工具链体系。用户不再只是找一个工具,而是在找一个可用的工作流,这种体验的黏性要比单纯的搜索大得多。

这些点我现在还没把全部实现落到代码里,但架构上已经把推荐位和反馈采集位都预留了。个人开发就是这样,先跑通核心体验,再做锦上添花的事。把一个窄口径的垂直搜索做好,本身已经能带来很大的实用价值了。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进