AI Agent应用发现机制:工具注册表、向量检索与混合排序实践

发布时间:2026/10/22 19:34:40
AI Agent应用发现机制:工具注册表、向量检索与混合排序实践 1. 缘起为什么AI Agent要一个发现应用的模块1.1 工具多了之后先乱的是Agent自己先交代一下背景。workbuddy是我所在团队从零开始做的一个偏办公场景的AI Agent项目定位是能干活的小助手你让它帮你整理会议纪要、预约会议室、催一下卡在审批流程里的单子它能把对应的工具串起来跑完。项目早期工具数量不超过二十个的时候整个系统的设计非常朴素——所有工具的name、description、参数结构全部写进系统提示词里模型每次推理都能直接看到完整列表选一个最像的调用就行。当时也跑得挺顺毕竟候选就那么点怎么选都不会太离谱。但当工具从二十个涨到八十多个我开始明显感觉到不靠谱了。首先是上下文长度八十多个工具的完整描述加上参数Schema光这部分的token就超过八千每个请求都在为这八千token付钱响应首字时间也肉眼可见地变慢。更麻烦的是准确率有些工具的功能描述本来就长得像比如查考勤记录和导出考勤报表模型经常在两者之间犹豫偶尔还会选错直接把查询工具当成导出工具去用。我们统计过工具数量过六十之后工具选择的准确率开始出现肉眼可见的下滑而且随着数量继续增长下滑趋势没有收敛的迹象。当时的处境很像一个只会看菜单点菜的人突然被端上来一本十几页的菜谱他反而不知道该点什么了。这个问题不是靠优化prompt措辞能解决的——只要工具列表还在持续膨胀无论怎么精写描述模型都绕不开在几百个候选项里做单选这个越来越困难的决策。我的结论是Agent需要一个独立的应用发现环节把工具选择的复杂度从提示词里剥离出去。1.2 发现应用到底解决什么问题发现应用这个名字听起来像是给用户做应用商店推荐但实际做下来它的第一服务对象是Agent自己。用户并不会直接对着这个模块说帮我发现一个应用用户只会说帮我把上个月的报销单整理成表格然后Agent内部需要回答三个问题这个需求对应哪个应用的能力这个应用现在能不能调用如果候选有好几个优先调哪个所以我把发现应用定义为Agent运行时和工具集之间的一个检索服务。它的输入是模型解析出来的任务语义输出是一个有序的工具候选列表。模型不再需要在上百个工具里做全文扫描它只需要看发现服务给它的那五六个候选再结合用户消息里的具体参数做最终选择。说白了发现服务不是给用户看的应用商店而是给Agent看的工具导航。这个定位确立之后发现服务的开发标准就清晰了召回要快排序要有解释性命中不了就要明确说没有绝对不能硬凑。后面所有实现细节都围绕这三条标准展开。2. 应用发现的两层设计注册表与意图匹配2.1 工具注册表给每个应用一张身份证第一件事把散乱的应用信息收拢成统一的注册表。此前每个工具的描述格式完全是主观的有人写功能有人写输入有人只写两三行说明还有人是直接把接口文档里的注释抄上来的。这种数据没法做检索必须先定Schema。我定了一套应用元数据核心字段包括字段说明示例app_id全局唯一标识app.send_email.v2name应用名称邮件发送助手domain业务域communication / document / data_querycapabilities能力动词列表send, draft, schedule, replytrigger_phrases常见触发表述发邮件、邮件抄送description面向检索的自然语言描述用于起草和发送邮件支持附件与抄送功能parameters_schema调用参数定义to, subject, body, attachmentsembedding描述向量1536维浮点数组freshness最近一次可调用状态ok / degraded / down这里最关键的是把domain和capabilities拆开。domain能回答这个应用属于哪个业务领域capabilities能回答它能对某个对象做什么动作。召回的时候两者分别匹配可以大幅降低功能相似但动作不同这类误匹配。注册表最开始我用SQLite存后来才迁移到向量库这个后面展开说。每个应用上线必须过一遍注册审核描述写不清楚的直接打回不满足元数据规范的应用不允许被Agent调用。这点在执行层面很重要——只要有一个注册项是脏数据整个发现服务的可信度就会被拖下去。2.2 意图匹配从用户请求到应用候选集的转化注册表只是静态数据真正的工作发生在请求时刻。整个匹配链路分两步第一步是意图解析由Agent的主模型完成。模型看完用户消息后不需要立刻选工具而是先输出一个结构化的检索条件包含domain、动作倾向、关键实体等字段。这个设计有点反直觉因为传统Agent都是直接想法到工具调用一步到位但拆成两步之后每一步都更可靠了。主模型只需要判断用户想干什么不用赌具体是哪个工具决策压力小很多。第二步是候选召回由发现服务完成。它拿到的检索条件来自上一步先去domain索引里过滤出一批应用再在这个子集里做向量相似度匹配。这样做的道理是向量匹配适合处理语义相近但描述措辞不同的情况但它的召回结果经常不带业务边界意识先把范围缩小到domain能避免跨领域瞎配。我举个例子。用户说把会议纪要让参会人确认一下意图解析可能输出domaindocument或者communicationcapabilities包含share、confirm。发现服务先在document和communication两个域里找出支持share和confirm的应用再做向量排序最后返回文档协作工具排在邮件发送工具前面。这个结果比纯向量检索靠谱得多因为确认这个词在向量空间里和邮件、审批都可能有较高相似度但业务上只有文档协作和审批流程才真正贴合这样的动作。3. 核心实现发现服务的数据链路3.1 应用元数据的实际存储方案设计归设计真正落地时存储选型花了些时间。最早图省事所有元数据以JSON文件维护应用启动时全量读进内存用Python的列表推导式做关键词过滤。二十个应用这么干没问题到了五十多个之后每次请求都全量遍历还能接受但加上向量计算后明显吃力。后来我换了组合方案结构化字段domain、capabilities、trigger_phrases、freshness落在SQLite里embedding向量落在向量库中。检索时先查SQLite拿候选id集合再根据id集合去向量库做相似度计算。这个先SQL过滤、后向量计算的顺序让计算量下降了一大截——向量库不需要全库扫描只需要对少量候选做内积计算。有一个交叉过滤的小细节容易被忽略。假设SQLite过滤完domain只剩三个应用向量匹配反而可能因为候选太少而错失相关结果。所以在设计回调数量的时候要留有冗余domain过滤后宁可多保留一些上限让向量匹配有充分的空间也不能把过滤条件收得太死。这个参数我调了至少三轮才算清楚。应用上线下线的同步逻辑也要注意。每当调整一个应用的状态注册表刷新后通过一个异步任务把变化同步到向量库避免出现应用已经废弃了发现服务还在推荐的情况。我用的是一个带版本号的心跳表每次同步带上递增的version字段发现请求进来时先校验注册表版本不一致就触发一次增量sync。看起来是个小细节但没有它线上会出现让人挠头的间歇性错误。3.2 向量检索和关键词检索的混合召回发现场景的难点在于用户表达任务的方式太多了。同一个人说发邮件可能具体说成给王姐邮一下上周的方案也可能说成把这个文档发给客户措辞和所指向的app完全不在一个表层。所以只靠关键词肯定不行必须有向量召回兜底。我实现的是双路召回BM25关键词召回一路向量相似度召回另一路两路结果用RRFReciprocal Rank Fusion做融合排序。为什么用RRF而不是直接加权平均因为BM25给的分数和向量相似度的分数分布不在一个量纲上直接相加会把量级大的一方带跑偏。RRF只看排名不看分数鲁棒性会好很多。核心代码大概是这样的def recall_candidates(intent, k20): sql_hits bm25_search(intent.keywords, domain_filterintent.domain) vec_hits vector_search(intent.embedding, topnk * 2) fused rrf_fusion([sql_hits, vec_hits], k60) return fused[:k]这里有个细节值得说vector_search的topn要比最终需要的k大一些因为融合之后顺序会发生改变很可能最终结果里前k名有不少来自BM25一路如果向量路只召回k个融合后的多样性不够。多召回一倍再做融合实测下来效果更稳。还有一点是关于embedding的生成时机。发现服务用的是静态描述预计算embedding应用注册时算好存好请求时只对用户意图做一次embedding计算。绝对不能搞成请求时实时去embedding所有工具描述那会把延迟推到不可用的程度。预计算虽然牺牲了一点描述更新的实时性但换来的是毫秒级的检索这笔账划算。3.3 排序与兜底策略召回只是把范围缩小到合理候选排序决定了模型最终看到哪些。排序打分我用了三个因子语义相似度分、应用热度分、以及一个近一周成功率分。热度分解决的是相似应用里选哪个的问题——两个应用都能写文档用户实际用得多的那个应该排前面。成功率分来自调用完成后的反馈应用频繁报错就自动降权。def rank_candidates(candidates, query_embedding): scored [] for app in candidates: semantic cosine_sim(app.embedding, query_embedding) hot app.weekly_heat * 0.15 success app.weekly_success_rate * 0.10 scored.append((app, semantic hot success)) return sorted(scored, keylambda x: x[1], reverseTrue)[:5]定制因子之外最重要的经验是兜底策略。发现服务必须有一个明确的无匹配出口。我设了一个阈值融合后的最高分低于它发现服务直接返回未发现合适应用而不是硬着头皮把最像的那个推给模型。宁缺毋滥这个原则在Agent场景里尤其重要推荐一个错误的应用比不推荐更糟。因为Agent如果真调用了错误的应用用户看到的是完全的失控感如果返回没找到模型还能走另一条路比如反问用户确认意图或者基于经验尝试其他策略。从实际表现看兜底策略在刚上线时触发率很高超过三成主要原因是注册表元数据质量太差。后来元数据补齐、双路召回调优之后这个比例降到了百分之十以内。它没有完全消失但我觉得这是个健康信号——说明系统知道自己不知道什么。4. 踩坑实录发现服务上线后的三个意外4.1 冷启动应用库是空的发现个啥发现应用第一个版本上线的时候注册表里只有二十多个应用而且大部分是团队早期工具改造过来的描述质量参差不齐。比如有个审批待办查询的应用description只写了查询审批待办但用户实际会问我有几个流程卡住了领导催的那个单到哪了这类口语化说法。向量检索对这种短描述抓瞎是必然的因为描述里既没有卡住也没有流程只有审批和查询。这轮踩坑让我认识到发现服务的上限由注册表的质量决定不在检索算法。后来我们把应用描述当成上线评审的一部分规定描述必须至少覆盖三类信息——面向的主对象、常见的动作、典型的使用场景并且允许登记trigger_phrases。团队花了一周时间把存量应用逐个补齐元数据再跑同样的查询效果肉眼可见地好。没有这一步后面所有优化都是空中楼阁。顺带说一句写注册元数据这件事是典型的脏活累活但它带给系统的提升远超过任何算法调优。如果你也在做类似的Agent工具库建议把元数据规范当作第一优先级哪怕晚一周上线都值得。4.2 误匹配把邮件应用推荐给了要写文档的人上线一段时间后收到反馈用户明明说写个操作手册Agent却调用了邮件起草工具。排查发现问题出在capabilities的设计上。当时起草这个能力动词同时挂在了文档协作应用和邮件应用下面因为邮件工具确实能起草邮件内容。写个操作手册被解析成draft语义之后两个应用都能命中排序时向量相似度又把它们拉到差不多的分数最终模型挑了一个看起来顺眼的。这个问题的根子是能力描述粒度过粗。同一份能力词汇表在邮件场景和文档场景里含义完全不同。我的解决办法是在元数据里加了一层对象限定capabilities不再只是一个动词列表而是动词对象的结构比如draft(doc)和draft(email)是两个能力。注册表里明确记录每个应用支持的动作对象对意图解析那边优先输出这个结构匹配精度立刻上来了。这也让我意识到做工具注册不能贪图字段少该拆的信息必须拆开否则后面所有的匹配逻辑都要为这个偷懒买单。4.3 性能问题发现服务成了Agent的瓶颈第三个坑是性能。发现服务独立化之后每次Agent决策前都要先走一遍意图解析→发现服务→模型最终选型链路变长了延迟跟着涨。最初意图解析复用主模型一次推理就要几百毫秒加上向量检索和融合排序最坏情况能到五百毫秒。用户感知就是问一句话转圈时间明显变久。我压性能做了三件事。第一意图解析换成了轻量小模型输出的结构化字段精度稍微下降一点但延迟从几百毫秒压到几十毫秒。精度下降怎么补靠发现服务这边的召回冗余来兜小模型偶尔输出偏了双路召回里还有另一路能拉回来。第二对高频工具做了热点缓存用户问法相似时会话内直接复用之前的召回结果。第三把向量库的索引参数调了调召回范围限定在domain过滤后的子集再做向量计算全库扫描被彻底去掉。三轮下来发现服务的整体耗时稳定在三十毫秒以内对整个Agent链路几乎无感知。压性能的过程也让我反思了一个架构层面的矛盾发现服务本来是为了减轻主模型负担而引入的结果它自己变成了链路里的新瓶颈。任何中间层都有这个风险所以上线之后一定要盯P99延迟而不是只看平均值。平均值好看不代表没有毛刺Agent链路里一个毛刺就可能让用户体验彻底崩盘。5. 下一步让发现应用变成应用之间互相发现5.1 从真实调用行为里学习排序跑通之后我开始收集一个关键反馈发现服务推荐了候选但主模型最终选的是不是排在最前面的那个这个信号非常宝贵。如果模型经常跳过第一名选第二第三名说明排序因子没有完全反映真实可用性。我把这类跳过行为记录成隐式的负反馈定期回算成功率分和上下文相关性分让排序逐渐贴近真实使用习惯。这在效果上有点像搜索引擎的点击率回传但Agent场景的反馈信号更干净因为模型每次选中哪个工具是明确的不像人点击链接还有误点。目前我们是每天离线跑一轮统计把最近一段时间的调用日志聚合进热度分。整体逻辑其实就是系统推荐→观察选择结果→修正权重→下一轮推荐更准。机制不复杂但跑起来之后发现服务的候选命中率在两周内提升了十几个百分点性价比非常高。5.2 组合发现从单个应用推荐走向工作流的推荐还有一件我一直在想的事复杂任务往往不是单个应用能解决的。准备季度汇报这个需求可能需要先查数据、再生成图表、再写文档、再预约演示会议室是一条完整的工具链。现在的发现服务每次只推荐一个应用对这类任务帮不上大忙。我的计划是把发现服务从应用发现升级为组合发现应用注册表里额外维护一份应用协作关系数据标记哪些应用可以串联。当意图解析识别出复合任务时发现服务返回的是一组有序的工具链推荐而不只是一堆独立候选。这个方向还比较早期但我们已经在做一个初步的验证把用户历史完成的任务拆成工具调用序列看哪些序列反复出现把这些高频序列沉淀成模板工具链。等这个跑通Agent在处理复杂任务时就不需要每次都从零规划了直接套用验证过的工具链组合即可。回头再看发现应用这个功能我最深的体会是它看起来是个简单的检索模块但真正难的是把注册表的规范、召回排序的策略、以及承认找不到的兜底心态一起做好。工具生态只要还在增长发现这条链路就值得持续打磨。后面如果组合发现落地了我再单独写一篇分享。

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询