惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Fox-IT International blog
Recent Announcements
Recent Announcements
D
Docker
IT之家
IT之家
B
Blog
Jina AI
Jina AI
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
F
Fortinet All Blogs
量子位
C
Check Point Blog
Microsoft Azure Blog
Microsoft Azure Blog
罗磊的独立博客
博客园 - 司徒正美
李成银的技术随笔
美团技术团队
Blog — PlanetScale
Blog — PlanetScale
雷峰网
雷峰网
The GitHub Blog
The GitHub Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
J
Java Code Geeks
T
The Blog of Author Tim Ferriss
酷 壳 – CoolShell
酷 壳 – CoolShell
MongoDB | Blog
MongoDB | Blog
P
Proofpoint News Feed
L
LangChain Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Y
Y Combinator Blog
大猫的无限游戏
大猫的无限游戏
有赞技术团队
有赞技术团队
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
V
Visual Studio Blog
T
Tailwind CSS Blog
H
Help Net Security
Engineering at Meta
Engineering at Meta
小众软件
小众软件
B
Blog RSS Feed
Stack Overflow Blog
Stack Overflow Blog
月光博客
月光博客
M
Microsoft Research Blog - Microsoft Research
宝玉的分享
宝玉的分享
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
GbyAI
GbyAI
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Last Week in AI
Last Week in AI
Martin Fowler
Martin Fowler
Stack Overflow Blog
Stack Overflow Blog

SumSec's Blog

模型人人都能用,什么才是你能带走的?我的答案是一个可进化的SKIL… 模型人人都能用,什么才是你能带走的?我的答案是一个可进化的Skil… AI 时代 ShiroAttack2 5.x:修改了什么 · SU… 在 AGI 降临前,先给 AI 开一条”脑内弹幕”通道 · SUM… 一篇博文,三种时间:网页幻灯与 Remotion 动效的交付逻辑 … 论如何优雅注入 Java 内存马 · SUMSEC Sensitive keys in codebases · SUM… SpringBoot GatewayEL表达式漏洞分析 · SUM… Java Swing To RCE 漏洞分析 · SUMSEC 2022 年年度总结 · SUMSEC 知识点面试题总结 SUMSEC https://sumsec.me/2021/weblogic%E4%B9%8BCVE-2020-2551iiop%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%A4%8D%E7%8E%B0.html https://sumsec.me/2021/Fastjson%E5%9B%9E%E6%98%BE.html https://sumsec.me/2021/Tomcat%E9%80%9A%E7%94%A8%E5%9B%9E%E6%98%BE%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0.html https://sumsec.me/2021/%E4%BB%8EJava%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E9%A2%98%E7%9C%8BCodeQL%E6%95%B0%E6%8D%AE%E6%B5%81.html https://sumsec.me/2021/Shiro-550%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90.html https://sumsec.me/2021/%E8%AE%B0%E4%B8%80%E6%AC%A1Log4j%E5%A4%B1%E8%B4%A5%E7%9A%84Gadget%E6%8C%96%E6%8E%98%E8%AE%B0%E5%BD%95.html https://sumsec.me/2021/ysoserial%E6%94%B9%E9%80%A0%E8%AE%B0%E5%BD%95.html https://sumsec.me/2021/JNDI%E6%B3%A8%E5%85%A5.html https://sumsec.me/2021/shiro-JRMP-gadget.html https://sumsec.me/2021/Fastjson_Mysql_gadget%E5%A4%8D%E7%8E%B0.html https://sumsec.me/2021/2021%E5%B9%B4%E5%BA%A6%E6%80%BB%E7%BB%93.html https://sumsec.me/2021/weblogic%E4%B9%8BCVE-2020-2551iiop%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90.html https://sumsec.me/2022/CodeQL%E4%B8%8EShiro550%E7%A2%B0%E6%92%9E.html https://sumsec.me/2022/Spring-Framework-RCE-CVE-2022-22965%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90.html https://sumsec.me/2022/%E7%9B%B8%E4%BC%BC%E5%BA%A6%E7%AE%97%E6%B3%95%E8%B0%83%E7%A0%94.html https://sumsec.me/2022/CVE-2022-33891%20Apache%20Spark%20shell%20command%20injection.html https://sumsec.me/2022/%E6%AD%A3%E5%88%99%E5%8C%B9%E9%85%8D%E9%85%8D%E7%BD%AE%E4%B8%8D%E5%BD%93.html https://sumsec.me/2022/CVE-2022-22980%20Mongodb%20SpEL.html https://sumsec.me/2022/CodeQL-Usage-Tricks.html https://sumsec.me/2022/Spring%20Boot%20RCE%E5%88%B0%E5%86%85%E5%AD%98%E9%A9%AC%E6%8E%A2%E7%B4%A2.html https://sumsec.me/2022/Shiro%E5%90%8E%E6%B8%97%E9%80%8F%E6%8B%93%E5%B1%95%E9%9D%A2.html https://sumsec.me/2022/shiro%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E%E6%94%BB%E5%87%BB%E6%8B%93%E5%B1%95%E9%9D%A2--%E4%BF%AE%E6%94%B9key.html https://sumsec.me/2022/GitHub%20Java%20CodeQL%20CTF.html https://sumsec.me/2022/Hack-Tools2Web.html https://sumsec.me/2022/VMWare-Workspace-ONE-Access-Auth-Bypass.html https://sumsec.me/2022/CodeQL%E5%88%9D%E8%A7%81Shiro550.html https://sumsec.me/2022/CodeQL%E4%B8%8EAST%E4%B9%8B%E9%97%B4%E8%81%94%E7%B3%BB.html https://sumsec.me/2022/Java%E5%8A%A0%E8%BD%BD%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93%E6%96%B9%E5%BC%8F.html https://sumsec.me/2022/Log4j2%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90.html https://sumsec.me/PL/Interprocedural-Analysis.html https://sumsec.me/PL/Data-Analysis-Foundation.html https://sumsec.me/PL/Data-Flow-Analysis.html https://sumsec.me/PL/Intermediate-Representation.html https://sumsec.me/2021/PII%E6%B3%84%E9%9C%B2--%E7%94%A8CodeQL%E8%AF%86%E5%88%AB%E6%97%A5%E5%BF%97%E4%B8%AD%E7%9A%84PII%E6%95%B0%E6%8D%AE.html https://sumsec.me/2021/CodeQL-workshop-for-Java-Unsafe-deserialization-in-Apache-Struts.html
🔍 别让大模型”想太多”:SKILL开发中的语义陷阱与抗幻觉设计 …
2026-04-11 · via SumSec's Blog

📌 引言:一个令人震惊的发现

在当今大模型应用蓬勃发展的时代,Skill(技能)作为大模型能力的重要延伸,正在发挥着越来越关键的作用。然而,我们在实际开发过程中发现了一个令人震惊的现象——仅仅替换一个关键词,就能导致 Skill 的准确率产生天壤之别

我们使用两个几乎完全相同的代码审计 Skill,在 Claude Code + DeepSeek V3.2 上针对同一批营销接口的测试集(共 56 个接口)进行了全面的对比实验。两个 Skill 的工作流程完全一致、参考文件结构完全一致、工具链完全一致,唯一的区别在于核心术语的选择:一个使用”漏洞”,另一个使用”风险”。

实验结果令人深思:

Skill 核心术语 正确率
biz-vul-security 漏洞 (Vulnerability) 89.3%
biz-risk-security 风险 (Risk) 62.1%

令人难以置信的是,27个百分点的巨大差距,竟然源于一个词的简单替换

准确率对比仪表盘:89.3% vs 62.1%

这不仅仅是一个孤立的案例。如果你曾经参与过 Skill、Prompt 或 Agent 工作流的开发,你很可能也遭遇过类似的困惑——明明指令逻辑编写得非常清晰,大模型却总是在”自由发挥”,产出大量超出预期范围的内容。

本文将深入探讨这一现象背后的深层原因。我们将其定义为”语义陷阱“——那些在人类日常语境中含义相近、但在大模型认知空间中语义边界截然不同的词汇对。一个词的不当选择,就可能悄无声息地突破你精心设计的 Skill 约束体系。


📖 第一章 一个词如何改变了审计结果

1.1 案例背景

为了确保不具备安全审计专业背景的读者也能充分理解,我们首先用通俗易懂的语言来阐述这个审计任务的核心内容:

我们面对的是一个的”端外券领取”接口(outflow/voucher/receive)。当用户在小程序中点击”领券”按钮时,系统就会调用这个接口。我们需要评估的核心问题是:这个接口是否存在安全隐患?具体而言,攻击者能否通过篡改请求参数的方式,非法获取不属于其营销活动范围内的奖品?

正确答案是”不存在安全隐患”。这是因为关键的营销参数(campId)是从服务端配置中读取的,而非从用户请求中传入。用户能够控制的参数(recordId、sendOrderIds)与营销活动的绑定关系没有直接关联。

1.2 两份报告的深度对比分析

两个 Skill 对同一段代码进行审计,却产出了截然不同的结论。这一对比深刻地揭示了语义选择对大模型行为的重大影响。

biz-vul-security(使用”漏洞”一词)的判断结果

是否为营销接口:是
任意发奖漏洞判定结果:无漏洞
判定逻辑链:
  1. campId从配置获取 → 非外部可控 → 任意发奖漏洞不成立
  2. sendOrderIds外部可控但不可遍历 → 按特定接口定义无漏洞
  3. 最终判定 → 无漏洞

整个分析过程条理清晰、逻辑严密。它严格按照定义文件中的判定标准,有条不紊地完成了全部流程,最终得出了准确无误的结论。

biz-risk-security(使用”风险”一词)的判断结果

是否为营销接口:否
接口风险等级:低风险
发现的安全问题与代码缺陷:
  1. 代码逻辑错误:第92行 && 应改为 ||
  2. 参数校验不足:sendOrderIds 未进行详细合法性校验
  3. 权限控制缺失:缺少ACL权限控制文件

这个 Skill 不仅将营销接口的判断完全搞错了(正确答案应该是”是”),而且还”创造性地发明”了三个在风险定义文件中根本不存在的问题类别——代码逻辑错误、参数校验不足、权限控制缺失。虽然这些确实属于代码质量层面的问题,但它们完全超出了 Skill 所定义的审计范围。

值得特别关注的是,”漏洞”版 Skill 在其 SKILL.md 中明确规定了:”只关注漏洞定义文件中定义的漏洞类型,其他漏洞类型不做评估,默认无漏洞”。”风险”版同样包含了一模一样的约束条款,仅仅是将”漏洞”替换为”风险”:”只关注风险定义文件中定义的风险类型,其他风险类型不做评估,默认无风险”。

然而,大模型在”漏洞”一词的约束下严格遵守了评估边界,但在切换为”风险”一词后,这条本应具有同等约束力的规则却形同虚设。这一现象深刻地揭示了词汇语义对大模型行为的潜在影响。

两份报告对比:精准聚焦 vs 发散失控

1.3 一个值得深思的关键问题

读到这里,你也许会产生这样的疑问:是否”风险”版 Skill 在某些细节方面的编写存在不足?

答案是否定的。我们对两个 Skill 的全部文件进行了详尽的 diff 比较——包括 SKILL.md 主文件、漏洞/风险定义文件、判定示例文件、Step 执行框架等所有组成部分。分析结果表明,所有内容都是通过机械式的文本替换完成的——将”漏洞”统一替换为”风险”(以及对应的英文 vulnerability 替换为 risk)。不存在任何结构性差异,没有遗漏任何约束条件,也没有改变任何判定逻辑。

那么,问题的根源究竟在哪里?


🛠️ 第二章 如何构建一个高质量的大模型 Skill

在深入分析”为什么会出现问题”之前,让我们首先审视”不出问题的正确做法是什么”。biz-vul-security 这个 Skill 虽然是专门为安全审计场景设计的,但其蕴含的设计方法论对任何领域的 Skill 开发都具有重要的参考价值和借鉴意义。

2.1 结构化工作流:用严谨的流程约束执行路径

biz-vul-security 将整个审计任务精心拆解为强制执行的 6 个关键步骤:

STEP 1: Progress 文件创建(新建进度文件)
STEP 2: 链路追踪分析(核心防御检测)
STEP 3: 参数流向分析(关键参数追踪)
STEP 4: 接口分析(营销接口识别)
STEP 5: 漏洞评估判定(基于漏洞定义标准)
STEP 6: 生成 Final Answer 报告

每个步骤都具备明确的输入、执行动作和输出。步骤之间存在严格的前后依赖关系,既不允许跳过也不允许乱序执行。SKILL.md 中明确规定:”STEP1-6步不能跳过或者忽略任意一个STEP,违反得重新从头执行。”

6步结构化工作流管道

这种设计思路的本质不是在编写说明文档,而是在为大模型精心铺设一条确定性的”执行跑道”。如果不为大模型提供这样清晰的跑道,它就会自行偏离到预期之外的方向上去。

🔑 可迁移的核心原则:无论你的 Skill 承担什么样的任务——撰写文档、分析数据、还是生成代码——将任务拆解为有序的、具有依赖关系的步骤序列,远比编写一段笼统的自然语言描述更加可靠。大模型并不惧怕步骤数量多,真正令其产生困惑的是步骤描述的模糊性。

2.2 “校验→执行→验证”三阶段机制:杜绝跳步的可能性

每个 STEP 的内部又被进一步细分为三个严格的执行阶段:

  • 阶段 1 — 前置校验:读取进度文件,确认上一步已经成功完成,标记当前步骤的开始状态。
  • 阶段 2 — 执行过程:记录即将执行的命令,执行具体命令,将分析结果写入进度文件。
  • 阶段 3 — 后置校验:回读进度文件的最后几行内容,检查命令执行记录是否确实存在,验证分析结论是否已经成功写入,最后标记完成时间。 校验-执行-验证循环机制 这一设计方案中蕴含着一个极为巧妙的机制:它强制大模型在每一步执行过程中都必须”回头审视”已有的工作成果。众所周知,大模型存在一个普遍性的问题——前面约定好的规则和标准,在执行到后续步骤时往往容易被”遗忘”。通过引入进度文件并配合强制回读机制,本质上为大模型构建了一套可靠的外部记忆系统。每个 STEP 开始前先读取进度文件,实际上是在明确地告知大模型”你之前执行到了哪个阶段,已经得出了哪些结论”。

🔑 可迁移的核心原则:对于任何关键步骤,都应当设计外部状态文件(如进度文件、中间结果文件等),并要求大模型在各个步骤之间进行读写操作。这种方式比依赖大模型自身的”记忆能力”要可靠得多。

2.3 定义文件:将边界精确定义,不留任何解释空间

biz-vul-security 配备了一份 vul_definitions.md 定义文件,虽然篇幅不算短,但其功能定位非常纯粹——通过穷举的方式精确定义”什么构成漏洞、什么不构成漏洞”。

例如,其中的”无漏洞场景”部分总共列举了 11 个具体条目,每一条都对应着明确的代码模式:

  1. 参数从配置获取:campId、prizeId等关键营销参数从配置文件、数据库配置、环境变量、关联配置等可信源获取,不从请求参数传入

更为周到的是,文件中甚至预先识别并纠正了常见的误判情况:

  • ❌ 误判:campId从配置获取但调用了营销接口 → 低危漏洞
  • ✅ 正确:campId从配置获取 → 非外部可控 → 无漏洞

此外,还配备了一份 vul_assessment_examples.md 文件,提供了 9 个完整的判定示例。每个示例都包含了代码片段、详细的分析过程以及最终结论。这是典型的 Few-shot 引导策略——通过具体的实际案例向大模型展示”这些抽象规则在真实代码中是如何体现的”。

定义文件结构示意

🔑 可迁移的核心原则

  1. 用穷举代替描述:不要使用”注意可能的误判”这样模糊的表述,应当明确指出”以下三种情况容易被误判为 X,正确判定应为 Y”。
  2. 提供判定示例:让大模型看到输入→分析→输出的完整链条,这比单纯罗列规则要有效得多。
  3. 分层组织参考文件:SKILL.md 仅放置工作流和核心原则,具体的定义标准和判定示例放在单独的参考文件中按需读取。这样既有效避免了上下文过载的问题,又确保了关键信息可以被精确定位和获取。

2.4 专属工具链:赋予 Skill 强大的执行能力

biz-vul-security 依赖于一个名为 code-search-tool 的专业 Skill,其底层是一个功能强大的 fast_code_client.py 脚本。这个工具具备代码搜索、方法体提取、ACL 权限检查、调用链追踪等丰富的功能。

传统的 MCP(Model Context Protocol)工具通常是通用型的——提供搜索文件、读取文件、执行命令等基础功能。这类工具有一个根本性的局限:它们无法告诉大模型什么时候该用、为什么要用、怎么用。大模型拿到一堆通用工具后,常常在”该不该调这个工具”“用什么参数调”上反复犹豫,甚至做出错误选择。而 code-search-tool 的设计思路完全不同——它在 Skill 中明确定义了每个命令的使用时机和使用方式。比如 STEP 2 要用 find_entry 定位接口入口,STEP 2 要用 defense 检测全局防御机制,STEP 3 要用 extract_method 提取方法体。搜索结果还按照审计优先级进行智能排序(Controller > Impl > Interface),让大模型不用自己判断”哪个结果更重要”。换句话说,code-search-tool 把”何时用、为何用、如何用”这三个问题在 Skill 层面提前回答了,大模型只需要按图索骥地执行。

领域定制工具链架构

🔑 可迁移的核心原则:如果你的 Skill 需要与外部系统进行交互,不应当仅提供通用型工具,而应当提供经过领域定制的专业工具。通用工具会让大模型面临过多的选择空间,而领域定制工具能够有效收窄选择范围,从而显著提升大模型做出正确操作的概率。

2.5 小结:构建高质量 Skill 的四大核心支柱

支柱 核心作用 对抗的问题
🏗️ 结构化工作流 规定明确的执行路径和顺序 防止跳步、乱序执行
✅ 校验-执行-验证循环 外部状态管理 + 强制回读 防止遗忘、防止”偷工减料”
📋 定义文件 + 判定示例 穷举式边界定义 防止自由发挥、越界判断
🔧 领域定制工具 收窄操作空间 防止无效探索、错误操作

构建高质量Skill的四大核心支柱

这四大核心支柱在 biz-vul-security 中展现出了卓越的协同效果。在”漏洞”这一语义边界清晰的词汇约束下,大模型严格遵循了六步工作流程,产出了精准的判定结果。

然而,当”漏洞”被替换为”风险”之后,同样的四大支柱体系却未能有效发挥其约束作用。这一发现引出了一个至关重要的问题——语义选择对大模型行为的深远影响。


🧠 第三章 语义陷阱——大模型幻觉的隐藏根因

3.1 什么是语义陷阱

首先,让我们给出一个严谨的定义:

语义陷阱:在人类日常语境中含义相近,但在大模型的语义空间中激活范围(即语义边界)存在巨大差异的词汇对。使用语义边界过宽的词汇,会导致大模型的输出突破 Prompt 所设定的约束范围,从而产生幻觉现象。

需要强调的是,这与传统 Prompt Engineering 中”用词要精确”的建议有着本质区别。传统方法论建议我们避免编写模糊的指令,例如将”分析一下这段代码”改为”检查这段代码是否存在SQL注入漏洞”。这本质上是在指令层面进行精确化处理。

然而,语义陷阱的问题则更加隐蔽和深层——它发生在你已经编写了非常精确的指令之后。即便你已经详细定义了判定标准、提供了丰富的示例、设置了严格的约束条件,但一个”关键名词”的不当选择就能让大模型的认知范围被悄然扩大,使得所有精心设计的约束机制都无法有效发挥作用。

3.2 “漏洞”与”风险”在大模型认知中的本质差异

让我们深入剖析这两个关键词汇的语义特征。

“漏洞”(Vulnerability)在大模型的语义空间中的语义指向

  • 一个具体的、可被利用的安全缺陷
  • 具有明确的二元判定标准:存在或不存在
  • 具有确定的验证方法:是否能够被复现和利用
  • 语义边界清晰而狭窄,指向范围高度集中

当 Skill 声明”只关注漏洞定义文件中定义的漏洞类型”时,大模型所接收到的约束信号是清晰而明确的。”漏洞”这一词汇天然具备”确定性”属性——它犹如一张收紧的网,将大模型的注意力精准地限制在定义文件中明确列出的那几种具体类型之上。

"漏洞"的紧凑聚焦语义空间

“风险”(Risk)的语义空间特征则截然不同

  • 代表一种可能性、一种潜在趋势
  • 缺乏明确的二元判定标准:本质上是程度性问题(高/中/低)
  • 天然携带”展望性”属性:潜在的、未来的、可能发生的
  • 语义边界模糊而宽泛,指向范围极为广阔

当 Skill 声明”只关注风险定义文件中定义的风险类型”时,大模型在表面上接受了这一约束,但”风险”这一词汇在其语义空间中已经激活了一个远为庞大的关联网络。于是大模型开始进行”发散性思考”——代码逻辑错误是否属于风险?参数校验不充分是否构成风险?缺少 ACL 权限控制是否也是一种风险?值得注意的是,大模型并非在凭空捏造,这些确实在某种广义层面上构成了”风险”。但它们不在 Skill 所定义的评估范围之内。

"风险"的发散扩张语义空间

这就是语义陷阱的核心本质:词汇本身固有的语义宽度,能够覆盖并突破 Prompt 所建立的边界控制机制

3.3 数据驱动的错误模式深度分析

在 56 个测试接口的实验中,biz-risk-security(使用”风险”一词)所产生的错误呈现出了非常清晰且具有规律性的模式:

错误模式分布:范围溢出68%、等级虚高24%、逻辑偏移8%

🔴 错误类型 1:范围溢出(占错误案例的 68%)

大模型输出了定义文件中完全不存在的风险类型。这些被”创造性发明”的风险类别主要包括:

  • “参数校验不充分风险”
  • “权限控制缺失风险”
  • “代码逻辑错误风险”
  • “配置变更风险”

🟡 错误类型 2:等级虚高(占错误案例的 24%)

本应被判定为”无风险”的接口被错误地归类为”低风险”。其典型路径为:大模型在代码中发现了一些”不够完美”之处(例如某个参数未进行格式校验),随后将其归类为”低风险”,尽管这些”不够完美”之处完全不满足定义文件中任何一条风险判定条件。

🟢 错误类型 3:逻辑偏移(占错误案例的 8%)

面对同一段代码,”风险”版大模型给出了与”漏洞”版截然不同的分析路径。以上述案例为例,”漏洞”版正确地识别出这是一个营销接口(因为它最终调用了营销RPC接口),而”风险”版却做出了”非营销接口”的错误判定。

上述三种错误模式共同揭示了一个核心特征:大模型的”思维过程”跳出了 Skill 所定义的分析框架。它并非在框架内部犯了计算性错误,而是带着”风险”这一更为宽泛的认知视角去审视代码,发现了更多的信息,然后将这些超出范围的信息也纳入了最终报告。

相比之下,biz-vul-security(使用”漏洞”一词)几乎完全不会犯这些类型的错误。其 10.7% 的错误案例主要源于复杂调用链中的代码分析技术性失误,与语义选择无关。

3.4 一个生动形象的类比

为了更加直观地理解这一现象,让我们设想这样一个场景:你派遣一位实习生前往仓库进行货物盘点,并为其提供一份详细的检查清单。

  • 版本 A 的指令是:”请检查仓库中是否存在破损的货物,严格按照清单上的破损标准进行判定。”
  • 版本 B 的指令是:”请检查仓库中是否存在有问题的货物,严格按照清单上的问题标准进行判定。”

清单的具体内容完全相同。然而,拿到版本 A 的实习生会将注意力完全集中在货物是否存在物理破损上——该标记合格就标记合格,该标记不合格就标记不合格。但拿到版本 B 的实习生呢?他很可能还会额外报告”这箱货物的存放位置不够规范”“那批货物的标签粘贴不够端正”“这个货架上有积灰”等等——因为”问题”这个词汇的语义边界比”破损”宽泛得多。

大模型的行为模式与此完全一致。”漏洞”对应”破损”,”风险”对应”问题”。

仓库盘点类比:精准检查 vs 过度发散

3.5 语义陷阱的普遍性——更多常见案例

类似的语义陷阱词汇对在 Skill 开发实践中比比皆是。以下是我们整理的一组典型代表:

窄边界词(✅ 推荐使用) 宽边界词(⚠️ 谨慎使用) 典型失控场景
检查 (Check) 审查 (Review) “审查”会触发主观评价性意见,而”检查”仅触发通过/不通过的客观判定
列出 (List) 描述 (Describe) “描述”会触发解释和评论性内容,而”列出”仅产出结构化条目
缺陷 (Defect) 问题 (Issue) “问题”的语义范围过于宽泛,甚至改进建议都会被归类为”问题”
总结 (Summarize) 分析 (Analyze) “分析”会触发推理和假设性思考,而”总结”仅提炼已有信息
要求 (Requirement) 建议 (Suggestion) “建议”会触发发散性思维,而”要求”仅输出明确条件
错误 (Error) 异常 (Anomaly) “异常”的边界定义模糊,甚至轻微偏差都可能被纳入报告

这些词汇对呈现出一个共同的规律性特征:左列词汇在大模型语义空间中指向更为紧凑的关联网络,右列词汇则会激活范围更为广阔的关联网络。

基于这一发现,我们将其抽象为一个具有实用指导价值的二维分析框架——LLM 语义敏感度矩阵

            边界清晰度
            高 ←————→ 低
        ┌───────────────────┐
  低    │  漏洞  缺陷  错误  │  ← 安全区
  ↑     │  检查  列出  要求  │
  发    │─────────────────── │
  散    │  总结  问题  审查  │
  倾    │  建议  分析  风险  │  ← 危险区
  向    │  异常  评估  描述  │
  ↓     └───────────────────┘
  高

LLM语义敏感度矩阵:安全区与危险区

矩阵中越靠近左上角的词汇,在大模型中的语义表征越为收敛,对应的输出也越具可控性。越靠近右下角的词汇,语义越趋于发散,大模型进行”自由创作”的空间也就越大。

3.6 理论升华:为什么语义边界控制比传统 Prompt Engineering 更为根本

传统 Prompt Engineering 的核心操作聚焦于”将指令编写清楚”。无论是格式约束、角色设定、Few-shot 示例,还是思维链引导……这些技术手段本质上都在”指令层面”进行优化工作。

然而,语义边界控制所关注的是更为底层和根本的维度——你用来构建指令的词汇本身,是否会在无形中扩大大模型的认知范围?

不妨做这样一个形象的类比:传统 Prompt Engineering 好比在为房子砌筑围墙,而语义边界控制则是在检验你所使用的砖块是否会自行膨胀。如果砖块本身具有膨胀的特性,那么无论你的围墙砌筑得多么精确,最终都无法有效防护。

在 biz-risk-security 的实际案例中,Skill 的”围墙”构筑得相当精良——包括完整的 6 步工作流、严格的校验-执行-验证循环、详尽的定义文件、以及穷举式的判定示例。然而,”风险”这块”砖”在大模型的语义空间中发生了自行膨胀,最终将整面精心构筑的围墙撑出了裂缝。

围墙与砖块:语义膨胀撑裂约束边界

这也深刻地解释了为什么众多开发者在调优 Prompt 时经常感到困惑和沮丧:”我明明已经将指令编写得非常清楚了,为什么大模型还是不按规则行事?”——问题的根源可能并不在于你的指令不够清晰,而在于某个关键词汇在大模型的认知世界里,比你所预期的要”宽广”得多。


🎯 第四章 实战避坑指南——识别和避免语义陷阱

4.1 词汇选择的核心原则:坚持偏向窄边界

核心原则:在能够准确表达意图的前提下,始终选择语义边界最窄的词汇。

具体操作方法如下:

  1. 使用名词代替形容词化的描述。例如,”检测代码中的安全漏洞”优于”评估代码的安全性”。前者具有明确的目标对象(漏洞),后者的目标对象(安全性)则是一个边界模糊的抽象概念。
  2. 使用动宾结构代替开放式动词。例如,”列出所有未处理的异常”优于”分析异常处理情况”。前者明确告知大模型输出格式(列表形式)和目标对象(未处理的异常),后者则赋予了大模型过多的自由裁量空间。
  3. 预先测试”同义词”的语义宽度。在最终选定核心术语之前,将候选词汇放入以下标准化测试句式中进行评估:”请{词}这段代码”或”请给出{词}报告”。如果你能够联想到多种差异较大的合理输出形式,则说明该词汇的语义边界过于宽泛。

4.2 系统化的语义漂移测试方法

在完成 Skill 编写后,建议采用以下三种方法系统地测试核心术语是否会触发语义漂移现象:

📝 测试 1——排除测试

将 Skill 中的关键约束语句(例如”只关注 X 定义文件中定义的 X 类型”)提供给大模型,然后向其提问:”除了定义文件中明确列出的类型,还有哪些 X 你认为也应当纳入关注范围?”

如果大模型能够轻松列举出大量额外内容,则表明你的核心术语语义边界过于宽泛,需要更换为更窄的词汇。

📝 测试 2——最小对比测试

准备一个你确定不存在问题的标准测试用例,使用当前 Skill 进行处理,仔细检查输出结果中是否包含”定义范围之外的内容”。如果发现此类内容,详细记录其所使用的措辞特征(例如”XX 风险”“XX 问题”),这些措辞即为语义漂移的典型痕迹。

📝 测试 3——换词对照测试

使用语义更为窄化的同义词替换核心术语,在同一批测试用例上重新运行,然后系统地对比两个版本的输出差异。这正是我们在 biz-vul-security 和 biz-risk-security 之间所实施的对比实验。

4.3 高效的边界锚定策略

当你因业务需求而不得不使用语义较为宽泛的词汇时(例如业务方明确要求使用”风险”这一术语),可以采用以下策略来有效锚定语义边界:

三种边界锚定策略:否定清单、硬约束、反例强化

🛡️ 策略 1——前置否定清单

在定义文件的最前面位置添加一份明确的”不包括”排除列表:

## 本 Skill 定义的"风险"仅包括以下类型:
1. 任意发奖风险
2. 扩展参数注入风险  
3. DTO层操作DB对象风险

## 以下不属于本 Skill 评估范围(即使它们在通常意义上也是"风险"):
- 代码质量问题(逻辑错误、命名不规范等)
- 通用安全问题(SQL注入、XSS等)
- 架构设计问题(缺少ACL、缺少限流等)
- 性能问题

🛡️ 策略 2——输出格式硬约束

将 Final Answer 的输出格式精心设计为结构化的”填空题”而非开放式的”作文题”:

{
  "任意发奖风险判定": "无风险 | 低危风险 | 中危风险 | 高危风险",
  "扩展参数注入风险判定": "无风险 | 低危风险 | 中危风险 | 高危风险",
  "DTO层操作DB对象风险判定": "无风险 | 中危风险"
}

当输出格式被严格限定为仅包含预定义的字段和枚举值时,大模型便失去了塞入”额外发现”的空间和可能性。

🛡️ 策略 3——判定示例的反例强化

在 Few-shot 示例集合中,有针对性地增加”虽然表面上看起来像是风险但实际上不属于风险”的反例案例:

## 反例:以下情况虽然不够完美,但不属于本 Skill 定义的风险

### 反例 1:参数校验不充分
代码中 sendOrderIds 没有做长度限制和格式校验。
判定:不在评估范围 → 默认无风险
原因:参数校验充分性不属于本 Skill 定义的风险类型

反例在此处发挥的作用是为大模型精确地划定一条不可逾越的红线——”当你在代码审计过程中遇到此类情况时,不应当将其纳入风险评估范围”。

4.4 完整的 Skill 自检清单

在完成一个 Skill 的开发之后,建议系统地逐项检查以下内容:

  • 🔤 核心术语检查:Skill 中使用的核心名词(包括任务类型名称、评估对象名称等)是否选择了语义边界最窄的词汇?
  • 🧪 排除测试:将核心约束语句加上核心术语提供给大模型,询问”还有什么也属于 X 的范畴”,其输出结果是否在可接受的范围之内?
  • 📋 否定清单:定义文件中是否包含了明确、详尽的”不包括”排除列表?
  • 📐 输出格式:Final Answer 的格式设计是结构化的”填空题”还是开放式的”作文题”?
  • ❌ 反例覆盖:判定示例集中是否充分包含了”表面上像但实际上不算”的反例案例?
  • ✅ 最小对比测试:在一个答案已确定的标准测试用例上,Skill 的输出是否精准匹配预期结果?是否存在”额外内容”?
  • 💾 进度文件:是否设计了外部状态文件来有效对抗大模型的遗忘问题?
  • 🔧 工具适配:所提供的工具是否具备足够的领域化程度,能够有效收窄大模型的操作空间?

🤖 第五章 从理论到工具——语义陷阱检测器

前面四章完整地呈现了问题的发现、原因的分析和应对的策略。但一个不可回避的现实是:人工逐词排查语义陷阱既耗时又容易遗漏。当你的 Skill 文件超过几百行、定义文件和判定示例分散在多个引用文件中时,依赖人工审查几乎不可行。

基于本文提出的理论框架,我们构建了一个自动化工具——语义陷阱检测器(semantic-trap-detector)。它本身也是一个 Skill,运行在 Claude Code / Cursor 等支持 Skill 的大模型开发环境中,专门用于在 Skill 编写完成后进行语义层面的”静态分析”。

5.1 设计思路:用 Skill 检测 Skill

语义陷阱检测器的核心思路是将第三章的理论发现和第四章的实战经验编码为可执行的检测规则。具体而言,它做了三件事:

  1. 将语义陷阱词汇对固化为词典。我们将实验中验证过的 7 组高危词汇对(如”漏洞/风险”“检查/审查”“列出/描述”)和基于语义模式推断的 10 组扩展词汇对,全部收录进一份结构化的词典文件。每组词汇对都标注了陷阱 ID、语义宽度差和典型失控场景。
  2. 将排查过程固化为四步工作流。不依赖使用者的经验判断,而是用确定性的步骤引导大模型完成检测:加载词典 → 提取关键词 → 逐词匹配与上下文分析 → 生成检测报告。
  3. 将边界锚定策略固化为输出建议。检测报告不仅指出哪些词有问题,还给出具体的替换方案和锚定策略,让使用者拿到报告后能直接行动。

5.2 四步检测工作流

检测器的工作流程如下:

语义陷阱检测器四步工作流

STEP 1:加载词典

检测器首先读取一份语义陷阱词典文件(semantic-trap-lexicon.md),其中包含全部已知的语义陷阱词汇对、LLM 语义敏感度矩阵、判定示例和边界锚定策略。这份词典是检测的知识基础。

STEP 2:提取关键词

从待检测文本中提取四类关键词:

  • 核心术语:任务类型名词,如”漏洞”“风险”“问题”
  • 动作指令:指导大模型执行的动词或动宾短语,如”分析”“检查”“审查”
  • 约束词:限定范围的词,如”建议”“要求”“原则”“规则”
  • 输出描述词:描述期望输出的词,如”描述”“列出”“报告”“洞察”

这四类关键词对应了 Skill 指令中最容易埋入语义陷阱的四个位置。

STEP 3:逐词匹配与上下文分析

对每个提取的关键词执行两层判定:

第一层是词典匹配——检查该词是否出现在已知的宽边界词列表中。第二层是上下文角色判定——同一个词在不同位置的危害程度不同。例如,”分析”出现在约束条件(”只分析 X 类型”)中属于高风险,出现在辅助描述(”以分析性的视角”)中则风险较低。

此外,即便某个词不在词典中,如果它满足宽边界词的共性特征——程度性而非二元性、带展望性、触发主观评价、关联网络松散——检测器也会将其标记为疑似陷阱。

检测器还会识别四种额外的结构性风险模式:

模式 示例 风险
开放式动词 + 无范围限定 “分析代码”但未指定分析维度 语义发散
形容词化目标 “评估安全性”而非”检测安全漏洞” 抽象名词扩大范围
情态动词降级 约束条件用”应该”而非”必须” 约束力削弱
缺少否定清单 使用宽边界词但未列出排除项 无边界兜底

STEP 4:生成检测报告

最终输出一份结构化的检测报告,包含三个部分:

  1. 检测详情表——逐词列出原词、陷阱 ID、风险等级、上下文角色和推荐替换。
  2. 替换建议——针对每个发现的陷阱,给出替换后的完整语句和替换理由。
  3. 边界锚定建议——当业务要求必须使用某个宽边界词时,给出前置否定清单、输出格式硬约束、反例强化等具体的锚定方案。

5.3 一个检测示例

假设我们编写了这样一段 Skill 指令:

请审查这段代码中的安全问题,只关注定义文件中的问题类型。

这句话看起来逻辑完整、约束明确。但检测器会标记两个语义陷阱:

原词 陷阱 ID 风险等级 推荐替换 理由
审查 T02 检查 “审查”触发主观评价,”检查”仅触发通过/不通过判定
问题 T04 漏洞 “问题”范围极宽,改进建议都可能被归类为”问题”

替换后的语句为:

检查这段代码中的安全漏洞,只关注定义文件中的漏洞类型。

仅仅两个词的替换,就将这条指令从语义敏感度矩阵的”危险区”拉回到了”安全区”。

三种系统化语义漂移测试方法

5.4 词典的持续演进

语义陷阱词典并非一次性产物。随着更多 Skill 的开发和更多实验数据的积累,词典会持续扩充。当前词典包含 17 组中文词汇对和 10 组英文词汇对,覆盖了核心术语、动作指令、约束词和输出描述词四个类别。

更重要的是,词典为每组词汇对提供了”失控场景”的具体描述,而非仅仅标注”推荐/不推荐”。这使得使用者在面对一个被标记的词汇时,能够根据自身的业务场景判断是否需要替换,还是通过锚定策略来收窄边界。

5.5 将检测融入 Skill 开发流程

我们建议将语义陷阱检测作为 Skill 开发流程中的一个标准环节,类似于代码开发中的静态分析(Lint):

Skill 编写 → 语义陷阱检测 → 修复 / 锚定 → 功能测试 → 发布

Skill开发CI/CD流程:将语义检测嵌入管道

在”Skill 编写”阶段完成后,运行检测器对 SKILL.md 及其引用的定义文件进行扫描。如果检测报告中出现高风险陷阱,优先替换为窄边界词;如果业务上无法替换,则按报告建议添加否定清单、硬约束输出格式或反例。

这一流程的价值在于:将原本依赖开发者个人经验的”语感判断”,转化为可重复、可审计的自动化检测步骤。即使是没有读过本文的开发者,只要在流程中嵌入这一检测环节,也能有效规避语义陷阱带来的幻觉风险。


💡 结语:重新认识词汇选择的深远影响

让我们回到本文开篇所引用的那组关键数据:89.3% 对比 62.1%,27 个百分点的显著差距。

这一差距并非源于模型性能的退化,也并非因为 Skill 的逻辑设计存在缺陷。它源于一个看似微不足道、却影响深远的选择——在”漏洞”与”风险”之间,选择了后者。

大模型从根本上来说并非一台精确执行指令的确定性机器。它是一个在海量文本语料上训练而成的语言模型,每一个词汇在其庞大的”认知世界”中都连接着一张复杂而深远的语义网络。有些词汇的语义网络紧凑而集中,有些则松散而弥漫。当你在编写 Skill 的过程中所选择的每一个关键词汇,都在潜移默化地决定着大模型将在多大的认知范围内去”理解”和”执行”你所定义的任务。

选择了语义边界精准的词汇,你的 Skill 约束体系就如同一个高效的漏斗,将大模型的注意力和产出精准地导向你所期望的方向。而选择了语义边界过于宽泛的词汇,即便是设计再精良的工作流体系,也终将被从内部撑破。

因此,在下次编写 Skill 时,在投入大量精力纠结工作流设计和调优 Prompt 格式之前,不妨先停下来,认真审视一下你所使用的那些关键词汇——它们在大模型的认知世界里,真的和你以为的一样大吗?