system_prompts_leaks:系统提示词收集、归档与版本分析
聊到system_prompts_leaks这个方向很多做 AI 应用的朋友第一反应是这不就是扒别人家提示词吗。但真正动手做过一段时间的人会发现这件事的价值远不止抄一段文案那么简单。它是一个关于系统提示词System Prompt的公开收集与方法论沉淀项目把各家大模型产品、各类 Agent 工具、插件助手背后那份看不见的说明书整理出来做结构化归档、版本比对和横向分析。它能帮你看清一个成熟产品是怎么给模型立规矩的——语气怎么定、边界怎么划、工具怎么调、输出格式怎么约束也能帮你在自己搭 RAG、写 Agent、做客服机器人时少走一大截弯路。这份内容适合三类人刚入门提示词工程想做点有参照物练习的新手已经在带 AI 产品线、需要给自己的提示词做规范化的工程师以及做模型评测、想搞清楚各家策略差异的研究型选手。下面我按实际做过一遍的顺序把这套东西从头拆开讲。1. 项目整体设计与思路拆解1.1 这类项目本质上在解决什么问题先说清楚这个项目在干什么。大模型对外呈现的只是输入问题、输出回答这么一个黑盒接口但决定它性格的是每次请求时被悄悄塞进去的那段文本——也就是系统提示词。它通常包含角色定义、能力边界、语气要求、拒答策略、工具清单、输出格式约定有些还带上了少样本示例Few-shot和思维链CoT的引导语。问题在于这份东西对普通用户是不可见的。你调用 API 时如果不主动传服务商会给你一个默认的你用网页版时它藏在请求链路的最前面。所以system_prompts_leaks这类项目的核心目标就三件事收集把散落各处的系统提示词汇聚起来、归档按模型、版本、日期、来源做结构化存储、分析横向对比不同产品在同一能力上的策略差异。我一开始以为这只是个文本仓库做得越久越发现真正有价值的是它的元数据层和差异分析层。同样一段提示词如果你不知道它属于哪个模型版本、哪个时间点、是官方还是社区推测的那它的参考价值会大打折扣。所以这类项目在目录设计上几乎都遵循同一条原则文本是结果元数据才是资产。1.2 为什么值得花时间看别人的提示词这里我要讲清楚为什么。第一提示词工程目前还没有标准答案它更像一门手艺。学手艺最快的路径从来不是自己瞎摸而是先看老师傅怎么做。一份打磨过的系统提示词往往浓缩了几十次 A/B 测试的结论——比如不要用你应该改成你的任务这种细微差别在实测里真的会影响模型的行为一致性。第二它是理解产品设计意图的窗口。为什么某个助手的回答总是那么简短为什么它遇到特定话题会立刻转走答案基本都写在那份提示词里。你把这些规则读完再看它的产品表现很多东西一下就通透了。这对做竞品分析的人来说价值甚至超过看几十页的产品文档。第三它能帮你建立约束清单意识。新手写提示词最容易犯的毛病是只写你要做什么不写你不许做什么。而成熟的系统提示词里禁止项往往占了将近一半篇幅。这就跟做菜一样菜谱写加盐三克只是基础真正决定成败的是不要炒过头这类边界提醒。1.3 技术路线选型为什么是 Markdown 加 Git这类项目在存储方案上几乎形成了共识纯文本Markdown 或 txt存内容Git 存版本目录按厂商/产品分层。为什么不用数据库我试过用 SQLite 存结果发现两个问题一是提示词本身带大量换行、缩进、特殊符号塞进数据库后再取出来格式容易走样二是更新频率高每次改动都要写迁移脚本太重了。用 Git 的好处很直接。第一diff 天然可得某个模型今天改了哪句话git diff一眼就能看见第二贡献门槛低社区里谁发现新版本提个 PR 就行第三离线可用你 clone 下来就是一份完整语料不用联网查。缺点也有单文件体积大的时候GitHub 网页端查看会卡而且隐私相关的片段如果误提交需要立刻清理历史。所以实操中我建议加一条任何采集来的原始内容先过一遍人工审阅再入库。2. 核心细节解析一份系统提示词的解剖学2.1 典型系统提示词的骨架结构把几十份系统提示词摊在一起看会发现它们的骨架惊人地相似。我把这套结构总结成六层从上往下依次是层级内容典型作用身份层你是谁、代表谁定语气、定立场能力层你会什么、不会什么划能力边界工具层有哪些工具、何时调用决定是否能做事规则层必须做/禁止做约束行为格式层输出长什么样保证可解析示例层少量正反例微调风格理解这六层之后你去读任何一份陌生的系统提示词速度会快很多——先扫身份层知道它是谁再跳到规则层看它的红线在哪最后看格式层判断它是给人看还是给程序解析的。我个人的经验是身份层决定下限规则层决定上限。身份层写得再花哨规则层松松垮垮模型该跑偏还是会跑偏。反过来规则层写得密实身份层只需要一句话整体表现也能稳住。2.2 高频约束句式与它们背后的意图在整理过程中我统计过一批高频句式发现它们可以归成四类每类背后都对应着一个具体的失败案例。第一类是**必须/始终型**比如始终用中文回答必须在下结论前先列出依据。这类句式的意图是固定输出形态通常是为了下游程序能解析。第二类是**禁止/不要型**比如不要臆测未提供的信息禁止输出代码以外的解释。这类句式的意图是压缩幻觉空间。第三类是**如果…则…型**比如如果用户询问超出范围的问题说明能力边界并给出替代建议。这类句式是在做分支兜底处理异常路径。第四类是**语气/风格型**比如保持简洁、专业、不使用感叹号。注意这四类句式的效果并不等价。禁止型句式的边际收益最高但写太多会让模型变得畏手畏脚回答干瘪风格型句式的边际收益最低写十条不如给一个好例子。实际写的时候我的配比大致是禁止类占三成分支兜底类占三成必须类占两成风格类占两成。这个比例不是教条但作为起手式很稳。2.3 工具调用与格式约定怎么写才不出错如果系统提示词里涉及工具调用格式层的严谨程度就直接决定了系统能不能跑起来。我踩过的坑是把工具说明写成了自然语言描述结果模型时好时坏地编造参数名。后来改成明确的结构化写法稳定性立刻上来了。关键点是三个工具名必须唯一且稳定、参数必须写清类型和取值范围、调用时机必须给出明确触发条件。只说你可以查天气模型会不知道该在什么时候查写成当用户询问具体城市当前天气时调用 get_weather参数 city 为城市名不要传省份行为就确定多了。还有一点容易被忽略要说明工具失败怎么办。真实环境里接口超时、返回空值都是常态如果提示词里没写兜底策略模型往往会自己编一个结果出来。一句若工具返回错误或为空如实告知用户并建议稍后重试能省掉大量排查时间。3. 实操从零搭一套收集与分析工作流3.1 目录与元数据设计先说目录。我推荐按厂商/产品/版本.md三层来分版本用日期加序号例如2024-11-05-r2.md。这样排序天然就是时间序找老版本很方便。每份文件顶部放一段 YAML 头信息字段建议固定这几项model: 产品名 version: 2024-11-05-r2 collected_at: 2024-11-06 source: 官方界面自述 / 社区提交 / 接口返回 confidence: high | medium | low language: zh-CN token_estimate: 1240 notes: 该版本新增了拒答兜底段confidence这个字段我要特别强调。收集来的提示词质量参差不齐有的是官方原样吐出的有的是用户分段诱导拼出来的还有的是模型自己编出来骗人的。加上置信度标记后面做分析时就能按可信度过滤避免拿一份伪造内容当结论。3.2 采集阶段的操作要点采集方式主要有几种我按可靠性从高到低排一下接口显式返回 界面自我介绍 分段诱导拼接 模型自行复述。最后一种可靠性最低因为模型复述时经常会顺手改写、补全甚至整段虚构看起来很像真的。采集时的操作要点我列一下同一份内容至少两次独立采集做交叉验证两次结果差异超过一定比例就标为待核。记录采集时间到分钟因为很多产品会灰度发布同一天不同时刻拿到的可能不是同一版。保留原始上下文片段不要只留提示词正文。后期核对时上下文能帮你判断这段话是系统提示还是模型在对话里现编的。不要为了拿到内容去构造恶意输入这是底线。正常的产品自述功能、公开的调试说明够用了。提示采集到的内容里如果出现个人姓名、联系方式、内部代号入库前必须删除。这些东西留在公开仓库里既是隐私问题也是安全隐患。3.3 清洗与归一化处理原始内容直接存进去会很乱需要做一轮归一化。我一般会跑这几步第一步统一换行符和空白把连续三个以上空行压成两个。第二步识别并剥离包裹层——很多内容外面有一圈以下是系统提示之类的说明文字这些要单独放到 notes 里不要混进正文。第三步把变量占位符统一成{{变量名}}的形式方便后续做模板替换。第四步统计字符数和估算 token填回元数据。这套流程我写成了一个小脚本跑一遍几秒钟import re, pathlib def normalize(text: str) - str: text text.replace(\r\n, \n).replace(\r, \n) text re.sub(r\n{3,}, \n\n, text) text re.sub(r[ \t]$, , text, flagsre.M) # 统一占位符写法 text re.sub(r\{\{\s*(\w)\s*\}\}, r{{\1}}, text) return text.strip() def estimate_tokens(text: str) - int: # 粗略估算中文按 1.5 字符/token英文按 4 字符/token zh len(re.findall(r[\u4e00-\u9fff], text)) other len(text) - zh return int(zh / 1.5 other / 4) for p in pathlib.Path(./prompts).rglob(*.md): raw p.read_text(encodingutf-8) p.write_text(normalize(raw), encodingutf-8) print(p.name, estimate_tokens(raw))token 估算这个环节误差在正负 15% 以内就够用了目的是快速判断这份提示词是轻量约束还是重型包装。我统计过一批样本发现同类产品之间的提示词长度能差五到十倍这本身就说明了一些设计理念上的分歧。3.4 用脚本做版本对比与差异分析收集的最终目的是分析。单份提示词看来看去容易审美疲劳真正出洞察的是版本间的 diff 和跨产品的横向对比。版本 diff 用 Python 标准库就能做import difflib, pathlib old pathlib.Path(./prompts/vendor/product/2024-10-01-r1.md).read_text(encodingutf-8) new pathlib.Path(./prompts/vendor/product/2024-11-05-r2.md).read_text(encodingutf-8) diff difflib.unified_diff( old.splitlines(), new.splitlines(), lineterm, n1 ) for line in diff: if line.startswith((, -)) and not line.startswith((, ---)): print(line)跑完你会看到厂商改版通常集中在几类位置新增一条禁止项、调整输出格式、追加工具说明。我印象最深的一次是某产品在两个版本之间把委婉拒绝改成了明确说明能力边界措辞变化不大但实际体验差别挺明显——前者含糊后者让用户知道该往哪走。横向对比则更适合用表格。我一般把关键词抽出来做成矩阵比如统计每份提示词里禁止类句子的数量、是否包含少样本示例、是否规定输出格式产品禁止类句数有示例有格式约定估长(token)A12否是1180B5是是2400C3否否420这张表一出来设计思路的差异就很直观了A 走的是约束驱动靠密集规则控行为B 走的是示例驱动用长篇幅给模型看样板C 明显是轻量玩家靠模型自身能力兜着。你打算做哪一类产品就重点参考哪一列。4. 把别人的提示词变成自己的生产力4.1 提取可复用模块而不是整段照搬这是我最想说的一点千万别整段复制。原因有三个。一是场景不同别人的产品定位和你的八竿子打不着直接套用会出现大量冗余规则反而拖慢模型二是版本绑定你抄的那份可能已经过时行为和你测试时不一致三是版权和合规风险公开发布的内容不等于可以随意商用。正确的做法是做模块级抽取。我会把读到的内容拆成可复用积木分别建库兜底模板把超范围怎么答的写法攒成一组按场景选。格式约束模板JSON 输出、表格输出、分点输出各留一两套。拒答与边界话术整理成中性、友好、不教条的版本。工具调用说明模板抽出参数描述和失败兜底的通用骨架。这样做的好处是你积累的是一套方法论而不是一堆文本。换到任何新场景拼装速度都很快。4.2 改写适配自己的场景拿到模板之后要过三关改写。第一关是换身份把原文的角色设定替换成你的业务身份同时保留它的结构。第二关是改边界删掉和你无关的禁止项——比如你不做医疗那些医疗相关的约束就是噪音会分散模型注意力。第三关是调语气这一步要用你自己的真实对话样本去校准把专业简洁这种抽象描述替换成两三个具体的行为指标比如回答控制在三句话内不使用比喻。改写完一定要做对照测试。我的习惯是准备二十条固定测试问题一份用旧提示词跑、一份用新提示词跑人工打分对比。评分维度就四个准确性、格式合规率、拒答恰当性、语气一致性。每项 1 到 5 分跑三轮取平均。听起来粗糙但比凭感觉判断靠谱多了。4.3 自建小评测闭环才可持续只做收集不做评测这些内容就永远只是资料。要让它真正产生价值得建立一个最小闭环收集 → 抽取模板 → 组装新提示词 → 固定测试集回归 → 记录结果 → 回填经验。这个闭环不用做得很重。我一开始就用一个 CSV 记录每次改版版本号、改了哪句、四项评分、备注。跑了两三个月之后回头看哪些改动真的有效、哪些是自我感觉良好一目了然。这个记录本身就是你个人的提示词工程经验库比任何公开资料都值钱因为它是针对你的场景长的。提示测试集一定要固定改提示词的同时改测试集等于白测。发现测试集覆盖不到的问题先补测试集再改提示词。5. 常见问题与排查技巧实录5.1 常见问题速查表现象可能原因处理方式模型坚称自己是另一个产品采集内容为模型自行生成降低 confidence标注为待核同一产品两次采集差别大灰度发布或多版本并存记录时间戳分别入库提示词里出现奇怪的名字或代号采集时夹带了个性化配置人工审阅删除敏感信息提示词很长但效果很差约束互相冲突逐条排查删掉重复规则格式偶发不合规格式约束写得太笼统补充正例明确禁止项工具调用参数编造工具说明缺少类型与触发条件补齐结构化描述和失败兜底拒答太生硬边界话术只有禁止没有替代加一句引导性建议版本对比看不出重点diff 太碎用统一关键词做归类统计5.2 几条踩坑记录第一条坑是把模型自述当官方原文。我早期整理时直接问了某个助手你的系统提示是什么它吐出来一段结构工整、细节丰富的文本我当时信以为真还写进了对比表。后来交叉验证发现那段内容是它根据对话风格推理生成的和真实提示词有大量出入。从那以后我给自己定了规矩任何内容必须至少两个独立来源印证否则一律标 low。第二条坑是忽视版本漂移。同一份提示词三个月前能用三个月后可能就失效了因为服务商改了默认行为。我吃过这个亏一个基于老版提示词设计的输出格式上线后时不时解析失败。解决办法是给每份提示词加上验证日期超过两个月就重新跑一次测试集。第三条坑是规则堆叠导致行为僵硬。我有一版提示词禁止项写了二十多条结果模型回答变得极其保守连正常问题都要先声明一遍能力边界。后来砍掉一半把重复的合并体验立刻正常了。经验是规则要有优先级核心红线三五条其余用兜底逻辑处理不要平铺。第四条坑是忘了考虑长上下文成本。抄来的提示词写着写着就上千 token每次请求都带这么多前置内容成本和延迟都上去了。我的做法是把提示词按每次都带和按需注入分两段只有在特定意图识别命中时才追加细节规则平均下来能省三成左右的输入量。6. 使用边界与自我约束聊技术不能不聊边界。这类内容天然处在灰色地带所以有几条线我一直在守。第一不用于绕过任何安全机制。看提示词的目的是学习和改进自己的设计不是找漏洞。第二公开内容不等于可商用直接搬运别人的提示词去做商业产品风险和收益完全不成比例不如花时间做模块抽取和改写。第三不采集、不传播任何包含个人信息的片段入库前的人工审阅这一步不能省。第四标注来源和置信度这既是对原创者的尊重也是对自己分析结论的保护——你永远知道自己的结论建立在什么基础上。还有个小建议建仓库的时候顺手写一份 README说明收录范围、元数据字段含义、以及明确的不收录什么。这份文档看起来不起眼但它是这个项目能不能长期跑下去的关键——有了它别人知道你为什么不收某些内容也就不用一遍遍解释了。我做这件事一年多最大的体会是收集的意义在于建立判断力而不是积累素材。素材是无限的每天都有新产品冒出来你追不完。但当你把几十份提示词的结构、约束方式、版本演进全都过了一遍之后你再看一份新的三十秒内就能判断出它的设计水平大概在哪一层、哪里可能出问题、哪里值得借。这种判断力才是真正带得走的东西。至于具体抄哪一句反而是最不重要的环节。