公文编写(worktool-gongwen-writing)
这个技能在做什么
把「写公文」从一次性对话变成可追溯的编制工程:
- 第一步先定工作根目录(阶段 -1):首次启动问用户要一个目录,在其下建
knowledge(知识库)/output(输出文件)/src(参考文件)三个子目录;没确认过就不往下走(init-task会挡住); - 需求先问清、后落库 → 每个任务有正式的任务记录;
- 一任务一文件夹:工作根目录由用户定(首次启动时问,见阶段 -1),其下三个子目录分工——
knowledge知识库、output输出文件、src参考文件;任务建在<根>/output/<公文名称>/,该公文全部产物(提纲、md、docx、评估 json/html、建议)都在这个文件夹里,绝不散落; - 成稿后的评估检测完全离线、隐私优先:逐节评估、跨节呼应度、评估报告 HTML、交付自检全部不联网——脚本入口会直接剥夺进程的 socket 联网能力(不是"约定不联网"),正文与参考资料不会离开本机;评估报告是单文件自包含 HTML,无 CDN / 无外部字体 / 无远程图片;
- 去 AI 味、反假大空:判据不是"像不像人写的",而是逐句可核——一句里有没有主体、动作、结果、时限。充实度里的「去AI味」维度会用规则表逐句匹配(万能过渡、空转句式、空洞意义、有力支撑、含糊其辞,加排比凑字/副词堆砌/黑话堆砌/长定语堆叠),把废句连"位置+原词+所在句+怎么改"列成清单;改完自动给出与上一版的分数对比;
- 先出提纲 + 每节 ≤50 字摘要让用户改到满意,再基于摘要成文(避免几万字返工);
- 每一版先出 Markdown(在对话里秒开、逐轮改),定稿后才出 Word;过程版正文用
{{Sx}}角标标注每处内容的出处,成文后定稿时角标与参考文献表自动剥离,交付版干净无引用标记; - 每次改完内容都自动重评一遍:
record-report一落盘就会跑「逐节完整度/充实度评估 + 跨节呼应度检查」,返回里直接带上与上一版的分数对比,并自动生成一份单文件 HTML 评估报告(report-vN.assess.html,断网可开、可打印、可随版本归档);模型要做的不是"记得跑脚本",而是把结论讲清楚并把评估报告打开给用户看; - 成文后逐节评完整度/充实度,指出哪一节薄、薄在哪个维度,并给出来自本机已有材料(任务 facts / 已归档参考件 / 本地知识库)的补强材料;
- 再做一次跨节呼应度检查:开头承诺的事结尾有没有落点、前一章提的问题后文有没有逐条回应、各章之间有没有承接表述、术语是否前后统一、有没有跨节重复——发现脱节就给出可执行的修改建议(多数组内低分不必强改,脚本会给判读提示);
- 每生成一版都是新版本,旧版本永不覆盖,且每版都记录「基于哪一版生成」「生成前用户提了哪些建议」;
- 未上传模板时,按 GB/T 9704-2012 直接排版到 Word(页边距、三号仿宋、每面 22 行每行 28 字、奇偶页不同页码全部落地)。
环境准备(首次使用,幂等)
PY=/Users/black/.venv-gongwen/bin/python
[ -x "$PY" ] || { /Users/black/.workbuddy/binaries/python/versions/3.13.12/bin/python3 -m venv /Users/black/.venv-gongwen \
&& /Users/black/.venv-gongwen/bin/pip install -q python-docx lxml; }
$PY -c "import docx;print('ok')"
脚本目录(下文记作 $SK):
SK=~/.workbuddy/skills/worktool-gongwen-writing/scripts
> 装好环境后的第一件事不是建任务,是定工作根目录(阶段 -1)。先跑
> $PY $SK/task_store.py workspace,看返回的 needs_setup。
目录约定(工作根目录 + 三个子目录,根目录由用户指定、可随时改)
工作根目录不是写死的——首次启动时问用户要(见阶段 -1),拿到后在其下建三个子目录,各干一件事:
| 子目录 | 用途 | 说明 |
|---|---|---|
<根>/knowledge |
知识库 | 沉淀下来的范文、体例与规范、素材条目,可检索复用。要参考资料先来这里翻,不要凭空要用户上传 |
<根>/output |
输出文件 | 每次新建任务就在此下建一个「以公文名称命名」的文件夹,该公文的所有产物都在这个文件夹里 |
<根>/src |
参考文件 | 用户丢进来的原件(格式模板、往年同类文、素材)。--template / --ref 先来这里找 |
根目录的当前值与三个子目录的实际路径,一律以命令输出为准,不要凭记忆写死:
$PY $SK/task_store.py workspace # 状态:needs_setup / root / 三个子目录
$PY $SK/task_store.py workspace --init "/工作根目录" # 首次设定,或改到别处
$PY $SK/task_store.py workspace --reconfigure # 清掉确认,下次启动重新问(不动文件)
$PY $SK/task_store.py config # 看生效值(含 config.json 原文)
路径优先级:环境变量 → 单项覆盖(config --set knowledge_root=…)→ <工作根目录>/<子目录名>。
老配置只写了 output_root / knowledge_root 也能跑(会从它们的共同父目录反推根目录),不必强行迁移。
翻参考文件与知识库:
$PY $SK/task_store.py list-knowledge [--search 消防] # 两个目录都列,where 字段标来源
--template / --ref 只写文件名即可——脚本会先按路径找,找不到就依次去 src → knowledge
按「相对路径 / 文件名」匹配(返回里的 template_from / refs_from 会说明取到了哪个目录)。
模板与参考文档会被复制进任务文件夹的 source/ 存档。
> 本机当前的根目录是 /Users/black/AI/write(knowledge / output / src 都已就位)。
> 下面示例里的路径都按它写;用户改过根目录就以 workspace 的输出为准。
任务文件夹结构(<公文名称> 就是文件夹名,同名冲突自动加 -2 / -3):
<工作根目录>/output/<公文名称>/
├── task.json 任务记录(全部填报字段,extra.sources[] 是引注键的唯一登记处)
├── format-config.json 排版配置(模板抽取结果 或 GB/T 9704 默认)
├── source/ 上传的模板与参考文档原件
├── outline/outline-vN.json|.md 提纲与摘要(每版都留)
├── report/report-vN.json 报告内容模型(正文带 {{Sx}} 引注标记;附件放顶层 appendix[])
├── report/<日期>_<名称>_vN.md 过程版 Markdown(快速评审用,带角标 + 文献表)
├── report/<日期>_<名称>_vN.docx 定稿 Word(角标与文献表已剥离)
├── report/report-vN.eval.json 逐节评估 + 扩展建议
├── report/report-vN.coherence.json 前后呼应度检查 + 脱节改进建议
├── report/report-vN.assess.html **评估报告(HTML,给人看、可交付)**
├── report/report-vN.assess.json 评估摘要底稿(含与上一版对比,供重渲染/复算)
├── notes/suggestions-*.json 生成前用户提的修改建议(原话)
├── notes/advice-report-vN.json 逐节扩展建议(模型填写,已合并)
├── notes/advice-coherence-vN.json 呼应度改进建议(模型填写,已合并)
└── manifest.json 版本索引 + 血缘
> --task 传的就是文件夹名(=公文名称),不再有 T20260929-001 这种编号。
> 名字里有 / \ : * ? " < > | 会被自动剔除(实际文件夹名以 init-task 返回的 task_id 为准)。
> 下文命令里统一用这两个变量:
T="关于全市消防安全专项整治工作情况的报告" # =文件夹名(= init-task 返回的 task_id),--task 传它
# 本次任务文件夹:机器上**当前生效**的输出库根目录 + 任务名(换过根目录也能取对,别写死)
OUT="$($PY $SK/task_store.py config | $PY -c 'import json,sys;print(json.load(sys.stdin)["effective"]["output_root"])')"
TD="$OUT/$T"
交付节奏:record-report 默认只出 md;确认定稿后 finalize-report 才排 Word。
record-report --docx 可一步到位(内容已确认、不需要再评审时用)。
评估报告是 HTML:每次评估都自动生成 report-vN.assess.html(单文件、零外部依赖、离线可开、
带打印样式),把它连同结论一起呈现给用户——见阶段 4D。
阶段 -1 · 首次启动:先把工作根目录定下来(任何事之前)
每次技能启动,第一件事都是跑这一条,看工作根目录确认过没有:
PY=/Users/black/.venv-gongwen/bin/python; SK=~/.workbuddy/skills/worktool-gongwen-writing/scripts
$PY $SK/task_store.py workspace
返回里 needs_setup: true 就说明还没问过用户。这时候不要接着往下走——
不要建任务、不要生成提纲、不要拿默认路径硬开工。要先把下面这句话问了:
> 「这份公文的工作根目录放在哪?我会在它下面建三个子目录:knowledge(知识库,
> 放沉淀下来的范文、体例规范、素材条目)、output(输出文件,每份公文一个文件夹)、
> src(参考文件,你丢进来的模板、往年同类文、素材原件)。以后想换随时说一声。」
拿到目录后一步到位(会当场建齐三个子目录,幂等;已存在的只登记、不清空):
$PY $SK/task_store.py workspace --init "用户给的工作根目录"
输出里会报:三个子目录哪些是 created(新建的)、哪些是 existed(本来就有)、
dropped_overrides(因改根而失效的老的单项路径覆盖)。把 existed 念给用户听——
如果他给的目录里本来就有旧内容,让他知道技能看到了、且一个字没动。
用户还没想好放哪 → 先给候选,别催
workspace 在未确认时会自动扫几个常见位置(当前目录、~/AI、~/Documents、~/Desktop
及其一级子目录),返回 detected[]:其下已存在 2 个以上同名子目录的目录按命中数排序。
把它们连同各自的 found 一起摆给用户挑("/Users/black/AI/write 下面已经有 knowledge、
output、src 了,就用它吗?"),比空口问一句"你想放哪"好答得多。
探测只是给提示,不自动选——最终以用户确认为准。实在不想选就给个建议路径,别把问题抛回去。
随时改根目录
$PY $SK/task_store.py workspace --init "/新的工作根目录" # 改到别处,三个子目录跟着走
$PY $SK/task_store.py workspace --detect # 重新扫一遍候选
$PY $SK/task_store.py workspace --reconfigure # 清掉"已确认",下次启动重新问(不动任何文件)
$PY $SK/task_store.py config # 看当前生效值
$PY $SK/task_store.py config --set root="/新目录" # 与 workspace --init 等价
改根目录 = 三个子目录整体跟着走:老的单项覆盖(output_root / knowledge_root /
src_root)会被清掉并报在 dropped_overrides 里——否则用户换了根却发现产物还落在旧地方。
原有目录与文件一个都不搬、不删,只改配置、只新建缺的目录。
> 想只把某一个子目录挪到别处(比如知识库故意放共享盘),那就在改完根之后单独指:
> config --set knowledge_root=/共享盘/公文知识库。优先级:环境变量 → 单项覆盖 → <根>/<子目录名>。
没确认根目录会怎样
init-task会直接挡住并返回success: false/error: workspace_not_configured,
提示先去workspace --init。用户这一次就把目录说了的话,可以init-task ... --root <目录>
一步登记并开工。- 其它命令在 stderr 打一行
[WARN] 工作根目录尚未确认…,不阻止执行(评估、看任务这些只读动作
不该被卡),但看到这行就说明该去问了。
离线与隐私(成稿后评估检测的硬约束)
成稿后的「评估检测」= 逐节评估(evaluate.py)+ 跨节呼应度(coherence.py)+
评估报告 HTML(build_assess_report.py)+ 交付自检(verify_docx.py),全程完全离线。
这一条是能力剥夺,不是把"别联网"写进口头约定:技能里所有脚本的入口都会调用
gongwen_lib.enforce_offline(),把出网的三个入口全部换成直接抛错——
socket.socket.connect / connect_ex / sendto(AF_INET / AF_INET6)、socket.create_connection、
socket.getaddrinfo / gethostbyname*(DNS)、ssl.SSLContext.wrap_socket(TLS)。
本机 IPC(AF_UNIX 本地套接字)照常放行——那是本机进程间通信,不是联网。
即使代码或依赖里混进了联网调用,也会当场 RuntimeError: [离线模式] … 失败,
而不会悄悄把正文或参考资料发出去;正常运行时 blocked_calls 应为 0(一次都没尝试出网)。
| 约束 | 落地方式 |
|---|---|
| 不出网 | 进程级 socket 能力剥夺(默认开);评估返回值与 HTML 里都写明「隐私模式:完全离线 / 拦截出网 N 次」 |
| 评估时不做联网检索 | 补强材料只从本机已有材料取:任务 facts / 已归档参考件(任务文件夹 source/)/ 工作根目录下的 src 与 knowledge。禁止在评估阶段调用任何联网检索工具 |
| HTML 不引外部资源 | 单文件自包含:无 CDN、无外部字体、无远程图片;补强材料的 URL 默认纯文本渲染(原样可复制),不生成可点击外链 |
| 数据不出本机 | 所有产物只写 <输出库>/<公文名称>/ 内;不上传、不写外部日志、不做遥测 |
| 真实性核对同源 | unverified_facts 只与本机语料比对,不依赖在线检索结果 |
唯一的例外通道:用户在评估之外明确要求"去公网找补强材料/政策原文"时,
那是独立于评估的单独动作,且必须:
- 用户显式授权(不要在评估流程里顺手联网);
- 由
GONGWEN_ALLOW_NETWORK=1显式放行(否则脚本会拒绝执行); - 结果只进建议区(
web_findings),标注来源与口径,经用户逐条确认后才可能进正文; - 该结果不改变离线评估的结论——评估报告里会如实标出"联网已放行"。
> 检查当前环境的隐私模式:$PY $SK/task_store.py config(会打印 offline 相关项),
> 或看任一评估返回值里的 assessment.offline(enforced / blocked_calls / reason)。
阶段 0 · 任务填报(信息不足就引导,别猜)
先算缺口、再提问——不要凭常识替用户补字段。用 intake.py 把"还缺什么"算出来:
PY=/Users/black/.venv-gongwen/bin/python; SK=~/.workbuddy/skills/worktool-gongwen-writing/scripts
$PY $SK/intake.py # 什么都不知道时,从哪问起
$PY $SK/intake.py --fields-json '{"genre":"通知"}' # 已填一部分,看还缺什么
$PY $SK/intake.py --genre 请示 # 附该文种专项追问
$PY $SK/intake.py --task "$TD" # 盘点已有任务还缺什么
必填字段(缺一个都别开工):报告名称 / 文种 / 行文方向 / 场景 / 发文机关 / 主送机关 / 篇幅目标。
> intake.py 的输出就是要念给用户听的话:每条问题都带 why(为什么问)与 example(答案长什么样)。
> 提问时把「为什么问」一起说出来——用户知道这个问题影响什么,才会认真回答。
> 完整清单见 references/task-fields.md 第 6 节;文种专项追问见第 6.8 节。
建任务前先翻参考文件(<根>/src)与知识库(<根>/knowledge)——用户把模板、往年同类文、
素材都放在那里,别一上来就要用户上传:
$PY $SK/task_store.py list-knowledge --search 消防 # 按名称/相对路径关键词找
找到相关的就把文件名直接传给 --template / --ref(不用给全路径,脚本会去库里取)。
库里没有、用户又想给新的,才请用户上传。
然后引导用户确认格式模板与参考文档,并说明:
> 「有格式模板就按你的模板排版;没有的话我按 GB/T 9704-2012 党政机关公文格式排(二号小标宋标题、三号仿宋正文、每面 22 行每行 28 字、单双页页码分置)。参考文档给我内容素材——内容我只用你给的、以及你确认过的公开事实。」
$PY $SK/task_store.py init-task \
--name "关于全市消防安全专项整治工作情况的报告" \
--genre 报告 --direction 上行 \
--issuer "XX市应急管理局" --addressee "XX市人民政府" \
--scenario "向市政府汇报阶段性成效" --target-chars 6000 \
--template ~/模板.docx --ref 2025年消防整治报告.docx \
--fields ~/fields.json # 或 --fields-json '{"purpose":"..."}'
--name 就是任务文件夹名:脚本会在 <工作根目录>/output/ 下建
<公文名称>/,该公文后续所有产物(提纲、md、docx、评估 json/html)都落在这个文件夹里。
同名时自动加 -2,不会覆盖既有任务。
返回 task_id(=实际文件夹名,后续 --task 传它)、task_dir、format_source
(template 或 gbt9704)、format_missing(模板里没抽到、已回落到国标的项)、
knowledge_dir 与 knowledge_files(库里现有参考资料,一眼看出还能用哪些)。
把 format_missing 念给用户听,不要默默回落。
建完把 T 与 TD 记牢(T 就是返回的 task_id),后面命令都用它们。
阶段 1 · 需求引导(渐进式,一轮 3~5 条,别一次抛完)
引导原则:问缺口里优先级最高的,而不是把清单念一遍。 用户只丢一句话时,
一次问 40 条只会得到"你看着办"。
1.1 四轮问答(答一轮、落库一轮)
| 轮次 | 组 | 问什么 | 为什么先问它 |
|---|---|---|---|
| 第 1 轮 | A 任务身份 | 名称、文种、行文方向、场景、发文机关、主送机关、篇幅 | 身份错了整篇白写;这轮问完就能建任务 |
| 第 2 轮 | C 素材与数据 | 可用事实清单、数据口径、成效指标、问题与原因、下一步措施、缺口 | 决定"有没有干货";越早拿到越好 |
| 第 3 轮 | B 内容与立意 | 核心目的、2~5 条核心判断、必须出现/不得出现、政策依据文号、立场口径 | 决定写什么、站在什么立场 |
| 第 4 轮 | D 结构与文风 + E 格式与交付 + F 合规与风险 | 章节框架、篇幅分配、文风与忌用词、模板与红头/密级/附件、审签与保密 | 收尾项,可在提纲阶段顺带确认 |
每轮取 intake.py 输出的 ask_now(最多 5 条),把 why 一起讲,答完立即落库:
$PY $SK/task_store.py update-task --task "$T" --fields-json '{"facts":[...],"must_exclude":[...]}'
$PY $SK/intake.py --task "$TD" # 每轮落库后再算一次,看下一轮该问什么
1.2 什么时候可以停止追问
- 必填齐备(
intake.py的ready_to_start为 true)即可开工; - 用户说"没有/不知道"→ 写进
open_questions,正文标【待补充】,不要反复追问同一件事; - 用户赶时间("快出个稿")→ 只问 A 组必填 + C 组事实清单,其余用文种惯例补齐,
并在回复里显式声明补了什么,请用户回看纠正。
1.3 文种专项追问(通用清单覆盖不到的,问与不问差别最大)
intake.py --genre <文种> 会自动附上这些;要点如下(完整版见 references/task-fields.md 第 6.8 节):
- 请示:请示事项(一件事一份文)/理由依据/拟办意见/上级此前是否表过态/有无时限压力;
- 报告:工作报告·情况报告·答复报告?(答复报告要写对应上级文号)/上级布置的文号与时限/要不要写问题建议;
- 通知:通知类型(发布·批转·转发·指示·会议·任免)/执行主体/执行时限/要不要反馈/转发的原文件标题文号;
- 批复:对应请示的标题与文号/批复结论/附加要求;
- 函:函类型(商洽·询问·答复·告知)/双方层级/希望对方做什么何时回;
- 纪要:会议名称时间地点主持人/出席列席范围/议题/议定事项/责任分工与时限;
- 通报:通报类型/典型对象(名称须准确)/事实与经过/处理或表彰决定/对各单位的要求;
- 意见:指导性还是实施性/指导对象与范围/实施期限/主要措施与保障措施;
- 决定:决定事项逐项/依据/生效时间/奖惩或处置措施;
- 实施方案:总体目标与量化指标/实施范围/时间步骤/组织保障/经费/考核督导;
- 工作总结:总结周期/主要任务/逐项完成情况/经验与不足/下一年度打算;
- 周报:报送周期与截止时点(覆盖上周几到本周几、几点前交)/报送对象与用途/有无固定栏目或上一期周报可参照/本周完成事项逐条给事实/下周计划与卡点、需要协调事项;
- 调研报告:调研背景目的/方法与样本/主要发现/问题与原因/对策建议;
- 汇报材料:汇报场合/听取人及其关切/时长篇幅/必须讲到的重点;
- 讲话稿:讲话人身份/场合与听众/时长(约 200~250 字/分钟)/核心口径/语言风格。
文种别名自动归一:用户写的文种名常与规范名不一致("工作周报"、"领导讲话稿"、"工作方案"、"述职报告"),
intake.py 内置别名表会自动归到规范键再取专项追问,genre_input 保留用户原写法(回读确认时不改用户的说法)。
别名表见 references/task-fields.md 第 6.8.1 节;认不出的自定义文种按原名处理,用通用清单兜住。
周报是唯一每周重复生成的文种,口径与其它文种不同(篇幅 300~800 字、栏目前后周必须一致、
必写卡点与需协调事项、不写"经验与不足"、不加红头)。写法与评估口径见
references/task-fields.md 第 6.8.2 节与 references/quality-rubric.md 第 5.1 节——
别拿工作总结的尺子量周报,否则每周出稿都会刷一堆误报。
问完回读一遍确认清单("我理解要写的是…,正文只会用这些数据:…,对吗?"),得到确认再进下一阶段。
阶段 2 · 提纲与摘要(关键闸门)
产出 outline.json,规则:
- 覆盖报告的所有标题(按
一、/(一)两层或三层); - 每个末级小节必须有摘要,且 ≤50 个汉字——这是「内容承诺」,正式报告要逐条兑现;兑现不了就在这一步删掉;
- 每节给
target_chars,合计 ≈ 目标篇幅; - 想写但没数据的地方写进
open_questions,不要写进摘要里含糊带过。
周报(及月报/日报等按周月重复出的文稿)另有一条:结构要复用上一期,不要每周重新设计。
栏目名一旦固定就不再改——读者靠它做周与周的横向对比,结构漂移等于周报白写。
归档方式二选一,先跟用户确认:① 每周一个任务文件夹(文件夹名含期次,标题里就带期次;
栏目复用靠把上一期 outline/outline-v2.json 复制到新任务、改期次与各节 summary 再 record-outline);
② 一个任务文件夹持续出版本(文件夹名不含期次,期次写进导语,换来周与周的血缘与分数对比)。
之所以不能两全,是因为 _record() 会把交付文档的标题无条件设成任务文件夹名,
而 --based-on 只是血缘元数据、不跨任务解析(详见 references/task-fields.md 第 6.8.2 节)。
结构照抄 assets/outline.example.json,然后:
$PY $SK/task_store.py record-outline --task "$T" --from outline.json \
--suggestions "第三章改成从三个维度剖析" "第四章拆成两节"
(首版不传 --based-on;改版时 --based-on outline-v1。)
脚本会硬拦超过 50 字的摘要(errors 非空即拒绝写入)。把生成的 outline-vN.md 内容在对话里完整展示,让用户逐轮改。
用户每改一轮 → 生成新版 outline-vN+1,--based-on 指上一版,--suggestions 填用户上一轮的原话。
摘要没获用户明确点头,不进入阶段 3。
阶段 3 · 正式成文(先出过程版 Markdown)
按已确认的提纲写 report.json(结构照 assets/report.example.json):
lead写缘由与引导语;sections必须与提纲末级节 id 一一对应;tail.closing_phrase用文种惯用结语(报告「特此报告。」/ 请示「妥否,请批示。」/ 通知「特此通知。」/ 工作总结「以上总结,请审阅。」/ 周报「本周情况如上,请审阅。」,见references/genres-and-structure.md);meta填齐署名、成文日期、附件说明、附注、抄送、印发机关与日期;- 正文只写公文体:层次序数只能
一、(一)1.(1),段首空二字,禁止 Markdown(#、**、-、---会被直接拦下); - 每个具体数字/文号都必须来自任务里的
facts或已确认的公开事实;没有就改成定性表述或标【待补充】。
去 AI 味 / 反假大空(写作时就要做到,不靠事后洗稿)
判据:一句里有没有主体、动作、结果、时限。 不是"读起来像不像人写的"——
凡是不能被核实的一句话,就是废话,无论它多通顺。
落笔时守住五条:
- 不写万能过渡。删掉「综上所述/由此可见/值得注意的是/不难看出/换言之」,
直接从事实、数据或结论起句。 - 不用空转开头。「随着…的不断发展」「在当今…的大背景下」一律换成具体时间 + 具体事实。
- 不写空洞意义。「具有重大意义」「发挥了重要作用」「再上新台阶」「注入新动能」
——要么改成可核实的结果(做了什么、达成什么指标),要么删。 - 一句只留一个程度副词。「切实、大力、全面、有效、持续、不断、进一步、深入、扎实」
八个一起上只会稀释信息;留一个,其余落成数字与动作。 - 排比宁少不凑。「新思路、新举措、新成效」「规范化、标准化、精细化」
必须项项可落地,凑不出来的项直接删。
把"加强/提升/完善/推进"换成人话:谁 + 做什么 + 到什么程度 + 什么时候。
黑话换机关日常说法:赋能→培训/支撑,抓手→具体措施,闭环→办结并回访,顶层设计→由谁统一制定。
正反例(照这个手感写):
| 假大空 | 去 AI 味后 |
|---|---|
| 高度重视此项工作,切实提高政治站位,进一步增强责任感使命感。 | 3 月 12 日局党组会专题研究,明确分管副局长牵头,5 个业务处室各确定 1 名联络员。 |
| 随着信息技术不断发展,我局大力推进数字化转型,取得显著成效。 | 2026 年 1—9 月上线业务系统 3 个,窗口平均办理时长由 40 分钟压减至 12 分钟。 |
| 下一步将加大力度、多措并举、形成合力,为高质量发展注入新动能。 | 下一步 10 月底前完成剩余 20 处隐患销号;11 月起每月通报整改进度,连续两次末位的约谈主要负责人。 |
> 成文后、写进正文前先自检一遍(规则表逐句匹配,会告诉你哪句要改、改成什么):
>
> bash
> $PY $SK/deai.py report.json # 整篇按节审计
> $PY $SK/deai.py --text "<一段草稿>" # 单段自检
>
>
> record-report 也会自动跑这一项,结果在 assessment.ai_flavor,
> HTML 评估报告里有「去 AI 味 / 反假大空」专节(逐条清单:位置 / 类型 / 命中词 / 所在句 / 怎么改)。
> 完整规则表与改写对照见 references/quality-rubric.md 第 3.1 节。
引注角标(过程版溯源,必做)
凡引用公开来源的段落,在段末标 {{Sx}}(多来源写 {{cite:S16,S17}})。
Sx 必须是 task.json 的 extra.sources[].id——未登记的键会被校验直接拦下,这是防编造的硬闸门。
需要引注的地方:数据与成效、会议/论坛发言、政策文号与条款、厂商或机构预测、他单位案例。
不需要引注的:本单位的思路、任务、保障措施等自我表述。
{"id": "2.2", "paras": ["…使人工策略配置工作量锐减90%。{{S4}}",
"…平均溯源时间由原来的1小时压缩至10分钟。{{cite:S4,S5}}"]}
参考文献节写成新式 refs[](单一事实来源,不必在报告里再抄一遍来源信息):
{"id": "5", "level": 1, "heading": "附:主要参考资料", "role": "references",
"paras": [], "refs": [{"key": "S1", "text": "标题,出版者,日期。https://…"}]}
refs[] 可留空但节必须存在——脚本会回落到 task.json 的 extra.sources[] 自动生成文献表。
附件(表格、清单、评测汇总等)
附件不是正文的"节",用报告顶层的 appendix[] 承载,结构同 sections 的节点:
{"appendix": [{
"id": "A1", "label": "附件一", "name": "当前大语言模型在网络安全领域的能力评估",
"paras": ["本附件汇总公开渠道可查证的……(导语,可带 {{Sx}} 角标)"],
"children": [
{"level": 2, "heading": "一、多场景对比评估",
"tables": [{"caption": "表1 国内外主流大模型网络安全能力横向对比(公开评测汇总)",
"header": ["评估场景", "评测来源与口径", "主要发现", "判读"],
"rows": [["进攻侧|CTF 类攻防任务", "NYU CTF Bench……{{S28}}", "……{{S28}}", "……"]]}]},
{"level": 2, "heading": "二、综合判断与选型建议", "paras": ["……", "……"]}
]}]}
节点可用的键:paras / tables(caption+header+rows)/ children[](递归,可再带表格)。
渲染规则(md 与 docx 已对齐,不用手调):
- 附件说明排正文之后(
附件:1. XXX,多件时逐条列出);没有显式写meta.attachments时,
脚本自动从appendix[].name生成; - 附件正文另页起排于版记之后:标识「附件一」三号黑体顶格,附件标题居中;
- 附件不进逐节评分(它不是正文的节),也不计入
body_chars——评估结果里单独给
appendix_count/appendix_chars(含子节与表格单元格)/appendix_prose_chars(只算段落)。
> 附件里的数字同样是"事实",同样不许编造。 附件的表格是外部评测数据的密集区,
> 每个型号名、分数、百分比都要有登记来源;evaluate.py 的 unverified_facts 会扫描附件全文
> (含子节与表格单元格)。查不到的格子宁可留白,并在导语里写明口径(如"未列出的模型或场景
> 表示在公开渠道未检索到该口径结果"),不要用其它口径的数字填空。
记录本版(默认只出 Markdown)
$PY $SK/task_store.py record-report --task "$T" --from report.json \
--based-on-outline outline-v2 --based-on-report report-v1 \
--suggestions "第三部分补基层监管力量的具体表现" "把空话改成可执行表述"
一条命令完成:校验(含引注键合法性)→ 分配新版本号 → 存 report-vN.json → 渲染
report/<日期>_<名称>_vN.md(角标渲染成上标 [n]、文末自动生成编号文献表)→ 写 manifest 血缘
→ 自动跑评估(写 report-vN.eval.json / report-vN.coherence.json)
→ 自动生成评估报告 HTML(report-vN.assess.html + 摘要 report-vN.assess.json)。
把 md 内容展示给用户逐轮改;改到用户点头为止,再定稿。
> 修订后必评估(用户明确要求,不要静默跳过):返回值里的 assessment 字段就是
> 这一版的评估结论——节数、综合/完整度/充实度均值、判定分布、需要动手的节、未核实事实、
> 呼应度均值与需改进项,以及与上一版的对比(delta / changed_sections;
> 首版则标为"首版基线")。同时已生成 HTML 评估报告(assessment.html 给出路径)。
> 每次回复都要按阶段 4D 的八点把结论讲给用户听,并把 HTML 评估报告打开给用户看,
> 不能只贴 JSON,也不能因为"这次只改了一句话"就省略。
> 用 --no-eval 可跳过(仅批量生成时用);用 assess 可单独重跑评估并重新出 HTML。
> 不要再跑一次 record-report 来"重新生成 md"——那条命令永远分配新版本号
> (--force 只表示"校验不通过也强行记录")。只想重渲染 md 视图用 refresh-md,
> 只想重看评估结论用 assess。
定稿出 Word
$PY $SK/task_store.py finalize-report --task "$T" --version report-v2 [--red-header]
不修改内容,只排 Word:引注角标与参考文献节在此刻被自动剥离,交付版干净无引用标记。
--force 用于该版已定稿、仅需按新排版配置重排(finalize-report --force 与
record-report --force 语义不同,见"坑与对策")。
需要内容与 Word 一步到位时用 record-report --docx。
交付前必须自检 + 深度检测:
$PY $SK/verify_docx.py $TD/report/*_v2.docx --format-config $TD/format-config.json
50 余项检查、按文种条件启用,分两层(普通非红头、无附件的文种实际执行 43 项;
带附件时会追加附件标识另页起排/顶格/黑体/排在版记之后/内容紧随等 5 项,
--red-header 时追加发文字号与签发人 2 项。脚本汇总行里的「共 N 项」就是本次实际执行的项数,
不要拿它跟固定数字对不上就以为漏检):
- 第一层(浅层,"配置有没有落地"):纸张尺寸 / GB/T 9704 A4 / 页边距 4 项 / 文档网格 /
Normal 样式 / 标题字号居中 / 正文字体字号 / 行距固定值 / 首行缩进 / 页码域 / 奇偶页不同页码 /
打开即刷新域 / 无 Markdown 残留 / 层次序数合法 / 无占位符 / 待补充清零 /
过程版引注角标已移除 / 参考文献节已移除 / 跨页重复表头 / 附件标识(另页起排·顶格·黑体·排在版记之后·内容紧随)。 - 第二层(深度,"落地的细节对不对"):版心回算(每行字数×每面行数)/ 标题字体 / 标题 keepNext /
层次序数字体分派(一、黑体/(一)楷体/1.仿宋加粗) / 序数配对连续(正文与各附件各自编号,
二级三级在各自上级块内重新计数) / 序数层级无跳级 / 序数段缩进 / 正文缩进一致性 /
未用空格代替缩进 / 中文里混用半角标点 / 数字用法(公历阿拉伯数字、年份写全)/ 无全角空格 /
无连续空段落 / 段末无多余空格 / 表格内字体字号一致 / 成文日期格式 / 署名与日期配对 /
主送机关冒号 / 正文字体族合法 / snapToGrid=0 / 页码一字线 / 版记要素 / 附件说明左空二字 /
版头要素(红头时的发文字号与签发人,--red-header或自动探测)。
FAIL 一律不许交付,WARN 要在回复里说明。自检通过后再把 docx 呈现给用户。
检测出问题就纠正(尤其当 docx 不是本技能直排、而是用户给的往年文或模板稿时):
$PY $SK/fix_docx.py $TD/report/*_v2.docx -o $TD/report/*_v2.fixed.docx # 输出新文件并自动复检
$PY $SK/fix_docx.py <某个旧稿.docx> --dry-run # 先看会改什么,不写文件
$PY $SK/fix_docx.py <某个旧稿.docx> --in-place # 就地修(先备份 .bak)
$PY $SK/fix_docx.py <某个旧稿.docx> --only indent,punct,seqfont # 只修指定项
铁律:纠正只动排版,一个字都不动。 可自动修复的 16 项见下节。
修完脚本会自动再跑一遍同样条件的全部自检并给出「纠正前 FAIL → 纠正后 PASS」的对照,
把这个对照连同结论讲给用户听。仍有 FAIL 的(脚本改不了的,如内容层面的日期缺失、
发文字号未提供)必须如实列出,不许粉饰。
阶段 4 · 评估:逐节打分 + 跨节呼应度 + 呈现给用户
> 这一阶段现在是自动跑的:record-report 落盘时已经执行了 4A 与 4B,结果在返回值的
> assessment 里(也写进了 report-vN.eval.json / report-vN.coherence.json)。
> 所以本节你要做的是三件事:① 读结论 → ② 需要时补填建议(4C)→ ③ 按 4D 的套路呈现给用户。
> 下面 4A/4B 的命令在单独重跑时用(例如只改了建议、或要回评历史版本),
> 一般不必再手工执行一遍。
4A 逐节评估(这一节自己够不够厚)
$PY $SK/evaluate.py $TD/report/report-v2.json \
--task $TD/task.json --outline $TD/outline/outline-v2.json \
--out $TD/report/report-v2.eval.json
> 也可以直接用 task_store.py assess --task "$T" --version report-v2:它会把 提纲从
> based_on_outline 自动解析出来(手工跑 evaluate.py 最容易漏传 --outline,
> 一旦漏传,打分口径就从"对标提纲承诺"退化成"只看节内自洽",分数会明显不一致)。
对每一节给出:完整度(章节齐备/篇幅达标/摘要兑现/待补充清零/段落充分)与
充实度(数据密度/事实具体性/政策依据/结构条理/去AI味/可操作性),并列出 weak_dimensions。
evaluate.py 会先剥离引注角标与文献表再打分,所以分数与最终交付的 Word 口径一致
(另给 authored_body_chars 保留原稿字数供对比)。附件不计入 body_chars,单独给
appendix_count / appendix_chars / appendix_prose_chars——看到正文汉字数比预期少时先看这三项,
不要以为漏算了。
同时输出两类必须处理的东西:
unverified_facts:正文与附件全文(含附件子节与表格单元格)里找不到出处的数字/文号/文件名
→ 逐条向用户交代,要么改要么确认;
若该数值确有来源、只是没登进task.json,把事实补进facts[]后加--extra-corpus <facts.json>
重跑即可归零(不要为了消告警直接删数字,详见references/quality-rubric.md第 7 节);cliche_hits/ai_flavor:空话词命中与 AI 味清单(硬命中/软命中/堆砌,逐条带"命中词 + 所在句 + 怎么改")
→ 空话词改写为"主体+动作+时限"的可执行表述;硬命中一条不留,软命中与堆砌按清单挑着改。
先做适格性判断,再决定补哪里(重要):政策依据(只数书名号)、结构条理(只认「一是/二是」)、
可操作性(要求可操作句 ≥50%)三项在情况章、问题章、趋势章会系统性报 0 分,属误报——
不要被它牵着走把叙述体硬改成公文体。真正确认偏薄要看
篇幅达标/段落充分/摘要兑现/数据密度/事实具体性。
经验判据:完整度 ≥ 4.5 且 充实度 < 3.0 且薄弱项恰为那三项 → 大概率是误报叠加。
三种情况的处置与判据见 references/quality-rubric.md 第 5 节。
然后对 overall < 3.5 或 完整度 ≥ 4.5 而充实度 < 3.0 的节填 advice.json
(照 assets/advice.example.json)——补强材料必须来自本机已有材料,不许联网检索:
按优先级在本机找:① 任务 facts(用户已确认的事实)→ ② 任务文件夹 source/ 里已归档的参考件
(extract_source_text 能读 docx/txt/md/csv/json/html)→ ③ 本地知识库
工作根目录下的 src 与 knowledge(先 list-knowledge,两个目录都会列)。找不到就照实写
「本机材料中没有该口径数据,建议由业务处室提供」,不要用联网结果或凭印象的数字填。
$PY $SK/evaluate.py $TD/report/report-v2.json \
--task $TD/task.json --outline $TD/outline/outline-v2.json \
--advice advice.json --out $TD/report/report-v2.eval.json
呈现率与归档:advice_gaps 必须为空(它列出 overall < 3.5 但没填 advice 的节);
advice.json 归档到 notes/advice-report-vN.json,评估结果留在 report/report-vN.eval.json。
> n 节偏薄:2.1(充实度 2.4,缺数据密度与政策依据)、4.2(可操作性 1.8)……
> 建议扩展:2.1 补分类整改成效并注明统计时点;4.2 补信用惩戒的依据与执行主体。
> 补强材料(离线取自本机,需你确认后才进正文):①《…》(来自 source/2025年消防整治报告.docx)
> 要点:…;注意:该数据为全国口径,与本市不可直接比照。
> 用户在评估之外明确要求联网找素材时,才单独走一次联网检索(需
> GONGWEN_ALLOW_NETWORK=1 放行),结果只进建议区、需用户逐条确认——见「离线与隐私」章节。
> 评估本身不因联网而改变口径。
4B 跨节呼应度检查(这一篇前后接不接得上)
逐节打分是"单节内部"的质量;呼应度看的是节与节之间——开头承诺的事结尾有没有落点、
前章提的问题后章有没有逐条回应、各章开头有没有承接、术语前后是否统一、有没有跨节重复。
$PY $SK/coherence.py $TD/report/report-v2.json \
--task $TD/task.json --outline $TD/outline/outline-v2.json \
--out $TD/report/report-v2.coherence.json
六项指标 + 一个均值:lead_tail(开头↔结尾)、chapter_chain(相邻章主题词前向呼应)、
problem_solution(问题章逐点核对方案章)、transition(章首承接表述 + 回指词)、
terms(同物异名、简称先于全称)、duplication(跨节重复句)。
读法(重要,别只看分数):
- 这三项用同报告内相对口径标定(
lead_tail 10%/chapter_chain 12%/problem_solution 12%),
不是绝对标准——跨节词汇重合天然低于同节内部。看每项的evidence里写的"同报告内参考线"。 - 真正可操作的是清单:
unanswered_points(问题章里在方案章找不到词汇对应的要点)、
missing_in_tail、missing_next、chapters_without_transition、chapters_without_lead、
short_before_full、duplicates。分数只用来定位,改什么看清单。 - 有些低分不必强改:
lead_tail的"缘由段↔结语段"用词本就不同;
chapter_chain:2→3若低是因为问题章没复现前一章的系统名,那是体裁要求(复现反而让两章分工混乱);
terms的"合称 vs 分称"常被误判为同物异名。每项都带hint教怎么读。 - 分数是提示性指标,不是判决。模型必须自己回读原文确认,再决定改不改——
并且要明确写出"这条属误报,不必改"及理由,不要为了消数把词硬塞进正文。
改进建议必须由模型填写(脚本只出客观信号,不拍脑袋)。照 assets/coherence-advice.example.json:
{"items": {
"problem_solution": {"expand_this": "…", "suggestions": ["…"], "rewrite": "改后示例句"},
"terms": {"no_change": true, "reason": "经核对为『合称』,非简称先于全称,不必改"}
}}
$PY $SK/coherence.py $TD/report/report-v2.json --task $TD/task.json \
--advice coherence-advice.json --out $TD/report/report-v2.coherence.json
advice_gaps 必须为空;建议归档到 notes/advice-coherence-vN.json。
4C 建议补填与归档(把 advice_gaps 清零)
脚本只出客观信号(哪节偏薄、哪项脱节、缺哪个维度),"该补什么内容"必须由模型填写——
从本机已有材料里找(任务 facts / 任务文件夹 source/ 已归档参考件 / 本地知识库
工作根目录下的 src 与 knowledge),不许联网检索(见「离线与隐私」):
照 assets/advice.example.json(逐节)与 assets/coherence-advice.example.json(逐项)两个模板。
> 写 JSON 时的引号纪律(踩过坑):建议正文里若要引用词语,必须用中文引号 “ ”,
> 绝不要用 ASCII 双引号 "——它会把 JSON 字符串提前闭合,assess --advice 直接报
> JSONDecodeError,且报错位置落在字符串中间、看不出真正原因。实测两种形态都出现过:
> ① 引号后面紧跟中文(如 说"预判/反映")→ Expecting ',' delimiter: line N column M;
> ② 引号后面紧跟逗号或句末(如 都"有词"而、把"预判"硬塞)→ 才可能报 Expecting value: line 1 column 1。
> 别只检查 line 1:见到 JSONDecodeError 就先在建议文件里搜 ASCII 双引号
> (grep -n '"' advice.json 数一下引号是否为偶数),比盯报错行号快得多。写完必跑一次:
> python -c "import json,sys;json.load(open(sys.argv[1]));print('ok')" advice.json
> 另:报告章节里若要写"存在的主要问题""下一步工作打算"这类带引号的词,同理只能用中文引号。
判据:evaluate.py 的 advice_gaps 与 coherence.py 的 advice_gaps 双双为空,才算评估闭环。
注意这两个 advice_gaps 现在始终存在(它是"overall < 3.5 但没填建议的节"的清单,不再只在传了
--advice 时才出现)——所以它非空就是真的还没填,不是"这个功能没开"。
把建议回灌给 assess,让这一次评估自带建议与缺口状态:
$PY $SK/task_store.py assess --task "$T" --version report-v2 \
--advice notes/advice-report-v2.json \
--coherence-advice notes/advice-coherence-v2.json
--use-cache 只在报告内容一行未改时才复用上次结论(按内容指纹 content_hash 判定);改了正文会自动重算,
不要为了省时间硬加这个开关。
归档:建议进 notes/advice-report-vN.json 与 notes/advice-coherence-vN.json;评估结果留在
report/report-vN.eval.json 与 report/report-vN.coherence.json,两者的摘要同步进 manifest.json。
4D 呈现给用户(每次修订后的固定动作)
这一节是硬性的。 record-report / finalize-report 的返回值里带 assessment(因为评估是自动跑的),
只要它存在,就必须按下面八点整理成人话发给用户——不要只贴 JSON,也不要静默跳过。
只在批量跑脚本、明确不需要看结论时才用 --no-eval。
评估报告是 HTML,必须打开给用户看。 每次评估都会生成
report/report-vN.assess.html(路径就在 assessment.html),把它随结论一起呈现(打开预览),
用户才能自己逐节翻、按需打印或随版本归档。HTML 里包含:KPI 卡、隐私模式(完全离线 /
拦截出网次数)、与上一版对比、判定分布、逐节明细表(含承诺摘要与薄弱维度)、
需要动手的节(补强建议 + 离线补强材料)、呼应度六项与相邻章明细、改进建议与"判定为不必改"的理由、
真实性核对、公文要素覆盖、行动清单,以及报告末尾的隐私与离线声明。
只想换一套建议重出 HTML(内容没变)时,不必重跑评估:
$PY $SK/build_assess_report.py report/report-v2.eval.json \
--coherence report/report-v2.coherence.json \
--summary report/report-v2.assess.json \
--task $TD/task.json \
-o report/report-v2.assess.html
> --summary 可省,改用 --prev-eval report-v1.eval.json(可再配 --prev-coherence)
> 让脚本现算对比——对比口径与 assess 完全一致(都走 gongwen_lib.eval_delta()),
> 不会出现"对话里说 +0.4、HTML 里说别的"这种两处不一致。
> HTML 渲染失败不会连累评估:评估结果仍照常返回,只是 html 为空并在 html_error 里记原因,
> 此时要如实告诉用户"评估结论已出,但 HTML 渲染失败"。
- 本版总评:
mean_overall+ 判定分布(verdict_counts:充分/基本可用/明显偏薄/不合格 各几节)+ 参评节数。
只看均值会掩盖极端节,分布必须念出来。 - 与上一版对比(
delta_vs/delta/changed_sections):哪几节升了、哪几节降了、各升降多少。
首版没有前版可比,直接写「首版基线」并给出绝对分数,不要凭空编一个"提升"。 - 需要动手的节:
weak_sections/thin_sections逐节列出薄弱维度与具体补法——这是行动项,不是分数播报。 - 未核实事实:
unverified_facts(逐条给出处或改写)——这属"数字能不能站住",
与第 8 点的 AI 味分属两件事,别混着说。 - 前后呼应度:
coherence_mean+coherence_metrics各项分 +coherence_weak(需改进项);
判定为误报的必须明写"属误报,不必改"及理由。 - 开放项:
element_missing_required(必备要素缺失,如未署发文机关)、advice_gaps/
coherence_advice_gaps(还没填建议的缺口)、以及仍需用户拍板的事(补数据、某口径要不要采用)
单独列出,别混进分数里。 - 隐私模式:说一句
assessment.offline的状态——「本次评估完全离线(拦截出网 N 次)」;
若显示"联网已放行"(用户显式设了GONGWEN_ALLOW_NETWORK=1),必须如实说明,
并提醒正文/参考件的隐私边界。不要在评估里联网,也不要为省事放行联网。 - 去 AI 味:
ai_flavor.score+severity(硬命中/软命中/堆砌各几条)+ 逐条清单
(位置、命中词、所在句、怎么改)。硬命中一律要求改掉,一条不留;软命中与堆砌说清"改哪几处",
不要求全清。若上一版也有这项,把delta.ai_flavor一起报(升了多少/降了多少)。
有硬命中时不能只念分数,至少把前几条原词念出来——用户要看到"哪句要改"。
跨节这一节的呈现照这个形状写:
> 前后呼应度均值 4.27(v1 为 3.11)
> 实质脱节:第三部分 19 个要点中 8 个在第四部分没有落点,集中在「自主与可控的平衡」「智能体越权风险」「模型能力边界」——建议 4.1 补自主可控、4.2 第二条点名"前沿模型对攻击链识别通过率不足半数"的现状。
> 第 1→2 章衔接偏弱(主题词覆盖率 0.081,参考线 0.12):第 2 章未回指第 1 章的政策要求,建议 2.1 首段把政策与公司动作接起来。
> 判定为误报、不建议改:2→3 章覆盖低是因为问题章没复现前一章的系统名,属体裁要求。
4E 评估外来稿(别人写的稿,不是本技能产出的)
用户丢来一份 docx 说「评估一下」时走这条链路。与自产稿的差别全在没有原始提纲、没有登记过的事实上:
- 建档时把原稿登记成
--ref(进source/),--genre走文种别名归一(如「实践锻炼总结报告」→工作总结),
并在--fields-json里写evaluation_only:true与source_kind:"外来稿"——提醒后续不代改内容。 record-outline用「反向还原提纲」:节 id 与标题照原文,summary按「这个标题应当兑现什么」写
(不要照抄正文措辞),target_chars按体裁常例给(一级 400/二级 300/三级 200),合计 ≈ 全文汉字数。
在open_questions里写明「本提纲为反向还原,非作者原始提纲」。report.json忠实转录,一字不改:文字、数字、标点照原稿;原稿没有的要素(成文日期、结语、
参考文献节)就留空——留空本身就是评估要指出的要素缺口,不要替它补上。assess→ 填两份 advice →assess --advice再跑一遍,与自产稿完全相同(两个advice_gaps必须为空)。
不要对外来稿跑finalize-report(那是替人成稿);要动它的排版先fix_docx.py --dry-run。
四个必须自己判断的口径陷阱(脚本照常报,但解读方式不同,别被牵着改正文):
| 现象 | 真实原因 | 怎么报 |
|---|---|---|
摘要兑现 普遍很低(7%~60%) |
反向还原提纲的摘要措辞与原文用词天然不同,实词命中率当然低 | 明写「属反向还原口径所致,对本稿不作缺陷判据」,改看篇幅达标/段落充分/事实具体性 |
unverified_facts 为 0 |
原稿作为 --ref 进了语料,稿里的数字在语料里自然「找得到」——自我循环 |
想要真实清单,复制 task.json 把 source_files 与 facts 清空,再单独跑一次 evaluate.py --task <临时task.json>;报出来的才是「只有原稿自己说过」的数字 |
element_missing_required 报「主送机关」 |
个人总结/外来稿本就没有主送机关 | 按体裁判误报;只把「成文日期」这类该有而没有的当缺口 |
terms 报「同物异名」 |
脚本比的是「为河北公司」vs「河北公司」这类动宾前缀差异,不是全称 vs 简称 | 判词汇层误报;但若原稿真的混用两种称呼,把这条实质问题单独写进 suggestions——方向有价值,机制不对 |
另有三项脚本查不到、要自己扫(外来稿常见,比 GB 细节更易被忽略):
- 零宽空格 U+200B:从网页/聊天工具粘来的稿常有(实测一稿 7 处)。
python -c "t.count('\u200b')"一扫即知;
它会让检索、目录、格式统一全部失效。清理见docx-ooxml-direct-fix技能。 - 称谓混用:同一主体多种写法(如「河北信通公司」15 次 /「河北公司」15 次 /「河北电力」2 次)——
数一遍出现次数再决定要不要提,别凭印象说。 - 成文日期缺失:外来稿常缺,且正文里的会议日期会被
verify_docx误认成成文日期;报的时候要写清「是缺,不是写错」。
顺手核该文种骨架齐不齐(references/genres-and-structure.md §2):缺章比句子写得差重要得多——
实测一稿最值得说的一条就是「五章里没有『存在问题/不足』这一章」。
阶段 5 · 定稿、改稿与新版本
定稿:用户确认 md 内容后 finalize-report 出 Word(角标与文献表此时剥离),
跑 verify_docx.py 自检,再把 docx 呈现给用户。定稿信息记进 manifest 与 md 状态行。
改稿:用户提修改意见时:
- 对某一历史版本的事后评价 →
add-suggestion --version report-v2 --text "...",写入notes/,不动既有内容; - 作为生成下一版的依据 → 传给下一条
record-report --suggestions,会同时落进 manifest 与notes/suggestions-report-vN.json; - 只改了排版配置、要重排 Word →
finalize-report --force; - 只想重看 md →
refresh-md(不新增版本)。
新版本号自动递增(report-v3),based_on_outline / based_on_report 记清血缘。旧 md、旧 docx 与旧 json 一律保留,用户可随时翻任意历史版本下载。
改进建议要闭环:下一版的 --suggestions 应与上一版的 advice-report-vN.json
和 advice-coherence-vN.json 对得上;上一版 ai_flavor 里的硬命中也要逐条对上——
这一版改了哪几条、还剩几条,在回复里说清楚。改完 record-report 会自动重跑两份评估并重出 HTML,
assessment.delta / changed_sections 就是前后分数对比(哪项升了、哪项判定为不必改)——
按阶段 4D 呈现(结论 + HTML)即可,不必再手工跑脚本,让用户看到改稿是否真的解决了问题。
旧的 assess.html 与旧 md/docx/json 一样保留,用户可随时翻任意历史版本的评估报告。
排版深度检测与纠正
verify_docx.py 负责查(50 余项按文种条件启用,浅层 + 深度两层),fix_docx.py 负责修(16 项自动修复)。
两者共用同一套判定口径,所以「修完再查」必然一致,不会出现「检测说好了、纠正说没改」的错位。
可自动修复的 16 项(fix_docx.py)
| 修复项 | 做什么 | 对应检测 |
|---|---|---|
page |
纸张与四个页边距按配置归位 | 纸张尺寸 / 页边距 4 项 |
grid |
按版心反算重设 docGrid(每行字数×每面行数) |
文档网格 / 版心回算 |
styles |
Normal 样式字体字号归位(全体正文的兜底) |
Normal 样式字体 |
settings |
补 evenAndOddHeaders + updateFields |
奇偶页不同页码 / 打开即刷新域 |
pagenum |
页脚缺 PAGE 域时按「— N —」补建(奇偶分置) | 页码域 / 页码一字线 |
spacing |
正文行距改固定值 + 补 snapToGrid=0 |
正文行距 / snapToGrid |
indent |
首行缩进归位(正文 2 字、序数段跟随各级样式、顶格段 0 字) | 首行缩进 / 序数段缩进 |
leadspace |
去掉段首空格(改用首行缩进表达) | 未用空格代替首行缩进 |
trailspace |
去掉段末多余空格 | 段末无多余空格 |
blankpara |
删除多余空段落(连续空段保留 1 个) | 无连续空段落 |
punct |
中文语境半角标点转全角(,→, 等) |
中文里未混用半角标点 |
seqfont |
按序数本身归位字体(一、黑体/(一)楷体/1.仿宋加粗) | 层次序数字体分派 |
title |
标题居中 + 字体字号 + keepNext | 标题字体 / 标题居中 / 标题 keepNext |
table |
补齐跨页重复表头 w:tblHeader |
跨页重复表头 |
date |
成文日期格式归一(去前导零,不推断日期) | 成文日期格式 |
attachment |
附件标识归位(黑体三号、顶格、另页起排) | 附件标识 4 项 |
内容红线(写死在实现里,不是"尽量遵守")
- 不改写、不增删任何文字。字符级归一化只允许两类:去掉段首/段末空格、半角标点转全角
——两者都不改变语义;除此之外一个字都不动。 - 不编造日期、机关名、数字。
date项只做09→9这种写法归一,不做日期推断。 - 删段落只删完全空白的段,且要求不含图形/分页符/域;连续空段至少保留一个。
--in-place前先备份.bak;默认行为是另存<原名>_fixed.docx,不动原件。- 修完自动复检并把「纠正前 → 纠正后」对照讲给用户;仍有
FAIL的必须如实列出。
什么时候用它
- 本技能直排的 docx:一般
verify_docx.py就该全绿;出现FAIL说明build_docx.py有回归,
用fix_docx.py兜底后回头查生成逻辑,不要把纠正当成常态。 - 用户给的往年文 / 别处转来的稿:先
--dry-run看会改什么,念给用户确认,再正式修。 - 模板稿:模板往往只带版式不带 GB 细节,
--format-config传模板抽出的配置,
让纠正按模板口径走(而不是硬套国标)。 - 只想改某一项:
--only indent,punct,避免动到不该动的部分。
硬纪律(违反即返工)
- 不编造。政策文号、统计数字、会议名称、领导姓名职务、媒体报道,一律不得臆造。查不到就写「未检索到可引用的公开数据,建议由业务处室提供」。
- 材料只进建议区。正文只用任务
facts与用户上传/确认的材料;要把任何材料(本机参考件或用户授权后的联网结果)写进正文,必须用户逐条确认,并在正文加来源标注。 - 引用必登记。正文里
{{Sx}}的每个键都必须在task.json的extra.sources[](或报告refs[])里有登记条目;未登记会被校验拦下。 - 过程版带角标、正式版不带。每一版先出 md(角标 + 文献表供逐处溯源);定稿 Word 时角标与文献表必须被剥离,
verify_docx.py会查这两项。 - 每节摘要 ≤50 字,且必须在正式报告里兑现。
- 新版本绝不覆盖旧版本;每版必记
based_on与「生成前的用户建议」。要"重出同一版视图"用refresh-md,不要重跑record-report。 - 交付前必跑
verify_docx.py,FAIL不许交付。coherence.py的advice_gaps与evaluate.py的advice_gaps都必须为空。 - 低分不等于要改。适格性误报(政策依据/结构条理/可操作性、lead_tail 文体差异、chapter_chain 不复现专名)必须写清"判定为误报及理由",不得为凑分把词硬塞进正文。
- 模板优先:用户上传了模板就按模板抽出的
format-config.json排;只有没模板才用 GB/T 9704。 - 字体缺失要提醒:文档里写的是
仿宋_GB2312/楷体_GB2312/方正小标宋简体,macOS 常缺,要提示用户「Word 会字形替换,装字体后查看终稿」。 - 附件不是正文的节。附件一律放顶层
appendix[](渲染时另页起排于版记之后),不得塞进sections。附件里的每个型号名/分数/百分比同样是事实,必须登记来源;查不到的格子留白并写明口径,不得拿其它口径的数字填空。 - 修订后必评估、必展示。任何一次报告内容修订(
record-report,以及改配置后重排的finalize-report)都会自动重跑完整性/充实度与跨节呼应度评估,返回值里的assessment必须按阶段 4D 的八点呈现给用户(含与上一版的分数对比),并把自动生成的report-vN.assess.html打开给用户看。跳过仅在批量场景用--no-eval;事后想补跑用assess(会同时重出 HTML)。 - 评估检测完全离线、隐私优先。逐节评估、呼应度检查、评估报告 HTML、交付自检一律不联网:
① 不要在评估阶段调用任何联网工具(搜索/网页抓取/浏览器等),补强材料只从本机材料取;
② 不要为了"方便"用GONGWEN_ALLOW_NETWORK=1绕开离线保护;
③ 不要把report/里的 json/html 贴到在线预览器或任何外部服务去打开(本地打开即可);
④ 评估产物只写本任务文件夹,不上传、不外发。
用户在评估之外明确要求联网找素材时,才可单独放行一次(见「离线与隐私」),且结果只进建议区。 - 去 AI 味、反假大空(用户明确要求)。每一版成文都要过一次「去 AI 味」自检,且硬命中一条不留:
① 不写万能过渡(综上所述/由此可见/值得注意的是…)、不写空转开头(随着…的发展)、
不写空洞意义(具有重大意义/发挥了重要作用/注入新动能)、不写空洞支撑(提供了坚强保障)、
不用含糊词(一定程度上/某种意义上);
② 一句里程度副词最多留一个;排比项必须项项可落地,凑不出来的项删掉;
③ 行业黑话换机关日常说法(赋能→培训/支撑,抓手→具体措施,闭环→办结并回访);
④ 不靠"读起来像不像人写的"自我判断——跑deai.py看清单,改完再跑一次确认命中消失;
⑤ 不要把规范表述当 AI 味删掉:文种结语("特此报告。")、引号内的上级原文/领导原话不算,
必要表态可以留,但结论后面必须跟得住事实和数字。 - 目录约定不许改:一切都挂在用户定的工作根目录下——参考资料与知识库只认
<根>/src与<根>/knowledge(先翻再问用户要),任务一律在<根>/output/<公文名称>/下作业。根目录没确认过就先问用户(阶段 -1),别拿默认值硬开工;不要把任务建到当前工作目录、也不要自造T20260929-001之类的编号目录——init-task会用公文原名建文件夹(同名自动-2)。产品只落在这个任务文件夹里,不要散落到别处。 - 信息不足必引导,不许猜字段。用户没给的信息(必填字段、事实数据、政策文号)一律先问:跑
intake.py算缺口 → 每轮问 3~5 条且把「为什么问」一起讲 → 答一轮落库一轮(update-task)。
只有必填齐备才开工;用户答"没有/不知道"就写进open_questions并在正文标【待补充】,
不要反复追问同一件事。用户赶时间时只问必填 + 事实清单,其余用文种惯例补齐但必须显式声明补了什么。
严禁凭常识把用户没说的事实、数字、文号"顺手补上"。 - 交付前必跑深度检测;查出排版问题要纠正。
verify_docx.py的自检项(浅层 + 深度)里
FAIL一条都不许带出去;能自动修的用fix_docx.py修完再复检,把「纠正前 → 纠正后」对照讲给用户。
纠正只动排版,一个字都不许改内容(允许的字符级归一化只有"去段首段末空格"与"半角标点转全角")。
修不了的(内容层面的缺失,如无发文字号、日期未给)如实列出,不许粉饰成"已通过"。
命令速查
> 下文 $T = 任务文件夹名(=公文名称,即 init-task 返回的 task_id);$TD = <工作根目录>/output/$T(本机当前是 /Users/black/AI/write/output/$T,实际以 task_store.py config 的 effective.output_root 为准)。
| 目的 | 命令 |
|---|---|
| 看/定/改工作根目录(启动第一步) | task_store.py workspace(未确认时 needs_setup:true)/ workspace --init "<目录>" / workspace --reconfigure |
新建任务(在 <根>/output 下建「公文名称」文件夹) |
task_store.py init-task --name "公文名称" ... [--template T.docx] [--ref R.docx] [--fields f.json] [--root <目录>] |
| 翻参考文件(src)与知识库(knowledge) | task_store.py list-knowledge [--search 关键词](返回带 where 标来源) |
| 看生效路径 | task_store.py config(effective.knowledge_root / output_root / src_root) |
| 列任务 / 看任务 | task_store.py list-tasks / task_store.py show --task "$T" |
| 补任务字段 | task_store.py update-task --task "$T" --fields-json '{...}' |
| 追加上网来源(只增不改) | task_store.py add-sources --task "$T" --from sources.json(id 冲突报错,防改写历史条目导致旧版角标指错) |
| 追加事实(只增不改) | task_store.py add-facts --task "$T" --from facts.json(或 --text "…" "…") |
| 记提纲 | task_store.py record-outline --task "$T" --from o.json [--based-on outline-v1] [--suggestions ...] |
| 记报告(出 md,自动评估) | task_store.py record-report --task "$T" --from r.json --based-on-outline outline-v2 [--based-on-report report-v1] [--suggestions ...] [--advice a.json] [--coherence-advice c.json] [--no-eval] |
| 记报告并直接定稿 | task_store.py record-report … --docx [--red-header] |
| 定稿出 Word | task_store.py finalize-report --task "$T" [--version report-v2] [--red-header] [--no-eval](已定稿仅重排加 --force) |
| 重渲染 md 视图 | task_store.py refresh-md --task "$T" [--version report-v2] |
| 单独重跑评估 | task_store.py assess --task "$T" [--version report-v2] [--advice a.json] [--coherence-advice c.json] [--use-cache](提纲自动解析,不会漏传;同时重出 assess.html) |
| 重出评估报告 HTML | build_assess_report.py report/report-v2.eval.json [--coherence c.json] [--summary s.json] [--prev-eval report-v1.eval.json] [--task task.json] [-o report/report-v2.assess.html] [--external-links] |
| 事后补建议 | task_store.py add-suggestion --task "$T" --version report-v2 --text "..." |
| 逐节评估 | evaluate.py <report-vN.json> --task task.json --outline outline-vN.json [--advice a.json] [--out r.json] |
| 去 AI 味自检(成文后必跑) | deai.py <report-vN.json> [--json];单段自检 deai.py --text "<草稿>" / --text-file draft.txt |
| 呼应度检查 | coherence.py <report-vN.json> --task task.json [--outline outline.json] [--advice c.json] [--out c.json] |
| 模板抽格式 | extract_template_format.py tpl.docx -o fmt.json |
| 单独排 docx | build_docx.py report.json -o out.docx [--format-config fmt.json] [--red-header] [--keep-references] |
| 交付自检(浅层+深度,50 余项按文种条件启用) | verify_docx.py out.docx [--format-config fmt.json] [--red-header] [--keep-references] |
| 排版深度纠正(只改排版不改内容) | fix_docx.py in.docx [-o out.docx] [--in-place] [--dry-run] [--only item,...] [--format-config fmt.json](修完自动复检) |
| 盘点信息缺口 / 生成引导提问 | intake.py [--fields f.json] [--fields-json '{...}'] [--task "$TD"] [--genre 文种] [--limit 5] |
| 查离线/隐私模式 | 任一评估命令返回值的 assessment.offline,或看 report-vN.assess.html 头部「隐私模式」行 |
全部脚本用 /Users/black/.venv-gongwen/bin/python 运行。
上表所有命令都在离线保护下运行(脚本入口自动剥夺 socket 联网能力);
唯一放行方式是显式 GONGWEN_ALLOW_NETWORK=1,仅在用户在评估之外单独要求联网时使用。
坑与对策
| 坑 | 对策 |
|---|---|
| 成稿读起来"很顺"但全是废话(通篇正确、零信息量) | 顺不等于实。跑 deai.py report.json,看硬命中清单;判据是"这句能不能被核实",不是"读着顺不顺"。硬命中一条不留 |
| 以为"空话控制"分高就没 AI 味 | 套话字占比低 ≠ 不空:满篇「值得注意的是」里的词都不算套话词,字占比照样好看。现在充实度用的是「去AI味」维度(套话字占比/硬命中句占比/AI 味句占比三项取最差),看的是后两项 |
| 为了降 AI 味把该有的表态、结语全删了 | 别过度。文种结语("特此报告。")、引号内的上级原文/领导原话、必要的立场句要留;只把没有事实与数字支撑的表态句改掉或删掉 |
| 引号里引用上级原文被判 AI 味 | 引号原文属"转述",规则不区分引号(刻意不增加复杂度)。处置:在对话里明说"这几处是引用原文,不计入改写范围",不要为降分改字 |
| 想把"首先/其次/最后"留着(讲话稿习惯) | 公文正文层次用「一是、二是、三是」;「首先/其次」属软命中,出现一两次不扣分,但连续用会被计入 AI 味句占比,能换就换 |
报 RuntimeError: [离线模式] 本流程禁止任何网络访问 |
这是离线保护生效,不是 bug。评估检测(evaluate/coherence/build_assess_report/verify_docx/task_store)默认剥夺 socket 联网能力。正常评估不需要联网——补强材料改从本机取(任务 facts / source/ 已归档参考件 / 本地知识库)。确需联网只用一次:GONGWEN_ALLOW_NETWORK=1 $PY $SK/…(会如实记进评估结果与 HTML 的「隐私模式」行) |
| 在评估阶段顺手联网搜补强材料(违反"完全离线") | 不要。评估阶段禁用一切联网工具;材料只从本机取,取不到就写「建议由业务处室提供」。用户单独要求联网找素材时,那是评估之外的独立动作,且结果只进建议区待用户逐条确认 |
| 离线报告里补强材料的 URL 想可点击 | 默认渲染成纯文本(可复制,不生成外链,避免离线件被误点外发)。确实需要可点击外链时显式加 --external-links,并在交付时说明该件含外链 |
把 report/*.assess.html / *.json 丢到在线预览器打开 |
别这么做——那是把正文与评估结论送到外部服务。本地双击 HTML 即可(单文件自包含、断网可开) |
任务建到了当前工作目录 / 自己编了个 T20260929-001 目录 |
统一走 init-task --name "<公文名称>":它在 <工作根目录>/output/ 下用公文的原名建文件夹(只剔除 / \ : * ? " < > \| 这些文件系统非法字符,不删「关于」「的」)。同名自动加 -2 |
--task 传了编号 / 传了 slug 后的短名,脚本报"任务不存在" |
--task 必须传文件夹名本身。用 list-tasks 看实际 task_id(就是文件夹名),或直接看 init-task 的返回值 |
| 要参考资料却让用户上传,用户说"我早放库里了" | 建任务前先 list-knowledge [--search 关键词](src 与 knowledge 都会列);--template / --ref 只写文件名即可,脚本会依次去这两个目录取 |
init-task 报 workspace_not_configured 或被挡住 |
工作根目录还没问过用户。先 task_store.py workspace 看 detected 候选,问用户确认后 workspace --init "<目录>";用户这次就直接说了目录的话,可以 init-task ... --root "<目录>" 一步登记 |
| 用户说"换到别的地方去",但产物还落在老路径 | 改根要跑 workspace --init "<新目录>"(会清掉老的单项覆盖并报 dropped_overrides);只 --set output_root=... 是单项覆盖,不会带动另两个 |
| 行距"多少磅"凭感觉写 | 别写死。build_docx.py 按「版心高 ÷ 22 行」反算固定行距,按「版心宽 ÷ 28 字」反算 docGrid.charSpace,换字号也能自适应 |
| 固定行距被文档网格二次放大 | 正文段必须写 w:snapToGrid val=0(脚本已做),否则 29 磅会变成别的值 |
| 字号大于行距被裁切 | 标题段用单倍行距,不套固定值(脚本已区分) |
| OOXML 子元素顺序错 → Word 报"文件已损坏" | 脚本用带顺序表的插入器(pPr/rPr/settings 三张顺序表),不要用 append 硬塞 |
| 模板抽取把正文样式认错 | extract_template_format.py 输出 _inferred/_missing,把 _missing 念给用户,必要时手改 format-config.json |
两个 --force 语义不同,容易误用 |
record-report --force = 校验不通过也强行记录(仍分配新版本号);finalize-report --force = 该版已定稿仍按新配置重排 Word(不新增版本)。只想重新生成 md 视图 → 用 refresh-md |
正文里写了 {{Sx}} 但来源没登记 |
校验会报 error 并列出未登记键。到 task.json 的 extra.sources[] 补条目(id/title/publisher/date/url/used_for),或写进报告 refs[] |
| 定稿后 Word 里还看得见角标或文献表 | build_docx 会自动 sanitize_report() 剥离;若仍出现,检查参考文献节的 role/heading 是否被正确识别(role: "references"、refs[]、标题匹配「附:主要参考资料」三者任一即可) |
evaluate.py 分数和手数字数不一致 |
它按正式版口径打分(先剥角标与文献表),所以比原稿少;authored_body_chars 是原稿字数 |
coherence.py 报了一大串低分 |
先看每项的 hint 与清单,再回读原文。terms 常把"合称"误判为"同物异名";chapter_chain 偏低常是因为后章没复现前章专名(体裁要求,不必改)——写成 no_change: true + reason 即可清掉缺口 |
| 报告太长,主上下文爆窗 | 超 1.5 万字的报告:派 general-purpose 子 Agent 分章产出 sections 片段 JSON,主 Agent 只做合并与 record-report。子 Agent prompt 要带完整任务记录、格式要求、片段的节 id 范围 |
| 各版内容几乎一样、只改了错别字 | --suggestions 必须是用户原话;若本版未体现实质性修改,主动提醒用户 |
| 页码在单双页都靠右 | 需 settings.xml 的 evenAndOddHeaders + even_page_footer(脚本已做,verify_docx.py 会查) |
| 表格跨页丢表头 | 脚本给每张表首行打 w:tblHeader;verify_docx.py 会查 |
| 附件和正文挤在一页、标识和标题没分开 | 附件正文用 w:pageBreakBefore 另页起排(脚本已做)。别把附件写进 sections——那样它会被当成正文的节参与逐节评分与摘要兑现比对,分数和篇幅口径全乱。附件一律放顶层 appendix[] |
| 附件的表格数字被报成"未核实事实"或反过来漏检 | 附件是树,扫描必须递归 children[]——旧版本只读顶层 paras/tables,挂在子节的表1与结论段会整段逃过核对(报出"无未核实事实"的假阴性)。现在 evaluate.py 会按节点递归扫,where 标到「附件1(名称) › 一、多场景对比评估」这一级 |
有正常出处的数字被判"未核实"(如 GLM-5 19.5%) |
数字签名必须在保留空白的原文上抽:语料归一化会把「GLM-5 19.5%」压成「GLM-519.5%」,签名随之变成 5195,与报告里的 195 对不上。脚本已改为 digit_signatures(collect_corpus_raw(...));若仍报,先核对是不是真没登记(见上一条) |
coherence.py 的 terms 报出莫名其妙的"同物异名"(如"这是我国首个关于智能体") |
中文无分词,候选正则从左贪心会吞进前文普通词语,句子碎片被当成"全称"。脚本已做两道过滤:①截到最后一个功能词之后,且不得只剩裸名词后缀(大模型/智能体 这种通用名词会把所有专名并成一簇);②候选必须真被复用(≥2 次)或带显式定义标记(X(以下简称Y))。代价是"全称只用一次"的轻微问题会漏报——这是刻意的保守取舍(宁漏报不误报),按 references/quality-rubric.md 第 8 节的判读纪律处理 |
| 评估口径漂移:同一份报告两次跑出不同的均值(如 3.64 vs 3.73) | 十有八九是漏传 --outline。不传提纲时打分口径从"对标提纲承诺"退化成"只看节内自洽",那几节的 篇幅达标/摘要兑现 会失去参照而偏低。用 assess 子命令,它从报告 based_on_outline 自动解析提纲;手工跑 evaluate.py 必须显式带 --outline |
| 提纲把「章」当末级节时,内容详实的章却被判得很低 | 报告常把正文放在章的子节里,若只取章自身导语,34 字的导语会把整章判成 1.97 分。脚本已给 section_text() / section_paras() 加 deep=True 口径(递归 children 汇总),assess 与 evaluate.py 默认都走深口径——如果某章分数明显与肉眼判断不符,先确认是不是被子节"藏"了内容 |
修订后明明改了几节,changed_sections 却是空的 |
判定已从 delta >= 0.05 改为非零即记录(if d:)。0.03 这类小幅变动也是变动,漏记会让用户以为"这版没改什么"。若仍为空,才是真的没动到评分维度 |
| 评估报告 HTML 打不开 / 打开是空白 | 它是单文件、零外部依赖,正常双击即开(不要用在线预览器去加载本地 html/json)。若 assessment.html 为空而 html_error 有值,说明是渲染期异常(多半是 advice / commented 里混进了非字符串结构)——用 build_assess_report.py --summary report/report-vN.assess.json 复现即可,不要去改 evaluate.py 或 coherence.py,那两处只负责出数据 |
| 对话里报的增减和 HTML 里对不上 | 两处都必须走 gongwen_lib.eval_delta()(task_store._assess_summary() 与 build_assess_report.py 共用同一实现)。若发现不一致,是有人另写了一份对比逻辑——合并回共享函数,不要在两边各调参数 |
assess --advice 报 json.decoder.JSONDecodeError: Expecting value: line 1 column 1 |
九成是 advice / coherence-advice 的 JSON 里在中文句子中间写了 ASCII 双引号 "(如 "建议补1个"发出一份建议"的实例"),把 JSON 字符串提前闭合了。写建议正文时一律用中文引号 “ ”,不要用 ASCII 引号;改完先 python -c "import json,sys;json.load(open(sys.argv[1]))" 你的advice.json 自检一次再回灌 |
| 首版成文严重低于目标篇幅,评估全线被"篇幅达标"拖低 | record-report 只给 warning 不拦。成文后先看 md 头部的状态行「正文 N 字 / 提纲目标 M 字(-x%)」,再逐节核对 target_chars。经验值:按每节 target 逐节写满,整篇才达标;凭感觉写通常只到目标的 55%~75%(本次首版 3248 字 vs 目标 5850 字,均值 2.99;补厚到 4493 字后升到 3.29) |
verify_docx.py 报 ! 待补充已清零: N 处【待补充】 |
用户明确选择"无现成数据、正文用定性表述 + 【待补充】"时,这条 WARN 是预期结果,不是缺陷。不许为了消警告直接删掉【待补充】(那等于把该填的数位抹掉);正确做法是在交付回复里写明"共 N 处需业务部门核定后填入,给我数据我立刻重出一版"。用户给了数据就把事实补进 facts[] 再重跑 |
| 用户只丢一句话就等稿("帮我写个关于 XX 的报告") | 别凭常识补字段。先跑 intake.py 算缺口,每轮问 3~5 条、把「为什么问」一起讲;必填齐备才开工。一次把 40 条问题甩过去,用户只会回"你看着办" |
| 写"周报"时按工作总结的尺子来(篇幅定 3000 字、写"经验与不足"、加红头) | 周报是短周期事务文稿:300~800 字(常见 400~600)、栏目固定、必写卡点与需要协调事项、不写"经验与不足"、不编发文字号不加红头。intake.py --genre 周报 会追问周期时点/报送对象/固定栏目/本周完成/下周计划与卡点,照它问就不会跑偏;口径见 references/genres-and-structure.md 第 2.1 节 |
| 周报每周重新设计栏目,前后周对不上 | 周报的价值在于周与周可比。首次定下栏目后就不再改:若每周建独立任务文件夹(标题含期次),把上一期 outline/outline-v2.json 复制到新任务、只改期次与各节 summary;若用一个任务文件夹持续出版本,则期次写进导语。别指望 --based-on 跨任务引用——它是血缘元数据,脚本不校验目标存在,manifest 又是任务级的 |
| 周报的标题里想带期次,但文件夹名不想带 | 做不到:_record() 里 content["report_name"] = task.get("name") 是无条件覆盖,交付文档标题永远等于任务文件夹名。要标题带期次就把期次写进任务名(→ 每周一个文件夹);不想动文件夹名就把期次写进导语(→ 一个文件夹持续出版本,还能拿到周与周的分数对比)。先跟用户确认选哪种 |
| 周报的评估报告一片红,看着像不合格 | 拿通用口径量短周期文稿会系统性误报:政策依据 几乎必然 0(周报不以政策立论)、可操作性 在"本周完成"节报 0(已然事实本就该用过去式)、chapter_chain/transition 也必然低(三个栏目讲三件不同的事,主题词本就不重合,加承接语反而破坏栏目独立性)。按 references/quality-rubric.md 第 5.1 节(含实测分数)过滤后再写 advice;周报真正的判据只有四条:本周完成事项逐条可核、进度词前后周一致、卡点写明需要谁支持要什么、栏目与上期一致。不要为了抬分给周报加政策引据、加承接语、改成措施体 |
周报的 摘要兑现 只有 10% 上下(正文明明把栏目都写全了) |
九成是提纲摘要写成了写法说明("按事项逐条写做了什么与推进程度""进度用固定词表")——脚本按摘要实词在正文中的命中率算,写法说明在正文里当然找不到。改成内容承诺("本周安全设备策略复核、测评保护整改、告警判读三项的完成情况与进度")即可回到 40% 以上。改完仍低,才是正文没兑现承诺 |
| 带具体日期的措施句被判为"不可操作" | 判据缺陷,已修(2026-10-04):CONSTRAINT_PAT 原来只认「月底前/年底前/每季度」这类相对时限,「10月14日前完成」「3个工作日内提交」全都不算约束,导致周报「下周工作计划」整节 0 分。现补入具体年月日、具体月日、N 个工作日内、本/下周与本月内/本季度四类。这是一次评分口径变更:变更前评估过的 可操作性 分数不可与变更后直接比,需要可比就对历史版本重跑 assess |
| 用户说"文种"用的词和清单不一样(如"工作周报""领导讲话稿""述职报告") | intake.py 内置别名表自动归一(GENRE_ALIAS,见 references/task-fields.md 6.8.1),照样出专项追问;genre_input 保留用户原写法,回读确认时不要改用户的说法。自定义文种名不在表内时按原名处理、不报错 |
用户说"资料我早提供过了"但任务里 facts 是空的 |
对话里说过 ≠ 落库了。用 update-task --fields-json 把他刚说的话结构化落盘,再跑 intake.py --task "$TD" 看还缺什么——别直接把聊天记录当事实来源 |
| 附件里「一、」被排成楷体(与正文一级标题不一致) | 附件子节的 level 常写成 2 而标题是「一、」。build_docx.py 已改为按序数本身判定视觉层级(heading_level()),序数是「一、」就是黑体,与声明的 level 无关。数据侧不用改 |
verify_docx.py 报「序数配对连续」FAIL |
先看是不是附件与正文被当成一个序列了——脚本已按「附件标识」切段,正文与每个附件各自编号;再看是不是二级序数被跨章比较——脚本按一级块分组。真 FAIL 只有一种可能:同一块里确实跳号或重号(如 一、二、四、) |
fix_docx.py 把正文改了(用户质问) |
不可能,也不允许。纠正只做两类字符级归一:去段首/段末空格、半角标点转全角,其余一个字不动。修完脚本自动复检并打印「纠正前 → 纠正后」;要核实可用 --dry-run 先看清单。若真发现文本被改,属脚本缺陷,立即停用并排查 |
纠正后还是有 FAIL |
脚本只能修排版,修不了内容层面的缺失(无发文字号、成文日期未提供、正文太短)。这些如实列给用户,不要反复跑纠正,也不要为消红而塞内容 |
用 fix_docx.py 处理用户给的往年文却没先看清单 |
别人的稿子可能有意为之(本单位惯例)。先 --dry-run 把"会改什么"念给用户确认,再正式修;有模板就用 --format-config 走模板口径,别硬套国标 |
参考文件
| 文件 | 内容 |
|---|---|
README.md |
面向人的使用说明(不是给模型读的):文种清单、首次启动/工作根目录、六步流程、四个真实使用案例、评估怎么读、命令速查、常见问题。用户问「这个技能怎么用」时直接指给他 |
references/gb-t-9704-2012.md |
GB/T 9704-2012 可落地参数表(页边距/版心/字体字号/行距算法/页码/版头主体版记要素/交付检查表) |
references/genres-and-structure.md |
15 种法定文种 + 非法定文种骨架(含周报及第 2.1 节周报特别约定)+ 结构要素清单 + 各文种结语 + 口语→公文表达对照 |
references/task-fields.md |
任务填报字段全集、缺失处置优先级、落盘结构、manifest 血缘字段规范、信息不足时的引导提问清单(第 6 节:六组问题库 + 15 类文种专项追问 + 文种别名归一 6.8.1 + 周报填报要点 6.8.2 + 停止追问的时机) |
references/quality-rubric.md |
完整度/充实度 11 项子指标口径、去 AI 味规则表与改写对照(第 3.1 节,含正反例)、前后呼应度 6 项跨节指标口径、周报专属判读口径(第 5.1 节)、分数门限、扩展建议方法论、材料纪律、真实性红线 |
assets/task-fields.example.json |
任务填报字段完整示例 |
assets/outline.example.json |
提纲与摘要示例(含 target_chars、open_questions) |
assets/outline.weekly.example.json |
周报专用提纲示例(三栏目固定、篇幅按周报口径、含 reuse_rule 逐周复用规则) |
assets/report.example.json |
报告内容模型示例(含 {{Sx}} 引注标记、章 role、参考文献节 refs[]、appendix[] 附件) |
assets/advice.example.json |
逐节扩展建议示例(含 web_findings 检索材料格式) |
assets/coherence-advice.example.json |
呼应度改进建议示例(含"判定为误报"的写法) |
assets/default-format-gbt9704.json |
默认排版配置(要微调行距字号就改它,再传 --format-config) |
与其它技能的衔接
- 需要在成稿上做 OOXML 级微调(单元格底纹、禁止跨页断行等本技能未覆盖的排版诉求)→ 用
docx-ooxml-direct-fix。 - 需要批量产出几十份长报告 → 用
batch-word-report-html2docx的并发编排思路;本技能负责单份的合规与版本管理。 - 需要把成稿放入在线文档协作 → 转交
tencent-docs-routing。