Coze(扣子)Agent 插件

Coze(扣子)Agent 插件

参考:Coze 官方文档 Agent 插件插件介绍


一、插件是什么?(一句话)

插件(Plugin)= 智能体可调用的一组工具(Tools / APIs)集合 ,用于把"模型会说"升级为"系统能做"(参考:插件介绍)。


二、插件的作用(为什么要用)

2.1 插件在智能体体系中的位置

需要外部能力
用户问题
智能体/工作流
插件/工具
外部系统/API/数据源
回复/卡片/动作

2.2 常见作用与收益(表格)

作用 解决什么问题 典型例子 直接收益
对接外部系统 模型无法直接访问业务系统 CRM/工单/订单查询 让回答"有数据可依"
执行动作 让智能体能"办事" 创建工单、发通知、审批 少一轮沟通,直接落地
结构化输出 输出可渲染的结构(如卡片) 列表卡片、详情卡片 可读性强、可交互
复用能力 一个能力多处使用 同一插件供多个智能体 降低重复开发成本

三、插件类型(围绕你要的 3 个核心点)

官方文档中常见插件分类/创建方式较多,这里按"落地视角"聚焦三类:

  1. 插件的作用(上面已讲)
  2. 可托管部署的代码插件
  3. 无授权插件(并给一条"名言式"提醒)

四、可托管部署的代码插件(Code Plugin)

4.1 这类插件解决什么

你只写业务代码,平台负责运行与托管 :不需要你自己买服务器、配环境、做部署(实践总结见:WayToAGI:使用 Coze IDE 创建插件)。

4.2 工作方式(从"写代码"到"上线")

在 Coze IDE 编写代码
定义工具入参/出参 Schema
本地/在线调试
发布插件版本
智能体绑定插件
工作流/对话调用工具
平台托管执行并返回 JSON

4.3 关键特性(精简但覆盖)

能力点 说明 注意事项(重要)
托管运行 代码由平台托管执行 超时/资源限制要按平台规则控制
多语言(常见) 常见为 Node.js / Python 以 Coze IDE 支持为准(见实践文)
依赖管理 可添加第三方依赖 依赖包大小有上限(例如 250MB,见:插件介绍
返回结构化 JSON 工具输出用于下游节点/卡片 必须稳定 Schema,避免"字段飘"

4.4 官方限制(做决策用)

以下是官方文档中"插件/工具"相关的常见限制示例(不同版本/套餐会变动,以官方为准):

限制项 示例值 参考
自定义插件 QPS 50 插件介绍
依赖包总大小 250MB 插件介绍
每个插件工具数 100 插件介绍

五、无授权插件(No-Auth Plugin)+ 一句名言

5.1 什么是"无授权"

无授权插件指:调用时不需要 OAuth / Secret / Token 等认证流程 ,直接请求并返回结果(实践归纳见:🛠️创建扣子插件:从零到上线WayToAGI:使用 Coze IDE 创建插件)。

5.2 适用场景

场景 为什么适合无授权 例子
公共信息查询 数据本来就是公开的 一句名言、公开节假日、公开百科摘要
内部测试/原型 快速验证链路 临时接口、Mock 数据

5.3 风险与边界(重点加粗)

风险点 说明 建议
接口可被滥用 无鉴权=更易被刷 设频控、加缓存、加白名单
不可访问敏感数据 无授权不等于无风险 一律避免把私有数据放在无授权接口
合规与条款 公共数据也可能有版权/协议 明确数据来源与可用范围

5.4 一句名言(用于提醒团队)

"没有授权的接口,只有两种结局:被滥用,或被下线。"

(这句是工程实践中的"提醒语",用于强调边界与风险控制。)


六、哪些场景该选"代码插件 / 无授权插件"

需求 推荐 原因
需要业务逻辑、清洗、聚合、多接口编排 代码插件 逻辑可控、可测试、可维护
只是拉取公开数据、无需身份 无授权插件 上手快、链路短
需要用户身份(代用户操作) ✅ OAuth/授权类插件 合规且可审计

七、快速检查清单(上线前 2 分钟自检)

  • 插件工具的 入参/出参 Schema 固定且可回归测试
  • 代码插件:考虑 超时、重试、限流、缓存、降级
  • 无授权插件:确认 不包含敏感数据 ,并做好 频控/缓存
  • 目标渠道(豆包/飞书等)验证:输出(文本/卡片)表现一致
  • 发布后跑一遍典型问题集(Top 20)

可托管部署的代码插件-示例

创建插件

云侧插件 - 在 Coze IDE 中创建

添加插件


工具使用

写一段python 代码 ,查询天气

申请高德 mapkey

1. 申请入口

  • 高德地图开放平台https://lbs.amap.com/
  • 控制台https://console.amap.com/

2. 申请步骤(通用)

步骤 操作 说明
1 打开高德开放平台并登录 没有账号先注册
2 进入控制台 https://console.amap.com/
3 进入 应用管理 / 我的应用 不同界面名称略有差异
4 创建应用 填写应用名称、用途等
5 在应用下 添加 Key 选择平台类型(Web/服务端/Android/iOS 等)
6 配置安全项 服务端建议配 IP 白名单 ;Web 端建议配 Referer 白名单
7 保存并复制 Key 这就是你代码里要用的 AMAP_KEY

3. Key 类型怎么选(最常见)

你要做什么 建议 Key 类型 备注
Python/后端调用天气 API Web 服务 API Key(服务端) 配 IP 白名单更安全
前端网页直接加载 JS 地图 JavaScript API Key 配域名/Referer 白名单
移动端 SDK 集成 Android/iOS Key 绑定包名/Bundle ID

4. 在本地配置 AMAP_KEY

4.1 macOS / zsh(推荐)

临时生效(仅当前终端):

bash 复制代码
export AMAP_KEY="你的Key"
python3 gdrn.py

永久生效(写入 ~/.zshrc):

bash 复制代码
echo 'export AMAP_KEY="你的Key"' >> ~/.zshrc
source ~/.zshrc

4.2 Windows(PowerShell)

powershell 复制代码
$env:AMAP_KEY="你的Key"
python gdrn.py

5. 安全注意事项(务必看)

  • 不要把 Key 直接写进代码并提交到仓库(尤其是公开仓库)
  • 服务端 Key 建议配置 IP 白名单,减少被盗刷风险
  • 如果 Key 泄露:到控制台 删除/禁用旧 Key,再创建新 Key

6. 相关文档

  • 高德开放平台:https://lbs.amap.com/
  • 控制台:https://console.amap.com/

用ai 写 python 代码

java 复制代码
"""
高德天气查询(无第三方依赖版本)

使用方法:
1) 先设置环境变量 AMAP_KEY(高德 Key)
   export AMAP_KEY="你的Key"
2) 运行:
   python3 gdrn.py
"""

import json
import os
import ssl
from urllib.error import URLError
from urllib.parse import urlencode
from urllib.request import urlopen, Request

AMAP_KEY = os.getenv("AMAP_KEY")  # 从环境变量读取,避免把 Key 写进代码


def _build_ssl_context() -> ssl.SSLContext:
    """
    构建 SSL 上下文。

    说明:部分 macOS / Homebrew Python 环境可能出现
    SSLCertVerificationError(找不到 CA 证书链)。
    这里会尝试常见 CA bundle 路径;实在不行可通过
    环境变量 AMAP_SSL_INSECURE=1 临时跳过证书校验(不推荐生产环境)。
    """
    if os.getenv("AMAP_SSL_INSECURE") == "1":
        return ssl._create_unverified_context()  # noqa: SLF001(仅兜底)

    candidates = [
        os.getenv("SSL_CERT_FILE"),
        "/etc/ssl/cert.pem",
        "/etc/ssl/certs/ca-certificates.crt",
        "/opt/homebrew/etc/ca-certificates/cert.pem",
        "/opt/homebrew/etc/openssl@3/cert.pem",
        "/usr/local/etc/openssl@3/cert.pem",
    ]
    for cafile in candidates:
        if cafile and os.path.exists(cafile):
            return ssl.create_default_context(cafile=cafile)

    return ssl.create_default_context()


def _get_json(url: str, params: dict) -> dict:
    """GET 请求并返回 JSON(带 SSL 兼容处理)"""
    qs = urlencode(params)
    req = Request(f"{url}?{qs}", headers={"User-Agent": "python/urllib"})
    ctx = _build_ssl_context()
    try:
        with urlopen(req, timeout=10, context=ctx) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except ssl.SSLCertVerificationError as e:
        raise RuntimeError(
            "HTTPS 证书校验失败(SSLCertVerificationError)。\n"
            "解决方案(二选一):\n"
            "1) 推荐:为 Python 配置 CA 证书。\n"
            "   - 可尝试设置环境变量 SSL_CERT_FILE 指向系统证书,例如:\n"
            '     export SSL_CERT_FILE="/etc/ssl/cert.pem"\n'
            "2) 临时:跳过证书校验(不推荐生产环境):\n"
            "   - export AMAP_SSL_INSECURE=1\n"
            f"\n原始错误:{e}"
        ) from e
    except URLError as e:
        raise RuntimeError(f"网络请求失败:{e}") from e

def geocode(city_name: str) -> str:
    """把城市名转成 adcode(更稳定)"""
    if not AMAP_KEY:
        raise RuntimeError("请先设置环境变量 AMAP_KEY")

    url = "https://restapi.amap.com/v3/geocode/geo"
    data = _get_json(url, {"key": AMAP_KEY, "address": city_name})
    if data.get("status") != "1" or not data.get("geocodes"):
        raise RuntimeError(f"地理编码失败:{data}")
    return data["geocodes"][0]["adcode"]

def get_weather(city_name: str, forecast: bool = False) -> dict:
    """查询实况/预报天气(forecast=False 实况,True 预报)"""
    adcode = geocode(city_name)
    url = "https://restapi.amap.com/v3/weather/weatherInfo"
    params = {
        "key": AMAP_KEY,
        "city": adcode,
        "extensions": "all" if forecast else "base",
    }
    data = _get_json(url, params)
    if data.get("status") != "1":
        raise RuntimeError(f"天气查询失败:{data}")
    return data

if __name__ == "__main__":
    # 示例:查询杭州实况
    if not AMAP_KEY:
        raise SystemExit('请先设置环境变量 AMAP_KEY,例如:export AMAP_KEY="你的Key"')

    print(get_weather("杭州", forecast=False))

    # 示例:查询杭州预报
    # print(get_weather("杭州", forecast=True))

用cursor ,生成一段coze 能用的代码,到时候再拷到coze 插件平台 。

java 复制代码
from runtime import Args
from typings.get_api_result.get_api_result import Input, Output

"""
Each file needs to export a function named `handler`. This function is the entrance to the Tool.

Parameters:
args: parameters of the entry function.
args.input - input parameters, you can get test input value by args.input.xxx.
args.logger - logger instance used to print logs, injected by runtime.

Remember to fill in input/output in Metadata, it helps LLM to recognize and use tool.

Return:
The return data of the function, which should match the declared output parameters.
"""
import json
import os
import ssl
from urllib.error import URLError
from urllib.parse import urlencode
from urllib.request import Request, urlopen

AMAP_KEY ="sk-xxxx"


def _build_ssl_context() -> ssl.SSLContext:
    """
    构建 SSL 上下文(兼容部分环境证书链缺失问题)。

    - 默认:使用系统 CA
    - 兜底:尝试常见 CA bundle 路径
    - 应急:设置 AMAP_SSL_INSECURE=1 跳过校验(不推荐生产)
    """
    if os.getenv("AMAP_SSL_INSECURE") == "1":
        return ssl._create_unverified_context()  # noqa: SLF001(仅兜底)

    candidates = [
        os.getenv("SSL_CERT_FILE"),
        "/etc/ssl/cert.pem",  # macOS 常见
        "/etc/ssl/certs/ca-certificates.crt",  # Debian/Ubuntu 常见
        "/opt/homebrew/etc/openssl@3/cert.pem",  # Homebrew(可能存在)
        "/usr/local/etc/openssl@3/cert.pem",  # Intel mac(可能存在)
    ]
    for cafile in candidates:
        if cafile and os.path.exists(cafile):
            return ssl.create_default_context(cafile=cafile)

    return ssl.create_default_context()


def _get_json(url: str, params: dict) -> dict:
    qs = urlencode(params)
    req = Request(f"{url}?{qs}", headers={"User-Agent": "coze-plugin/urllib"})
    ctx = _build_ssl_context()
    try:
        with urlopen(req, timeout=10, context=ctx) as resp:
            return json.loads(resp.read().decode("utf-8"))
    except ssl.SSLCertVerificationError as e:
        raise RuntimeError(
            "HTTPS 证书校验失败(SSLCertVerificationError)。可尝试:\n"
            '1) export SSL_CERT_FILE="/etc/ssl/cert.pem"\n'
            "2) 临时跳过校验(不推荐生产):export AMAP_SSL_INSECURE=1\n"
            f"原始错误:{e}"
        ) from e
    except URLError as e:
        raise RuntimeError(f"网络请求失败:{e}") from e


def geocode(city_name: str) -> str:
    """城市名 -> adcode"""
    if not AMAP_KEY:
        raise RuntimeError("未配置环境变量 AMAP_KEY(高德 Key)")
    data = _get_json(
        "https://restapi.amap.com/v3/geocode/geo",
        {"key": AMAP_KEY, "address": city_name},
    )
    if data.get("status") != "1" or not data.get("geocodes"):
        raise RuntimeError(f"地理编码失败:{data}")
    return data["geocodes"][0]["adcode"]


def get_weather(city_name: str, forecast: bool = False) -> dict:
    """查询实况/预报天气(forecast=False 实况,True 预报)"""
    adcode = geocode(city_name)
    data = _get_json(
        "https://restapi.amap.com/v3/weather/weatherInfo",
        {"key": AMAP_KEY, "city": adcode, "extensions": "all" if forecast else "base"},
    )
    if data.get("status") != "1":
        raise RuntimeError(f"天气查询失败:{data}")
    return data


def _get_input(args: Args[Input], name: str, default=None):
    """兼容 pydantic / dataclass / dict 的取值方式"""
    inp = getattr(args, "input", None)
    if inp is None:
        return default
    if isinstance(inp, dict):
        return inp.get(name, default)
    return getattr(inp, name, default)


def _format_weather_message(weather_data: dict, forecast: bool) -> str:
    if not forecast:
        lives = (weather_data or {}).get("lives") or []
        if not lives:
            return f"未查询到实况数据:{weather_data}"
        w = lives[0]
        return (
            f"{w.get('province','')}{w.get('city','')}\n"
            f"天气:{w.get('weather','-')}\n"
            f"温度:{w.get('temperature','-')}℃\n"
            f"湿度:{w.get('humidity','-')}%\n"
            f"风:{w.get('winddirection','-')} {w.get('windpower','-')}\n"
            f"发布时间:{w.get('reporttime','-')}"
        )

    # 预报:高德通常返回 forecasts -> casts
    forecasts = (weather_data or {}).get("forecasts") or []
    if not forecasts:
        return f"未查询到预报数据:{weather_data}"
    f0 = forecasts[0]
    casts = f0.get("casts") or []
    if not casts:
        return f"未查询到预报明细:{weather_data}"
    lines = [f"{f0.get('province','')}{f0.get('city','')} 预报({f0.get('reporttime','-')})"]
    for c in casts[:3]:
        lines.append(
            f"{c.get('date','-')} {c.get('week','-')}:"
            f"{c.get('dayweather','-')} {c.get('daytemp','-')}℃/"
            f"{c.get('nighttemp','-')}℃,"
            f"{c.get('daywind','-')}{c.get('daypower','-')}"
        )
    return "\n".join(lines)


def handler(args: Args[Input]) -> Output:
    # 入参约定(按你的 metadata 为准;这里做兼容):city / forecast
    city = _get_input(args, "city", "杭州")
    forecast = bool(_get_input(args, "forecast", False))

    try:
        data = get_weather(str(city), forecast=forecast)
        msg = _format_weather_message(data, forecast=forecast)
        # 注意:Output 目前模板只有 message 字段;为避免 schema 不匹配,这里只返回 message
        return {"message": msg}
    except Exception as e:
        if hasattr(args, "logger") and args.logger:
            args.logger.error(f"weather tool error: {e}")
        return {"message": f"查询失败:{e}"}

发布代码

这里需要注意,尽量不要涉及到个人信息 。

新建插件进行测试

选择刚刚自己创建的插件

开始测试

发布插件即可使用。

无授权插件

云侧插件 - 基于已有服务创建

上面的插件URL 截图错了,后缀不要加 /

调用这个接口开始测试 ,因为这个接口是无参数的,因此这里就不设置参数了。

这个url 是怎样来的呢? https://api.apiopen.top/docs 访问这个网站

选择这个url,之前的url 有问题,我换一个吧。 https://api.apiopen.top/api/images


配置输出参数

无授权插件开始测试

插件中添加刚刚创建的无授权插件

开始测试

授权插件

以这个为例

https://api.apiopen.top/swagger/index.html#/认证/post_api_auth_login

点击try out ,得到token

coze 中配置授权插件

参数配置

发送邮件

收取邮件

参考链接

相关推荐
之歆11 小时前
Coze(扣子)消息卡片(Message Card)使用指南
card·coze
zhyongrui2 天前
WordMark:把「查词」变成一种自然的阅读习惯
开源软件·插件
用什么都重名4 天前
【Dify学习笔记】:Dify插件离线转换教程
插件·dify·ollama
weixin_462446236 天前
【Dify 实战】基于 Workflow + LLM 的智能语音合成(TTS)完整教程(支持情感 / 语速 / 自动语言)
人工智能·语音识别·coze·mcp
RichardLau_Cx6 天前
Google Chrome 浏览器安装「豆包插件」完整教程
前端·chrome·插件·豆包
大脑经常闹风暴@小猿7 天前
Coze开源了!! 扣子(Coze) 和 dify怎么选?
dify·coze
GGBondlctrl7 天前
【Coze】从零开始:解锁扣子Coze工作流的新起点
智能体·coze·扣子
装疯迷窍_A8 天前
ARCGIS国土超级工具集1.8更新说明
arcgis·插件·变更调查·尖锐角·勘测定界·分割矢量
合合技术团队10 天前
5分钟自动化财报抽取:基于TextIn+Coze的实践方案
自动化·coze·textln