Narrative Focus:一个检测技术文章"重心错位"的 Skill

38 阅读16分钟

Narrative Focus:一个检测技术文章"重心错位"的 Skill

用 agent 收集资料生成技术文章的时候,我注意到一个反复出现的问题:生成的文章里,概念的叙述权重经常对不上它实际的重要性——响亮但表层的细节拿了一大堆篇幅,真正决定行为的机制反而被压成几行。后来我把这个问题形式化了,做成了一个可复用的后处理检测工具。这篇文章分享的就是这个尝试。

这个 Skill 面向什么需求

篇幅分配出了问题,不是内容写错了。这个问题在两个场景里特别明显:

场景一:Agent 生成的技术文章

这是这个 Skill 最初的驱动力。

用 agent 收集资料、生成技术文章越来越常见。但在没有额外引导的情况下,agent 有一个倾向:它倾向于把训练数据中出现频率最高的概念给最大的篇幅,而不是把最重要的概念给最大的篇幅。

如果使用了多线程子 agent 分配任务的方式进行面向课题的批量生产,这个问题会扩散到每篇文章里去——每个子 agent 各自高效地产出内容,但它们的上下文是隔离的,彼此之间看不到对方写了什么、也不知道全局的权重应该怎么分配。

举个实际例子。让 agent 写一篇 React 事件系统的文章,它把内容组织成了"三大核心机制":SyntheticEvent 包装机制、事件委托(React 17 挂载点变化)、事件委托的运行时流程——三者各占独立章节,篇幅均等。为什么?因为"事件委托"在 React 相关的博客、教程、Stack Overflow 里被讨论了无数遍,agent 觉得它"重要"。

而真正决定事件系统行为的 Fiber 树遍历,被压缩在"运行时流程"章节的流程步骤里(标题写的是"事件委托",内容其实已经是 Fiber 遍历了),只占 ~5%;stopPropagation() 的跨层行为差异更惨,只在对比表里占了一行。

场景二:已有文章的审稿

同样的问题不限于 AI 生成的内容。真人写的技术文章一样会重心错位——直觉会把"熟悉的"和"重要的"搞混。这个 Skill 同样适用于对已有文章做后处理审稿:扫描全文,检测每个概念的叙述权重是否与其实际角色匹配,输出错位报告和修正建议。当然,自己写完文章跑一遍检测也可以——看看有没有无意中把某个「传输性」细节写成了独立章节。

这个问题怎么发现的

响亮但表层的实现细节,容易抢了真正决定行为的「架构性」机制的风头。

这个认识来自一次真实的阅读体验。我读了一篇 agent 生成的 React 事件系统文章,"事件委托"被列为"三大核心机制"之一——独立章节、详细迁移指南、大量篇幅,放在文章靠前的位置。我围绕它追问了好几轮,但每次追问之后,心里都有一种奇怪的感觉——好像越学越远,好像有什么东西对不上。反复了好几轮之后,我终于问出了一个问题——后来我把它叫做"0号问题":

"为什么我会有这种感觉?是文章写得不好吗?"

就是这个问题让我意识到:不是文章写错了,是叙述重心偏了。"事件委托"后来被替换实验证明只是「传输性」细节,而真正决定行为的机制——Fiber 树遍历、stopPropagation() 的跨层行为——虽然文章里有,但被压在中后段,没有获得与之匹配的叙述权重。我追问的那些问题,全都是顺着错误的锚点展开的。

这个 Skill 的开发需求,就是从这里来的。

这个 Skill 做了什么

Narrative Focus 是一个主要面向后处理的工具——对已有的技术文章进行检测,找出叙述重心错位的地方,并输出修正建议。

它的核心方法是『替换实验』:

对文章中的每一个技术概念提问:如果这个概念传达的命题被替换为另一种实现,读者的可观测行为会改变吗?

  • 会变 → 「架构性」(Architectural)→ 决定系统行为的机制 → 值得高叙述权重
  • 不会变,只是传递方式变了 → 「传输性」(Transport)→ 信号传递管道 → 低叙述权重
  • 行为不变,只是配置不同 → 「可配置性」(Configurable)→ 现有机制上的开关/选项 → 中等叙述权重

可配置性和传输性的边界确实模糊。一个粗略的区分方式:如果替换改变的是信号从哪里来(管道本身),它是传输性的;如果替换改变的是已有机制的运行参数(管道上的阀门),它是可配置性的。前者换了基础设施,后者调了配置。

比如"监听挂载点从 document 变成 #root":如果文章把它当作事件系统的一次管道迁移来展开,它是传输性的;如果文章只是提了一嘴"配置项变了",它就是可配置性的。但在实际操作中,这个边界取决于文章的展开深度——如果文章把一个配置变化写成了独立章节,它就不再只是"阀门"了。

三个角色标签,一个判定方法。用"替换"而不是"直觉"来判断——因为直觉因人而异,而替换至少有一个可复现的标准。

分析文章的命题:替换实验的关键前置步骤

应用替换实验之前,必须先识别每个概念在本文中实际传达的命题。同一个技术细节,在不同粒度上读出的命题不同,替换实验的结果也不同。

比如"JSX 是 React.createElement() 的语法糖":

  • 如果文章花了一整节讲 Babel 编译 → 命题在编译层面 → 替换为 jsx() 不影响用户行为 → 传输性
  • 如果文章只是一笔带过,用 JSX 来说明组件模型 → 命题在概念层面 → 替换为"JSX 有自己的指令系统"会根本改变读者对 React 的理解 → 架构性

判定标准不是这个细节"本身"重不重要,而是文章在这个细节上实际展开了多深。文章给了多少篇幅,反映的是它在主张什么粒度的命题。

这听起来像是在给篇幅找借口——"写得多就算主张得深"。但替换实验本身就是对此的校验:即使文章给了一个传输性细节大量篇幅,替换实验仍然会指出"替换后行为不变"。篇幅决定命题粒度,替换实验决定角色判定,权重比对再把两者拉开来看——如果三步走完,发现一个传输性细节占了 30% 篇幅,那问题就暴露了。

React 17 挂载点迁移就是个好例子:很多技术文章给了它独立章节和迁移指南,篇幅很大。如果按照"篇幅大就算主张深"的逻辑,它应该被判定为架构性。但替换实验会问:在这个讨论事件核心机制的文章里,把挂载点从 document 换成 #root,事件分发的行为变了吗?答案是不变。篇幅再大,角色判定仍然是传输性——篇幅和角色的错位,正是这个 Skill 要检测的东西。

Skill 实际怎么工作

用 React 事件系统那篇文章走一遍完整流程。

第一步:提取核心概念

扫描文章,找出所有被当作核心概念呈现的技术细节:

概念呈现方式篇幅
SyntheticEvent 包装机制独立章节 + 代码示例~30%
事件委托(挂载点变化)独立章节 + 迁移指南~30%
事件委托的运行时流程独立章节 + 流程步骤~30%
stopPropagation 差异对比表一行~5%
Fiber 树遍历压缩在流程步骤中~5%

第二步:命题识别 + 替换实验

对每个概念执行替换(角色判定基于本文实际展开的命题粒度,而非技术细节在系统中的客观地位——同一细节在不同文章中可能得到不同判定):

概念命题替换后行为变吗?角色
SyntheticEvent"React 用合成事件包装原生事件"变——onChange/onClick 接口行为改变架构性
事件委托(挂载点变化)"React 17 将监听从 document 移到 #root"不变——事件分发的核心路径(Fiber 遍历 + handler 收集)不受影响传输性
挂载点变化"监听挂载点从 document 变成 #root"不变——核心机制不受影响可配置性
stopPropagation"只阻止内部冒泡,不影响原生监听器"变——用户代码出 bug架构性
Fiber 树遍历"React 遍历 Fiber 树而非 DOM 树收集 handler"变——Fragment/Provider 上的 handler 丢失架构性

表格中"事件委托(挂载点变化)"和"挂载点变化"两行看起来在说同一件事,但命题粒度不同。第一行的命题是"React 17 做了一次管道迁移"——信号获取管道从 A 容器换到了 B 容器,这是传输性的;第二行的命题是"监听配置从 A 变成 B"——已有机制上的一个参数变了,这是可配置性的。如果文章只花一段话提了这个变化,它是可配置性的;如果文章给了独立章节和迁移指南,它的命题就升级成了传输性管道的迁移——权重也该跟着变。

这里有一个值得展开的判断——React 17 把事件委托的挂载点从 document 改到 #root,在微前端场景下是有架构性影响的:多个 React 根节点之间的 stopPropagation 行为因此改变。如果这篇文章的命题是"React 为了微前端需求做了什么",那挂载点迁移就该拿大篇幅,它是架构性的。

但本文的命题是"React 事件系统的核心机制是怎么运行的"。在这个命题下,监听挂载点从 A 容器换到 B 容器,不改变事件分发的核心路径——Fiber 遍历、handler 收集、合成事件包装,这些都不受影响。它是信号获取管道的一次迁移,不是系统行为的改变。

同一个技术细节,在不同的命题粒度下,角色不同。 这不是说挂载点迁移不重要——它很重要,重要到值得一篇专门讨论 React 微前端适配的文章。但在本文的讨论范围内,它的命题是"监听点变了",而不是"事件系统为微前端做了什么架构调整"。

这也正好说明了替换实验的一个特点:判定结果不是概念"本身"的客观属性,而是概念在特定文章语境下的角色。文章展开多深,就读多深。

第三步:权重比对

概念角色文中权重判定
SyntheticEvent架构性30%✅ 合理
事件委托(挂载点变化)传输性30%❌ 过度突出
事件委托的运行时流程传输性30%❌ 过度突出
挂载点变化可配置性含在上述两项中❌ 独立成章
stopPropagation架构性5%❌ 被埋没
Fiber 树遍历架构性5%❌ 被埋没

第四步:修正

修正原则:只改权重,不改事实

  • 事件委托:"三大核心机制" → "信号获取手段",压缩为一段话
  • 挂载点变化:独立章节 → 补充条目
  • Fiber 遍历:流程图三行 → 独立核心机制,展开完整分发流程
  • stopPropagation:对比表一行 → 独立代码示例 + 踩坑 + 解决方案

修正后的结构:

核心机制一:Fiber 层事件模拟——React 事件的真正运行方式
  ├── 第一步:获取信号(原生 DOM 层)          ← 事件委托降为一句话
  ├── 第二步:Fiber 层分发(核心)             ← Fiber 遍历独立展开
  ├── stopPropagation() 的真实行为            ← 新增独立代码示例
  └── capture vs bubble 顺序

核心机制二:SyntheticEvent——事件包装层        ← 权重不变

补充:信号获取方式——事件委托与挂载点            ← 降级为补充

第五步:二次检测 + 权威校验

修正后重新跑一遍检测,确认所有错位已解决。然后对照官方文档和技术博客,验证修正后的段落没有引入技术事实错误。

完整『后处理』工作流

React 示例展示了方法论在具体案例上的操作。以下是通用的后处理流程,可直接应用于任何技术文章:

  1. 提取核心概念 — 扫描文章,找出所有出现在章节标题、有独立代码示例、或在总结中被优先提及的技术细节
  2. 命题识别 — 对每个概念回答:本文在这个概念上实际主张什么?读者会从中获得什么关键洞察?注意命题粒度:文章展开多深,就读多深
  3. 替换实验 — 对每个命题提问:如果这个命题被替换为另一种实现,读者的可观测行为会改变吗?据此标注角色(架构性/传输性/可配置性)
  4. 权重比对 — 将每个概念的角色与文中实际篇幅对比:架构性应获得高权重,传输性应低权重,可配置性中等
  5. 输出检测报告 — 列出所有错位项(过度突出 / 被埋没 / 权重失衡)
  6. 修正 — 只改权重不改事实:降级传输性概念(压缩/移除独立章节),升级架构性概念(独立展开/添加代码示例)
  7. 二次检测 — 对修正后的文章重新执行步骤 1-5,确认所有错位已解决
  8. 权威校验 — 对照官方文档、技术博客、MDN 等权威源,验证修正后的段落没有引入技术事实错误。只验证修改过的段落,未修改的内容不需要重新校验

这个 Skill 覆盖多大的范围

适用:技术教程、深度解析、面试准备文章、框架对比——任何读者在构建心智模型的技术内容。

不适用:API 参考文档(不需要心智模型)、观点文/新闻(没有因果层级)、非技术内容。

覆盖的错位类型

错位类型典型症状例子
传输性过度突出管道层细节被当成核心机制事件委托被列为"三大机制"
架构性被埋没决定行为的机制被压缩成几行Fiber 遍历藏在流程图里
可配置性失衡配置选项占了独立章节React 17 挂载点变化独立成章
标题-内容不匹配标题承诺 A,篇幅给了 B标题写"编排",内容大量在讲构建

快速试用一下?

基于 SKILL.md 开放标准,主流 agent 工具(OpenClaw、CodeBuddy、Claude Code、Cursor、Windsurf 等)均已支持。将 skill 文件放到对应目录即可。

安装后,两种使用方式:

推荐方式——让 agent 自主检测:

使用 narrative-focus skill 检测这篇文章的叙述重心情况

显式指定——直接对文件做后处理:

使用 narrative-focus skill 对 <文件路径> 进行后处理

后者是本人的常用方式——写完文章直接甩路径,一步到位。

两种方式都会自动执行检测、修正、二次验证的完整流程。

这个方案框架的边界

修正后的权威校验是后处理流程的最后一道防线:修正只做权重迁移(移动章节、压缩/扩展篇幅),不做事实重写,但迁移过程中仍可能意外改变技术语义。因此修正后的段落需对照权威源(官方文档、团队博客、MDN)验证核心命题是否仍然准确。如果发现偏差,应报告给用户而非自动修正——语义偏差的修复可能需要重新审视命题识别这一步。

替换实验用"可观测行为是否变化"作为判定标准,这比直觉判断更可复现,但也有自己的盲区:

  • 概念提取的质量依赖:替换实验依赖第一步概念提取的完整性。如果一个架构性概念被压缩到其他概念的章节里,甚至没有独立标题,概念提取阶段可能识别不出来——替换实验就无从校验。这也是为什么第一步"提取核心概念"不应该只看标题和章节结构,还需要通读正文内容。

  • 部分变化:某些场景变、某些不变时,判定会变得模糊。比如一个传输层方案在小规模下行为不变,但在高并发下触发了不同的故障模式——这算架构性还是传输性?目前依赖人工判断。

  • 间接影响:当前层替换后行为不变,但下游的性能特征、调试体验、读者的心智模型都可能受影响。替换实验只捕捉直接的可观测变化,间接效应需要额外推理。

  • 认知层面:行为完全不变,但读者对系统的理解方式变了。比如把"事件委托"从核心机制降级为补充说明,技术上没有影响,但读者不再会从这个角度去思考事件系统——这是好是坏,取决于读者的需求。

这些边界情况目前没有自动化方案。在实践中,建议保留完整的过程日志,让每个判定都有可追溯的推理链,这样当边界情况出现时,至少可以沿着日志回溯到替换实验那一步,判断推理是否成立。


这个 Skill 重点面向"后处理"——对已有文章的检测和修正。它不检查内容缺失、主题边界或体裁一致性,只回答一个问题:每个概念的叙述权重,是否与其在系统中的实际角色匹配?

回头看,整个事情的起点是那个"0号问题"——"为什么我会有这种感觉?是文章写得不好吗?"那个问题让我意识到,不是内容错了,是重心偏了。替换实验、角色标注、命题粒度,都是从那个问题一步步长出来的。它们不完美——边界情况需要人工判断,间接效应还捕捉不到——但至少给了一个可复现的标准,让"重心不对"从一种模糊的感觉变成了可以讨论、可以修正的东西。

如果你也在读技术文章时有过类似的感觉,也许问题不在你。

GitHub 仓库:Co-Kyo/narrative-focus-skill — 项目刚开源,欢迎试用反馈,试用前请做好原文件备份。