<aside> 🧭
当前、可直接用于 PR 评审的架构与案例说明请看:AIL-546 / PR #90|从直连 Apify 到 Exa-first search_person:架构、案例与 PR 说明。新文档已按 2026-08-19 工作区复核:DEV/FAT 已显式启用 Exa primary,并收录“习翔宇”E2E 反例与尚未修正的 gate/回退问题。
</aside>
历史快照:本页最初的结论是“Exa 尚未接入,建议先 shadow”。该状态已经过时;以下内容保留为设计演进与早期评审记录。
| 阶段 | Agent 看见什么 | 工具做什么 | 身份由谁判断 | 当前状态 |
|---|---|---|---|---|
旧版 dev |
多个原始 Apify MCP 工具 | Actor 运行与 Dataset 读取分散给 Agent 编排 | Agent,但容易被弱候选或不完整结果误导 | 旧实现 |
| PR #90 | 单一 search_person |
统一多路检索、Dataset 拉取、标准化、去重、排序、证据账本 | Agent | 已在远端 PR |
| 当前本地增强 | 同一 search_person |
进一步保留 SERP 线索、帖子上下文、证据覆盖与停止原因 | Agent | 尚未提交到 PR |
| Exa 方案 | 仍是同一 search_person |
Exa 作为模糊姓名的候选发现源;Apify 做档案/帖子验证 | Agent | 设计与实验阶段,尚未接入 |
旧版最大的问题,不是 Actor 不够多,而是 Agent 同时承担了太多机械工作:选择 Actor、拆分中文姓名、拼参数、等待运行、拿 Dataset ID、再读取 Dataset、合并候选、识别失败。任何一步遗漏,Agent 拿到的就不是“搜索结果”,而只是一次 Actor 的运行摘要。
PR #90 之后,责任划分变成:
| 层 | 应该负责 | 不应该负责 |
|---|---|---|
| Agent | 理解用户线索;生成姓名变体;判断证据是否足以确认;必要时继续搜索或提出一个高信息量问题 | 了解 Actor ID、Dataset ID、轮询状态、供应商字段差异 |
search_person |
执行有界搜索;调用供应商;读取实际结果;标准化;去重;按检索价值排序;返回匹配、冲突、未知项和搜索缺口 | 宣布“这就是本人”;替 Agent 询问用户;写联系人 |
| Apify / Exa / SERP | 提供公开职业档案、URL、摘要、工作经历或帖子线索 | 决定业务身份 |
这里的“工具不判断”不是“工具完全不排序”。工具仍然可以为了让 Agent 更快阅读而给候选排序,但排序只表示 retrieval ordering,不能升级为身份结论。
sequenceDiagram
participant U as 用户
participant A as Agent
participant R as Apify Actor
participant D as Apify Dataset
U->>A: 金淦,做 AI
A->>A: 手工拆 firstName / lastName
A->>R: 选择并调用姓名搜索 Actor
R-->>A: runId + defaultDatasetId + 运行状态
A->>D: 再调用 get-dataset-items(datasetId)
D-->>A: 原始候选数组
A->>A: 自己理解供应商字段、合并和判断
旧版 Agent 直接面对的工具包括:
harvestapi--linkedin-profile-search-by-name:按 firstName / lastName 搜索。harvestapi--linkedin-profile-search:按查询词、公司、岗位、地点等结构化条件搜索。dev_fusion--Linkedin-Profile-Scraper:拿已知 LinkedIn URL 抓完整档案。get-dataset-items(datasetId):Actor 调用完成后,再读取真正的结果。典型旧调用是两段式:
{
"actor": "harvestapi/linkedin-profile-search-by-name",
"input": {
"profileScraperMode": "Short",
"firstName": "淦",
"lastName": "金",
"strictSearch": true,
"maxPages": 1,
"maxItems": 20
}
}