大纲 → 并行搜索 → 内容合成 → DOCX 生成 → 来源验证 → 交付
unified-search skill → install from https://clawhub.ai/ccmxigua/unified-search-suitetavily-research skill → requires Tavily API keyyaml
title: "章节标题"
description: "章节定位与目标"
sections:
- heading: "3.1 第一级标题"
topics:
- "子主题 1"
- "子主题 2"
- heading: "3.2 第一级标题"
topics:
- "..."
reference_docx: "/path/to/reference.docx" # 可选,DOCX 样式参考
output_dir: "/path/to/output" # 可选,默认 ~/.openclaw/media/outbound/
/unified_search <关键词> + Tavily Research 深度搜索 → 来源采集必须 使用 sessions_spawn(runtime="acp", agentId="claude", mode="run"), 禁止 默认 runtime="subagent"(继承 Telegram 路由会失败)。
ACP 参数固定规则:以上参数为固定模板, 禁止 添加
lightContext(仅 subagent 有效,ACP 不认)、 禁止 添加runTimeoutSeconds等额外参数。AC 使用各自后端默认超时。
⚠️ #50597 警告:ACP Claude CLI 有 ~30% 概率返回空结果(只含 thinking block,0 输出 token)。 见 GitHub #50597。 降级策略:子代理返回空、超时、或 Internal error 时,触发自动重试(最多 2 次)。 若 3 次全空/全失败, 降级走
/unified_search(三引擎搜索),禁止直接使用 llm-task。为什么禁止 llm-task 降级:llm-task 让模型直接搜索时,模型会编造/猜测 URL (已验证:BrowserStack
/guide/beta-testing、/guide/alpha-vs-beta-testing、 Testim/blog/beta-testing/、SoftwareTestingHelp/alpha-testing-vs-beta-testing/均为 llm-task 幻觉 URL,返回 404)。/unified_search返回真实可访问的 URL。
每个 ACP 子代理执行两路搜索后合并:
① unified_search(快速结构化搜索)
text
/unified_search <英文关键词>
记录每个来源的 URL、标题、日期、权威度、原文摘录。
② Tavily 深度研究(补充覆盖面与深度)
bash
node ~/clawd/skills/tavily-research/scripts/research.mjs \
"<英语研究问题>" --model pro --out /tmp/tavily_<topic>.md
读取 /tmp/tavily_<topic>.md,从报告中提取:
Tavily Research 耗时 20-60s,等待期间可先整理 unified_search 的结果。
③ 合并去重
source_channel返回结构化 JSON:
text
{
"topic": "...",
"sources": [
{
"url": "...",
"title": "...",
"date": "...",
"authority": "gov|academic|news|commercial",
"source_channel": "unified_search|tavily_research|both",
"quotes": ["原文句1", "原文句2"],
"key_data": {"metric": "value"}
}
],
"suggested_body": "基于来源的正文草稿"
}
更新 research_results.json:回填研究数据(仅更新,不覆盖已存在的 sources):
name ← 从 topics.json 取对应的 heading(如 "Alpha 测试")summary ← 从 ACP agent 返回的 suggested_body 提取摘要(2-4 句)key_findings ← 从 suggested_body/ sources 提取 3-5 条关键发现status ← "research_completed"合并所有子代理返回结果
⚠️ 跨 agent URL 去重(强制硬步骤,不可依赖 LLM 自觉): bash
python3 scripts/dedup_sources.py <research_dir>
脚本自动完成:
research_results.json 中所有重复 URLchapter.md 中所有 [^N] 引用chapter.md 中同一脚注号的重复定义verification_keywords.jsondedup_report.json 记录去重详情必须在生成 chapter.md 正文之前执行此步骤。
生成 MD 正文:每处数据/观点标注脚注引用 [^N](每个来源只有一个脚注号,全文统一使用该号引用)
脚注格式: [^N]: 作者/机构。《标题》。发布日期。URL
脚注从 0 起连续编号
同步输出 verification_keywords.json:每写入一处 [^N] 时,顺带记录:
footnote_id: Nsource_url:对应的来源 URLkeywords:该处引用的核心术语/数据(2-5 个英文词/短语,如 ["defect reduction", "85%", "alpha testing"]){ "footnotes": [ { "id": "0", "url": "...", "keywords": [...] }, ... ] }输出草稿 → 人工审阅(必须,不可跳过)
当 verification_keywords.json 未在阶段三同步产出(或关键词来自 research quote 而非声明),
可使用 keyword_generator.py 基于声明(claim)反向生成关键词:
bash
python3 scripts/keyword_generator.py chapter.json research_results.json verification_keywords.json
原理:遍历 chapter.json 中每个 [^N] 脚注,提取其所在句作为中文声明(claim),
在 research_results.json 中查找该脚注对应的英文研究原文,调用
claim_keyword_extractor.py(LLM)将中文声明翻译为英文关键词。
关键差异:
示例(fn#2 "CLSC 的关键特征包括:产品可回收性设计优先…"):
"Jones Elite Logistics The", "Closed Loop Supply Chain", "includes product design""closed-loop supply chain", "recyclable product design", "forward reverse logistics", "full lifecycle value", "re-use and recycling"原则:同一套关键词既驱动内容写作,也驱动截图验证——声明驱动,追溯闭环。
此阶段不可跳过。 在进入 DOCX 生成前,对 chapter.md 正文扫描 行内引用残留——即未纳入 [^N] 脚注系统的括号引用。
扫描正则(Python):
python
INLINE_CITE_RE = re.compile(
r'(?:'
r'[((][A-Z][A-Za-z]+(?:\s+et\s+al\.?|\s+等)?[,,\s]+\d{4}[a-z]?[))]' # (MDPI, 2022) / (Author, 2023)
r'|[A-Z][A-Za-z]+[((]\d{4}[))]' # Nature(2025)
r')'
)
检测流程:
bash
python3 -c "
import re, sys
with open(sys.argv[1], 'r') as f:
text = f.read()
INLINE_CITE_RE = re.compile(
r'(?:'
r'[\((][A-Z][A-Za-z]+(?:\s+et\s+al\.?|\s+等)?[,,\s]+\d{4}[a-z]?[))]'
r'|[A-Z][A-Za-z]+[\((]\d{4}[))]'
r')'
)
for i, line in enumerate(text.split('\n'), 1):
if line.lstrip().startswith('[^'): # skip footnote definitions
continue
for m in INLINE_CITE_RE.finditer(line):
print(f'L{i}: \"{m.group()}\" — 未纳入 [^N] 脚注系统')
" chapter.md
处理规则:
每处匹配 → ERROR 级别。必须逐条回答:
[^N] 脚注引用检查通过条件:扫描零输出
此检查必须在 pandoc 生成 DOCX 之前完成;若任一 ERROR 未解决,阻断进入阶段四
常见坑:
[^N]:)自动跳过,不误报bash
{{- if .args.reference_docx }}
# 先验证 reference.docx 存在,不存在则去掉 --reference-doc(否则 Pandoc exit 99)
pandoc chapter.md -o chapter.docx \
--reference-doc="{{ .args.reference_docx }}" \
--from markdown+footnotes+tex_math_dollars --to docx
{{- else }}
pandoc chapter.md -o chapter.docx \
--from markdown+footnotes+tex_math_dollars --to docx
{{- end }}
--reference-doc可选:不指定时 Pandoc 使用内置默认样式。⚠️ Pandoc 3.7 兼容性:
tex_math_single_dollar扩展在 Pandoc 3.7.0.2 中不再支持, 仅使用tex_math_dollars。若--reference-doc指向不存在的文件,Pandoc 会以 exit code 99 失败; 执行前必须test -f验证文件存在。
Heading 层级映射: Pandoc 将 Markdown heading 映射为 Word 内置样式:
# → Heading1## → Heading2### → Heading3#### → Heading4
章节编号需手动写入标题文字,Pandoc 不自动编号。脚注 URL 超链接化(强制):
Pandoc 默认将脚注中的 URL 输出为纯文本,在 Word 中不可点击。
生成 DOCX 后必须执行后处理脚本 add_hyperlink_footnotes.py:
bash
python3 add_hyperlink_footnotes.py chapter.docx chapter.docx
⚠️ Pandoc 会重编号脚注:markdown 中的
[^42]在 DOCX 中可能被重编号为 ID 37、38 等 (Pandoc 按出现顺序分配连续 ID,且重复引用会被复制到不同 ID)。 排查时必须按 URL 内容定位,不可假设 markdown 编号 = DOCX 编号。
⚠️
add_hyperlink_footnotes.py依赖research_results.json: 脚本从research_results.json读取 URL→脚注映射来构建超链接。 若在修改chapter.md/research_results.json后未重跑此脚本, DOCX 中的脚注 URL 可能仍为旧值。变更三文件后必须重新执行:pandoc→add_hyperlink_footnotes.py→verify_docx.py。
后处理原理:
word/footnotes.xml())<w:hyperlink> 元素(不含 (日期访问) 等中文后缀)<w:r> 添加 <w:rStyle w:val="Hyperlink"/> 以显示蓝色下划线word/_rels/footnotes.xml.rels 中注册对应的 relationship借鉴 citation-check v2 的 Two-Pass Architecture、Status Decision Tree、Numerical Precision Rules、Mandatory Search Templates。 Pass 1 提取声明 → 直接进入 Pass 2 验证(无需人工闸门)。
从 chapter.md 提取所有可验证的事实声明。使用 scripts/extract_claims.py:
bash
python3 scripts/extract_claims.py chapter.md claims_pass1.json
提取规则(8 类声明,对齐 citation-check v2):
类型模式示例Statistic含数字+单位的断言"准确率达 92.3%", "$4.7B 市场"ComparativeX 比 Y 更/快/高/大"比基线快 3 倍"Temporal时间限定断言"2024 年采用率达到…"Attribution引用来源的声明"据 WHO…", "Smith 等发现…"Causal因果关系"这使延迟降低了 40%"Existence断言存在/为真"有 500M 用户"Ranking排名/排他声明"最大", "首次", "前 3"Quote直接引用引号内归因文本
排除(不提取):定义、明确标注的观点、假设、问题、无法来源的未来预测、方法论描述、致谢。
脚本输出 claims_pass1.json,包含每条声明的 claim_id、 text、 claim_type、 footnote_ids。
对 Pass 1 输出的每条声明,使用以下决策树逐条验证。
核心工具: /unified_search(三引擎搜索)执行 Mandatory Search Templates。
text
START
│
├─ 是否为 Attribution 类型(引用论文/报告/来源)?
│ ├─ YES → 进入 CITATION VALIDATION
│ └─ NO → 进入 STATISTIC/FACT VALIDATION
│
│
CITATION VALIDATION
│
├─ Step 1: 引用来源是否存在?
│ │ 运行 Academic Search Templates(见 references/search_templates.md)
│ │
│ ├─ NO → Status: "Citation Not Found"
│ │ Issue: "无法在任何数据库中定位 [引用]"
│ │ STOP
│ │
│ └─ YES → Step 2: 来源是否讨论声明所述主题?
│ │
│ ├─ NO → Status: "Misquoted"
│ │ Issue: "来源存在但不讨论 [主题]"
│ │ STOP
│ │
│ └─ YES → Step 3: 来源是否支持原句?
│ │
│ ├─ YES (exact match) → Verified (exact)
│ ├─ YES (paraphrase) → Verified (paraphrase)
│ ├─ PARTIALLY (缺上下文) → Misleading
│ └─ NO (矛盾) → Hallucination
│
│
STATISTIC/FACT VALIDATION
│
├─ Step 1: 能否找到权威来源?
│ │ 按声明类型运行对应 Search Templates
│ │
│ ├─ NO → Status: "Unverified"
│ │ Issue: "未找到权威来源"
│ │ STOP
│ │
│ └─ YES → Step 2: 数值是否精确匹配?
│ │
│ ├─ YES → Verified (exact)
│ │ STOP
│ │
│ └─ NO → 进入 NUMERICAL ERROR DETAILS
│
│
NUMERICAL ERROR DETAILS
│
├─ 记录:来源值 / 声明值 / 偏差 / 来源位置
├─ 分类规则:
│ • 任何四舍五入 → Numerical Error
│ • 任何截断 → Numerical Error
│ • 有效位数不匹配 → Numerical Error
│ • 单位不匹配 → Numerical Error
│ • 方向反转 → Hallucination
│ • 数量级错误 → Hallucination
└─ 例外:来源自身提供近似值时(如 "96.555% (约 97%)")→ Verified
规则来源声明状态精确匹配96.555%96.555%✓ Verified任何四舍五入96.555%97%✗ Numerical Error截断96.555%96.5%✗ Numerical Error有效位不匹配0.8340.83✗ Numerical Error单位不匹配96.555%0.96555✗ Numerical Error方向反转+12% growth+15% growth✗ Hallucination数量级错误$4.7B$47B✗ Hallucination
Rank来源类型示例1Primary source原始研究、官方报告、原始数据2Government / InstitutionalWHO, CDC, World Bank, 国家统计局3Peer-reviewedNature, Science, IEEE, ACM4Industry reports (named)Gartner, McKinsey, Statista5Reputable news citing primaryNYT, Reuters 引用原始来源6Secondary compilationsWikipedia(需核实其来源)
规则:仅 Rank 5-6 来源 → Status = "Unverified" + 标注 "仅找到二级来源"。
Level标准使用场景exact≥95% 词重叠或同数字同单位直接引用、精确统计paraphrase同事实,不同措辞,未加解读重述发现interpretation从来源数据推断从来源计算、综合得出
不确定时使用更保守的级别并标记审核。
条件所需来源找到 Primary source1 个(若权威:.gov, peer-reviewed, 官方)仅有二级来源≥2 个独立来源一致来源冲突Status = "Unverified",标注冲突
情况规则声明缺日期假定指最近可用年份;标记 "需补充日期"来源冲突使用最新权威来源;引用双方;标注冲突所有搜索模板跑完未找到Status = "Unverified"(不是 Hallucination)数字因币种/单位转换不同标记 "需澄清:币种/单位"同一机构多份报告使用最新;标注日期声明使用 "约""大约" 等仍验证基数在来源 ±10% 范围内来源 paywalled标注 "来源有付费墙,无法验证精确文本"来源为其他语言翻译后验证;标注翻译
保留 verify_docx.py 的 DOCX 结构检查,合并进统一报告:
bash
python3 verify_docx.py chapter.docx
检查项:URL 重复(坑 #4)、URL 无 hyperlink(补漏)、footnoteRef 缺失(坑 #6)、字体污染(坑 #7)、hyperlink 无样式、脚注编号缺口。
详见 references/search_templates.md。按声明类型分 5 组:Academic / Statistics / Company / Health / Government。
Pass 2 优先复用 Phase 2 的 research_results.json 中的搜索结果作为缓存(标注 source: phase2_cache),未覆盖的独立执行搜索。
合并为统一验证报告 chapter_verification.json(Schema 见 references/claim_verification_schema.json):
json
{
"metadata": { ... },
"pass1_extraction": { ... },
"pass2_verification": {
"summary": { "verified": N, "numerical_errors": N, "hallucinations": N, ... },
"verified": [...],
"numerical_errors": [...],
"hallucinations": [...],
"unverified": [...],
"misleading": [...],
"structural_issues": [...]
},
"sources_consulted": [...]
}
Phase 6 触发前必须经用户确认(见 6A)。用户批准后方可执行截图。
在截图开始前,输出以下信息并要求用户批准:
text
即将对 N 个来源进行截图验证:
- 可达 URL: X 个
- PDF(跳过): Y 个
- 不可达(跳过): Z 个
- 骨架网站(跳过): W 个
每个截图将使用 Playwright 紫色高亮关键词标注。
预计耗时约 X 分钟。
请批准:回复 "批准截图" 继续 / "跳过截图" 跳过此阶段
未收到用户批准前,绝对不执行任何截图操作。
使用 scripts/purple_highlight_screenshot.py, 禁止 自行编写普通截图脚本。
bash
# 单 URL 截图(Claim-Driven 推荐)
python3 scripts/purple_highlight_screenshot.py --smart --keywords-file verification_keywords.json <URL> <output.png>
# 单 URL 截图(手动指定关键词)
python3 scripts/purple_highlight_screenshot.py --smart <URL> <output.png> <keyword1> [keyword2] ...
# 批量截图(Claim-Driven 推荐)
python3 scripts/screenshot_verify.py <chapter.json> <output_dir> \
--research research_results.json \
--url-status url_status.json \
--keywords-file verification_keywords.json
--smart 模式:自动提取页面文本,用 LLM 匹配关键词(处理同义改写)。
--keywords-file:从 verification_keywords.json(由 keyword_generator.py 或阶段三生成)
中读取 Claim-Driven 关键词。传递后,截图脚本使用声明驱动的英文关键词定位页面位置并高亮,
而非从 research quote 中提取关键词。
关键词来源(优先级):
--keywords-file 传入的 Claim-Driven 关键词(推荐)verification_keywords.json(阶段三或 keyword_generator.py 产出)特殊来源处理:
reason: PDFcurl -s <URL> 检查 HTML < 2000 chars → 跳过reason: unreachable每张截图分级(Grade):
Grade标准含义Ahighlighted_count > 0 AND body 含相关正文高亮有效,可验证B页面加载正常但 highlighted_count == 0关键词不在页面或同义改写未匹配C页面加载但 body text < 100 chars骨架页/反爬/JS 渲染失败F截图失败(网络/超时/Roxy 额度不足)截图不可用N/A跳过(PDF/不可达/骨架网站)非截图问题
声明对齐:对 Grade A/B 的截图,提取页面中可见的数值/关键短语,与 Pass 1 对应声明做值级对比:
text
截图 fn03 → 声明 C004 "准确率 92.1%"
页面可见文本:"92.1% accuracy" → exact match ✓
判定:Verified
截图的 summary.json 合并到统一验证报告 chapter_verification.json 的 phase6_screenshots 字段中(同 Schema)。
以下规则已纳入阶段五的 Pass 1 声明提取规则。声明提取时会自动标记以下类型的声明确保严格验证。
措辞类型示例Pass 1 检查Claim Type排他性声明"列为重点""核心行动""首次提出"提取为 Ranking / Attribution来源原文必须逐字匹配框架性声明"纳入…框架""建立…机制"提取为 Attribution / Existence需查看官方文件原文量化断言"占比 X%""排名第 N"提取为 Statistic / Ranking来源直接引用,适用数值精度规则时间关联"自 X 年起""Y 年 Z 月至"提取为 Temporal日期需与 HTTP Last-Modified 一致
原则:如果源文件中找不到逐字匹配的原句,降级措辞。宁可保守,不可夸大。
修改已有 DOCX 正文前:
<ns0:r> 的文本和脚注引用web.archive.org 缓存版本严重度定义处理策略示例FATAL管线无法继续中断执行,报告用户大纲解析失败、Pandoc 未安装ERROR某阶段失败但管线可降级降级走 /unified_search(非 llm-task),跳过后继不阻塞ACP 返回空/失败、URL 不可达、Tavily Research 超时/失败WARN非阻塞异常记录到报告,不中断某个脚注缺 footnoteRef、字体异常INFO信息性提示仅日志使用了默认 reference.docx
当截图验证(阶段六)遇到普通 Playwright 打不开的 URL(如 ACM DL、BMC、Splunk、ScyllaDB、CAP FAQ、AWS、HBase),需要走 Roxy 严格链路:
正确链路:
text
@roxybrowser/openapi MCP 开浏览器 → 从 open_browsers 响应提取 CDP WS
→ @roxybrowser/playwright-mcp --cdp-endpoint <ws_url>
→ browser_connect_roxy({ cdpEndpoint: ws_url })
→ browser_navigate → browser_take_screenshot
关键约束:
get_connection_info 拿 WS URL — 它返回所有已打开浏览器,regex 可能选错 → playwright-mcp 启动崩溃bufsize=0 不生效browser_take_screenshot 的 filename 为完整绝对路径时,文件保存到该路径( ~/.openclaw/media/outbound/xxx/screenshots_roxy/ 需提前 mkdir -p)参考实现: /tmp/roxy_full.cjs(Node.js,2026-05-28 验证通过,6/7 URL 截图成功)
规则优先级:所有 DOCX 结构检查规则以 verify_docx.py 代码实现为准,本文档描述为辅助说明。若本文档与代码不一致,以代码为准。
坑描述规避方法#50597ACP 空返回(~30%)自动重试 2 次 → 降级 /unified_searchllm-task 幻觉llm-task 直接搜索会编造 URL(404)禁止 llm-task 降级,必须走 /unified_searchURL 重复同一 URL 在 <w:t> 和 <w:hyperlink> 各一份verify_docx.py 自动检测footnoteRef 缺失ACP 修改后丢失 <w:footnoteRef>``verify_docx.py 检查字体污染ACP 引入显式字体声明verify_docx.py 检查 BANNED_FONTSURL 不可点击Pandoc 输出纯文本 URLadd_hyperlink_footnotes.py 后处理footnote_gapPandoc 重复引用同一脚注时,后续出现复制到不同连续 ID,中间 ID 被跳过(如 16→18、28→30)非阻塞 warning;由 verify_docx.py 报告,不影响脚注功能。原因:Markdown 中同一 [^N] 被多次引用时 Pandoc 会占用新 ID超链接无样式URL 可点击但无蓝色下划线(缺 rStyle="Hyperlink")add_hyperlink_footnotes.py 已自动添加; verify_docx.py 检查 hyperlink_no_styleRoxy CDP WS 取错get_connection_info 返回所有浏览器,regex 可能匹配错误的 WS URL → playwright-mcp init timeout + EPIPE从 open_browsers 响应中按 dirId 精确提取 CDP WebSocket URLRoxy 窗口额度不足创建新浏览器报「窗口额度不足」优先复用已有浏览器;截图后 close + delete 释放额度MCP stdio Python 缓冲Python subprocess.Popen stdout 在 text=True 下有缓冲 → MCP 响应延迟 → 脚本卡死用 Node.js child_process.spawn + stdout.on('data') 逐行解析 JSON-RPC
pandoc(MD → DOCX 转换)curl(URL 可达性检查)python3 + lxml(DOCX XML 检查)大型章节管线执行时间较长(10+ 分钟),为避免重启丢失进度,每阶段完成后应将中间产物保存到 output_dir:
阶段产物保存路径阶段一主题拆分 JSONoutput_dir/topics.json阶段二研究结果 JSONoutput_dir/research_results.json阶段三正文草稿 MDoutput_dir/chapter.md阶段三验证关键词 JSONoutput_dir/verification_keywords.json
恢复时从最近的 checkpoint 继续,跳过已完成的阶段。在 lobster pipeline 中可通过 {{ .args.checkpoint_dir }} 指定 checkpoint 目录(默认同 output_dir)。
chapter.md — 正文 + 脚注chapter.docx — 样式化的 DOCX(含 reference.docx 样式)chapter_verification.json — 验证结果(Phase 6)verification_keywords.json — 脚注 → 关键词映射(可由阶段三同步产出,或事后通过 keyword_generator.py 生成)scripts/keyword_generator.py — Claim-Driven 关键词生成编排器scripts/claim_keyword_extractor.py — LLM 驱动的声明→英文关键词翻译器screenshots/ — 来源截图(Playwright 紫色高亮)本 skill 中的 Citation 提取(Pass 1)与验证(Pass 2)两阶段架构,在设计上参考了 serenakeyitan/citation-check-skill(MIT License, Copyright (c) 2026 Serena Keyi Tan)。感谢 Serena 的开源贡献。