SToneX EN
← 全部文章

How Jev Won 9× as Often in treg’s Search

从几千个工具里,给 agent 当前的任务找到合适的那几个,是我们做 treg 时遇到的一道难题。我们把 Jev 接进了线上搜索:在交错展示的实验中,按 agent 后续调用归因的记分,Jev 与原词法搜索的对比得分约为 9:1。

我们在做的 treg,让 agent 轻松地查找和调用外部 API。公开 catalog 已经收录了 3,600 多个工具,从网页与社交数据、公司和联系人查询,到金融行情、图片和视频生成。我们想让 agent 手头的各种任务,都尽可能在 treg 里找到可用的工具。

覆盖越广,选择就越难。同样是“查一个人”,可能是搜索符合条件的人、补全已知用户的资料,也可能是找邮箱;同一种能力还可能有多个供应商。

这次我们把 Jev 用在这个选择过程里,并通过真实搜索之后发生的调用观察效果。

agent 描述网页抓取任务,在 treg 搜索到相关工具,选择并调用 anyapi,获得网页内容。一个任务,从搜索到调用描述任务01 描述任务> 抓取这个网页返回网页内容agent 用任务描述搜索不必先知道 API 名称返回相关工具02 在 treg 里找anyapi网页抓取dataforseo原始 HTMLtreg 返回相关工具调用工具并获取结果03 选中并调用anyapi.web.scrape网页内容agent 拿到结果后继续任务agent 描述网页抓取任务,在 treg 搜索到相关工具,选择并调用 anyapi,获得网页内容。一个任务,从搜索到调用描述任务01 描述任务> 抓取这个网页返回网页内容agent 用任务描述搜索不必先知道 API 名称返回相关工具02 在 treg 里找anyapi网页抓取dataforseo原始 HTMLtreg 返回相关工具调用工具并获取结果03 选中并调用anyapi.web.scrape网页内容agent 拿到结果后继续任务

但工具接进来以后,还得让 agent 找得到。它发出的查询往往就是手头的任务,里面混着公司名、时间范围和平台要求,不会刚好照着 API 文档里的词来写。

这次我们尝试用 TypeSafe 的 Jev 检查搜索候选,判断工具能否满足查询。这篇记录想分享几个实际遇到的问题、我们的改法,以及接下来想做的事。

一、词法搜索漏掉了什么

treg 的 catalog_search 原来只做词法匹配:把查询切成词,去掉停用词,按 BM25 打分,再要求大部分稀有词命中。这套搜索只需要几毫秒,也容易排查:一个结果为什么出现、另一个为什么被过滤,看分数和命中词就能知道。

看零结果日志时,我们发现有些工具明明在目录里,却搜不出来。再检查返回的结果,还发现另一类问题:词匹配上了,工具却不适用。

先看搜不到的情况。agent 经常把参数值也写进查询。比如:

apple stock closing prices for last year

这条查询有六个稀有词,规则要求至少命中四个。但 apple 指的是股票,last year 指的是时间范围,端点描述通常只会写“按 ticker 获取日线价格”。相关价格工具可能因为命中词数不足而被过滤。

查询的六个词全目录命中行数apple16stock70closing2prices27last37year15tiingo.daily.pricesmarketstack.eod.latest3 / 63 / 6准入门槛:6 个稀有词至少命中 4 个 → 两条都差一个,返回零结果参数词不一定出现在相关端点的描述中
latest 工具仅返回最新价格,不能用于完整年度历史查询。

这条查询其实已经把需求说得很清楚:哪只股票、什么价格、哪段时间。但这些细节到了搜索里,却成了过滤工具的条件。让 agent 先删掉公司名和时间、猜一遍目录里的用词,才能搜到工具,这个要求不该由 agent 来承担。

另一类问题是词相同,指的却不是同一件事。搜 “trending TikTok videos today”,前六条里有五条是抖音(Douyin)榜单。因为它们的描述也包含 “TikTok”“trending”“videos”,光靠词法匹配区分不了这两个平台。

二、agent 实际在找什么

接入 Jev 后,我们回看了这些查询。下面几组对比,也能看出 agent 平时会拿 treg 做什么。

抓网页却搜出了帖子抓取。查询是 “scrape webpage html fetch url content”,想找的是通用网页抓取工具。词法结果靠前的却是 Instagram 和 LinkedIn 帖子抓取,因为描述里也有 fetch、content、url。Jev 留下了 anyapi 的通用网页抓取(0.90)和 dataforseo 的原始 HTML 抓取(0.71),两条都没有出现在原词法结果里。随后,agent 调用了 anyapi.web.scrape

找符合条件的人。查询是 “people search LinkedIn professional profiles”。词法结果靠前的是 people.enrich 和 people.email.find,偏向补全已知用户的资料或查邮箱。Jev 留下了 LinkedIn 用户搜索端点,agent 随后调用了 harvestapi 那条,它没有出现在原来的词法结果里。另一条查询 “search people by company name domain employees” 也有类似情况:词法返回找邮箱的工具,Jev 留下按公司找员工的工具。

从搜索结果到一次调用从搜索结果到一次调用people search LinkedIn professional profiles词法 · 部分结果1 treg.people.enrich2 crustdata.people.enrich3 treg.people.email.find4 leadmagic.x.b2b-profile-email偏向资料补全和邮箱查找没有展示 agent 最后调用的工具Jev · 保留 4 / 30 条1 moltsets.linkedin.profile.search0.912 harvestapi.linkedin.profile.search0.953 anyapi.linkedin.search_profiles_thin0.784 anyapi.linkedin.search_profiles_email0.78过滤的候选包括crustdata.people.enrichtreg.people.email.findagent 随后调用harvestapi.linkedin.profile.search仅 Jev 列表包含 → 这一分归 Jev从搜索结果到一次调用从搜索结果到一次调用people search LinkedIn professional profiles词法 · 部分结果1 treg.people.enrich2 crustdata.people.enrich3 treg.people.email.find4 leadmagic.x.b2b-profile-email偏向资料补全和邮箱查找没有展示 agent 最后调用的工具Jev · 保留 4 / 30 条1 moltsets.linkedin.profile.search0.912 harvestapi.linkedin.profile.search0.953 anyapi.linkedin.search_profiles_thin0.784 anyapi.linkedin.search_profiles_email0.78过滤的候选包括crustdata.people.enrichtreg.people.email.findagent 随后调用harvestapi.linkedin.profile.search仅 Jev 列表包含 → 这一分归 Jev

这些查询都不复杂,难处在于相近的词可能对应完全不同的工具。我们希望搜索结果能保留这种区别,让 agent 少花几轮去换词和试错。

三、用 Jev 检查候选

先召回候选,再判断相关性,是搜索和 RAG 里常见的做法。我们想验证的是,把它用到 treg 的工具目录后,能不能让 agent 少花几轮换词和试错。

这次补上的是逐条检查候选的能力:调用这个端点,能不能完成查询里的任务?

Jev 是 TypeSafe 的 System One 模型。输入是一段 state 和一组带类型的问题,返回的是对应的答案,不需要生成一段解释。我们用其中的 Noul 类型,问一个是非问题,拿到回答“是”的概率值。

对 treg 来说,这个接口比较容易接进现有搜索:

  • 候选可以批量判断。把 30 个候选对应的 Noul 问题放在同一个 state 下,一次请求就能拿到结果。
  • 返回分数,方便接入排序。我们可以按阈值过滤和分组,继续沿用已有的排序规则。
  • 输入成本较低。按本次实验采用的每十亿输入 token 42 美元计算,一次搜索约 4500 个输入 token,对应约 0.0002 美元。

我们先选 Jev,主要因为它能一次处理多个候选,直接给出数值答案,输入成本也足够低。接入以后,我们又用相同的查询、候选和工具描述,离线测试了 Qwen3-Reranker 和社区开源实现。Jev 和 Qwen 都能纠正一些词法排序中的错误,但这批小样本还不足以证明谁普遍更好。

我们暂时保留 Jev,同时继续比较效果、延迟和稳定性。这里分享的是它相对 treg 原有词法搜索的线上结果;后续模型对照还没有在同样的线上部署条件下完成。

对“先找到一家公司的负责人,再找他的邮箱”这样的多步任务,我们仍希望由使用 treg 的 agent 负责拆解。treg 这次改的是每一步找工具的过程。至于搜索本身能否在低分时用 LLM 帮忙改写查询,我们还想继续试。

四、在原有搜索里加一步判断

我们保留了原来的词法搜索,用它快速找出候选,再交给 Jev 筛选。整个过程分为召回、判断和排序三步。

词法召回门槛放宽:任一稀有词命中工具目录 → 30 个候选Jev30 个 Noul,一次请求,服务端并行p50 ≈ 160 ms · 约 4.5k token分桶 + 原有的实测重排< 0.4 丢弃 · ≥ 0.7 高桶桶内保留词法顺序 → 8 条候选30 个概率Jev 超过 2.5 秒未答、报错或未配置:跳过,直接用词法页面

先放宽召回。把“六个词命中四个”的门槛降到“命中任意一个稀有词”,按词法分数取前 30 个。这样价格端点能进候选,但也会带进只命中 apple 的 App Store 搜索,需要下一步筛选。

再让 Jev 判断。把查询和 30 个候选放进同一个 state,对每个候选问一个 Noul 问题:

{
  "model": "jev-latest",
  "state": {
    "task": "apple stock closing prices for last year",
    "candidates": [
      {"i": 0, "id": "tiingo.daily.prices",
       "name": "End-of-day stock prices by ticker - adjusted, 30+ years",
       "capability": "End-of-day price history for a ticker", "platform": "stocks"},
      {"i": 1, "id": "serpapi.app-store.search.apps",
       "name": "Search apps in the App Store by keyword", "platform": "app-store"}
    ]
  },
  "questions": {
    "c0": {"type": "noul", "instructions": "Calling the API endpoint `candidates[0]` would directly accomplish, or be a necessary step of, the task described in `task`, on the platform or data source the task implies."},
    "c1": {"type": "noul", "instructions": "..."}
  }
}

返回分数:c0 = 0.91c1 = 0.06

在这个例子里,价格端点得到了 0.91,App Store 搜索是 0.06。

最后按阈值分组。低于 0.4 的候选丢弃,0.4 到 0.7 的放在一组,达到 0.7 的放在优先组。组内保留词法顺序,原有的实测成功率和价格重排也继续生效。我们没有直接按概率从高到低排序,避免细小的分数差异覆盖原有排序规则。

五、怎么知道 agent 更容易找到工具了

只看结果列表,很容易觉得“这几条都挺相关”。但 agent 实际选了什么,才让我们知道哪些结果被采用了。

treg 既处理搜索,也处理后续调用,我们能把这两个动作连起来看。即使没有人工标注的评测集,也可以先观察哪些结果被采用、哪些查询之后又换了词。这不能证明任务已经完成,但比只检查搜索列表多了一点反馈。

实验主要采用交错展示:分别算出词法和 Jev 的结果,再用 team draft 合并成一个列表。每轮随机决定哪边先选,双方依次放入自己排名最靠前、尚未出现的端点,并记录来源。

查询:scrape webpage html fetch url content想抓取网页内容,却搜出了社交平台的帖子抓取工具词法结果Jev 结果1Instagram帖子抓取2LinkedIn帖子抓取3anyapi网页抓取4dataforseo原始 HTML1anyapi网页抓取2dataforseo原始 HTMLJev 保留两条通用抓取工具过滤掉限定社交平台的结果交错展示第 1 轮 · Jev 先选第 2 轮 · 词法先选1anyapi网页抓取Jev 选入2Instagram帖子抓取词法选入3LinkedIn帖子抓取词法选入4dataforseo原始 HTMLJev 选入词法剩下的两条已被 Jev 选入,跳过重复项,合并结束。agent 调用 anyapi.web.scrape:Jev 排第 1,词法排第 3 → 记 Jev 得分
为展示去重,图中将两条通用工具补在词法列表末尾;实际查询中,它们未出现在词法结果里。

agent 调用端点后,我们比较它在两份原始结果中的位置。只有一边包含它,这一边得分;两边都有,排得靠前的一边得分;位置相同则记平局。两份结果完全相同时,这次调用无法帮助我们区分两种方案。

这样,同一次搜索就能比较两种排序,不必等不同用户恰好发出相近的查询。不过,混合列表仍有长度限制,不能保证保留词法列表中的每一条结果。我们也保留了少量流量,分别只展示词法或 Jev 的结果,用来观察搜索后的调用转化率和改词重搜率。

六、目前看到的变化

目前的结果让我们愿意继续做下去:agent 更常在搜索后调用工具,也更少马上换词重搜。最新交错记分约为 9:1;下文调用率、重搜率和延迟来自此前一轮线上观察,数字均取约数。

指标观测结果
Jev 延迟 p50约 160 ms
Jev 延迟 p95约 280 ms
最新交错记分,Jev : 词法约 9:1
原本无结果的查询,Jev 组后续有调用约 1/4

搜索后有没有调用。在两个纯对照组中,我们统计搜索后 10 分钟内,agent 是否调用了展示结果里的端点,再按原词法搜索有没有结果分开看:

原词法搜索只展示词法结果只展示 Jev 结果
有结果约 47%约 72%
无结果无可调用结果约 26%

词法原本有结果时,Jev 组的调用转化率高了约 25 个百分点。词法原本无结果时,Jev 组约四分之一的搜索产生了调用。空列表没有可供调用的端点,因此这部分不能直接比较两组的调用率,也不能据此判断 agent 后来是否通过其他方式完成了任务。

交错结果里选了谁。排除平局后,Jev 与词法的记分实际约为 8.6:1,本文以约 9:1 作概数表述。

有没有马上换词再搜。我们还统计了搜索后两分钟内再次搜索、且中间没有调用的情况:

只展示词法结果交错展示只展示 Jev 结果
约 59%约 43%约 33%

展示 Jev 结果时,agent 更常接着调用,也更少马上换词重搜。调用率和重搜率来自同一轮流量,衡量的都是搜索后的行为。差异能否长期保持、调用后是否拿到了需要的结果,还要继续观察。

后来回看多轮搜索,我们也发现“又搜了一次”有不同原因:有时是在换词,有时是在找下一步需要的工具,比如查地图评论前先找地点 ID;还有些工具第一次已经展示过,agent 仍然继续搜索。因此,重搜率只能提供线索,需要连同查询变化和后续调用一起看。

七、有些查询,还是没解决

目录缺少对应平台。查询 “hh.ru vacancies search” 指定了 hh.ru 招聘网站,当时目录没有它的端点。词法搜索靠 vacancies 匹配到五条 LinkedIn 和通用职位搜索端点。Jev 给 30 个候选的分数都低于 0.4,返回空列表。agent 最后调用了词法结果中的一条通用职位搜索,这一分归词法。

hh.ru 职位查询的两条路径:Jev 严格匹配后返回空列表,词法提供通用职位搜索。agent 采用了通用工具,记分归词法,但任务是否完成尚不确定。指定的平台没有,替代工具要不要给?查询:在 hh.ru 上找职位严格匹配返回空结果Jev · 按指定平台筛选没有对应工具符合查询中的平台限制但没有可供调用的结果通用替代工具被 agent 采用词法 · 按相近能力返回通用职位搜索不等于 hh.ru 专用工具✓ agent 最后调用了它这次记分归词法hh.ru 职位查询的两条路径:Jev 严格匹配后返回空列表,词法提供通用职位搜索。agent 采用了通用工具,记分归词法,但任务是否完成尚不确定。指定的平台没有,替代工具要不要给?查询:在 hh.ru 上找职位严格匹配返回空结果Jev · 按指定平台筛选没有对应工具符合查询中的平台限制但没有可供调用的结果通用替代工具被 agent 采用词法 · 按相近能力返回通用职位搜索不等于 hh.ru 专用工具✓ agent 最后调用了它这次记分归词法同一条查询,另一种结果

按查询指定的平台看,Jev 过滤这些结果有道理:LinkedIn 职位搜索无法直接完成 hh.ru 查询。但 agent 后来选择了通用职位搜索,说明它也可能接受替代方案。仅凭这次调用,还不能判断任务是否完成,也不能断言空列表就更有用。

这次词法得分,让我们多问了一句:搜索该多严格地遵守查询里的平台要求?只留完全匹配的工具,可能让 agent 无路可走;给出替代工具,又可能让它误以为找到了指定来源。我们想继续试的做法是,把“没有对应工具”说清楚,再单独列出可能有用的替代项。

搜不到的查询也值得留着。把这些查询放在一起看,能发现一些反复出现的需求,比如读写办公数据。我们会先检查现有工具能不能完成,再决定改搜索还是补工具。

不过,30 个候选全被拒绝,不等于整个目录都没有合适工具。还要检查相关端点是否漏在召回阶段,或被 Jev 误删。反过来,词法原本无结果、放宽召回后有工具被选中,也不一定只需加同义词:前面的股票例子,是参数词把命中门槛抬高了。我们会先区分这些原因,再决定改召回、补同义词,还是接入新工具。

查询没有说清楚需求。同样是“查一个人”,查询未必说明要找资料还是邮箱。Jev 只能根据查询和候选描述判断,agent 没写出来的意图仍然可能被漏掉。

八、尾巴

这次实验让我们看到了 agent 实际怎么找工具,也发现了不少光看搜索结果想不到的问题。接下来会继续检查误删的候选、补上常见说法,并把通用替代工具的适用范围交代清楚。

这些搜索记录也在帮我们决定 treg 接下来该加什么。用户想做的事,目录里未必都能满足。我们会根据实际需求持续补充新工具,也会继续分享接入和使用中遇到的问题。

如果你手头有想让 agent 做的事,欢迎到 treg.to 试试。没搜到合适的工具,或者搜到了却不好用,都可以告诉我们。更多工具在路上,敬请期待。