EN
English
简体中文
Log inGet started for free

Blog

API

在-dify-工作流里接入-thordata-实时网页搜索

在 Dify 工作流里接入 Thordata 实时网页搜索

把 Thordata SERP 插件装进 Dify,用自己的 API Token 完成授权,把一个按引擎生成的搜索工具接进工作流,然后在编辑器里看到真实的 Google 返回。

Dify 把 LLM 应用的外壳都给好了:可视化编辑器、工作流画布、Agent 运行时、运行日志。它唯一给不了的是今天的网页。一旦工作流需要价格、发布说明、新闻标题或今年的产品横评,训练数据停在几个月前的模型就只能靠猜。

解决办法是把搜索变成画布上一个普通节点。本教程用 Thordata SERP 插件完成这件事:它为每个搜索引擎提供一个独立的 Dify 工具,请求发出前用该引擎的线上 schema 校验参数,并返回结构化的 JSON,供下游节点逐字段读取。

读完之后你会掌握:

  • 把插件装进自托管 Dify,并完成 provider 授权
  • 看清它给工作区带来的 34 个引擎工具
  • 把 Thordata Google Web 接在开始节点与结束节点之间
  • 设置真正重要的参数(q、gl、hl、num、location)
  • 运行工作流,在 Test Run 面板里读到实时结果 JSON
  • 知道坑在哪:签名校验、动态选项、高级 JSON 回退、错误分支

目录

  1. Dify 是什么(一节讲完)
  2. 为什么 Dify 工作流需要实时搜索
  3. Thordata SERP 插件速览
  4. 动手搭建:安装 → 授权 → 接线 → 运行
  5. 继续扩展:更多引擎、高级 JSON、上线注意事项

Dify 是什么(一节讲完)

Dify 是开源的 LLM 应用开发平台。你不需要自己写对话循环,而是拿到一套可视化工作流编辑器、Agent 运行时、模型与提示词管理和运行日志——可以用 Dify Cloud,也可以自托管(Docker Compose,或从源码分别起 API、Web 控制台和插件守护进程)。

这里只需要它三块能力:

  • 工作流(Workflow) —— 一张从上到下执行的节点图。节点类型包括开始、LLM、知识检索、代码、条件分支、HTTP 请求,以及工具。
  • 工具节点(Tool) —— 调用某个工具的节点。在编辑器里,工具节点就是”把外部 API 变成一个步骤”的地方。
  • 插件(Plugin) —— 工具进入 Dify 的方式。从 Dify 1.0 起,所有工具 provider(包括内置工具)都是插件,作为独立进程跑在插件守护进程后面;安装插件,就是给工作区加上它的工具。

插件不是粘进提示词的一段代码,而是一个带 manifest、凭据定义和逐工具声明的包。Dify 在编辑器里渲染这些声明,所以下面工具节点显示的是真实的下拉框,而不是一个让你手填 JSON 的输入框。

模型知道的一切都停在训练截止那一刻。价格、发布、故障、法规、今年的横评——不去联网的工作流回答这些问题时,产出的是自信的虚构。有三件事让这成为产品问题而不是理论问题:

  • 截止点是隐形的。 模型不会标注哪些事实过期了,答得一样流畅。
  • 模型很少说”我不知道”。 被问到近期事件时,它会编出看起来合理的细节,包括引用来源。
  • 记忆不是证据。 在业务工作流里,听起来正确的答案如果没有可核对的链接,就没法用。

真正的成本藏在”自己抓”里

用一个 HTTP 请求节点抓搜索结果页,看上去是十行配置。维持它可用才是成本:验证码与反爬对抗、代理轮换、按国家/语言的本地化结果、随时改版的 HTML,以及每个引擎一套解析。解析最容易被低估——新闻框、answer box、本地商家卡片、购物卡片、相关问题落在不同位置,各引擎的排布还都不一样。

Thordata 的 SERP API 把这部分接过去:一次 HTTPS 请求返回目标引擎解析好的 JSON,代理与地理定位都已包含在内。

Dify 节点真正关心的另一半

接口再好,也不足以支撑画布上的一个节点。节点还需要知道有哪些参数:编辑器才能渲染正确的字段,运行时才能在消耗请求前拦掉无意义的取值。引擎之间差异很大——Google Web 要查询词加地区与地点,机票引擎要机场标识,Lens 要图片 URL。猜错参数名轻则 400,重则悄悄搜错东西。

这个插件用 n8n 集成同源的 Schema API 解决这一点。安装时,schema 被转成一份份具体的 Dify 工具声明——每个引擎一个工具——于是编辑器只显示该引擎接受的字段。运行时插件仍会拉取当前 schema(带缓存与内置快照回退),并在请求发出前校验取值。

Thordata SERP 插件速览

包名 thordata_serp 0.1.0,作者 thordata,类别 tool。它只声明两个出网域名——api.thordata.com 用于引擎 schema,scraperapi.thordata.com 用于搜索——并作为本地 Python 插件跑在守护进程的 Python 3.12 运行时上。

安装后它带来 34 个工具,当前 schema 里每个引擎一个:

分组数量示例
Google26google、google_ai_mode、google_web、google_shopping、google_news、google_maps、google_scholar、google_trends、google_flights、google_hotels、google_lens…
Bing6bing、bing_images、bing_news、bing_maps、bing_shopping、bing_videos
其他2yandex、duckduckgo

这里没有”先选引擎再填参数”的通用工具。选引擎就是选工具,这也正是 Dify 能显示各引擎自有字段的原因:google_web 暴露 23 个参数,google_news 只有 4 个,bing_news 用 cc 和 mkt 而不是 gl 和 hl。

所有引擎工具返回同一个信封,因此一个错误分支就能覆盖全部:

{"ok": true,  "status": 200, "engine": "google_web", "data": { ... }}

{"ok": false, "error": {"type": "SerpApiError", "status_code": 401, "message": "..."}}

接线之前,有三个行为值得先知道:

  • 保存凭据会消耗一次搜索。 Dify 的”授权”步骤会用引擎 google、查询词 Dify credential validation 发一次真实请求。Token 不对时你当场拿到可读的错误,而不是等到工作流跑起来才发现。(插件请求的是单条结果,但 num 不是该引擎的可见字段,所以返回的是引擎默认条数——这次调用仍然只花一次请求。)
  • 响应会被压缩。 生成的工具内部固定 json=1 与 compact 模式;压缩会在每一层嵌套里去掉 search_metadata、search_parameters、serpapi_pagination 和 request_metadata。排查请求时这些字段有用,进了模型上下文就是纯浪费。
  • 选项在安装时就固化了。 Dify 按已安装包里的声明渲染工具参数,所以编辑器立刻就有静态选项(国家、语言、地点)。在支持运行时动态选项的 Dify 版本上,插件会刷新选项;但运行时刷新无法给已安装的工具新增字段。

本地构建的包没有签名。 自己打的 .difypkg 没有 Marketplace 签名,插件守护进程默认会拒绝,报错是 “plugin verification has been enabled, and the plugin you want to install has a bad signature”。两条路:从 Dify Marketplace 安装已签名版本;或者在你可控的自托管实例上,把插件守护进程的 FORCE_VERIFYING_SIGNATURE 设为 false 并重启。下面的截图走的是本地包这条路。

动手搭建:安装 → 授权 → 接线 → 运行

前置条件

  • 一个可以装插件的 Dify 实例 —— 本文用的是自托管 1.17.1;Dify Cloud 也可以,只是要从 Marketplace 而不是本地文件安装。需要一个 owner 账号。
  • Thordata SERP 插件 —— 从 Dify Marketplace 安装已签名版本,也可以使用组织提供的 release;如果你自己维护 Dify 实例,也可以使用本地插件包。
  • Thordata SERP API Token —— 在 Thordata 控制台创建,含免费试用额度。

1. 登录,先看清工作区

下面全部操作都在 Dify 控制台里。登录后进入 Studio,这里列出你的应用。

参考实例的控制台登录页。

2. 获取 Thordata SERP API Token

在 Thordata 控制台打开 SERP API → API Token(API Playground 里的 Token 是同一个)并复制。还没生成的话先生成一个,免费试用额度也在同一处。别把它写进提示词、工作流变量或截图里——插件只需要在 provider 凭据里用它。

3. 安装插件

在侧边栏打开 Integrations,点 Install,从 Marketplace 选择带签名的 Thordata SERP 插件。如果你使用自托管 Dify,且组织提供了 release 包,同一页面也支持 GitHub release 或本地包文件。下面的截图展示的是本地包路径,但安装完成后的工作流配置完全相同。

三种入口。本地构建的包走 Local Package File——并且需要关掉签名校验(见上面的提示框)。

Dify 把包传给插件守护进程解码,然后启动安装任务:守护进程解包插件、为它创建 Python 3.12 虚拟环境、安装运行时依赖(dify-plugin 与 requests),最后拉起插件进程。完成后插件出现在 Integrations → Tools → Tool Plugin,按来源标注为 LOCAL PLUGIN 或 MARKETPLACE。

装好并列出,和内置工具并存。此时它还什么都没接——插件装了不等于有人用它。

4. 授权 provider

点插件卡片打开右侧抽屉,展开 Authorization,填入第 2 步复制的 API Token。Dify 会把它存成工作区凭据,并立刻执行 provider 的凭据校验——那是一次真实搜索请求。成功后抽屉里显示一条绑定该 Token 的授权;Token 本身不会再回显。

一条授权,保存为该工作区的默认凭据。之后每个工作流里的每个节点都用它。

校验已经用掉一次请求。 如果你在盯额度面板:每完成一次授权,就是一次成功的 SERP 调用。校验失败不消耗额度,返回的是归一化错误(比如 Token 错误时的 401)。

同一个抽屉也告诉你插件到底带来了什么:34 actions included,每一条就是一个引擎。从上往下滚一遍是理解这个插件最快的方式——Thordata Google Search、… AI Mode、… Web、… Shopping、… Local、… News、… Maps、… Scholar,一直到 Bing 和 DuckDuckGo 的条目。

一个插件 34 个引擎工具。选引擎就是选工具——Dify 因此能显示各引擎独立的字段。

5. 新建工作流,把工具加进去

回到 Studio,选 Create from Blank,选 Workflow,起个名字并创建。编辑器会打开一张空画布,并询问工作流从哪种触发器开始:选 User Input。

接着加搜索步骤。点开始节点右侧的 + 手柄(或侧栏里的 Select next step)打开节点面板,切到 Tools 标签,搜索 Thordata,插件就展开成引擎列表。

Tools 面板。每一项都会变成一个带该引擎自有参数的节点——经典网页搜索选 Thordata Google Web。

点 Thordata Google Web,节点落到画布上,右侧设置面板同步打开。

6. 填节点

面板分两部分。Input variables 放可以交给 Agent 或上游节点填写的字段——这里就是必填的查询词。Settings 放该引擎其余参数,全部按已安装的声明渲染:Device、Domain、Country、Language 是下拉框,JS render 与 Disable Caching 是 True/False 开关,国家与语言过滤器是多选,Location 是地点列表,结果偏移与条数是数字输入,表单没覆盖到的都归 extra_parameters_json。

节点设置:一个必填查询词,加上引擎自有控件。这里的一切都会在请求发出前按引擎 schema 校验。

本次演示的查询词是 best budget coffee grinders 2026,Country 保持 United States,Language 保持 English,结果条数从默认的 10 改成 3。这三个参数几乎在每次搜索节点里都值得显式设置:

  • num —— 返回多少条结果。十条原始 JSON 是很大的上下文;做摘要通常三条就够。
  • gl(Country)—— 查询哪个国家的 Google。不同国家结果集不同,而没有任何东西能推断你要哪一个。
  • hl(Language)—— 结果的界面语言。

Location 是第四个有细节的参数:同时暴露 location 与 uule 的引擎会自动生成 UULE。你只选地点,插件从地点推导出编码后的 UULE,并把推导值显示在选项标签上——没有单独的 UULE 字段给你填错。

最后把节点接到输出:加一个 End 节点,把工具的 result 变量映射进去。整张图就三个节点。

Start → Thordata Google Web → End。工具节点把设置回读出来:gl=us、hl=en、location=United+States、num=3。

7. 运行并读取结果

点右上角 Test Run。工作流逐节点执行:工具节点调用插件,插件调用 Thordata 接口,运行面板逐渐填满。这张图的真实运行只需几秒,而且不消耗 LLM token——工具节点不是模型调用。

一次真实的 Test Run:2.2 秒 SUCCESS,零 LLM token,OUTPUT 里是工具的 JSON。

返回的就是前面说的信封。compact 模式下输出很小,可以直接读:

{
  "result": {
    "ok": true,
    "status": 200,
    "engine": "google_web",
    "data": {
      "cache_status": false,
      "code": 200,
      "credits": 1,
      "google_ai_overview": false,
      "organic": [
        {
          "position": 1,
          "title": "Best Budget Coffee Grinders for 2026",
          "link": "https://coffeegeek.com/guides/feature-guides/best-budget-coffee-grinders-for-2026/",
          "description": "The Kingrinder P2 at $45, the K2 at $75, the Mavo Phantox Pro at $130…"
        }
      ]
    }
  }
}

这段节选藏了两件事。第一,organic 里实际有 num 要求的三条结果,上面只打印了第一条。第二,data 会随页面内容变化:同一次调用在引擎提供时还会返回 people_also_ask、related 和 spider_parameter,所以上面这些键是下限,不是完整结构。

下游节点用 Dify 的变量选择器往里取:result.data.organic[0].link 是可以直接放进答案的链接,result.data.organic 是可以用 Iteration 节点遍历的数组。注意各引擎字段不同——Maps 返回 places,Shopping 返回 shopping,Bing 返回 organic_results——所以先看一眼运行面板,别假定只有一种字段名。

工具节点不是答案。 上面截图里是原始搜索结果;把它们变成成句的回答,是 LLM 节点或挂了同一批插件工具的 Agent 应用的事。保持这个分工:搜索这一步就能单独测试、缓存和排查。

继续扩展

换一个引擎

引擎只是同一个插件里的其他工具,工作流本身不用改:要标题用 google_news,要价格用 google_shopping,要地点用 google_maps,要论文用 google_scholar,想要第二意见就上 bing 或 duckduckgo。字段名各不相同,把 End 节点接到正确的键上即可——运行面板会告诉你哪个才对。

够到表单没显示的字段

每个引擎工具末尾都有 extra_parameters_json,一个高级 JSON 对象。它只能设置该引擎已声明且保持可见的参数——实际上就是表单上没有控件的两个:uule(想自己给出编码后的地点,而不是从 location 推导)和 json(覆盖响应格式)。engine 与 isjson 会被忽略,所以固定引擎与结构化响应模式都不会被改掉。引擎没有声明的名字——包括 schema 里隐藏的字段(例如 ai_overview)——会被静默丢弃:不报错,也没有任何效果。这是这里唯一的坑:如果某个高级参数看起来没生效,先对着节点自己的字段列表检查拼写,再怀疑接口。

在一处处理失败

因为所有引擎工具共用同一个信封,一个分支就够:读 result.ok,为 false 时走错误路径,那里 result.error.status_code 与 result.error.message 会说明是认证问题、额度问题还是上游故障。工具失败不会打印你的 Token——预期错误都是可控的,配置的 Token 会在消息跨出工具边界前被抹掉。

上线注意事项

  • schema 来源。 运行时插件保留五分钟的内存 schema 缓存,schema 接口不可达时回退到内置快照。schema 并没有固化进已安装的工具:新引擎和新字段要在重新生成并重装包之后才会出现。
  • 上限。 请求体上限 1 MB,响应上限 10 MB;搜索超时 120 秒,schema 请求 30 秒。这些天花板不会因为你填了什么而改变。
  • 网络。 插件只与 api.thordata.com 和 scraperapi.thordata.com 通信,且不跟随重定向。如果实例跑在出网代理或防火墙白名单后面,需要放行的就是这两个域名。
  • 算的不只是额度,还有 token。 你返回的每一条结果都可能是模型必须读进的上下文。compact 模式加一个较小的 num,比换更大的上下文窗口更省钱。
  • Token 留在凭据里。 插件会把响应里的 Token 抹掉,但你自己贴进提示词、代码节点或截图的 Token,从定义上就已经泄露了。

如果 Test Run 一直卡在 “Running” 且没有任何节点事件,说明工作流根本没送到 worker。自托管 Dify 的控制台 Test Run 会把执行任务入队,由 Celery worker 消费;启动一个 worker(例如 celery -A app.celery worker -P solo -Q workflow_based_app_execution,plugin,workflow_storage,conversation)后同样的运行几秒就完成。这是部署细节,不是插件问题——在 worker 真正调用工具之前,插件守护进程的日志会一直是安静的。

结语

把 Dify 和 Thordata 的 SERP API 配在一起,得到的是一条建立在两样你能掌控的东西之上的搜索链路:工作流跑在你自己的 Dify 实例里,数据在每次执行时实时取回,而不是写死在提示词里。三个节点的形状小到一眼读完——Start、一个引擎工具、End——而每一部分都能替换:换引擎、换查询词、收紧 gl、hl 或 num,或者把返回的 JSON 交给 LLM 节点,都不需要动其它环节。一次 Test Run 只需两三秒,而且完全不消耗 LLM token。

同一套形状远不止能做网页搜索。插件把平台的全部引擎目录装成了独立工具——34 个,从新闻、购物、地图、学术论文到趋势、酒店、航班,另有 Bing 与 DuckDuckGo——所以在 google_web 与 google_news 之间切换,是换一个节点,而不是重写参数。而由于每个引擎都是 Dify 的普通工具,当你想让模型自己决定搜什么时,同一个节点也能挂进 Chatflow 或 Agent 应用。

要用你自己的账号跑起来,先在 Thordata 控制台创建一个 API Token,并把 doc.thordata.com 打开备查参数——那里写明了 34 个引擎各自接受什么;插件可以从 Dify Marketplace 安装,也可以使用你的 Dify 实例能够访问的 release。本文的工作流很小,只有 User Input → Thordata Google Web → End 三个节点;新建一个空白工作流,按照上面的字段说明和截图配置即可复现。