ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Coze Skill Prompt实战:四段式模板、参数设计与技能包部署

Coze Skill Prompt实战:四段式模板、参数设计与技能包部署

做AI Bot开发的朋友应该都清楚,真正决定一个Bot好不好用的,不是工作流画得多复杂,也不是插件接得多花哨,而是它有没有一套定义清晰、边界明确、输出稳定的技能层。在Coze生态里,这套东西就叫Skill。Skill说白了就是你给模型注入的专业能力,它可以是纯Prompt驱动的单步技能,也可以是Prompt配合插件、工作流组合出来的复合能力,而这个Skill写得行不行,90%取决于Prompt的设计水平。

很遗憾,绝大部分人搭Bot时根本没有"Skill概念",只会把需求一股脑塞进系统提示词里,结果就是:简单任务还行,稍微复杂点就开始胡编乱造、输出结构不稳定、参数传错位置,最后只能靠加一大堆规则去补救,越补越乱。所以这篇内容想把Skill的Prompt撰写这件事彻底讲透,从标准模板、参数设计、实操落地到技能包部署,一条线走完。适合正在用Coze做Bot开发、想提升Bot稳定性的读者,也适合那些从GPTs或其他Agent平台迁移过来、想快速建立Skill工程化习惯的人。

1. 先想清楚再动手:Skill Prompt的整体设计思路

1.1 先搞清楚Coze Skill到底是个什么层

很多人会把Skill和Plugin、Workflow混在一起,这是第一步就该纠正的概念。Plugin解决的是"模型够不到的外部能力",比如查天气、读网页、调数据库;Workflow解决的是"确定性流程编排",它要求每步都走固定逻辑;而Skill解决的是"模型内部能力的定向激活"。一个更直白的类比:Plugin像是给机器人装上手和脚,Workflow像是给它画好动线,Skill则像是给它定义职业素养——会做菜的厨师技能、会做报表的财务技能,Skill决定了它在什么场景下按什么标准去思考和产出。

这意味着Skill的载体必然是一段高度结构化的Prompt,它可以引用Plugin,也可以不引用。在设计技能包时,你要先回答三个问题:这个技能负责什么任务?任务的输入是什么形态?任务的输出长什么样?如果没有回答清楚这三件事,后续所有的Prompt填写都是打补丁。

我见过很多人一上来就打开编辑器写提示词,写到一半发现逻辑不通,又回头改参数,改完参数又发现输出格式不对,整个下午都在原地打转。先回答上面三个问题,大概率能避开这种内耗。这就像写代码之前先画接口,表面看多花了一点时间,实际上省掉的返工时间远大于这点投入。

1.2 Skill Prompt和普通Prompt的差异:工程化是分水岭

普通对话Prompt是给"人"看的,目标是让模型理解意图;Skill Prompt是给"系统"用的,目标是让模型在不同上下文下稳定执行同一套逻辑。差异具体表现在三个方面。

第一,参数化。Skill Prompt不写死具体输入,而是通过变量占位符接收外部传入值,比如总结技能要接收"原文",翻译技能要接收"目标语言",这些变量必须有明确的命名规范。第二,结构化。Skill Prompt内部要分层:角色层、任务层、约束层、输出层,层级之间彼此独立,每一层只回答一个问题,这样模型才不会被庞杂信息带偏。第三,容错性。因为Skill会被反复调用,它必须能应对空输入、异常输入、边界情况,所以需要在Prompt里预留"兜底策略",比如遇到无法处理的内容时要明确拒绝而不是硬编。

这三条差异决定了Skill Prompt的撰写不能凭感觉,必须落地到模板上。倒不是说每个Prompt都要一模一样,而是骨架要统一、逻辑要闭环,具体内容可以根据技能类型替换。举个例子,内容审核技能和代码生成技能,角色定义差了十万八千里,但它们都需要回答"我是谁、要做什么、不能做什么、产成什么"这四件事,骨架完全一致。

1.3 模板化的真正价值:可复用、可测试、可部署

我见过不少开发者自己手写Skill Prompt,写的时候很爽,但过两个星期再回来看,完全看不懂自己当初的设定逻辑。模板化至少解决三个痛点。

一个是可复用。一套模板可以快速派生多个技能,比如"文章摘要技能"和"合同翻译技能"只是角色、任务、输出格式不同,骨架完全一样,复制粘贴改参数就能用。一个是可测试。模板固定了变量位,测试时只要换变量值就能跑回归,不会因为Prompt风格差异导致测试结果不可比。还有一个是可部署。Coze的Skill最终会以技能包的形式发布,技能包里的Prompt、参数、插件关联都需要按固定目录组织,模板化和这个部署模型天然契合。

所以这篇文章的主体思路就是:先给你一套通用的Skill Prompt模板,再手把手拆解每个字段怎么写,最后用一套脚本方式把技能包批量生成出来。整条链路打通之后,你就不再是"写Prompt",而是在"工程化地生产技能"。这一步思维转变,借着Coze这类平台的能力,哪怕只有一两个Bot的小团队也能做到。

2. 四段式模板逐段拆解:从角色定义到输出规范

2.1 一套能用的Skill Prompt模板长什么样

先把骨架摆出来。我常用的通用模板是四段式,它适用于大多数任务型技能,包括内容生成、信息抽取、数据处理、文本转换、问答决策等。

角色定义段:你是这个技能的掌控者,你的身份是XXX,你负责YYY,你的专业背景决定了你处理问题时优先考虑ZZZ。

任务描述段:你的核心任务是完成以下动作:第一步……第二步……第三步……。任务目标是……。请注意,如果输入缺少关键信息,你应该主动向调用方索要,而不是擅自假设。

入库约束段:在处理过程中,你必须遵守以下规则:1. 禁止……;2. 必须……;3. 当遇到……情况时,直接返回固定错误信息……。所有规则优先级从高到低依次为……

输出规范段:最终输出必须严格遵循以下格式:字段1:……;字段2:……。输出语言为……。如果任务失败,输出格式统一调整为……

这个模板不是拍脑袋来的,每个部分都对应一个真实的工程诉求。角色定义解决的是"立场稳定性",任务描述解决的是"流程可执行性",约束段解决的是"边界可控性",输出规范解决的是"结果可解析性"。四段合并之后,模型能同时回答"我是谁、要做什么、不能做什么、产成什么"四件事,这就是一个稳定技能的最小完备集。

提示:在Coze中,Skill Prompt会作为系统提示词注入,因此不要使用"帮我""请你"这类协商式措辞,改用"你是""你必须""输出如下"这种命令式结构,模型对命令式指令的跟随度更高。

2.2 角色、任务、约束、输出,逐段打磨要点

先讲角色段。角色的定义不能太宽泛,比如"你是文本处理专家"这种几乎没作用,因为任何语言模型天然就是文本处理专家。好的角色定义要满足三个点:有细分领域标签、有任务倾向描述、有工作原则提示。举个例子,你做一个"会议纪要技能",不要写"你是会议纪要助手",要写"你是企业运营团队的项目文档专员,你擅长从冗长的会议录音转写稿中提取决策、待办事项和风险点,你的工作原则是只依据原文信息,不做猜测性补充"。这样模型在后续生成时就会自动把信息抽取的优先级放在决策和待办上。

再讲任务段。任务段最忌讳写成一个笼统的句子,比如"把这段文本总结一下",模型的执行方差会非常大。正确的做法是把任务拆成步骤,用编号写明执行顺序,步骤数一般控制在3到8步。步骤之间要有逻辑递进,不要并列堆砌。比如会议纪要技能的任务段可以写成:第一步,识别发言人与时间线;第二步,提取会议决策事项;第三步,梳理待办负责人与截止时间;第四步,将结果按指定模板输出。任务段的表述也要注意动作词,多用"提取""识别""生成""校准"这种可观测动作,少用"了解""理解"这种不可观测动词。

约束段是很多人的薄弱环节,但恰恰是它决定了技能的专业度。约束段要覆盖四类风险:禁止性约束(不能做什么)、强制性约束(必须做什么)、边界性约束(什么情况是任务失败)、兜底性约束(失败时怎么反馈)。每一条约束都应该是一个可验证的布尔条件,而不是模糊的感受。比如"不要编造原文中不存在的内容"这算一条合格约束,而"尽量保证准确"这种就不合格。约束和任务会有重叠,但它们的侧重点不同:任务描述定义正向主流程,约束描述定义负向边界和兜底分支。

输出规范段直接决定技能能不能被下游解析。如果技能输出是要给工作流或另一个Skill消费的,那就必须用机器可解析的格式,比如JSON或严格的表格结构。如果是给人看的,也要给出版式要求,比如"标题使用三级结构""每条待办前加方括号"等。输出规范里还建议加一条"失败统一格式",这样在技能出错时下游也能识别。

这四段之间不是松散的堆砌,它们是互相咬合的。角色段的工作原则要在约束段里得到呼应,任务段的步骤要在输出规范段里有所映射。如果角色说了"只依据原文信息",但输出规范允许"补充背景知识",那这两段就直接打架了,模型会困惑于到底听谁的。

2.3 参数设计与变量管理:别把值写死在Prompt里

写Skill Prompt和写普通Prompt最大的思维转变,就是所有可能变化的输入都要参数化。参数设计的核心原则是"显式声明、默认值兜底、命名具象、敏感度分级"。

显式声明指的是在Prompt中明确用占位符标识输入变量,我习惯用{{参数名}}这种格式,并且每个参数都要在参数表里登记,包括参数名、类型、是否必填、默认值、输入示例。命名具象指的是参数名要能自解释,比如用article_content而不是text,用target_language而不是lang,这样后期维护和跨Skill复用都会舒服很多。

默认值兜底是一个容易被忽视的点。很多参数在大多数场景下是可选的,比如"输出语言""总结长度上限",你必须在参数表里设好默认值,并在Prompt的约束段注明"当调用方未传入该参数时,使用默认值XX"。这样做的好处是技能始终有确定的行为,不会因为缺参数就随机发挥。

敏感度分级针对的是技能部署时的权限问题。如果技能包要给别人使用,参数设计时就要区分哪些参数允许调用方自定义,哪些参数是内部固定的。比如底层Prompt里的判断逻辑、错误码定义就应该写死在技能包里,不要暴露成可配置参数;而调用方需要控制的只有入参和少量出参选项。把不可变的东西暴露成可变参数,是技能包后期被玩坏的最大原因。

我早期做过一个技能,把"输出语言"和"错误提示文案"都设置成了可配置参数,结果被调用方改得千奇百怪,最后各环境输出的错误提示都不一样,排查起来非常痛苦。从那以后我就养成了一个习惯:每加一个参数都要先问自己,调用方真的需要碰这个东西吗?如果答案是不确定,那就默认写死。

3. 从模板到技能包:完整落地实操与自动化生成

3.1 从零到一:构建"文章摘要技能"的六个步骤

讲完理论,下面用一个完整案例把所有环节串起来。我以"文章摘要技能包"为例,这套流程完全可以复制到你自己的场景。

第一步,定义能力边界。摘要技能的输入是文章原始文本,输出是三句话摘要加三个关键词,同时要求摘要长度不超过200字。能力边界想清楚后,参数表也就出来了:input_text(必填,String)、max_length(可选,Int,默认200)、language(可选,String,默认中文)。

第二步,按四段式模板填Prompt。角色定义为"资深编辑与信息提炼专家,擅长在噪声信息中快速定位核心观点,工作原则是不改变原文含义、不添加外部知识"。任务描述写成三步:先通读全文识别主旨句,再筛选支撑论据不超过3个,最后组织成摘要并提取关键词。约束段写明:不得生成原文没有的观点;若原文无效输入长度少于50字,直接返回错误码ERR_EMPTY_INPUT;摘要必须为自然段,不得使用列表。输出规范定义JSON结构:{"summary": "...", "keywords": ["...", "..."]}。

第三步,在Coze控制台新建Skill,把上面的Prompt填入系统指令面板,然后维护参数表。这个动作看似简单,但很多人随手就填完了,我建议你在提交前做一次"干跑验证":不接任何插件,直接用几个典型输入测试输出,看看四段式是否真的被执行了。

第四步,按需关联插件。摘要技能一般不需要额外插件,但如果输入源是URL而不是纯文本,就需要加一个网页抓取插件,并把插件输出映射到input_text参数上。关联插件的原则是:技能只依赖最小必要能力,能不加就不加,因为每加一个插件就多一个失败点。

第五步,准备测试用例。至少准备两个正例、一个边界例、一个空输入例、一个异常格式例,跑完后把结果和预期对比,记录成一份调试日志。第六步,生成技能包目录并按规范命名,确认manifest和params.json都完整后,导入Coze做端到端验证。这六步走完,一个技能才真正算落地了。

3.2 技能包目录结构与部署配置细节

在Coze里,一个可部署的Skill包并不是只有一段Prompt,它还要携带元信息。我习惯把技能包整理成如下目录结构:

skill_article_summary/ ├── SKILL.md ├── params.json ├── prompts/ │ ├── main.txt │ └── fallback.txt ├── examples/ │ ├── example_input_1.txt │ └── example_input_2.txt └── manifest.json

SKILL.md是技能包的说明文档,用来描述技能用途、适用场景、输入输出约定;prompts/main.txt是主Prompt,就是前面写的四段式正文;params.json对应参数表,声明每个参数的类型、默认值、校验规则;examples目录放测试用例,这一步非常推荐你养成习惯,因为技能升级时没有测试用例就没法做回归;manifest.json是部署清单,里面声明技能名、版本号、主Prompt路径、参数文件路径、依赖插件列表。

当你在Coze中导入技能包时,平台会先读manifest确认元信息,再把prompts/main.txt注入模型上下文,同时在运行时把params.json声明的外部参数映射成Prompt里的占位符。理解这个机制后,你就明白为什么参数表必须和Prompt里的{{占位符}}一一对应,也明白为什么不能把参数配置文件删掉,一旦占位符找不到对应的参数声明,技能包导入就会校验失败。

注意:技能包版本号一定要在每次修改后递增,并在manifest里保留changelog字段。我在实际开发中吃过一次亏,因为版本号没改,线上Bot缓存了旧技能,查了半天才发现是新包没生效。

3.3 一键批量生成可部署技能包的自动化方案

既然模板和参数表都固定了,批量生成技能包就成了一个工程问题。这里提供一个轻量级方案:用Python写一个模板渲染脚本,把Prompt模板文件读进来,替换掉变量位,再自动生成manifest和params.json,最后输出一个标准的技能包目录。

原理很简单,核心就是两次替换。第一次是模板变量替换,把SKILL模板里的{{role}}、{{task}}、{{constraints}}、{{output_spec}}替换为具体的技能定义;第二次是参数映射替换,把运行时占位符{{input_text}}、{{max_length}}等和params.json做一次交叉校验,确保没有未注册的占位符。Python脚本可以用jinja2作为模板引擎,也可以直接用字符串Template,关键是逻辑要清晰。

下面是一个简化示例,展示核心骨架:

import json from pathlib import Path from string import Template def build_skill_pack(cfg: dict) -> None: prompt_tpl = Template(Path("prompt_template.txt").read_text(encoding="utf-8")) main_prompt = prompt_tpl.substitute( role=cfg["role"], task=cfg["task"], constraints=cfg["constraints"], output_spec=cfg["output_spec"], ) out_dir = Path(cfg["name"]) (out_dir / "prompts").mkdir(parents=True, exist_ok=True) (out_dir / "prompts" / "main.txt").write_text(main_prompt, encoding="utf-8") (out_dir / "params.json").write_text( json.dumps(cfg["params"], ensure_ascii=False, indent=2), encoding="utf-8" ) (out_dir / "manifest.json").write_text( json.dumps({"name": cfg["name"], "version": cfg["version"], "main_prompt": "prompts/main.txt"}, ensure_ascii=False, indent=2), encoding="utf-8", )

整套流程跑通后,你就能在一个配置文件里维护几十个技能的差异点,然后一条命令批量产出所有技能包。对我来说,这是从"手艺人模式"切换到"流水线模式"的关键一步。特别是当团队里多人协作维护技能库时,只需要让大家各改各的配置区块,生成脚本统一处理,就避免了合代码时Prompt互相覆盖的尴尬。

4. 踩坑记录与排查技巧:把Skill从能用调到好用

4.1 我在部署Skill时反复踩过的5个坑

坑一:Prompt过长导致上下文污染。我早期写过一份特别详尽的Skill Prompt,洋洋洒洒两千多字,看起来面面俱到,实际上模型执行时被大量无关细节干扰,输出的摘要反而丢掉了重点。后来把Prompt压缩到500字以内,只保留角色、任务、约束、输出四段,性能立刻稳定了。这里给一个经验值:单技能Prompt控制在300到800字之间,超过800字就要考虑把一部分逻辑改成工作流。

坑二:参数名不一致导致注入失败。有一次我在Prompt里写了{{source_text}},但在params.json里注册的参数名是{{text_content}},运行的时候模型完全没有接收到外部传入的文章内容。这个问题表面看是手滑,根本原因是缺少自动化校验。从那以后,我每次部署前都会跑一遍脚本,把Prompt里所有{{占位符}}提取出来和params.json做并集比较,多一个少一个都能立刻发现。

坑三:插件与Skill职责不清晰。我之前做过一个数据整理技能,既想让它做数据清洗,又想让它顺势调用数据库插件写入结果,结果技能本身复杂了,插件又多了一个,整体调试成本飙升。后来我把"清洗"和"写入"拆成两个技能,各自只做一件事,再用工作流串联,稳定性好了很多。职责边界的事,越早划清楚成本越低。

坑四:只测正例不测反例。很多人在测试Skill时只喂几个典型输入,看到输出不错就发布。结果技能上线后,遇到空输入、超长输入、恶意输入时,行为完全不可控。正确做法是每个技能至少准备5个测试用例:2个正例、1个边界例、1个空输入例、1个异常格式例,并且把这5个用例存进examples目录,方便后续回归。

坑五:版本管理混乱。技能包改了十几版之后,目录里堆满了skill_v1、skill_v2_final、skill_v3_真正最终版这种命名,几乎没法追溯谁改了哪个参数。建议从一开始就用manifest里的版本号管理,每次改动必须更新版本号和changelog,目录只保留最新版,旧版全部走版本控制系统存档。

4.2 快速排查定位问题的四步法

如果你发现某个Skill上线后输出不对,不要急着改Prompt,先按顺序走一遍排查流程。

第一步,查输入。在Coze的调试记录里确认外部参数是否真的传进来了,参数名是否和Prompt里的占位符匹配。很多"输出不对"其实是"输入没到",这一步能排除掉至少三成的案例。

第二步,查Prompt静态结构。把主Prompt完整拉出来,检查四段是否齐全,约束段是否覆盖了当前失败场景,角色段会不会和任务段矛盾。我有一个习惯:每次排查都把Prompt里每个{{占位符}}高亮出来,人工确认一遍它们的上下文位置,很多时候参数其实传对了,但占位符被写进了约束段,导致模型根本没有把它当作输入变量。

第三步,做最小复现。构造一个最简单的输入,只触发当前失败的路径,把Skill的输出和工作流后续节点的预期对齐。最小复现的价值在于,它能帮你区分是Skill本身的问题还是工作流串联的问题,这两个问题的修法完全不同。

第四步,回归对比。把当前版本和上一个可用版本的输出放在一起对比,通常是某个约束条件或者参数默认值在改动的过程中被误删了。这四步走完,90%的Skill问题都能锁定在具体某一层,剩下10%属于模型偶发表现,重试或者小幅调整Prompt即可。

4.3 把Skill Prompt从"能用"调到"好用"的进阶思路

基础模板能保证技能稳定,但离"好用"还有一段距离,我把调优经验总结成四点。

第一,加入少样本示例。如果输出规范对格式要求高,光写JSON结构描述还不够,模型偶尔会在字段命名上自由发挥。此时在Prompt末尾附加一个参考示例,给一组真实的输入和期望输出,模型的格式遵守度会立竿见影。示例要选"中等难度"的,太简单学不到规律,太难会挤占上下文。

第二,设置主动拒绝策略。专业技能必须敢于说"不"。比如你做的是法律咨询技能,遇到非法律问题就应该明确拒绝并引导用户回到正轨,而不是硬着头皮回答。在约束段里写好"当任务超出能力边界时,直接返回固定提示语并将is_out_of_scope字段置为true",这种策略能让技能在开放环境中长期保持信誉。

第三,输出后处理。有些技能的输出需要再走一步机器校验,比如解析JSON、校验字段类型、检查枚举值范围。我通常会在技能外层包一层轻量后处理逻辑,如果模型输出不合法,不是重新跑模型(成本高且不稳定),而是基于模型部分有效内容做修正,或者触发fallback提示。记住,模型输出是概率性的,后处理才是确定性的兜底。

第四,控制技能复用粒度。一个技能只解决一类问题,不要搞成"瑞士军刀"。我在项目里见到最典型的问题就是把"文本总结"和"情感分析"塞进同一个技能,结果模型一会输出摘要,一会输出情感标签,格式总是打架。拆开之后每个技能都专注,复用率高,调试也简单。

我个人在实际操作中还有一个体会:写Skill Prompt不要追求一次性完美,先按模板搭一个能用版本,跑通之后再看实际表现逐步调优。大部分人在第一步就卡住了,因为总想着把所有边界情况都提前想到,结果反而迟迟交付不了。先用模板把骨架立起来,再用测试用例把血肉填起来,这才是技能包从模板到落地的最短路径。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进