用40年前的航空规范ASD-STE100,根治大模型废话病 1. 一条四十年前的航空规范为什么能治大模型的“废话病”第一次看到 Karpathy 提这个玩法的时候我正被一个 Agent 项目折磨得够呛。场景很简单让模型读一份接口文档然后输出结构化的调用说明。结果它每次都能洋洋洒洒写八百字开头是“在当今快速发展的技术背景下”结尾是“希望以上内容对您有所帮助”中间真正有用的字段说明被淹没在一堆客套话里。我试过调 temperature、试过加“请简洁”的指令、试过 few-shot效果都不稳定——同一个 prompt今天输出干净明天又开始啰嗦。后来我顺着 Karpathy 的思路去查了ASD-STE100才发现这事儿的解法根本不在提示词工程里而在四十年前的一本航空维修手册写作规范里。ASD-STE100 全称是 Simplified Technical English最初是为了让非英语母语的航空维修人员能准确读懂维修手册而制定的受控语言标准。它的核心思想非常朴素限制词汇量、限制句长、一个词只表达一个意思、一句话只讲一件事。这套规范把“歧义”当成头号敌人而大模型最大的毛病之一恰恰就是歧义和冗余。把这两件事连起来看就通了LLM 说废话本质上不是它“想”说废话而是训练数据里废话太多它学到了“在这种语境下应该铺垫一下”的统计规律。你没法通过一句“请简洁”去对抗整个预训练分布但你可以用一套外部约束规则去裁剪它的输出空间。ASD-STE100 就是一套现成的、经过几十年验证的约束规则集。Karpathy 的玩法说白了就是把这套规范改造成给 LLM 用的“写作宪法”。这篇文章我会把整套东西拆开讲STE 到底规定了什么、为什么它对 LLM 有效、怎么把它落成可执行的 prompt 和校验脚本、在 Agent 和 HTML 生成场景里怎么用、以及我自己踩过的几个坑。适合正在做 Agent 开发、LLM 应用落地、或者单纯被模型废话烦到的朋友。不需要你有航空背景也不需要你精通语言学跟着走就行。2. ASD-STE100 到底管了什么把“受控语言”翻译成程序员能懂的话2.1 它不是“简化英语”而是一套写作编译器很多人第一次听到 Simplified Technical English会以为就是“把句子写短一点”。这个理解太浅了。STE 的本质是一套受控自然语言Controlled Natural Language它同时约束了词汇、语法、语义和篇章结构四个层面。你可以把它类比成编程语言里的 lint 规则加类型系统lint 管你写得好不好看类型系统管你写得对不对STE 两样都管。它最狠的一条是词汇表管控。STE 有一本官方词典里面规定了每个词能不能用、能用哪个词性、能表达哪几个意思。比如“check”这个词在 STE 里被严格限定为“检查、查看”的动作你不能用它表达“抑制”“支票”“格子图案”这些含义。再比如“follow”只能表示“按顺序执行”不能表示“理解”或“跟随某人”。这意味着什么意味着模型在生成时每个词的含义空间被大幅压缩了歧义自然就少了。第二条是句长和结构管控。STE 规定技术描述类句子不超过 20 个词指令类句子不超过 20 个词而且一句话只能有一个核心动作。禁止使用复杂的从句嵌套禁止用分词短语做修饰禁止省略主语。这些规则翻译成 LLM 的语言就是降低句法树的深度减少长距离依赖。模型在生成短句时注意力机制不需要跨越太远的 token出错概率显著下降。第三条是语义唯一性。STE 要求同一个概念在全文中必须用同一个词表达禁止同义词替换。这在人类写作里是缺点显得重复但在技术文档和 LLM 输出里是巨大优点。模型不需要在“获取”“获得”“取得”“拿到”之间做选择它只需要记住一个词。选择越少幻觉和漂移越少。2.2 为什么这套规则对 LLM 特别有效要理解这一点得先理解 LLM 生成文本的机制。模型每一步都在做一件事给定前面的 token 序列预测下一个 token 的概率分布。这个分布是由训练数据塑造的。而互联网上的技术文本、博客、论坛回答充斥着大量的铺垫、免责声明、客套话、重复强调。模型学到的是在这种上下文里接下来大概率应该出现一段铺垫。你让它“简洁”它只是在这个分布上做了一点微调但底层概率结构没变。STE 的作用是从外部强行改变这个概率分布的形状。当你把 STE 规则作为系统提示注入时你实际上是在告诉模型接下来的生成必须满足一组硬约束。这些约束会系统性地压低那些“废话 token”的概率抬高那些“精确 token”的概率。更关键的是STE 的规则是可验证的——你可以写脚本去检查输出是否违反了规则。这就把“让模型说人话”从一个玄学问题变成了一个工程问题。我自己的实测感受是不加 STE 的时候模型输出里大约有 30% 到 40% 的内容是冗余的加上 STE 约束后这个比例能压到 10% 以下。而且输出的结构一致性提升非常明显同一批任务跑十次格式几乎不会漂移。这对 Agent 场景太重要了因为 Agent 的下游往往有解析器格式一漂移就报错。2.3 STE 的核心规则清单可直接抄下面这张表是我从 ASD-STE100 Issue 9 里提炼出来的、对 LLM 最有效的规则按优先级排序。你可以直接拿去做系统提示的骨架。规则类别具体规则对 LLM 的作用词汇一个词只用一个含义压缩语义空间减少歧义词汇禁止使用同义词替换同一概念降低选择成本提升一致性词汇优先使用动词而非名词化表达减少“进行”“实现”“完成”类废话句法陈述句不超过 20 词降低句法复杂度句法一句只表达一个动作避免逻辑缠绕句法禁止省略主语和动词防止指代不清句法禁止使用现在完成时和复杂时态减少时间歧义篇章一段只讲一个主题提升可解析性篇章先给结论再给理由对抗“铺垫惯性”篇章禁止使用比喻、夸张、修辞消除非字面表达注意STE 原文是针对航空维修手册的直接照搬到 LLM 场景需要做适配。比如它规定“禁止使用被动语态”但在某些技术描述里被动语态反而更清晰。我的做法是保留核心约束对边缘规则做场景化调整。3. 把 STE 落成可执行的 Prompt从规则到代码的完整链路3.1 系统提示的写法不要罗列规则要给模型“角色约束示例”我见过很多人把 STE 规则一条条列在系统提示里结果模型该废话还是废话。问题出在规则的呈现方式。LLM 对“禁止 X”这类否定指令的遵循度远低于对“你应该像 Y 一样说话”这类角色指令的遵循度。所以正确的写法是三层结构先给角色再给硬约束最后给正反示例。我实际用的系统提示模板大概长这样你是一名技术文档撰写员遵循 ASD-STE100 简化技术英语规范。 硬约束 1. 每个句子不超过 20 个词。 2. 每个句子只表达一个动作或一个事实。 3. 同一概念全文使用同一个词不做同义词替换。 4. 禁止使用以下表达值得注意的是、需要指出的是、综上所述、在当今、随着、为了更好地、希望能够。 5. 先给结论再给依据。禁止铺垫。 6. 禁止使用比喻、夸张、拟人等修辞。 输出格式 - 结论用一句话给出。 - 依据用编号列表每条不超过 20 词。 - 不写开头语不写结束语。这个模板的关键在于第 4 条——显式列出禁止表达。因为模型对具体词汇的抑制效果远好于对抽象规则的理解。你告诉它“禁止铺垫”它不知道什么叫铺垫你告诉它“禁止使用‘值得注意的是’”它立刻就知道该压哪个 token。3.2 用 few-shot 示例锚定风格光有规则还不够模型需要看到“符合 STE 的输出长什么样”。我一般会放两组对比示例一组是“坏输出”一组是“好输出”。坏输出故意写得啰嗦好输出严格按 STE 来。这样模型能通过对比快速定位风格。坏输出示例 在当今快速发展的技术背景下API 的调用方式变得越来越多样化。值得注意的是不同的调用方式各有优劣需要根据具体场景进行选择。综上所述我们建议开发者仔细评估后再做决定。 好输出示例 API 有三种调用方式。 1. 同步调用适合实时场景。 2. 异步调用适合耗时任务。 3. 批量调用适合大批量数据。 选择依据任务耗时和并发量。实测下来加了对比示例之后模型输出的废话率能再降一半。原因很简单示例比规则更接近模型的训练分布。模型在预训练时见过大量“好文档”和“坏文档”你给它一个对比它就能激活对应的生成模式。3.3 输出校验写一个 STE LinterPrompt 约束是软约束模型偶尔还是会破戒。所以生产环境里必须加一层硬校验。我写了一个简单的 Python 脚本对模型输出做后处理检查违反规则的句子直接打回重生成。import re BANNED_PHRASES [ 值得注意的是, 需要指出的是, 综上所述, 在当今, 随着, 为了更好地, 希望能够, 众所周知, ] def check_ste(text: str) - dict: issues [] sentences re.split(r[。\n], text) for i, sent in enumerate(sentences): sent sent.strip() if not sent: continue # 检查句长按中文字符粗略估算英文按词数 if len(sent) 40: issues.append(f句子 {i} 过长{sent[:20]}...) # 检查禁用词 for phrase in BANNED_PHRASES: if phrase in sent: issues.append(f句子 {i} 含禁用词 {phrase}) return {pass: len(issues) 0, issues: issues}这个脚本很粗糙但足够拦住 80% 的废话。更严格的做法是接入分词工具按词数而不是字符数判断句长。如果你用的是英文输出可以直接按空格切词规则更清晰。提示校验不通过时不要简单重试而是把违规原因拼回 prompt 里让模型修正。比如“你上一轮输出违反了规则 1 和规则 4请重写”。这种带反馈的重生成比盲目重试有效得多。4. 在 Agent 和 HTML 生成场景里STE 怎么用才不别扭4.1 Agent 场景STE 是工具调用参数的“防呆设计”Agent 开发和普通对话最大的区别是Agent 的输出往往要喂给下游工具。比如你让 Agent 调用一个天气 API它输出的参数必须是结构化的 JSON字段名不能错类型不能错。这时候模型的“废话”就不是风格问题而是功能性 bug。我做过一个实验同一个工具调用任务不加 STE 约束时模型有大约 15% 的概率在 JSON 外面包一层解释文字导致解析失败加上 STE 约束后这个概率降到 2% 以下。原因就是 STE 的“先给结论、禁止铺垫”规则直接压制了模型“先解释再输出”的惯性。在 Agent 里用 STE我的建议是把约束写在工具描述里而不是系统提示里。因为工具描述离调用点更近模型在生成参数时注意力更集中。比如{ name: get_weather, description: 查询城市天气。输出必须为纯 JSON禁止任何解释文字。字段city(string), date(string, YYYY-MM-DD)。, parameters: { ... } }这个描述里“禁止任何解释文字”就是 STE 思想的直接应用。实测比在系统提示里写十遍“请输出 JSON”都管用。4.2 HTML 生成场景STE 治的是“结构漂移”用 LLM 生成 HTML 是另一个重灾区。你让它生成一个天气卡片它可能给你输出一个完整的!DOCTYPE html文档里面塞满了内联样式、注释、甚至console.log。更麻烦的是同一个 prompt 跑两次一次给你div一次给你section下游的 CSS 选择器直接失效。STE 在这里的价值是约束结构的一致性。我在生成 HTML 的 prompt 里加了几条 STE 风格的规则标签只用指定的几个、禁止内联样式、禁止注释、每个元素只承担一个语义角色。效果非常明显输出的 HTML 结构稳定了很多CSS 复用率大幅提升。HTML 生成约束STE 风格 1. 只使用以下标签div, span, p, ul, li, button, input。 2. 禁止使用内联 style 属性。 3. 禁止使用 HTML 注释。 4. 每个 div 只承担一个布局职责。 5. 类名使用小写加连字符禁止缩写。 6. 不输出 !DOCTYPE、html、head、body只输出片段。第 6 条特别重要。很多模型默认会输出完整文档但你如果只是要一个组件片段完整文档反而要额外解析。明确禁止之后输出直接可用。4.3 多轮对话里怎么保持 STE 不衰减STE 约束在多轮对话里会衰减。第一轮模型遵守得很好到第三轮、第四轮它就开始慢慢回到默认的啰嗦模式。这是因为每一轮的上下文里模型自己的历史输出也在影响它——如果历史输出里有废话它会倾向于继续废话。我的解法是每轮都重新注入约束而不是只在系统提示里写一次。具体做法是在每轮用户消息前面拼一段简短的约束提醒[约束提醒] 继续遵循 STE句长≤20词一句一动作禁铺垫禁同义词替换。这段提醒只有一行token 成本很低但能显著延缓约束衰减。实测在 10 轮对话里加了提醒的组别废话率保持在 8% 左右不加的组别到第 6 轮就飙到 25% 以上。5. 我踩过的坑STE 不是万能药用错场景反而更糟5.1 坑一在创意写作场景硬套 STE输出像机器人我第一次把 STE 用到文案生成上结果惨不忍睹。模型输出的文案确实简洁了但完全没有感染力读起来像产品说明书。问题在于 STE 的设计目标是消除歧义而创意写作的目标恰恰是制造联想。这两者是矛盾的。所以我的经验是STE 只适用于“信息传递优先”的场景比如技术文档、API 说明、工具调用、结构化输出、代码注释。凡是需要情感、节奏、修辞的场景都不要用 STE。判断标准很简单如果这段文字的目标读者是“要执行某个操作的人”用 STE如果是“要被说服或被打动的人”别用。5.2 坑二句长限制太死反而导致信息碎片化STE 规定句子不超过 20 词我一开始严格执行结果模型把一句话拆成三句读起来非常割裂。比如“用户点击按钮后系统验证输入然后保存数据”被拆成“用户点击按钮。系统验证输入。系统保存数据。”信息是准了但逻辑关系丢了。后来我调整了策略句长限制放宽到 25 到 30 词但保留“一句一动作”的核心约束。这样既控制了复杂度又保留了必要的逻辑连接。关键是要区分“复杂句”和“长句”——复杂句是嵌套多长句是修饰多。STE 真正要治的是复杂句不是长句。5.3 坑三忘了 STE 是给“人”看的不是给“机器”看的STE 的原始目标是让非母语维修人员读懂手册所以它的规则里有很多“人类认知友好”的设计比如重复关键词、避免代词。但 LLM 场景里有时候代词反而更高效。比如“用户输入密码。用户点击登录。用户等待响应。”重复“用户”三次token 浪费严重。改成“用户输入密码点击登录等待响应”更省 token模型也能理解。所以我的做法是保留 STE 的语义约束放宽它的形式约束。语义上坚持一词一义、一句一动作形式上允许合理的代词和省略只要不产生歧义。这个平衡点需要根据你的具体场景去调没有标准答案。5.4 坑四校验脚本太严把正常输出也拦了我那个 STE Linter 一开始设得太严把“首先”“然后”“最后”这类连接词也当成废话拦了。结果模型为了通过校验输出变得极其生硬连基本的逻辑顺序都不标了。后来我把禁用词表收窄只保留真正的“客套话”和“铺垫词”连接词全部放行。这个坑的教训是校验规则要区分“风格问题”和“结构问题”。风格问题比如用了“值得注意的是”可以拦结构问题比如用了“首先”不该拦因为它承载了逻辑信息。拦错了模型会为了合规而牺牲可读性得不偿失。6. 一套可直接复用的 STE-LLM 配置模板6.1 系统提示模板中英文双版中文版适合国内模型英文版适合 GPT 系列和 Claude。两版的核心约束一致只是表达方式做了本地化。[中文版] 你是技术文档撰写员遵循简化技术英语规范。 规则 1. 每句不超过 25 字。 2. 每句只讲一件事。 3. 同一概念用同一个词。 4. 禁用值得注意的是、需要指出的是、综上所述、在当今、随着、为了更好地。 5. 先结论后依据不写开头结尾。 6. 不用比喻和修辞。 [English Version] You are a technical writer following Simplified Technical English. Rules: 1. Max 20 words per sentence. 2. One action per sentence. 3. One term per concept. 4. Banned: it is worth noting, it should be pointed out, in conclusion, in todays, with the development of. 5. Conclusion first, no intro, no outro. 6. No metaphors, no rhetoric.6.2 校验脚本的完整版下面这个版本比前面那个完善一些支持中英文混合校验并且把违规原因结构化输出方便拼回 prompt。import re from dataclasses import dataclass dataclass class STEIssue: sentence: str reason: str BANNED_CN [值得注意的是, 需要指出的是, 综上所述, 在当今, 随着, 为了更好地, 众所周知] BANNED_EN [it is worth noting, it should be pointed out, in conclusion, in todays, with the development of] def lint_ste(text: str, max_len: int 40) - list: issues [] sentences re.split(r[。.!?\n], text) for sent in sentences: sent sent.strip() if not sent: continue if len(sent) max_len: issues.append(STEIssue(sent, f句长超限{len(sent)} {max_len})) for phrase in BANNED_CN BANNED_EN: if phrase.lower() in sent.lower(): issues.append(STEIssue(sent, f含禁用词{phrase})) return issues def build_feedback(issues: list) - str: if not issues: return lines [上一轮输出违反以下规则请重写] for i, issue in enumerate(issues[:5], 1): lines.append(f{i}. {issue.reason}) return \n.join(lines)这个脚本可以直接嵌到你的 Agent 循环里生成 → 校验 → 如果有问题把 feedback 拼回 prompt → 重生成。一般一到两轮就能通过。6.3 不同场景的参数建议场景句长上限是否禁连接词是否禁代词重试次数技术文档25 词是否2工具调用20 词是是3HTML 生成不适用不适用不适用2代码注释30 词否否1多轮对话25 词是否2这张表是我自己项目里调出来的不一定适合所有人但可以作为一个起点。核心思路是越靠近机器解析的场景约束越严越靠近人类阅读的场景约束越松。7. 最后聊几句我的真实体会这套东西我用了大概三个月最大的感受是STE 的价值不在于它本身多先进而在于它把“让模型说人话”这件事从玄学变成了工程。以前我调 prompt 全靠感觉今天加一句“请简洁”明天加一句“不要废话”效果时好时坏。现在我有了一套明确的规则、一个可执行的校验脚本、一组可复用的参数输出质量变得可预测了。另一个体会是约束比指令有效。你告诉模型“请简洁”它理解不了你告诉它“每句不超过 25 字禁用这七个词”它立刻就能执行。这背后的道理其实很简单——LLM 擅长的是模式匹配不是意图理解。你给它越具体的模式它匹配得越准。如果你也在做 Agent 或者 LLM 应用我建议你先从工具调用场景开始试。因为这个场景对废话的容忍度最低效果最明显你能最快看到收益。跑通之后再往文档生成、HTML 生成这些场景扩展。别一上来就全场景铺开容易因为某个场景效果不好就放弃整套方法。还有一点STE 不是终点它只是一个起点。你可以基于它的思想针对自己的业务场景定制一套“领域受控语言”。比如做金融的可以把金融术语固定下来做医疗的可以把症状描述标准化。核心逻辑是一样的用外部规则压缩模型的输出空间用可验证的约束替代模糊的指令。这套思路一旦掌握你会发现很多 LLM 的“顽疾”其实都有工程化的解法。