创建模块
创建可安装模块,说明模块类型、属性、方法以及纳入 Bundle 的发布验证要求。
当现有模块无法覆盖业务能力时,可以创建自定义模块。源码项目可以独立存在,但模块定义 必须在 Bundle 内创建。完成后先冻结不可变版本、更新 Bundle Manifest、创建 Bundle 版本, 再安装到目标 Runtime;完成真实调用验证后,才交给应用、智能体、技能、 后端服务或工作流使用。
先选择模块类型
| 类型 | 适用场景 | 运行方式 | 发布前必须验证 |
|---|---|---|---|
| 普通业务模块 | CRM、审批、知识库、财务等由平台运行时承载的业务能力。 | 模块定义、属性、方法和用户域随 Bundle 安装物化到 Runtime。 | Bundle 能在目标工作区物化模块,方法能在运行时被调用。 |
| 外部服务接入模块 | 飞书、企微、钉钉、支付、电话通知等依赖独立服务的能力。 | 模块调用外部服务;已有租户和凭据可以通过安装配置提供。 | 外部鉴权、租户隔离、错误返回和调用链可追踪。 |
| HTTP 代理模块 | 已有稳定 HTTP 服务,只需要把接口包装成模块方法。 | 模块方法把入参映射为 HTTP 请求,返回结果写回调用方。 | 请求 URL、鉴权头、超时、错误返回和日志可追踪。 |
| 渠道模块 | 微信、飞书、企微、钉钉、Webhook 等入口接入。 | 模块保存渠道凭据和回调配置,运行时负责消息接入与事件分发。 | 回调地址可访问,消息能进入正确工作区,事件链路有日志。 |
先定责任边界
如果模块依赖外部系统,先明确哪些状态由百积木保存,哪些状态由外部服务保存。不要把长期 token、租户密钥或外部实例 ID 写进页面文案或前端代码。
创建前准备
创建模块前,先确认这些信息:
- 模块所属工作区和项目。
- 模块名称、描述、适用用户和业务边界。
- 需要保存的属性,例如 token、租户 ID、回调地址、默认用户域、外部实例 ID。
- 要暴露的方法清单、每个方法的入参、出参、错误语义和调用权限。
- 整个 Bundle 是否需要自动创建、迁移或回收平台外部资源。
- 模块要纳入哪个 Bundle,以及模块版本和 Bundle 升级策略。
定义模块属性
模块属性用于保存安装后可配置或由服务端回写的值。属性定义需要写清字段名、类型、是否必填、默认值、是否敏感、是否由外部托管服务管理。
常见属性:
| 属性 | 用途 |
|---|---|
serviceBaseUrl | 外部服务或代理服务的业务 API 地址。 |
tenantId | 外部系统租户标识。 |
accessToken | 外部系统访问令牌,应标记为敏感属性。 |
externalInstanceId | Bundle 生命周期插件创建外部资源时返回的安装实例主键。 |
status | 外部实例或模块配置状态。 |
敏感属性只用于运行时调用,不应被页面、日志或普通接口明文展示。用户已有的租户编号可以 作为安装配置填写;自动创建的外部实例标识应由 Bundle 生命周期插件输出,再由 Bundle Service 校验并写入目标资源属性。
定义用户域
用户域用于说明哪些用户可以调用哪些方法。创建模块时至少定义默认用户域,例如 authenticated,再按业务需要拆分管理员、普通成员、外部客户等域。
设计用户域时,重点确认:
- 普通用户能否新增、编辑、删除业务数据。
- 管理员是否拥有配置、审核和导出权限。
- 智能体或工作流调用模块方法时使用哪个用户身份。
- 外部渠道消息进入后映射到哪个用户域。
获取当前访问用户
专用模块通常不需要自己实现登录态,也不应依赖前端把 userId、手机号或外部账号 ID 作为普通入参传入。页面、后端服务、智能体、工作流或渠道消息调用模块方法时,百积木运行时会按入口建立当前 Runtime、已验证调用方、工作区和访问用户等上下文字段。模块方法应只读取当前入口已经建立的字段,再根据模块自己的用户映射关系调用企业原有系统。
如果企业原有系统使用独立账号体系,建议在模块属性或模块业务表中保存“百积木用户 ID 与企业系统账号”的映射,例如外部员工 ID、CRM 用户 ID、门店账号或部门编码。模块方法收到调用后,先用上下文中的当前用户确认百积木侧权限,再查映射关系,最后带企业系统需要的身份凭据访问原有系统。不要让页面直接传入要代操作的外部账号,除非该方法本身就是管理员代办能力,并且已经定义了对应用户域、审计日志和权限校验。
使用运行时身份
模块方法只消费平台运行时已经建立的 Runtime、调用方、工作区和当前用户上下文,不自行生成、转发或解析平台内部身份凭据,也不直接调用平台内部接口。字段清单、出现条件和 HTTP 映射方式见 模块调用上下文。需要访问项目、数据库、托管服务等平台能力时,应使用当前 Runtime 已公开的模块方法或 SDK,并以运行时返回的方法定义为准。
不要把业务参数当成当前用户
请求参数、请求体或页面自行提交的 userId 都是不可信业务输入。模块必须从运行时调用上下文读取当前用户;管理员代办场景需要单独的用户域、权限检查和审计,不能使用固定管理员 ID 或兼容回退。
定义模块方法
每个模块方法都要写清:
- 方法名称和业务说明。
- 入参字段、类型、是否必填、默认值。
- 返回结构和失败返回。
- 调用时需要的模块属性。
- 是否允许智能体、工作流、后端服务或页面直接调用。
- 是否需要幂等键、重试或超时控制。
模块方法应保持业务语义清晰,例如 createLead、sendMessage、queryOrder,不要暴露内部实现名。方法返回值要稳定,方便页面、智能体和工作流复用。
确定外部生命周期归属
模块自身不绑定整个产品的生命周期插件。模块只需要声明哪些属性用于调用外部服务,以及 这些属性是否敏感、必填或允许由安装输出写入。
如果用户已有外部账号,让用户在安装配置中填写租户编号和凭据即可。如果安装 Bundle 时 必须自动创建外部租户、数据库或许可证,再由 Bundle 顶层绑定生命周期插件。详细判断和 协议见 高级 Bundle 开发。
生命周期插件需要针对整个 Bundle 验证安装、配置变更、升级、停止和卸载,尤其要确认 卸载不会误删仍被其他 Runtime 使用的外部资源。
纳入 Bundle
模块不作为独立市场商品发布。先在目标 Bundle 内创建模块定义,再从项目 Git 快照冻结
不可变模块版本,由 Bundle 项目中的 baijimu.bundle.json 引用精确版本:
baijimu bundle module create <workspace> <bundle> \
--project-id <projectId> \
--name <moduleName> \
--description <description>
baijimu bundle module version create <workspace> <bundle> <projectId> \
--module-id <moduleId> \
--version <semanticVersion> \
--commit-id <commitId>创建模块版本不会自动修改 Bundle 或升级已安装 Runtime。必须修改并提交
baijimu.bundle.json,再通过带完整 --git-commit-id 的 bundle version create、Bundle 审核和
bundle market publish 完成统一发布。
纳入 Bundle 前确认:
- 模块定义、方法定义和用户域已经同步到版本快照。
- 版本号语义清楚,破坏性变更使用新大版本或明确迁移说明。
- 示例属性和默认值不会覆盖用户生产配置。
- 安装到新工作区后能生成运行时可识别的服务名和业务 ID。
- Bundle 版本内容指向预期模块语义版本和安装 Artifact,不携带内部持久化身份或额外包装层。
安装与验证
Bundle 创建版本并纳入模块后,按真实使用路径验证:
- 把 Bundle 安装到目标 Runtime,由 Bundle 自动安装模块。
- 填写或确认模块属性,敏感属性只在配置页输入。
- 打开目标运行时,确认模块安装记录、服务名和版本正确。
- 调用每个核心方法,检查入参、返回、日志和错误信息。
- 让页面、后端服务、智能体或工作流各完成一次实际调用。
- 修改属性后再次调用,确认新配置已生效。
常见问题
| 问题 | 排查顺序 |
|---|---|
| 安装后看不到模块 | 先确认工作区和 Runtime,再确认 Bundle 版本内容、模块安装记录和当前账号权限。 |
| 方法调用失败 | 先看模块属性是否完整,再看运行时日志、方法入参、外部系统返回和用户域权限。 |
| 外部实例未创建 | 先确认 Bundle 是否声明生命周期插件,再检查插件注册、执行记录和外部服务健康状态。 |
| 属性被覆盖 | 检查默认值、Bundle 允许的插件输出、模块版本和 Bundle 升级逻辑。 |
| 工作流调用不到模块 | 确认包含该模块的 Bundle 已安装,模块已在工作区默认 Runtime 物化,服务名和方法名与工作流节点一致。 |