🐦 第3章 扣子插件和卡片
📄 一句话概括

自定义插件六步:找到接口、写描述、填参数、校验、真调一次、把返回解析成下游能用的形状。 前四步是填表,第五步是验证,第六步最容易被跳过——也是故障最多的地方。 这一节真起一个服务、真发一次请求,最后把接口那边的字段改个名,看链怎么坏。

📝 本章和前面几章的关系

上一节讲怎么用现成插件,这一节讲怎么做自己的。 这一节是全章最实操的一节,也是后面第 10 章(视频解析插件)、 第 13 章(多维表格节点)的前置——那两个案例卡住的地方,都是这一节的第六步。 沙箱里真起了一个本地 HTTP 服务当「股票接口」,所以下面的每一步都是真跑的。

一、第一步:找到接口,先看它返回什么

做插件之前先拿到接口文档,看清楚三件事:请求地址、要哪些参数、返回什么结构。 最重要的是第三件。 因为插件配好之后,下游节点要从返回里取字段。返回结构不清楚,下游就没法写。 演示里本地起了一个服务,访问 /stock?code=600519 返回一段 JSON:代码、名称、最新价、涨跌幅。

四个字段里,下游真正要用的往往只有两个:名称和最新价。剩下两个是给别的地方用的。 先想清楚你要哪两个,再动手配。

二、第二步:写描述

描述要写「用户会怎么说」。 查股价这件事,用户会说「茅台今天多少钱」「600519 现在多少」,不会说「查询证券行情数据」。 所以描述写成「按六位股票代码查询最新价、名称与涨跌幅」,比「股票行情接口」好得多。 描述里还要写清「输入什么」:六位代码。 不写这一句,模型可能拿「茅台」这两个字去填 code,接口当然查不到。

三、第三步到第五步:参数、校验、真调

参数只有一个:code,类型 string,必填。类型写错平台会拦——把 string 写成 text 就存不进去。 填完点保存,平台跑一遍校验。校验通过不等于能用,还要真调一次。 真调的时候填一个真实的代码,看返回对不对。 这一步必须做,不能跳过。很多人配完直接去工作流里试, 结果报错时不知道是插件的问题还是节点的问题。

演示里调 600519,返回贵州茅台 1688.5 元,涨 1.23%。到这儿插件就算能用了。

四、第六步:把返回解析成下游能用的形状

插件节点吐出来的是一整段 JSON,下游要大模型节点读它,得先拼成一句话。 拼的时候就要取字段。这时候如果字段名对不上,问题就来了。 演示里把接口的 price 改成了 last_price,下游还在取 price,取到的是空值, 于是拼出「贵州茅台 现价 元,涨 1.23%」。

注意它没有报错。 链是通的,日志是绿的,只是那句话缺了个数。这是插件最常见也最难查的故障形态。 防它的办法只有一个:把「取不到值」当错误处理。 取不到就停,别往下走。 宁可报错,也别吐一句缺了角的答案。

五、什么样的插件值得自己做

平台已有的别做。官方插件稳定,第三方插件有人维护,只有平台没有的才值得自己做。 值得做的三类:自家系统的接口(查订单、查库存)、垂直领域的数据源(行业数据库、内部文档)、 有特殊格式的转换(平台不支持的文件类型)。 不值得做的两类:通用能力(搜索、翻译、画图,平台都有)、一次性的小工具(用完就扔, 不如手工做一次)。

这条判断能省很多时间。做插件最贵的不是写,是之后接口变了要跟着改。

六、动手 Demo:从一份接口到一次真调用,再到一次静默失败

本地起一个服务当股票接口,看它返回什么;写成插件描述;真调一次。 最后把接口的字段改个名,看下游会出什么事。

base, stop = serve({'/stock': (200,
    '{"code":"600519","name":"贵州茅台","price":1688.5,"pct":1.23}')})

s = spec('股票行情', '按六位股票代码查询最新价、名称与涨跌幅',
         base + '/stock', [('code', 'string', True, '六位股票代码')])

code, data = call_plugin(s, arg={'code': '600519'})
print(code, data['name'], data['price'], data['pct'])

# 接口那边把 price 改成了 last_price
s2 = spec('股票行情', '按六位股票代码查询最新价',
          base2 + '/stock', [('code', 'string', True, '六位股票代码')])
_c, data2 = call_plugin(s2, arg={'code': '600519'})
v = data2.get('price')          # None,但不报错

实跑输出:

--------------------------------------------------------------------
自定义插件:从一份接口到一次真调用
--------------------------------------------------------------------


  ① 目标接口返回什么
  --------------------------------------------------------------------
  本地起了一个服务,地址 http://127.0.0.1:62459/stock?code=600519。
  HTTP 200,返回 {"code":"600519","name":"贵州茅台","price":1688.5,"pct":1.23}

  ② 把它写成插件描述
  --------------------------------------------------------------------
  名字:股票行情
  描述:按六位股票代码查询最新价、名称与涨跌幅(19 个字,模型靠它决定用不用)
  地址:GET/62459/stock
  参数:code(string,必填)
  校验:通过

  ③ 真调一次
  --------------------------------------------------------------------
  HTTP 200
  返回:{"code": "600519", "name": "贵州茅台", "price": 1688.5, "pct": 1.23}
  拼成一句话:贵州茅台 现价 1688.50 元,涨 1.23%

  ④ 接口那边改了个字段名
  --------------------------------------------------------------------
  HTTP 200,返回里没有 price 这个键了
  下游取 data['price'] → None
  于是拼出:贵州茅台 现价 元,涨 1.23%——数字位置空着,但整句话照样吐出去了。
  ! 这就是插件最常见的故障形态:不报错,只是少了一段。链路通、日志绿,答案缺个角。
  防它的办法只有一个:把返回结构的校验也写进链里,取不到就停,别往下走。

①第一段先看接口返回什么。四个字段里下游真正要用的往往只有两个,先想清楚要哪两个再动手。 ②描述那段:「按六位股票代码查询最新价、名称与涨跌幅」比「股票行情接口」好——前者是用户的话, 后者是接口的学名。 ③真调那一次返回 200,四个字段都在。到这儿插件能用了。 这一步不能跳,跳了后面报错时分不清是插件的问题还是节点的问题。 ④最后一段是本节的重点。 字段名改了,请求照样成功,data2.get('price') 返回 None,整条链一路绿灯。 ⑤真机上这表现成「答复里少了个数」或者「现价 元」。查起来很费劲,因为没有任何报错。 所以取不到值要当错误处理。

30 秒实验

  1. 拿一个你能接触到的接口,把它的返回字段数一遍。数完问:我真正要哪两个。
  2. 给你现有的插件加一句判断:取不到值就停。加完再看一遍日志。
  3. 找三个平台已有的插件,看看它们能不能替掉你手上那个自定义插件。

常见误区

  1. 「配完直接去工作流里试。」报错时分不清是插件还是节点。先在插件页面单独调一次。
  2. 「返回字段差不多就行。」字段名差一个字母,取到 None,链照样跑完。差别在答复里少了一个数。
  3. 「什么都自己写插件。」通用能力平台都有,自己写要长期维护接口变更。只有平台没有的才值得做。
自测三问(点开对答案) 1. 做插件之前先看接口文档的哪一项? —— 返回结构。因为下游要从里面取字段,取哪几个决定了插件该怎么配。 2. 为什么插件页面要单独真调一次? —— 分开验证。配完直接进工作流,报错时分不清是插件的问题还是节点的问题。 3. 接口改了字段名,链会怎么表现? —— 不报错。请求成功,只是取到空值,答复里少一段——链通、日志绿、答案缺个角。

插件让它能办事,但办完怎么把结果摆给用户看? 纯文字排下来又挤又乱,下一节讲卡片——一种结构化的回复形状。

相关笔记