插件不是一段代码,是一份接口描述。 它告诉模型「有这么个能力,名字叫这个,要填这些参数」, 告诉系统「请求打到哪、返回什么样」。 拆开是四样:名字与描述、地址与方法、参数、返回结构。缺一样就废。 这一节把四样摆开,也讲清「描述」为什么比「地址」更要紧。
第 2 章把平台拆成五层,这一章讲能力层里的一半:插件。另一半是卡片,3.4 节讲。 插件这个概念在 21 课(Web 技术原理)和 37 课(图解 HTTP)里都出现过, 那两本讲的是「HTTP 请求怎么发出去」,这一节讲的是「怎么把它包装成模型能用的东西」。 读完这一节,第 8 到 16 章那些案例里凡是出现「插件节点」的地方,你都知道它在干什么。
一、插件是一张说明书
很多人第一次接触插件,以为要写代码。其实平台上的「插件」大部分时候是填表:填名字、填地址、填参数。 填完这些东西,平台就多了一个能调用的能力。 真正干活的代码在别人家服务器上,你只是告诉平台「怎么去敲那扇门」。 所以准确的说法是:插件是一张说明书,不是一台机器。机器在别人那儿,说明书告诉你机器在哪、 要投什么币、出来什么东西。
这也解释了为什么平台上的插件那么多:写说明书比造机器便宜太多。
二、四样,缺一样就废
名字与描述给模型看。它靠这段决定「这个工具能不能办用户这件事」。名字要短,描述要说人话。 地址与方法给系统用。请求打到哪个 URL、用 GET 还是 POST。 这一项写错就是 404,写不全平台直接不让存。 参数给调用方填。每个参数要有名字、类型、必填与否。 类型写错(比如把 string 写成 text)平台会拦。
返回结构给下游解析。 这一项最容易忽略,因为平台不一定强制你填——但下游节点要用里面的字段,字段名对不上就白调。 演示里五份描述只有一份能存进去。剩下四份各缺一样,报的错都很直白。
三、描述比地址更要紧
地址写错,调不通,你马上知道。描述写错,调得通,但永远不会被选中——你甚至不知道它没被用过。 演示里四份描述对三句请求打分。「查股票今天的股价」在「茅台今天股价多少」那一列得分最高; 「金融数据查询接口 v2」四列全零。 最后那份技术上完全正确,参数、地址、返回结构都没问题。 它只是用了接口的语言,而不是用户的说法。
所以写描述的规矩只有一条: 用用户会说的话,写这个工具能办的事。「查询金融数据」不如「查股票今天的股价」。
四、平台里的三类插件
官方插件:平台自己维护的,搜索、网页读取、图片生成这些。稳定,但能力有限。 第三方插件:别人发布到插件市场的。选的时候看两件事——最近更新时间和调用量。 半年没更新的,接口多半已经变了。 自定义插件:自己写的。3.3 节整节讲这个。
三类里官方的最省事,第三方的最容易踩坑,自定义的最灵活。能解决同一个问题的时候,按这个顺序挑。
五、插件的边界:读还是写
插件分两种,这个区分比什么都重要。 只读的:查天气、查股价、搜网页、读文档。调错了最多给个错答案,世界没有变化。 有副作用的:发消息、下单、改数据、删文件。调错了世界变了,而且常常变不回来。
对只读插件,可以让模型自己决定什么时候调。 对有副作用的,必须走工作流加确认——这一条第 3.2 节还会讲一次。 判断方法很简单:问一句「调错了会怎样」。 答「答案不对」是只读,答「发出去了」是副作用。
六、动手 Demo:五份描述,四份存不进去
造五份插件描述:一份完整的,四份各缺一样。逐个过一遍平台的保存检查。 再拿四份描述对三句真话打分,看哪份会被选中。
def spec(name, desc, url, params):
return {'name': name, 'description': desc,
'url': url, 'parameters': params}
S = spec('查股价', '查股票今天的股价',
'http://x/stock', [('code', 'string', True, '六位代码')])
def check_spec(s):
bad = []
if not s['name']: bad.append('缺 name')
if not s['description']: bad.append('缺 description')
if not s['url'].startswith(('http://', 'https://')):
bad.append('url 不是 http 开头')
for nm, tp, req, _d in s['parameters']:
if tp not in ('string', 'integer', 'number', 'boolean'):
bad.append('参数 %s 类型不认识' % nm)
return bad
实跑输出:
--------------------------------------------------------------------
插件拆开是四样东西
--------------------------------------------------------------------
① 四样,缺一样就废
--------------------------------------------------------------------
名字与描述:给模型看的,它靠这段决定要不要用。
地址与方法:给系统用的,请求打到哪、用什么动词。
参数:给调用方填的,每个要名字、类型、必填。
返回结构:给下游解析的,字段名对不上就白调。
| 描述 | 校验 | 报了什么 |
|---|---|---|
| 完整 | 通过 | — |
| 缺描述 | 拦下 | 缺 description |
| 地址不完整 | 拦下 | url 不是 http 开头 |
| 参数类型写错 | 拦下 | 参数 code 类型不认识 |
| 必填写成 maybe | 拦下 | 参数 code 必填没填 |
五份里只有一份能存进去。平台保存插件时做的也是这几个检查。
! 注意第三个:地址写 /stock,看着没毛病,但它不是 http 开头——平台会拦,因为拼不出完整请求。
② 描述是给模型看的,写法决定它被不被选中
--------------------------------------------------------------------
| description | 茅台今天股价多少 | 明天宜昌下雨吗 | 把这份报告发给张总 |
|---|:---:|:---:|:---:|
| 查股票今天的股价 | 0.29 | 0.00 | 0.00 |
| 查明天天气与是否下雨 | 0.13 | 0.27 | 0.00 |
| 发给某人一个文件 | 0.00 | 0.00 | 0.12 |
| 金融数据查询接口 v2 | 0.00 | 0.00 | 0.00 |
每一行都有一个明显偏高的格子,正好落在它该管的那句上。零星的 0.1 是哈希碰撞带来的噪声。
最后一行叫「金融数据查询接口 v2」——技术上完全正确,但用户不会说这句话,所以四个分数全零。
! 描述要写「用户会怎么说这件事」,不是「这个接口在技术上是什么」。
①四样东西那段是本节最该背的。 名字描述给模型,地址方法给系统,参数给调用方,返回结构给下游——四个不同的读者。 ②五份里四份被拦下,报的错都很直白:缺描述、地址不完整、类型不认识、必填没填。 平台保存插件时做的也是这几个检查。 ③注意「地址不完整」那份:写 /stock 看着没毛病,但它不是 http 开头,平台拼不出完整请求,只能拦。 ④第二张表是关键。四份描述四行,三句请求三列。每一行都有一个明显偏高的格子——除了最后一行,全零。 ⑤最后那行「金融数据查询接口 v2」技术上没错,只是没人会这么说话。 描述写的是用户的说法,不是接口的学名。
30 秒实验
- 打开平台的插件列表,随便点开三个,看它们的 description 用的是什么词。你会发现写得好的都很口语。
- 把你自己的插件描述念给一个不懂技术的人听。他听不懂,说明模型也听不懂。
- 给你常用的插件标一下:只读还是副作用。副作用那些,别让模型自己决定调不调。
常见误区
- 「插件要会写代码才能做。」大部分是填表。要写代码的是接口本身,那是别人的事。
- 「描述随便写,反正模型很聪明。」模型只读到你写的那几个字。 写「金融数据接口」,它就不知道这能查股价。
- 「能调通就说明配对了。」调通只说明地址和鉴权对了。 描述写得没人会选,或者返回字段解析不出来,都是「调通但不能用」。
自测三问(点开对答案)
1. 插件的四样东西分别给谁看? —— 名字与描述给模型,地址与方法给系统,参数给调用方,返回结构给下游节点。 2. 为什么说描述比地址更要紧? —— 地址错马上报错,描述错则永远选不中——它调得通,只是从来没人用,你还不一定发现。 3. 怎么判断一个插件该不该让模型自己决定调用? —— 问「调错了会怎样」。答案不对是只读,可以让模型定;发出去了是副作用,必须走工作流加确认。说明书有了,接下来是真用起来:插件有两种接法,挂给智能体和插进工作流,两种的差别不在于谁更先进, 在于「谁来承担调错的责任」。下一节把这条讲透。
- ☐ (本篇完,下一篇 3.2 如何使用插件)