
FastGPT Agent Skill 设计解析空白工作区约束、内置辅助生成与沙箱安全部署【免费下载链接】FastGPTFastGPT is a knowledge-based platform built on the LLMs, offers a comprehensive suite of out-of-the-box capabilities such as data processing, RAG retrieval, and visual AI workflow orchestration, letting you easily develop and deploy complex question-answering systems without the need for extensive setup or configuration.项目地址: https://gitcode.com/GitHub_Trending/fa/FastGPT本篇技术文章基于 FastGPT 的设计文档 Agent Skill 当前设计系统讲解平台级 Skill 的完整生命周期以“空白工作区 Agent 辅助编辑”为核心的创建体验、skills/skill-name/SKILL.md的强制目录约束与最小发布校验、Pro 内置辅助生成 Skill 的 etag 幂等同步与目录隔离机制以及运行态沙箱中版本包的权限校验、ZIP 安全解压和 entrypoint 受控执行。读完后你将能够对照源码理解一个 Skill 从创建、发布到在 Sandbox 中被部署、扫描和提醒注入的完整链路并在自行扩展 Skill 功能时准确定位各校验环节的实现位置。一、总体目标平台管运行态用户管内容FastGPT 的平台 Skill 采用“空白工作区 Agent 辅助编辑”的创建体验。职责划分非常清晰平台负责资源管理、版本管理、发布校验和运行态部署用户负责Skill 的具体内容在编辑工作区中自行创建创建弹窗不生成内容不预生成默认需求文案也不自动生成SKILL.md。这一设计在代码层有直接体现。新建 Skill 的初始版本由 createBlankSkillWorkspacePackage 生成它只建立一个“工作区外壳”export async function createBlankSkillWorkspacePackage(): PromiseBuffer { const zip new JSZip(); zip.file(.gitignore, DEFAULT_GITIGNORE_CONTENT); zip.folder(skills); return generateZipBuffer(zip); }源码注释明确说明空目录在 ZIP 中需要显式写入否则解压后skills/目录不会存在。也就是说创建成功后用户拿到的是一个带默认 .gitignore排除node_modules/、venv/、dist/、媒体大文件等和空skills/目录的初始工作区。文档中“创建接口不接收requirements也不根据名称或描述生成默认 Skill 内容”的约定与这条代码路径一一对应。创建成功后的标准流程为创建一个空白 workspace 初始版本进入 Skill 详情和编辑聊天用户自行创建skills/skill-name/SKILL.md及相关文件或使用内置辅助生成 Skill。二、工作区约束skills/name/SKILL.md是唯一的合法产物位置用户 Skill 产物必须位于固定路径workspace/skills/skill-name/SKILL.md禁止把用户 Skill 写到 workspace 根目录或系统内置 Skill 目录。编辑态下 Agent 的 reminder 会明确提供当前工作目录和写入边界引导模型只在约定位置落盘。2.1 SKILL.md 的 frontmatter 解析要求SKILL.md必须是带 YAML frontmatter 的 Markdown 文件。平台使用轻量解析器 parseSkillMarkdown 处理frontmatter 必须由---成对包裹缺失时直接返回错误SKILL.md must contain YAML frontmatter (delimited by ---)解析器只覆盖key: value与一层嵌套对象的简单结构所有标量值按文本保留不做数字、布尔值或 null 的类型推断复杂 YAML 解析失败会通过error字段返回给调用方平台真正依赖的元数据只有name和description两个字段。目录名与 skill 名的对应关系由 getSafeSkillDirectoryName 保证空白字符替换为中划线、仅保留中英文数字及中下划线、连续分隔符合并、首尾分隔符去除、长度截断到 50 字符非法结果回退为skill。编辑发布时 standardizeSkillPackageBySkillMdName 还专门处理了一个错位问题数据库里的skill.name只是产品展示名真实的可执行 skill 目录名必须跟随SKILL.mdfrontmatter 中的name否则下次打开编辑器会出现“展示名目录包住真实 skill”的错误结构。2.2 发布前的最小结构校验文档要求发布/保存版本前执行最小结构校验实现位于 validateDeployableSkillWorkspacePackage。它对工作区 ZIP 逐条检查校验项实现逻辑失败报错ZIP 安全性先走validateZipSafety见 2.3 节Unsafe ZIP entry path: ...存在skills/目录任一归一化后以skills/开头的条目Missing required directory: skills/至少一个一级 skill 目录收集skills/dir下含子文件的目录The skills/ directory must contain at least one first-level skill folder每个一级目录都有SKILL.md正则^skills\/([^/])\/SKILL\.md$匹配Each first-level skill folder under skills/ must contain SKILL.md: 缺失目录列表注意源码中的一个设计取舍该校验只做 workspace 级最小结构检查不解析 frontmatter而创建阶段的空白初始包只有.gitignore 空skills/目录不应调用该校验——只有用户主动发布时才要求至少存在一个可执行 Skill 目录。这与“空白工作区创建”和“发布必须可运行”两个阶段解耦的文档表述一致。2.3 ZIP 安全校验拒绝绝对路径、..与符号链接validateZipSafety 是“版本包不能通过绝对路径或..逃逸工作区”这条约束的具体实现对每个 ZIP 条目拒绝空路径与含\0的路径拒绝以/或\开头的绝对路径拒绝C:\风格的盘符路径任一路径段等于..即判为不安全通过 Unix 权限位0xa000识别符号链接条目直接拒绝ZIP symlink entries are not allowed累计所有非目录条目的解压后大小超过maxUncompressedBytes上限时报ZIP archive uncompressed size exceeds maximum allowed size。此外 validateZipStructure 在安全校验之上再做结构兼容优先找根目录SKILL.MD其次找/skills/.../SKILL.MD最后兜底任意子目录下的SKILL.md以兼容历史单 skill 包与多 skill 包两种形态。三、内置辅助生成 SkillPro 注入、HOME 隔离与 etag 幂等同步平台Pro可以提供内置的辅助生成 Skill 源码让用户在空白工作区里用“一句话需求”生成 Skill。运行时遵循严格的边界全部体现在源码中3.1 通用注入协议与目录隔离注入协议的类型定义非常薄BuiltinSkillSource 只描述“一个名字 一组relativePath → Buffer的文件”社区版因此可以通过可选注入接口保持零依赖——不注入任何 source 时整个同步流程直接短路返回。同步实现 syncBuiltinSkillsToSandbox 的关键行为写入位置homeDirectory/.fastgpt/skills/name即 Sandbox HOME 之下而非用户 workspace。源码注释明确指出目标路径不在用户 workspace 内因此不会进入编辑器文件树、导出包或发布包——这就是“内置 Skill 不进入用户版本包”的实现依据先清理再写入若目标目录已存在目录或文件先删除旧内容再重建避免新旧文件混叠失败即抛错任一文件写入失败会抛出Failed to write builtin skill files: ...不会留下半同步状态。3.2 etag 幂等同步“内容没有变化时不覆盖”由 computeBuiltinSkillEtag 实现对每个文件内容做buildRuntimeHash与relativePath配对按relativePath字典序排序保证同内容必然产生同序将path:hash\n拼接后整体再哈希一次得到整个 Skill 目录的 etag。每个 etag 以builtinSkill:name为键写入沙箱 runtime stategetBuiltinSkillStateHashKey。同步前先比较 state 中记录的 etag 与本次计算值全部未变化时直接返回不产生任何写盘操作部分变化时只重写有变化的 Skill。这使得重复进入编辑会话不会反复覆盖 HOME 下的内置目录。四、发布不可变 ZIP 包 持久化前校验Skill 版本保存为不可变 ZIP 包并记录 storage key版本记录本身由 createVersion 写入MongoAgentSkillsVersion集合支持传入事务 session保证与 skill 主记录的原子性。文档强调的“发布校验在持久化版本前执行失败时不生成可运行版本”对应的就是第二节所述的结构/安全校验链路校验不过则 ZIP 不会进入对象存储、版本记录不会落库运行态也就无从注入一个损坏的包。五、普通 Agent 运行从选中 Skill 到 reminder 注入文档列出的五步运行流程在 injectAgentSkillFilesToSandbox 和 getAgentSkillInfos 中有完整实现。5.1 权限校验团队归属 成员读权限注入函数先按skillIds teamId deleteTime: null查询MongoAgentSkills确认 Skill 属于当前团队且未被删除随后对每个 Skill 调用 authSkillByTmbIdper: ReadPermissionVal校验当前成员读权限。无权限或已不存在的 Skill 会被静默跳过打 warn 日志而不是让整个运行失败——这保证了“校验团队和成员读取权限”不会放大为可用性故障。5.2 以 versionId 为部署目录避免同名覆盖“已发布 Skill 以 versionId 作为部署目录”的落地方式部署根目录为workDirectory/projects每个版本解压到projectsRoot/versionIdversionId是 24 位十六进制 Mongo ObjectIdisSafeDirectSkillVersionDir 用/^[a-fA-F0-9]{24}$/严格识别合法版本目录注入结束时清理所有不在期望集合内的旧版本目录stale cleanup并顺带删除崩溃残留的.tmp-*临时目录由于同一个 versionId 的内容不可变部署是幂等的目标目录已存在则跳过下载。5.3 沙箱内的 ZIP 双重安全检查ZIP 包从对象存储以流式方式写入临时目录后在沙箱容器内执行一条统一的解压命令core.ts 中 unzipCommandunzip -Z -t package.zip | awk -v maxmaxPackageBytes BEGIN { ok0 } /uncompressed,/ { ok(($3 0) max) } END { exit ok ? 0 : 1 } unzip -Z1 package.zip | awk BEGIN { ok1 } /^\/\// || /(^|\/)\.\.($|\/)/ { ok0 } END { exit ok ? 0 : 1 } unzip -o -q package.zip -d tempDir三段短路执行第一段用unzip -Z -t解析清单在“uncompressed”汇总行的未压缩总字节数超过getAgentSandboxSkillMaxBytes()上限时退出码非零第二段用unzip -Z1逐行检查条目名出现绝对路径/...或..路径段即失败全部通过才执行真正的unzip -o -q。解压成功后删除 ZIP、将临时目录moveFiles到版本目录任何一步失败都会回滚清理临时目录。Skill 编辑会话的 prepare 链路deploySkillPackage复用同一套三段式检查命令并在工作区缺少.gitignore时写入默认内容。5.4 entrypoint.sh可选的版本初始化脚本“可选执行版本根目录的entrypoint.sh”由 runAgentSkillVersionEntrypoints 实现仅当版本目录根下存在entrypoint.sh文件时才执行getFileInfo探测命令通过buildLimitedOutputShellCommand包裹为/bin/bash entrypoint.sh以限制输出规模工作目录为该版本目录——即“entrypoint 在隔离 Sandbox 中执行限制时间和输出”执行成功标记只记录versionId到沙箱 runtime state 的skillEntrypoints列表entrypoint.ts#L49-L55。源码注释解释了依据版本包以 versionId 为目录且内容不可变因此无需再记录脚本 hash同一版本已执行过就跳过失败result为假值则不写入成功标记下一轮可重试符合“失败不标记为成功”每次执行后同步裁剪 state 列表只保留当前选中的 versionId防止列表无限增长。5.5 扫描 SKILL.md 并注入当前轮 remindergetAgentSkillInfos 负责“扫描SKILL.md并把可用 Skill 信息注入当前轮 reminder”扫描命令为find dir \( -name node_modules -o -name .venv -o -name venv \) -prune -o -iname SKILL.md -print0多目录并发 find单个目录失败只 warn 不级联对找到的每个SKILL.md调用parseSkillMarkdown没有合法name的条目被丢弃frontmatter 不满足平台解析要求的文件不会进入 reminder扫描范围同时覆盖用户 workspace 与内置 Skill 目录HOME 下的.fastgpt/skills普通运行与 edit-debug 统一以沙箱工作区为准输出结构包含name、description、directory、skillMdPath并关联已发布版本的appId/appName/appDescription供 reminder 拼装。文档中“模型必须先读取匹配 Skill 的完整SKILL.md不能仅凭描述推断工作流”是 reminder 文案层的约束注入的只是名称、描述和路径模型被要求在真正使用某个 Skill 前读取该路径下的完整文件避免用一句话描述代替完整工作流指令。六、Skill Edit Debug直接复用编辑沙箱工作区编辑调试edit-debug不下载已发布版本而是直接使用 Skill Edit Sandbox 的当前工作区做 SKILL.md 扫描——getAgentSkillInfos的注释明确区分了这两条路径“普通运行先注入 skill 包edit-debug 复用编辑器正在运行的 sandbox然后统一扫描 SKILL.md”。这避免了用旧发布版本覆盖用户正在编辑内容的风险而内置辅助生成 Skill 依然位于 Sandbox HOME与用户工作区保持隔离两条路径互不干扰。七、安全边界汇总将分散在各实现中的安全控制汇总如下每条都可回溯到具体源码安全约束实现位置ZIP 解压前校验总大小与路径穿越构建侧 validateZipSafety运行侧 core.ts 的 awk 三段式检查部署前检查团队归属与成员读权限injectAgentSkillFilesToSandbox内置 Skill 不进入用户版本包写入 HOME 下.fastgpt/skills见 builtin.tsentrypoint 隔离执行、限制输出、失败不标记成功runAgentSkillVersionEntrypointsversionId 作为部署目录避免同名覆盖isSafeDirectSkillVersionDir 及 stale 目录清理版本目录仅接受 24 位十六进制 ID临时目录仅接受.tmp-*前缀同上两个正则识别函数八、验证范围文档给出的回归验证清单可作为改动该模块时的测试基线空白 workspace 创建和创建接口 schema不接收requirements最小发布结构skills/存在、一级目录必须有SKILL.md与非法路径校验绝对路径、..、符号链接Skill 包权限团队归属 读权限、大小限制maxUncompressedBytes和部署目录versionId 命名、stale 清理edit-debug 不覆盖当前工作区不注入旧发布版本内置 Skill 路径隔离HOME 下.fastgpt/skills、etag 幂等同步内容不变不写盘与扫描workspace 内置目录双目录 findentrypoint 的成功、失败和重复执行行为成功标记按 versionId 去重、失败可重试、state 列表裁剪。相关核心文件索引通用注入协议 packages/global/core/ai/skill/runtime/builtin.ts、沙箱同步 packages/service/core/ai/sandbox/application/runtime/skill/builtin.ts、运行态扫描与部署 packages/service/core/ai/sandbox/application/runtime/skill/core.ts、ZIP 构建与校验 packages/service/core/ai/skill/package/zipBuilder.ts、SKILL.md 解析工具 packages/service/core/ai/skill/utils.ts、默认 .gitignore 模板 packages/service/core/ai/skill/package/constants.ts。【免费下载链接】FastGPTFastGPT is a knowledge-based platform built on the LLMs, offers a comprehensive suite of out-of-the-box capabilities such as data processing, RAG retrieval, and visual AI workflow orchestration, letting you easily develop and deploy complex question-answering systems without the need for extensive setup or configuration.项目地址: https://gitcode.com/GitHub_Trending/fa/FastGPT创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考