如果你稍微接触过大模型应用开发,就一定听过这句话:系统提示词决定了模型的上限。我做了几年对话系统相关的开发,OpenClaw是我最近在推进的一个智能体项目,它的核心是系统提示词的构建机制。坦白说,提示词本身不难写,难的是怎么在复杂的多轮对话、多工具调用场景里,让提示词始终“稳得住”,既不啰嗦冗余,也不遗漏关键约束。这篇文章就把OpenClaw的提示词构建思路拆开来讲,从前期的设计拆解、模块划分,到动态组装、回归测试和常见故障的排查,全程用我实际踩过的坑作为注脚,希望能给正在做同类项目的人一些实证参考。
市面上的大模型应用,大部分输出质量波动都出在提示词本身——不是模型不行,而是提示词没有把模型的“角色感”和“行为边界”完全立住。OpenClaw最开始也是靠单段长提示词硬撑,后来在实际测试中频繁出现规则冲突、上下文污染、记忆错乱,才慢慢演化出当前这套分层的构建机制。这篇文章不是理论堆砌,更像是我在重构过程中的工程笔记。如果你也在做智能体、AI助教、客户助手之类的东西,这里的很多细节可以直接拿过去用。
1. 系统提示词:大模型行为的“隐形方向盘”
1.1 为什么系统提示词能决定输出质量
先说一个我在OpenClaw开发中反复验证过的结论:模型生成内容的质量,大部分在进入对话之前就已经被确定了。你给它什么样的身份设定、什么样的行为准则、什么样的任务上下文,它就大概率返回什么水平的结果。模型本身是通用的,但系统提示词是为它划定“工作方式”的那个角色。
很多新手会有一个误区,觉得提示词就是把需求写清楚就够了。我早期也这么干过,后来发现差得远。需求写清楚只是第一步,更关键的是让模型理解它的“岗位职责”。比如同样让模型写一段产品介绍,如果是客服助手,它必须保持服务语气,不能过度承诺;如果是技术助手,它要更偏向方案拆解和数据严谨性。角色如果没有在系统提示词里立住,后续所有对话都容易跑偏。
OpenClaw的系统提示词设计,本质上是在回答一个问题:我们希望模型在哪些维度上保持一致性?从我自己的项目实践看,至少包括三个维度:身份一致性、行为一致性、输出格式一致性。这三者缺一个,都会在长对话中被放大成明显的失控问题。
1.2 OpenClaw要解决的三类核心问题
OpenClaw这个名字是我自己项目里的叫法,它本质上是一个智能体框架,核心任务是把模型接入到真实的工具链里,让它能够调接口、查文档、处理指令。在这个过程中,系统提示词承担了非常重的协调职责。我总结下来,它要解决的主要有三类问题。
第一类是角色失控。模型在长对话中会出现“人格漂移”,比如你明明给它设定成严谨的技术顾问,聊着聊着它就会开始说“建议您可以试试”,语气变得像销售。这种现象在多轮对话后特别明显,早期OpenClaw几乎每周都会遇到。
第二类是规则冲突。当系统提示词里同时存在多条约束时,比如既要内容安全审查,又要快速响应用户需求,模型可能不知道优先级怎么排,结果就是安全审查卡住了正常回复,或者反过来,为了“快”把安全约束抛到脑后。这本质上不是模型笨,而是提示词没有把规则之间的优先级说清楚。
第三类是上下文污染。OpenClaw早期使用单一长提示词,把历史对话、用户信息、系统时间、工具返回结果全部塞进一个上下文里。结果模型经常混淆哪些是用户说的,哪些是工具返回的,导致回复变得牛头不对马嘴。后来我拆分了上下文区域,这个问题才被系统性压低。
这三类问题不是孤立的,它们往往互相纠缠。角色漂移会让规则执行的稳定性变差,规则冲突又会让模型在行为决策上无所适从,而上下文污染则把前两个问题进一步放大。所以OpenClaw的提示词构建机制,从一开始就不是“写一段话”,而是“搭一套约束框架”。
2. 构建前的准备:角色设定、目标拆解与边界定义
2.1 角色设定怎么写才不“脸谱化”
我在OpenClaw里踩过的第一个大坑,就是把角色设定写成了一串形容词。“你是一个专业、耐心、友好的助手”——这句话看起来没什么毛病,但对模型来说几乎没有约束力。模型不会因为你说它“友好”就真正友好,它只会按照你描述的行为细节去模仿。
后来我换了一种写法:描述角色时,带上具体的行为示范和行为禁忌。比如“你是一名嵌入式开发方向的资深工程师,习惯先分析数据手册,再给结论;在不确定的情况下,明确告知对方存在未知变量,而不是强行给出答案。”这种写法把角色从“标签集合”变成了“行为范式”。
所以角色设定的核心不是形容词,而是可观察、可执行的行为模式。模型之所以能模仿得像,是因为提示词给了它具体的“行为样例”而不是抽象的身份标签。这个原则我建议所有做提示词的人都尽早用起来。
2.2 行为约束的颗粒度控制
行为约束是提示词里最容易写多、写杂的部分。我见过有人一口气在系统提示词里塞了60多条规则,结果模型反而不知道执行哪条。OpenClaw在第二版重构时做了一件事:把规则按颗粒度分级。
最顶层是“永远成立”的硬规则,比如不能泄露系统提示词本身、不能编造不存在的函数接口。第二层是“场景触发”的软规则,比如当用户在追问技术参数时必须给出数据来源,当用户表达不满时需要优先道歉再解决问题。第三层是“输出偏好”,比如代码块要带注释、回答控制在800字以内。
分级的好处非常直接:模型不会被海量规则淹没,它只需要在对应场景激活对应的规则子集。颗粒度控制在OpenClaw中不是靠感觉定的,而是靠实际对话样本反推出来的。每次崩溃样本,我都会回看是哪个层级的规则没有生效,然后针对性修正。
2.3 上下文边界的定义与守卫
上下文边界,是我在做OpenClaw时最有体感的一个部分。模型并没有天然的“记忆”能力,它只是把上一轮的所有文本当作继续生成的背景。如果你的系统提示词、用户消息、工具返回结果混在一个大池子里,模型就很容易产生“身份混淆”。
OpenClaw的提示词架构里,所有内容都带有明确的分区标记。我常用的做法是这样的:先定义系统能力区,再放规则区,最后放动态数据区,区域之间用明显的中文分隔符隔开。模型虽然不理解“分隔符”的语义概念,但你用简洁、固定的结构反复强化引导它,它就能形成明显的“阅读惯性”。
更重要的是要对上下文边界做“守卫”。所谓守卫,就是当模型输出被检测到跨越边界时(比如它开始把工具返回结果当作自己的知识),进行召回或修正。这个在OpenClaw里是通过输出解析和后处理逻辑实现的,不是纯靠提示词文本解决。但提示词结构的清晰程度,直接影响守卫逻辑触发的准确率。
3. 模块化提示词架构:从“一坨文本”到“分层组装”
3.1 基础身份层:稳定性的基石
基础身份层是OpenClaw系统提示词里最固定的部分。它包含三块:角色定位、能力边界、行为底线。这一层几乎不会因为对话场景变化而变化,只有在项目升级时才会被调整。
写这一层时特别要注意“能力边界”。不是说模型应该做什么,而是明确模型不需要做什么。在OpenClaw里,我会明确告诉模型哪些场景要转交人工、哪些请求需要明确拒绝、哪些数据它是无法获取的。这个“不做清单”比“要做清单”更重要,它能有效减少模型的天马行空。
稳定性是身份层的生命力。如果你频繁修改身份层,模型的整体行为会变得很不稳定。我已经养成习惯:每次改动身份层前都会跑完整个回归测试集,对比改动前后的输出差异,确认只影响目标场景,不波及其他功能。这是一种面向风险控制的更新策略。
3.2 能力声明层:告诉模型“你有什么牌”
能力声明层要解决的核心问题是:让模型知道在特定场景下,它可以通过哪些工具、函数、数据源来完成用户的请求。没有这一层,模型就像一个不知道自己工具箱里有什么工具的工人,只能在想象中瞎干。
在OpenClaw里,能力声明层的写法经历了几次版本迭代。最初我写得非常详细,把每个函数的参数、返回结构全部罗列在系统提示词里,结果上下文膨胀严重,模型反而会因为信息过载而忽略部分工具。后来我优化成“能力摘要 + 按需详情”的模式:系统提示词里只写每个工具一句话能做什么,详细的参数在模型决定调用某个工具时再注入到用户侧的上下文区域。
这种方式有很明显的收益:模型理解成本降低,调用工具的成功率反而提升了。因为模型只需要在调用前获取必要的细节,不需要在每次对话时都扛着全套说明书。
3.3 规则约束层:行为红线的具体落地
规则约束层是OpenClaw在提示词构建机制中投入迭代时间最多的模块。它本质上是在回答两个问题:哪些事绝对不能做,哪些事在什么条件下可以做。这两个问题如果不明确,模型的行为就会忽左忽右。
具体到写法,我总结出一个非常实用的公式:规则描述 = 触发条件 + 禁止行为 + 替代路径。举个例子:“当用户请求中包含明显情绪负能量时,不要对用户的要求进行是非评判,而是先以确认共情的方式进行回复。”这里触发条件是情绪负能量,禁止行为是是非评判,替代路径是共情式确认。三条信息缺一不可,否则模型就不知道该在何时以何种方式执行规则。
规则约束层很容易越写越长,所以我设置了上限:单条规则描述不超过50个字,同一层级下的规则总数不超过12条。如果超过,我就会考虑把规则下放给特定场景的子提示词去承载。这个规则已经成了OpenClaw提示词开发的一个纪律性要求。
3.4 任务执行层:从“知道规则”到“完成任务”
任务执行层是OpenClaw的提示词中最具动态性的部分。它包含当前对话需要完成的具体目标、可参考的执行步骤、输出格式要求等。这一层会根据用户输入、业务场景甚至时间变化进行动态替换。
这里有个关键的经验点:不要试图在任务执行层里“引导”模型自由发挥,而是要把任务的验收标准写清楚。比如“当用户询问天气时,你需要调用天气查询工具并返回温度、湿度、未来3小时降雨概率三项数据,同时附上一句话简评。”当验收标准清晰时,模型会显著减少自我发挥的空间,输出内容也更可控。
任务执行层和工具调用逻辑的衔接,也是我在OpenClaw里花了不少心思的地方。模型决定调用工具之后,工具返回的结果需要被重新整合进它的上下文,而且要明确标识这是“工具返回结果”,而不是“模型自己生成的内容”。我在这些结果前加固定前缀,让模型知道接下来的文本是对用户问题的补充性应答材料,而不是它自身的表达。
3.5 记忆与上下文管理层:让模型“记性好”的秘诀
OpenClaw的记忆管理一开始非常混乱。模型对话超过10轮后,早期的关键信息会丢失,用户需要反复重复自己的需求。后来我引入了一个“三段式记忆管理”的思路,效果不错。
第一段是“固定档案”,比如用户偏好、已知项目背景,这部分始终保留在系统提示词内。第二段是“会话快照”,每5轮对话后总结一次当前对话的关键信息,替换掉早前冗余的完整历史。第三段是“指令性备忘”,当用户在对话中提出新的偏好或修正要求时,把它以指令形式加入促进短期遵循的上下文区域。
这套机制里最难的是如何判断哪些信息值得保留、哪些可以丢弃。我给出的经验是:只需要保留那些在未来对话中出现概率较高且影响响应行为的信息。判断方法也很简单——问自己,如果这个信息丢了,用户的下一句话会不会受到影响。如果答案是不会,那条信息就属于可丢弃的冗余上下文。
4. 变量注入与动态组装:让提示词真正活起来
4.1 变量占位设计:从写死到参数化的关键一步
如果一个系统提示词在所有场景下都是同一份模板,那它基本只适用于最简单的Demo。OpenClaw在正式版本里,把提示词做成了参数化模板——所有随时间变化的信息(时间、用户身份、工具状态、业务上下文)都以变量占位符的形式存在。
举个例子,OpenClaw的系统提示词中会有这样的结构:“今天是{{current_date}},用户所处的会员等级为{{membership_level}},当前会话的目标是{{session_goal}}。”在实际组装提示词时,框架会根据当前上下文去填充这些变量值。
变量占位设计的关键在于,哪些信息该用变量,哪些信息不该。我踩过的坑是,把一些本应该相对固定的行为规则也做成了变量,结果模型规则稳定性大幅下降。变量应该用于承载“事实信息”,而不是“约束信息”。事实信息可以随场景变化,但约束信息必须保持恒定。
4.2 动态检索与实时拼装:把提示词变成一个执行过程
OpenClaw的提示词组装,不是一次性把所有模块拼好就够了,而是根据当前对话阶段进行动态拼装。理论上模型每次请求的提示词都可能不同。这个做法大幅度提升了系统对复杂场景的适应力。
举个例子,用户在对话中如果只是简单询问“帮我推荐几个适合学习编程的资源”,系统拼装的提示词只需要身份层加一个任务执行层;如果用户进一步询问具体课程对比,系统则会把工具能力声明层调出来,并注入对比分析所需的输出格式模板。每次请求的上下文都经过裁剪,让模型只关注当前任务所需的最小必要信息。
这种动态拼装的实现方式并不复杂,本质上是模板渲染函数的多次调用。真正麻烦的是如何设计模块间的接口,确保拼接处的语义顺畅。我是这样处理的:每个模块都自带“进入语”和“退出语”,比如身份层结束时固定加上一句“以下是本次交互中你面对的场景信息。”这让模型在阅读时能自然切换理解区域。
4.3 版本控制与灰度发布:提示词也要像代码一样管理
提示词会在迭代中不断变化,而每一次变化都可能引入新的行为问题。OpenClaw从一开始就把提示词当作代码来管理。所有模块改动都走提交记录,每个版本会附带一份预期的行为变化说明。
这里我说一个很多开发容易忽略的细节:提示词的版本控制不仅要管文本内容,还要管评测样本集的版本。因为当你访问某一版提示词的历史时,你还需要当时用来测试它的那些样本和判定标准,否则你无法判断它为什么会表现好或差。
灰度发布是另一个在OpenClaw里做得很关键的动作。就算我有很强的直觉认为某个新规则会带来正向效果,我也不会直接全量替换。我会先切一小部分流量,对比在线数据中的失败率和回复长度等指标,确认稳定之后再逐步放量。这个习惯帮OpenClaw避开了好几次隐性回归,尤其是那些在离线条例测试里看不出来的长尾问题。
5. 实测调优:从“能用”到“好用”的迭代方法
5.1 建立回归测试集:提示词改动的“安全网”
OpenClaw的提示词迭代如果没有回归测试集,我根本不敢频繁改动。回归测试集是我自己从历史真实对话里挑选出来的一批代表性样本,数量未必很多,大概一两百条,但它们的覆盖面非常重要。
我会按照多轮场景、单轮场景、风险场景、工具调用场景四类来分类,每类下面再细分子场景。每跑一次回归测试,我会人工逐条对比模型输出和期望输出的差异。做这个事很费时间,但它是保证提示词迭代安全性的最低成本方案。
回归测试集要持续更新。每当我发现某类问题在线上反复出现,我都会把对应的失败样本加入测试集,确保同类问题在后续迭代中不会再度复现。久而久之,测试集的质量会越来越高,提示词调优的容错率也会越来越大。
5.2 失败样本分析法:从个案反推规则缺陷
在OpenClaw提示词开发的早期,我习惯只看成功样本,觉得回复完美就说明提示词没问题。后来发现这是一种错觉。真正能暴露提示词缺陷的,恰恰是那些失败样本。
我的分析流程是这样的:拿一条模型输出不符合预期的样本,先记录它属于哪一类失败,再反向排查是哪一层提示词模块没有约束到位。有时候问题出在规则层没有写清优先级,有时候是能力声明层让模型误以为自己能够直接回答,还有时候是记忆管理层把历史信息丢得太早了。
失败样本分析最好是多人协作的,因为不同人看到的“失败”角度不同。至少在我维护OpenClaw的这几个月里,每次和团队成员一起翻失败样本,总能发现我单独分析时看不到的盲区。这个习惯强烈建议每个提示词开发团队都保留下来。
5.3 小步快跑:单变量调参而非大改
“大改一次,问题遍地”是我在OpenClaw开发中认得很深的一条教训。早期我经常因为一次不满意就重构掉整个提示词模块,结果改完不但没有变好,还把原来稳定的部分也搞懵了。
后来我给自己定下一条规矩:每次迭代只改动一个变量。要么只改身份层的一句话,要么只调规则层的某条优先级,要么只更新工具描述的关键词。改完之后,跑回归、看样本、判断效果,然后再决定下一步。这样做的直接好处是:当效果变差时,我能精确地知道是哪个改动导致了问题,而不是在一堆改动里大海捞针。
小步快跑听起来慢,实际上是最快的路径。因为提示词调优的曲线不是线性上升的,它会反复波动。只有保持变量可控,波动才能被快速识别和纠正。OpenClaw现在的提示词版本号已经迭代了几十版,但每一版相比上一版的变化都非常有限,这让整个系统的稳定性曲线始终处于可控范围。
6. 常见问题与排查技巧实录
6.1 模型“忘记”规则怎么办
这是OpenClaw开发中出现最频繁的问题:对话进行到中段,模型突然违反了系统提示词里的硬性规则。比如明确要求不能编造参数,它却开始一本正经地给出不存在的配置项。
首先我会排查规则是否被放在提示词的尾部。“尾部遗忘”是一种客观存在的现象,模型对提示词开头和结尾的内容更敏感,中间内容容易被忽略。如果你的规则在中间,试着把它移到靠近开头或者结尾的位置。
第二个排查点是规则表述是否过于抽象。我遇到过一条规则“回答内容应保持专业严谨”,这个表述太模糊,模型很难判断什么算专业严谨。改成“当涉及技术参数时,必须标注来源或声明参数未知”,模型的表现立刻改善。
第三个排查方向是上下文长度膨胀导致规则稀释。如果对话历史太长,模型可分配的注意力被历史内容占据,系统规则的权重就会下降。这时需要做的是启用对话摘要,而不是继续堆叠完整历史。我在OpenClaw中设定的触发值是历史文本超过一定长度时自动启用摘要,不是等模型出错了才手动干预。
6.2 提示词过长导致关键指令稀释
规则写得太多太长,模型反而抓不住重点。这个问题的本质是信息过载,不是模型能力不足。OpenClaw的一条针对性经验是:把“必须遵守”和“可以参照”分成两段书写,模型会对“必须”类信息保持更强关注。
再往深一层说,过长的提示词还会影响接口的响应时间。你发的每多一个token,回复首字延迟都会增加。为了控制提示词长度,OpenClaw做了很多取舍:能函数化处理的不要写成规则、能按需注入的不要常驻系统提示词、能用摘要替换历史的不要全量保留。
如果你发现提示词已经超过正常模型窗口的一半以上,我建议你做出一个结构性的压缩决定:把部分规则降级为“场景触发规则”,从全局提示词中移除,改为在特定场景中临时注入。这个做法在OpenClaw里帮我把主提示词的长度减少了四成多,而核心功能的稳定性反而有所提升。
6.3 多轮对话中模型表现的角色漂移问题
角色漂移是长对话系统中一个绕不开的挑战。OpenClaw早期在单个会话内对话超过10轮后,模型的语气和立场就会从“开发者助手”逐渐滑向“通用闲聊助手”,开始说一些与项目无关的客套话。
排查下来的主要原因是:多轮对话中的用户消息和历史回复,侵占了系统提示词应有的注意力权重。模型的上下文混合在一起,系统提示词不再是最具引导性的那部分。我的解决方向有两个。一是尽量缩短历史消息的长度,用摘要替换早期对话;二是在系统提示词里增加“每当用户的问题与该系统身份能力无关时,你应以设定的角色身份交换话术说明自己无法处理,而不是切换到通用助手的语气”。这个思路对OpenClaw非常有效。
角色漂移的另一个高频来源是模型输出里叠加了通用的“安全结构化”表达习惯。很多人没有意识到,有些通用回复措辞会与你的系统角色风格冲突。所以我在OpenClaw的系统提示词中明确加了一条:回答用户的任何问题时,不要使用“作为一种语言模型”这类表达。这一小步对消除角色漂移非常有用。
6.4 与工具调用冲突的典型场景
当系统需要调用外部工具时,系统提示词的构建就更需要注意了。OpenClaw在早期经常出现的一个冲突是:模型不知道怎么在回答中融合工具结果,导致输出要么直接把原始数据倒出来,要么忽略工具结果重新用训练记忆来回答。
我解决这个问题的办法是在提示词中明确给出“工具结果使用规则”:当工具返回的数据与用户问题直接相关时,必须以工具数据为准并标注数据来源;当工具返回结果不足以回答用户问题时,明确告诉用户信息有限,不要自行编造。这个规则加进去后,OpenClaw的工具调用输出质量有了明显提升。
还有一种冲突是模型“跳过工具直接回答”。这种情况通常会发生在工具描述写得过于模糊时,模型没有意识到自己需要调用工具。我的排查手段是把工具能力声明写得更有“强制感”,明确在何时必须调用,而不是列出“你可以使用”。语气上的细微差别,实际效果差距很大。对于一定要走的函数,我用“必须”而非“可以”。这个用词层面的变化,在OpenClaw的多次迭代中被验证是影响调用率的关键变量之一。
7. 一套值得长期固化的构建心法
OpenClaw的提示词构建机制走到今天,已经不再是单纯的“写提示词”这么简单。它更像是一套持续演进的系统工程。我回头看这几十次的迭代,真正长期起作用的心法其实可以归纳成几条很朴素的规则。
提示词模块边界要清晰,每一层只解决一个问题。不要在规则区里写任务描述,也不要在身份区里排布工具调用步骤。各守其位,模型才可能在长上下文里找到关键信息,不会被语义交叉带偏。结构化带来的收益不只是规范整洁,它更是在给模型降低理解负担。
尽量用“行为描述”代替“身份标签”。不要直接说你是专家,而是写出一个专家会如何思考、如何提问、如何限定答案边界。行为是模型可以模仿的,标签只是一个名词,实际约束力非常有限。这一点是OpenClaw在角色稳定性上取得突破的关键点。
动态组装并不意味着复杂。有时候最笨的办法——用一个清晰的模板函数,把可变信息填进固定结构——反而是最稳定的方案。不要在提示词构建初期就被所谓的高级技术带跑了,先把基础分层做好,再逐步加入变量和记忆管理,这是稳妥可复现的路径。
我也越来越相信一件事:提示词的调试和软件开发一样,需要回归测试、版本控制、灰度发布。它不是一个写一次就结束的静态文档,而是需要随业务变化持续维护的活系统。把提示词当作代码来对待,才能从根本上避免那些反复出现的低级错误。
如果你正在做一个类似OpenClaw的系统,我的建议是先花两天时间,把当前所用提示词的所有模块画出来,拆开看它们的边界和衔接。大部分问题,在你拿起笔的那一刻就已经找到了答案。高级技巧不是第一步,清晰结构才是。