LingSpark · 灵光

让 AI 代理写的文档,交稿前先过一道闸门。

个人独立开发的 Agent 插件。灵光挂在 Claude Code、Codex 等代理的 Hook 上:代理每写完一篇中文文档,它就检查一遍,发现问题就把代理拦下、退回修改,改完才算交稿。代理不需要“记得”调用它,也无法跳过它。

01痛点

代理写的文档,问题总在交稿之后才被发现。

我日常用 Claude Code、Codex 起草需求文档、技术方案和汇报材料。代理写得很快,但有几类问题几乎每次都会出现:同一个数字前后文对不上;说“有三点”,列表只有两项;引用了一个不存在的章节;整段读下来都是正确但没有信息的空话;用“因此”引出一个前文找不到依据的结论。

这些问题单看都不大,却最伤文档的可信度:评审的人只要发现一处数字对不上,就会开始怀疑整份文档。而它们总是在交稿之后、被别人读到时才暴露,返工成本最高。

“我需要的不是一个更会写的模型,而是一道它交稿前绕不开的检查。”

提示词、Skill 和自查,都是代理可以不执行的建议。

做法一

写进提示词 / CLAUDE.md

做法 把写作规范放进系统提示或项目指令文件。

规范只是上下文里的一段文字,执行与否由模型决定。任务一长,它会被不断增长的上下文稀释,被“尽快完成任务”的目标挤到后面。

做法二

做成 Skill 或 MCP 工具

做法 提供一个检查能力,让代理写完后自己去调用。

调不调用仍由代理自己判断,仍是软约束。越是赶进度的长任务,越容易被跳过。

做法三

让模型写完自查

做法 在任务末尾要求“再检查一遍”。

写和查是同一个模型、同一段上下文,它倾向于认可自己刚写下的内容:写的时候没发现的问题,查的时候大概率也发现不了。

Claude Code、Codex 等代理都提供 Hook:在写完文件、准备结束一轮回答这些固定时机,代理会启动一个外部程序,并按它返回的退出码决定下一步。这个程序不在对话里,模型无法选择不调用它,也改不了它的判断。

灵光就挂在这个位置。代理不需要知道它的存在,写作规范也就不再依赖模型的记忆和自觉;检查结果由规则和独立的判定给出,而不是由写文档的那个模型自己说了算。

约束必须放在模型之外,由代理在固定时机强制执行。

灵光的设计前提

把“写得好不好”,拆成可以重复回答的封闭问题。

“这段写得好不好”是开放问题,让模型写评语,每次结论都不一样,也没法设门槛。能用规则判断的就交给规则:数值前后不一致、计数不符、悬空引用、占位符残留、必备章节缺失,共 10 条,不调用任何模型,毫秒级完成。

必须读懂意思才能判断的,比如指代不明、空话套话、结论没有依据、内容与标题不符,共 9 条,逐段问模型一个是非题。每个问题带明确的判断标准、反例清单和置信度门槛,模型把握不够时不报。

误报比漏报更伤信任

一个检查器只要误报几次,使用者就会开始无视它。所以每条规则都配至少 5 个正例,和 5 个“看起来像、其实不是”的反例,这些例子同时就是自动测试。

语义规则的上线门槛是:反例零误报,正例召回不低于 60%。达不到的规则只以影子模式运行,记录结果但不打扰使用者。

两个挂载点、一组退出码,让检查成为交稿的前置条件。

01 / 写完文件PostToolUse快速检查只跑确定性规则。发现错误时返回退出码 2 告诉代理;文件已经写入,这一步只提醒、不阻断。
02 / 准备收工Stop完整检查加上语义规则。还有错误就返回退出码 2,代理这一轮无法结束,问题作为理由交给它修改。
03 / 改完再交Stop复检放行代理改完再次收工,灵光重新检查;没有错误时返回退出码 0,放行交稿。
04 / 兜底Loop guard不会卡死每一轮最多拦一次;同一个问题连续拦 3 轮仍未修复,记录后放行。
结束之前,lingspark 在 docs/退货流程优化.md 中还有 2 个问题需要处理: 1. 第 3 行 [D111] 正文说「有三点」,但下面的列表有 2 项。 建议:把数字改成实际的项数,或者补齐列表。 2. 第 9 行 [S204] 这段主要是空话套话,读者得不到具体信息。 建议:写清楚具体做什么、做到什么程度、怎么衡量。

几处关键设计

问题指纹每个问题用 sha256(规则编号 + 段落文本) 生成指纹,刻意不含行号。上方插入一段导致问题下移,仍会被认出是同一个问题:代理无法靠挪动位置让问题“看起来修好了”,同一个问题也只提醒一次。
退出码协议返回 0 放行,返回 2 阻断并把理由交给代理。核实 Claude Code 的 Hook 协议后发现:写完文件时的退出码 2 拦不住任何东西,真正能拦住代理的只有 Stop。所以写完时只提醒,收工时才强制。
出错一律放行灵光自身的任何异常都返回 0。会话状态写不进去时,收工检查直接放行,避免丢了计数后无限拦截。检查工具不能变成代理新的故障点。
判定缓存语义判定以 sha256(审稿后端 + 规则 + 规则版本 + 段落) 为键缓存。问过的段落不再重复问,长文档反复修改时不用重新等待、重新付费。
两段式加载先用只读文件系统的轻量预检判断“这次有没有活”:代理写的是代码文件时 29.6 ms 就退出;完整检查一篇文档约 60.9 ms。代理几乎感觉不到它的存在。
安全边界判定服务的地址只认用户级配置:克隆一个不可信的仓库,也无法让它把文档和 API Key 发到别处。出站请求只记录哈希与字节数,不记录正文。

从自用的检查脚本,到一个可以安装的开源产品。

灵光源自我给自己项目写的一个文档检查脚本:用代理的收工钩子,把“检查过了才算完”从自觉变成硬约束。在自己的项目里跑通之后,我把它重写成通用工具并开源:产品定义、规则设计、工程实现和发布都由我一个人完成。

v0.1 以 Apache-2.0 协议开源,支持 Claude Code、Codex、Cursor、WorkBuddy 一键接入,提供 Mac 客户端和命令行两种形态。语义判定默认由正在写文档的代理在对话内自审,免登录、免装模型;需要更客观时,可以换成后台另起的模型、Claude API 或本机的 Ollama 来审。

v0.1 的规则与上线门槛

来自仓库 README 与设计记录
内置规则1910 条确定性 · 9 条语义
一键接入的代理4Claude Code · Codex · Cursor · WorkBuddy
语义规则反例误报0上线门槛
写代码文件时的开销29.6ms预检后直接退出

好的检查器,要能从使用者的修改里继续学习。

下一阶段是周报与自动回测:读取使用者在代理会话里提出的修改意见,总结出候选规则,用历史文档回测误报率,再交给使用者审核上线。规则不只来自我的经验,也来自每一次真实的修改。

分发侧还要补齐自动更新、macOS 签名与公证,以及 Intel Mac 和 Windows 版本。真实文档里的误报和新代理的接入实测,是现阶段最需要的反馈。

“把质量要求写进工作流,而不是写进提示词里,指望模型记得。”

让代理写的每一篇文档,都先过一道闸门。

灵光沉淀的不只是一组检查规则,而是一种约束 AI 代理的产品方式:
检查放在模型之外、问题拆成封闭问答、宁可漏报也不误报、出错一律放行。