
# 基于函数创建插件
在AgentArts智能体开发平台中，当官方插件市场无法满足特定业务需求时，开发者需要自主创建插件。根据实现机制与运行形态的不同，自定义插件主要分为"API类型插件"和"函数类型插件"两种形态。API型插件介绍及创建请参考[基于API创建插件](https://support.huaweicloud.com/usermanual-agentarts0/agentarts_05_0126.html)。
#### 前提条件
- 已[开通AgentArts服务](https://support.huaweicloud.com/qs-agentarts0/agentarts_04_0000.html)。
- 登录用户为空间所有者、空间管理员、开发工程师，详细信息请参考[管理团队空间成员](https://support.huaweicloud.com/usermanual-agentarts0/agentarts_05_0216.html)。
 
#### 函数形式插件
函数类型插件是指直接在AgentArts智能体开发平台中编写并运行的一段代码脚本（Python3.9或Node.js14.18脚本），它不依赖外部服务器，而是利用平台提供的算力即时执行。
**典型适用场景：**
- 精确计算：利息计算、日期推算（下周三是几号）、单位换算。
- 逻辑校验：身份证/手机号正则校验、JSON格式修复。
- 数据清洗：数据进行去重、排序、过滤。
**不适用场景：**大规模数据存储、重型计算（如视频渲染）、复杂的持久化状态管理。
**插件调用链路：**
1. 用户输入：修复这段JSON：{'name': '张三', age: 25,}。
2. Agent分析：Agent识别用户意图为"JSON修复"，命中代码插件fix_json_format。
3. 参数生成：模型提取用户提供的原始文本，生成入参：{ "raw_text": "{'name': '张三', age: 25,}" }。
4. 沙箱启动：Agent启动一个隔离的Python运行环境（Sandbox）。
5. 代码执行：加载用户编写的修复逻辑，代码尝试解析并重新序列化数据，确保输出符合标准JSON规范。
6. 返回结果：代码运行结束，返回结构化结果：{ "is_valid": true, "formatted_json": "{\\"name\\": \\"张三\\", \\"age\\": 25}" }。
7. 最终回复：模型根据代码返回的结果，向用户输出："已为您修复JSON格式，修复后的内容如下..."。
 
#### 创建插件的流程
函数型插件是直接在平台提供的沙箱环境中的一段脚本代码，本文将直接通过具体示例进行演示，助您快速上手。
| 序号                                          | 流程环节                                                       || 说明                                                                                                            |
|:---|:---|---|:---|
| 1                                           | 创建插件                                                       || 在函数插件中，"插件"仅作为管理和分类的容器，实现对同类工具的管理。                                                                            |
| 2  | 创建工具  | 创建工具         | 工具真正干活的实体。每一个工具都对应一个独立的函数实例。代码逻辑、依赖包、入参出参定义全部都在这里配置。                                                          |
| 2  | 创建工具  | 创建自定义依赖包（可选） | 支持使用Python3.9或Node.js14.18创建工具代码。**为了保持轻量和安全，平台只提供最基础的语言环境，即除了Python3.9、Node.js14.18本身自带的标准库外，其余依赖包均需要手动上传。** |
| 示例1                                         | [文本相似度计算插件]，基于Python，不需上传依赖包。                                                                                                    |||
| 示例2                                         | [网页HTML内容清洗插件]（需上传依赖包），基于Python，需上传依赖包。                                                                                         |||
| 示例3                                         | [创建Python依赖包]                                                                                                                     |||
| 附录1                                         | [Python编码规范]                                                                                                                    |||
| 附录2                                         | [Node.js编码规范]                                                                                                                    |||
   
 #### 示例1：文本相似度计算插件
该插件的主要作用是接收两个文本输入（text1和text2），并通过以下三种算法之一计算它们的相似程度（0.0到1.0之间）：
- Cosine(余弦相似度)：默认算法。通过词频向量计算文本在语义/内容上的重合度。
- Jaccard(杰卡德相似系数)：计算两个文本中相同字符（token）在总字符中的占比，适合集合重合度计算。
- Edit Distance(编辑距离)：计算将一个文本变成另一个文本需要变动多少字符，适合检测拼写错误或短文本的字面差异。
同时配置了停用词表（DEFAULT_STOPWORDS）、预处理配置（PREPROCESS_CONFIG）、文本预处理（preprocess_text）单元。
- 停用词表：定义了一组常见的无实际意义的词（如"的"、"了"、"是"等），用于过滤。
- 预处理配置：转小写；去除标点符号（只保留汉字、字母、数字）；去除停用词；切分粒度。
- 文本预处理：清洗：将文本转为小写，并使用正则表达式；分词：将文本打散成字符列表；过滤：移除在停用词表中的字符。
**文本相似度计算插件创建步骤如下：**
1. 登录[AgentArts智能体开发平台](https://console.huaweicloud.com/versatile/#/home/overview)，在左侧导航栏"个人空间"区域，选择目标空间。
2. 在左侧导航栏中选择"开发中心 \> 组件库"，在"插件"页签，单击页面右上角"创建插件"。
3. 选择"函数类型"类型的插件，然后根据以下步骤配置插件信息。 
   表1基本信息 
   | 参数   | 说明                                                                                                                                                                                                                      | 示例                                                                |
   |:---|:---|:---|
   | 插件类型 | 根据实现机制与运行形态的不同，插件分为"API类型"和"函数类型"两种形态。                                                                                                                                                                                  | 函数类型                                                              |
   | 插件图标 | 单击默认图标按钮，可上传本地图片作为插件的自定义图标。 支持jpg、jpeg、png格式，不超过200KB。                                                                                                                               | 系统默认图标                                                            |
   | 名称   | 用于标识当前插件，在"组件库 \> 插件"页面会展示该名称。 命名规则：按照插件的实际功能命名，有助于Agent进行插件的精准识别和调度。 命名要求：可以包含中文、英文、数字、下划线； 长度限制：2\~64个字符。 | 文本相似度计算                                                           |
   | 描述   | 描述当前插件的类型、功能和适用场景。 需要按照插件的实际功能填写描述，有助于Agent进行插件的精准识别和调度。                                                                                                                            | 使用Python内置库（re/math/difflib）计算两段文本的相似度（适配Agent意图匹配、问答匹配、文本查重等场景）。 |
      
   
   
4. 配置完单击"确定"。 
   平台会自动跳转至工具信息页面，请参考后续步骤创建工具，在创建工具阶段会配置代码脚本、输入、输出参数等信息。
   
   
5. 在"工具信息"页面，单击"创建工具"，在"添加工具"弹窗单击"新建函数"。 
   图1添加函数   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002569425283.png)
   
   
6. 填写函数名称与描述，执行语言选择"Python3.9"。 
   表2函数基本信息 
   | 参数   | 填写示例                                                              |
   |:---|:---|
   | 名称   | Text_similarity_calculation                                       |
   | 描述   | 使用Python内置库（re/math/difflib）计算两段文本的相似度（适配Agent意图匹配、问答匹配、文本查重等场景）。 |
   | 执行语言 | Python3.9                                                         |
      
   
   
7. 单击"编辑源码"，复制如下代码脚本。 
   图2编辑源码   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002538545536.png)
   ```
   # -*- coding:utf-8 -*-
   import re
   import math
   import difflib
   # ===================== 全局配置 =====================
   DEFAULT_STOPWORDS = {
       "的", "了", "是", "我", "你", "他", "她", "它", "们", "在", "有", "就",
       "不", "和", "也", "都", "这", "那", "此", "彼", "之", "于", "及", "与",
       "哦", "啊", "呢", "吧", "吗", "哈", "哎", "哼", "嗨", "喂", "嗯", "一个",
       "一些", "一点", "一般", "一样", "怎么", "怎么样", "哪里", "什么", "多少"
   }
   DEFAULT_ALGORITHM = "cosine"
   PREPROCESS_CONFIG = {
       "lowercase": True,
       "remove_punctuation": True,
       "remove_stopwords": True,
       "split_granularity": "char"
   }
   # ===================== 文本处理工具函数 =====================
   def preprocess_text(text: str, config: dict = None) -> list:
       if text is None:
           text = ""
       config = config or PREPROCESS_CONFIG
       text = str(text).strip()
       if config.get("lowercase", True):
           text = text.lower()
       if config.get("remove_punctuation", True):
           text = re.sub(r"[^\u4e00-\u9fa5a-zA-Z0-9\s]", "", text)
       if config.get("split_granularity", "char") == "char":
           tokens = list(text)
       else:
           tokens = text.split()
       if config.get("remove_stopwords", True):
           tokens = [t for t in tokens if t and t not in DEFAULT_STOPWORDS]
       return tokens
   def cosine_similarity(vec1: list, vec2: list) -> float:
       if not vec1 or not vec2:
           return 0.0
       dot_product = sum(v1 * v2 for v1, v2 in zip(vec1, vec2))
       norm1 = math.sqrt(sum(v * v for v in vec1))
       norm2 = math.sqrt(sum(v * v for v in vec2))
       if norm1 == 0 or norm2 == 0:
           return 0.0
       return round(dot_product / (norm1 * norm2), 4)
   def jaccard_similarity(tokens1: list, tokens2: list) -> float:
       set1 = set(tokens1)
       set2 = set(tokens2)
       intersection = len(set1 & set2)
       union = len(set1 | set2)
       return round(intersection / union, 4) if union != 0 else 0.0
   def edit_distance_similarity(text1: str, text2: str) -> float:
       text1 = str(text1).strip() if text1 is not None else ""
       text2 = str(text2).strip() if text2 is not None else ""
       return round(difflib.SequenceMatcher(None, text1, text2).ratio(), 4)
   # ===================== 平台入口函数 =====================
   def main(args: dict) -> dict:
       """
       平台标准入口函数，函数名不可修改
       :param args: 输入参数字典，包含 text1、text2、algorithm
       :return: 输出参数字典，包含相似度计算结果
       """
       try:
           # 1. 获取输入参数
           text1 = str(args.get('text1', '')).strip()
           text2 = str(args.get('text2', '')).strip()
           algorithm = str(args.get('algorithm', DEFAULT_ALGORITHM)).strip().lower()
           # 2. 非空校验
           if not text1 or not text2:
               return {
                   "similarity": "0.0",
                   "status": "failed",
                   "used_algorithm": "",
                   "confidence": "0.0",
                   "error_msg": "text1 和 text2 不能为空，请检查输入参数"
               }
           # 3. 计算相似度
           if algorithm == "jaccard":
               tokens1 = preprocess_text(text1)
               tokens2 = preprocess_text(text2)
               similarity = jaccard_similarity(tokens1, tokens2)
               used_algorithm = "jaccard"
           elif algorithm == "edit_distance":
               similarity = edit_distance_similarity(text1, text2)
               used_algorithm = "edit_distance"
           else:
               tokens1 = preprocess_text(text1)
               tokens2 = preprocess_text(text2)
               vocab = {token: idx for idx, token in enumerate(set(tokens1 + tokens2))}
               vec1 = [tokens1.count(token) for token in vocab]
               vec2 = [tokens2.count(token) for token in vocab]
               similarity = cosine_similarity(vec1, vec2)
               used_algorithm = "cosine"
           # 4. 返回成功结果
           return {
               "similarity": str(similarity),
               "status": "success",
               "used_algorithm": used_algorithm,
               "confidence": str(similarity),
               "error_msg": ""
           }
       except Exception as e:
           # 5. 返回错误结果
           return {
               "similarity": "0.0",
               "status": "failed",
               "used_algorithm": "",
               "confidence": "0.0",
               "error_msg": f"计算失败：{str(e)}"
           }
   ```
   
   
8. 设置函数的输入、输出参数。 
   输入参数为两个待识别的文本，分别为text1、text2。
   输出参数在本次示例代码中，定义在body参数中，因此需要新增一个body参数。返回的JSON体会包含similarity（相似度数值）。
   图3输入参数   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002538545546.png)
   图4输出参数   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002569345293.png)
   
   
   
9. 代码配置完成后，单击"确定"完成工具的创建。
10. 在"工具列表"页面，单击"调试"按钮，输入参数值，单击"开始调测"检查调测结果。 
    在本示例中，输入text1、text2文本后，返回的body体中已经包含similarity（相似度数值）。
    图5工具调试   
    ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002569345297.png)
    
    
11. 调试成功后，工具状态随之变为"成功"，此时可单击右上角"发布"，发布插件。 
    只有经过发布的插件可以给智能体使用。
    
    
 
 #### 示例2：网页HTML内容清洗插件
该插件的主要作用是解析和清洗网页HTML内容，该插件主要实现了以下功能。
- 标签过滤：强制移除script(JS脚本)，style (CSS样式)，meta，iframe (广告/视频)，svg等非文本标签。
- 注释移除：删除HTML注释（往往包含无用信息）。
- 安全机制：代码中有一个逻辑if len(tag.get_text()) \< 200。只有当这些区域字数很少时才删除。防止误删了被错误标记为class="content-sidebar" 的正文长文。
![](https://support.huaweicloud.com/usermanual-agentarts0/public_sys-resources/note_3.0-zh-cn.png)
**由于不同的网页HTML内容与样式千差万别，本示例仅作为简单的功能演示使用。正式场景中，一般会对HTML网页样式订制专属的清洗策略。**
**网页HTML内容清洗插件创建步骤如下：**
1. 登录[AgentArts智能体开发平台](https://console.huaweicloud.com/versatile/#/home/overview)，在左侧导航栏"个人空间"区域，选择目标空间。
2. 在左侧导航栏中选择"开发中心 \> 组件库"，在"插件"页签，单击页面右上角"创建插件"。
3. 选择"函数类型"类型的插件，然后根据以下步骤配置插件信息。 
   表3基本信息 
   | 参数   | 说明                                                                                                                                                                                                                      | 示例                                                       |
   |:---|:---|:---|
   | 插件类型 | 根据实现机制与运行形态的不同，插件分为"API类型"和"函数类型"两种形态。                                                                                                                                                                                  | 函数类型                                                     |
   | 插件图标 | 单击默认图标按钮，可上传本地图片作为插件的自定义图标。 支持jpg、jpeg、png格式，不超过200KB。                                                                                                                             | 系统默认图标                                                   |
   | 名称   | 用于标识当前插件，在"组件库 \> 插件"页面会展示该名称。 命名规则：按照插件的实际功能命名，有助于Agent进行插件的精准识别和调度。 命名要求：可以包含中文、英文、数字、下划线； 长度限制：2\~64个字符。 | 网页HTML内容清洗                                               |
   | 描述   | 描述当前插件的类型、功能和适用场景。 需要按照插件的实际功能填写描述，有助于Agent进行插件的精准识别和调度。                                                                                                                            | 解析网页HTML源码，支持智能清洗并提取正文文本。它能自动过滤脚本、样式及广告噪音，将杂乱代码转换为结构化数据。 |
      
   
   
4. 配置完单击"确定"。 
   平台会自动跳转至工具信息页面，请参考后续步骤创建工具，在创建工具阶段会配置代码脚本、输入、输出参数等信息。
   
   
5. 在"工具信息"页面，单击"创建工具"，在"添加工具"弹窗单击"新建函数"。 
   图6新建函数   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002569345307.png)
   
   
6. 填写函数名称与描述，执行语言选择"Python3.9"。 
   表4函数基本信息 
   | 参数   | 填写示例                                                     |
   |:---|:---|
   | 名称   | WebHtmlParser                                            |
   | 描述   | 解析网页HTML源码，支持智能清洗并提取正文文本。它能自动过滤脚本、样式及广告噪音，将杂乱代码转换为结构化数据。 |
   | 执行语言 | Python3.9                                                |
      
   
   
7. 单击"编辑源码"，复制如下代码脚本。 
   图7编辑源码   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002538545534.png)
   本示例中会使用Python的beautifulsoup4依赖包，打包上传方法请参见[示例3：创建Python依赖包]。
   ```
   # -*- coding:utf-8 -*-
   import json
   import re
   # 依赖包：beautifulsoup4 (需打包上传)
   from bs4 import BeautifulSoup, Comment
   # ===================== 业务逻辑工具函数 =====================
   def clean_text(soup):
       """
       深度清洗 HTML，提取纯净文本
       """
       for tag in soup(["script", "style", "meta", "head", "input", "iframe", "noscript", "svg", "link"]):
           tag.extract()
       for comment in soup.find_all(text=lambda text: isinstance(text, Comment)):
           comment.extract()
       for tag in soup.find_all(class_=re.compile(r'(nav|footer|header|sidebar|menu|copyright)', re.I)):
           if len(tag.get_text()) < 200:
               tag.extract()
       text = soup.get_text(separator='\n')
       lines = []
       for line in text.splitlines():
           clean_line = line.strip()
           if clean_line:
               lines.append(clean_line)
       return '\n'.join(lines)
   def extract_links(soup, base_url=""):
       links = []
       seen = set()
       for a in soup.find_all('a', href=True):
           href = a['href'].strip()
           text = a.get_text(strip=True)
           if not href or href.startswith(('javascript:', '#', 'mailto:', 'tel:')):
               continue
           if base_url and not href.startswith(('http', '//')):
               base_url = base_url.rstrip('/')
               if href.startswith('/'):
                   href = base_url + href
               else:
                   href = base_url + '/' + href
           key = (text, href)
           if text and key not in seen:
               links.append({"text": text, "url": href})
               seen.add(key)
       return links
   def extract_images(soup, base_url=""):
       images = []
       seen = set()
       for img in soup.find_all('img', src=True):
           src = img['src'].strip()
           alt = img.get('alt', '').strip()
           if base_url and src and not src.startswith(('http', '//', 'data:')):
               base_url = base_url.rstrip('/')
               if src.startswith('/'):
                   src = base_url + src
               else:
                   src = base_url + '/' + src
           if src and src not in seen:
               images.append({"alt": alt, "src": src})
               seen.add(src)
       return images
   # ===================== 平台入口函数 =====================
   def main(args: dict) -> dict:
       """
       HTML 内容解析插件入口函数
       :param args: 输入参数字典，包含 content、mode、base_url
       :return: 输出参数字典，包含解析结果
       """
       try:
           # 1. 直接从 args 获取输入参数
           html_content = str(args.get('content', '') or args.get('html', '')).strip()
           mode = str(args.get('mode', 'text')).strip().lower()
           base_url = str(args.get('base_url', '')).strip()
           # 2. 非空校验
           if not html_content:
               return {
                   "status": "failed",
                   "mode": mode,
                   "result": {},
                   "error_msg": "未检测到 content 参数，请检查输入"
               }
           # 3. 业务处理
           soup = BeautifulSoup(html_content, 'html.parser')
           data = {}
           if mode == "links":
               data["links"] = extract_links(soup, base_url)
               data["count"] = len(data["links"])
           elif mode == "images":
               data["images"] = extract_images(soup, base_url)
               data["count"] = len(data["images"])
           elif mode == "summary":
               title = soup.title.string if soup.title else ""
               desc = ""
               meta = soup.find('meta', attrs={'name': 'description'}) or soup.find('meta', attrs={'property': 'og:description'})
               if meta:
                   desc = meta.get('content', '')
               full_text = clean_text(soup)
               data["title"] = title.strip()
               data["description"] = desc.strip()
               data["summary_text"] = full_text[:800] + "..." if len(full_text) > 800 else full_text
           else:
               cleaned = clean_text(soup)
               data["cleaned_text"] = cleaned
               data["length"] = len(cleaned)
           # 4. 直接返回字典
           return {
               "status": "success",
               "mode": mode,
               "result": data,
               "error_msg": ""
           }
       except Exception as e:
           return {
               "status": "failed",
               "mode": "",
               "result": {},
               "error_msg": f"处理失败：{str(e)}"
           }
   ```
   
   
8. 设置函数的输入、输出参数。 
   输入参数为content，类型为string，表示待提取的网页文本。
   输出参数在本次示例代码中，定义在body参数中，因此需要新增一个body参数。返回的JSON体会包含清洗后的内容。
   图8输入参数   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002569425287.png)
   图9输出参数   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002569425277.png)
   
   
9. 添加Python依赖包，本示例中会使用Python的beautifulsoup4依赖包，打包上传方法请参见[示例3：创建Python依赖包]。
   
   图10添加依赖包   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002538385604.png)
   
   
10. 将获取的依赖包上传至平台后，单击"确定"完成工具的创建。
 
 #### 示例3：创建Python依赖包
除了Python3.9、Node.js14.18本身自带的标准库外，其余依赖包均需要手动上传。
本小节结合[示例2：网页HTML内容清洗插件]作为演示，介绍制作Python的beautifulsoup4依赖包。
1. 准备一台Huawei Cloud EulerOS 2.0环境的服务器。 
   **制作函数依赖包推荐在Huawei Cloud EulerOS 2.0环境中进行**。 使用其他系统打包可能会因为底层依赖库的原因，运行出问题，比如找不到动态链接库。
   本示例中创建一台EulerOS镜像的[弹性云服务器](https://console.huaweicloud.com/ecm/#/ecs/manager/vmList)进行后续操作的演示（创建一台按需计费、最低规格1u1g、EulerOS镜像的服务器，使用完成即可删除释放）。
   
   
2. 创建完成后，远程登录至该服务器（可使用弹性云服务器默认的CloudShell方式登录）。
3. 依次执行以下命令，下载Python的beautifulsoup4依赖包，并将其压缩为zip包。 
   ```
   # 1. 创建临时目录，用于存放beautifulsoup4依赖包，该依赖包缩写为bs4，创建相同名称的目录
   mkdir -p /tmp/bs4
   # 2. 安装依赖（自动包含soupsieve）
   pip install beautifulsoup4 --root /tmp/bs4
   # 进入临时目录
   cd /tmp/bs4
   # 查找 site-packages 路径（Linux 下通用命令）
   find . -name "site-packages"
   # 示例输出：./usr/local/lib/python3.9/site-packages
   # 进入找到的 site-packages 目录（替换为上面步骤中查询的实际路径）
   cd ./usr/local/lib/python3.9/site-packages
   # -r：递归打包（包含 bs4、soupsieve 等所有文件）；-q：静默模式
   # 将包生成到 /tmp 目录，方便后续下载
   zip -rq /tmp/bs4.zip *
   ```
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002569425273.png)
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002538385590.png)
   
   
4. 打包完成后即可在tmp路径下查询到bs4.zip文件，下载该依赖包。 
   图11下载依赖包   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002569345301.png)
   
   
5. 返回插件的"添加工具"页面，单击"添加依赖包"。选择"私有依赖包"，按照页面提示前往FunctionGraph创建依赖包。 
   图12添加依赖包   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002538385598.png)
   
   
6. 在FunctionGraph页面，单击"创建依赖包"。在创建依赖包页面填写依赖包名称、选择运行时为Python 3.9，并选择ZIP上传方式。 
   **插件支持Python3.9、Node.js14.18版本的代码，因此运行时也需要选择对应的版本。**ZIP上传方式较为便捷，推荐使用。创建依赖包后会自动生成对应的版本号。
   图13创建依赖包   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002569345311.png)
   
   
7. 返回插件的"添加工具"页面，选择所需的依赖包。 
   图14添加依赖包   
   ![](https://support.huaweicloud.com/usermanual-agentarts0/zh-cn_image_0000002538545550.png)
   
   
 
 #### Python编码规范
本小节主要说明平台支持的Python函数的结构、参数定义及开发规范。开发者需基于此模板编写业务逻辑，实现插件的具体功能。
- **简单场景代码示例：**
  示例代码：
  ```
  def main(args: dict) -> dict:
      """
      运行代码节点会调用此函数，请勿对下面的函数名做修改
      :param args: 输入固定为args字典类型，kv为输入参数键值对
      :return: 输出参数为字典类型，kv为输出参数键值对
      """
      ret = {
          "key0": args.get('input', 'default'),
          "key1": "hi"
      }
      return ret
  ```
  通过固定的main函数触发代码执行，输入参数 args 是一个字典（dict），包含在界面上配置的所有输入参数，通过args.get('参数名', '默认值')读取。返回值必须与界面上配置的输出参数名称完全一致。
  
- **复杂场景代码示例：**
  示例代码：
  ```
  # -*- coding:utf-8 -*-
  import json
  import base64
  """
  公共函数使用方法示例
  import common
  headers = {}
  body = ""
  data = common.httpRequest("http://localhost:3300/test", headers, body, "POST")
  if data.get("code") < 300:
      return data.get("body")
  return "error: " + data.get("error")
  接口返回res = {"headers": {},
                "body": string,
                "code": number,
                "error": string}
  """
  """"
  mssiAuthData参数样例
  {
       "header":{}, // 连接器认证header参数
       "path": {}, // 连接器认证path参数
       "query":{}, // 连接器认证query参数
       "body":{}, // 连接器认证body参数
       "host":"https://demo.com // API主机地址
  }
  """
  def extractRequestParam(rawValue, encoded, defaultValue):
      if encoded and rawValue:
          rawValue = str(base64.b64decode(rawValue), "utf-8")
      return json.loads(rawValue) if rawValue else defaultValue
  ## 请勿对下面的函数名做修改
  def handler(event, context):
      """
      函数是方法的入口
      :param event: 执行事件（event）， 包含用户定义的函数参数以及所选择的的连接器认证相关参数
      :param context: Runtime提供的函数执行上下文
      :return:
      """
      isBase64Encoded = event.get('isBase64Encoded', False)
      inputData = extractRequestParam(event.get('body'), isBase64Encoded, {})  # 用户定义的函数参数数据
      mssiAuthData = extractRequestParam(event.get('mssiAuthData'), isBase64Encoded, {})  # 连接器认证数据
      mssiAuthData["securityToken"] = context.getToken()
      dataExtendConfig = extractRequestParam(event.get('dataExtendConfig'), isBase64Encoded, {})  # 流步骤扩展参数
      result = {}
      return json.dumps(result)
  ```
  
  代码主要包含三个部分：
  - 公共库引用说明：代码顶部的注释展示了如何使用平台内置的common库发起HTTP请求。
  
  - 辅助工具函数：extractRequestParam用于处理参数的解包与格式转换。
  
  - 主入口函数：handler(event, context)是插件执行的核心，包含业务逻辑。
  
  
  **主入口函数：**
  ```
  def handler(event, context):
      # ...
  ```
  - 约束：请勿修改函数名handler。平台通过此名称定位并执行函数。
  
  - 参数：
    - event (Dict)：包含本次调用的所有输入数据。
    
    - context (Object)：运行时上下文对象，提供系统级能力。
     
  
  
  **输入参数：**
  event对象中包含了经过Base64编码的原始数据。模板代码通过extractRequestParam函数自动完成了解码和JSON反序列化，开发者可直接使用以下变量：
  表5变量说明 
  | 变量名              | 含义      | 用途                                           |
  |:---|:---|:---|
  | inputData        | 用户业务参数  | 对应插件定义中用户填写的入参（如查询关键词、日期等）。                  |
  | mssiAuthData     | 连接器鉴权数据 | 包含调用第三方API所需的host，header等鉴权信息（由平台连接器配置自动注入）。 |
  | dataExtendConfig | 扩展配置    | 流程步骤中的高级配置参数（通常用于低代码编排场景）。                   |
     
  ```
  代码示例
  # 获取用户输入的 "city" 参数
  city_name = inputData.get("city", "city_name")
  # 获取连接器配置的主机地址
  api_host = mssiAuthData.get("host")
  ```
  **上下文与安全凭证：**
  context提供与运行环境交互的能力。
  context.getToken():获取当前执行环境的安全令牌（Security Token）。
  用法：模板代码已自动将Token注入到mssiAuthData\["securityToken"\]中，通常用于身份验证。
  **发起网络请求：**
  平台预置了common模块用于处理网络请求。请勿使用Python原生requests库，建议使用common.httpRequest以确保兼容性和安全性。
  入参：
  - url (str)：请求完整地址。
  
  - headers (dict)：请求头。
  
  - body (str/json)：请求体。
  
  - method (str)：请求方法("GET", "POST", etc.)。
  
  
  返回值(data) 结构：
  ```
  {
      "code": 200,          # HTTP 状态码
      "body": "...",        # 响应体字符串
      "headers": {...},     # 响应头
      "error": "..."        # 错误信息（如有）
  }
  ```
  **返回值规范：**
  函数最终必须返回一个JSON格式的字符串。
  ```
  代码示例
  result = {
      "status": "success",
      "message": "查询成功",
      "data": { "temperature": 25 }
  }
  return json.dumps(result, ensure_ascii=False)
  ```
  
 #### Node.js编码规范
本小节主要说明平台支持的Node.js函数的结构、参数定义及开发规范。开发者需基于此模板编写业务逻辑，实现插件的具体功能。
- **简单场景代码示例：**
  示例代码：
  ```
  /**
   * 运行代码节点会调用此函数，请勿对下面的函数名做修改
   * @param {Object} args - 输入固定为args对象类型，kv为输入参数键值对
   * @returns {Promise<Object>} 输出参数为Promise包裹的对象类型，kv为输出参数键值对
     */
     exports.main = async (args) => {
     const ret = {
         "key0": args?.input ?? 'default',
         "key1": "hi"
     };
     return ret;
     }
  ```
  平台通过固定的exports.main异步函数触发代码执行。输入参数args是一个对象（Object），包含在界面上配置的所有输入参数，通过可选链操作符?.和空值合并操作符??读取（如args?.input ?? 'default'）。返回值必须与界面上配置的输出参数名称完全一致。
  
- **复杂场景代码示例：**
  示例代码：
  ```
  /**
   * common是平台提供的公共函数，包括方法有post和get请求
   *
   * const common = require("./common.js");
   * const headers = {};
   * const body = "";
   * 示例1：异步调用
   * common.httpRequest("http://localhost:8080/test", headers, body, "POST").then((data) => {
   *      if(data.code < 300){
   *         return data.body;
   *      }
   *      return {};
   * });
   *
   * 示例2：同步调用
   * const data = await common.httpRequest("http://localhost:8080/test", headers, body, "POST");
   * if(data.code < 300){
   *     return data.body;
   * }
   * return {};
   * 接口返回 data = {
   *                "headers": {},
   *               "body": string,
   *               "code": number,
   *               "error": string
   *               }
   */
  /**
   *
   * mssiAuthData参数样例
   * {
   *      "header":{}, // 连接器认证header参数
   *      "path": {}, // 连接器认证path参数
   *      "query":{}, // 连接器认证query参数
   *      "body":{}, // 连接器认证body参数
   *      "host":"https://demo.com // API主机地址
   * }
   *
   */
  function extractEventData(event, name) {
      let data = event[name]
      if (event.isBase64Encoded && data) {
          data = new Buffer(data, 'base64').toString()
      }
      return data ? JSON.parse(data) : {}
  }
  /**
   * 函数是方法的入口
   * @param {*} event  执行事件（event）， 包含用户定义的函数参数以及所选择的的连接器认证相关参数
   * @param {*} context  Runtime提供的函数执行上下文
   * @returns
   */
  exports.handler = async function (event, context) {
      const inputData = extractEventData(event, 'body') // 用户定义的函数参数数据
      const mssiAuthData = extractEventData(event, 'mssiAuthData') // 连接器认证数据
      mssiAuthData.securityToken = context.getToken()
      const dataExtendConfig = extractEventData(event, 'dataExtendConfig')  // 流步骤扩展参数
      let result = "{}";
      return result;
  }
  ```
  
  代码采用CommonJS规范，主要包含以下部分：
  - 依赖引入：通过require("./common.js") 引入平台内置的HTTP请求库。
  
  - 辅助工具：extractEventData函数用于自动处理Base64解码与JSON反序列化，开发者通常无需修改此函数。
  
  - 主入口：exports.handler是异步函数入口，承载核心业务逻辑。
  
  
  **主入口函数：**
  ```
  exports.handler = async function (event, context) {
      // 业务逻辑区域
  }
  ```
  - 约束：必须保留exports.handler命名。
  
  - 特性：函数被定义为async，您可以在函数体内使用await语法来处理异步操作（如网络请求）。
  
  
  **输入参数：**
  代码模板通过extractEventData帮助您从event中提取并格式化了以下关键对象，您可以直接在handler中使用：
  表6变量说明 
  | 变量名              | 类型     | 含义      | 用途                                       |
  |:---|:---|:---|:---|
  | inputData        | Object | 用户业务参数  | 对应插件定义中用户填写的入参。                          |
  | mssiAuthData     | Object | 连接器鉴权数据 | 包含调用第三方API所需的host, header, query等鉴权配置信息。 |
  | dataExtendConfig | Object | 扩展配置    | 流程编排中的高级配置参数。                            |
     
  ```
  代码示例
  // 获取用户输入的参数 "keyword"
  const keyword = inputData.keyword || "default";
  // 获取连接器配置的主机地址
  const apiHost = mssiAuthData.host;
  ```
  **上下文与安全凭证** **：**
  context对象提供运行时的系统能力。
  - context.getToken()：获取当前执行环境的安全令牌（Security Token）。
  
  - 自动注入：模板代码已执行mssiAuthData.securityToken = context.getToken()，将令牌自动合并到鉴权数据中，方便后续调用使用。
  
  
  **发起网络请求：**
  平台提供了common模块用于发送HTTP请求。为了代码的可读性和维护性，强烈建议使用await方式（同步写法）进行调用。
  ```
  接口定义
  const common = require("./common.js");
  // ...
  const response = await common.httpRequest(url, headers, body, method);
  ```
  ```
  响应结构
  {
      "code": 200,          // HTTP 状态码 (Number)
      "body": "...",        // 响应体 (String)，通常需要 JSON.parse 解析
      "headers": {},        // 响应头 (Object)
      "error": "..."        // 错误描述 (String)
  }
  ```
  
