| name | deep-research |
| description | 多源深度调研与专业报告生成。适用场景广泛——只要用户的问题涉及需要深度分析的专业话题,就应使用此技能。包括但不限于:(1) 用户明确要求调研/research/综述/报告/发现;(2) 用户提出一个技术或科学话题,话题复杂度需要多源深度分析;(3) 用户要求对比多种技术方案的优劣;(4) 涉及生物医药、蛋白质、基因、药物靶点等需要专业数据库支撑的问题。核心能力:根据问题性质自动组合 arXiv 论文检索 + ToolUniverse 科学工具(UniProt/OpenTargets/PubMed/FAERS 等 1000+ 工具)+ Web 搜索,多源采集数据,交叉分析,生成专业 PDF/DOCX 研究报告。 |
Deep Research — 多源深度调研系统
端到端的深度调研系统:从用户问题出发,智能选择数据源组合(arXiv 论文 + ToolUniverse 科学工具 + Web 搜索),多维度采集数据,逐源深度解读,围绕用户问题进行交叉归纳,最终生成专业研究报告。
工作流程总览
Phase 1: 问题拆解与数据源规划
→ Phase 2: 多源数据采集
2A: arXiv 论文检索 + 筛选 + PDF 下载
2B: ToolUniverse 科学工具数据采集
2C: Web 搜索补充采集
→ Phase 3: 数据提取与整理
→ Phase 4: 逐源深度解读
→ Phase 5: 围绕用户问题的交叉分析与报告撰写
→ Phase 6: 生成 PDF/DOCX 研究报告
工作空间路径:所有文件输出到 /home/scienceclaw/sessionid/ 目录下。
Phase 1: 问题拆解与数据源规划
收到用户问题后,不要直接执行。先分析问题,拆解为多个调研维度,并规划需要哪些数据源。
1.1 问题拆解
将用户问题按以下维度展开:
| 维度 | 说明 | 示例 |
|---|
| 核心概念 | 问题的主题词 | BRCA1, data center cooling |
| 技术路线 | 不同的技术方案 | PARP inhibitors, liquid cooling |
| 应用场景 | 特定的应用环境 | triple-negative breast cancer |
| 关联领域 | 密切相关的交叉领域 | DNA repair, homologous recombination |
| 优化目标 | 关注的性能指标 | survival rate, PUE |
1.2 数据源决策
⚠️ 强制规则:对于任何研究型问题,ToolUniverse 和文献检索都是必选项,不可跳过。
| 数据源 | 状态 | 说明 | 典型场景 |
|---|
| 文献检索 | 必选 | 任何研究问题都必须检索学术文献。根据领域选择来源:CS/AI/物理/数学 → arXiv;生物医药/化学 → PubMed/PubTator/EuropePMC(通过 ToolUniverse);通用学术 → OpenAlex/Semantic Scholar(通过 ToolUniverse)。多个来源可叠加使用。 | 所有研究型问题 |
| ToolUniverse | 必选 | 任何研究问题都必须使用 ToolUniverse 获取专业数据库的结构化数据。即使不涉及生物医药,也应搜索是否有适用工具(天文、地球科学、化学、统计等均有覆盖)。 | 所有研究型问题 |
| Web 搜索 | 推荐 | 获取最新资讯、行业报告、非学术数据补充 | 市场规模、最新进展、政策法规 |
决策原则:
- 文献检索 + ToolUniverse 是所有研究任务的双必选底线,Web 搜索作为推荐补充
- 生物医药领域:ToolUniverse(UniProt/OpenTargets/PubMed/PubTator 等结构化数据) + 文献检索(
PubTator_search_publications 或 EuropePMC_search 通过 ToolUniverse 调用,以及 arXiv 补充前沿预印本) + Web 搜索
- CS/AI/工程领域:arXiv 论文检索 + ToolUniverse(搜索领域相关工具如 HuggingFace/OpenML/DBLP 等) + Web 搜索
- 跨学科/其他领域:arXiv(如适用) + ToolUniverse(搜索领域工具,如天文 SIMBAD/NASA、地球科学 USGS、化学 COD 等) + 通用文献检索(OpenAlex/Semantic Scholar 通过 ToolUniverse) + Web 搜索
- 绝对禁止只用单一数据源就直接开始写报告
1.3 生成调研计划
将上述分析写入计划文件:
import json
plan = {
"question": "用户原始问题",
"dimensions": ["维度1", "维度2", "..."],
"data_sources": {
"literature": {
"enabled": True,
"arxiv": {
"enabled": True,
"queries": [
{"arxiv_query": "abs:%22keyword%22+AND+abs:topic", "label": "描述"},
],
"relevance_phrases": ["phrase1", "phrase2"],
"target_total": 50,
"top_k": 15,
},
"pubmed_via_tooluniverse": {
"enabled": True,
"tools": ["PubTator_search_publications", "EuropePMC_search"],
"queries": ["搜索词1", "搜索词2"],
},
"general_academic": {
"enabled": True,
"tools": ["OpenAlex_search_works", "SemanticScholar_search_papers"],
"queries": ["搜索词1", "搜索词2"],
},
},
"tooluniverse": {
"enabled": True,
"tasks": [
{"tool_query": "protein function", "purpose": "获取蛋白功能信息", "example_tool": "UniProt_get_function_by_accession"},
{"tool_query": "disease targets", "purpose": "获取疾病靶点", "example_tool": "OpenTargets_get_associated_targets_by_disease_efoId"},
],
},
"web_search": {
"enabled": True,
"queries": ["搜索词1", "搜索词2"],
},
},
"output_dir": "/home/scienceclaw/sessionid",
}
with open("/home/scienceclaw/sessionid/research_plan.json", "w", encoding="utf-8") as f:
json.dump(plan, f, ensure_ascii=False, indent=2)
Phase 2: 多源数据采集
根据 Phase 1 的计划,并行或顺序执行各数据源的采集。所有采集结果保存到 research_data/ 目录。
⚠️ 强制检查点:Phase 2 必须同时包含"文献检索"和"ToolUniverse 数据采集"两个环节。如果你发现自己只做了其中一个就准备进入 Phase 3,请停下来补齐另一个。
2A: arXiv 论文检索(如已启用)
构造 arXiv API Query
每个 query 使用 arXiv API 的搜索语法:
基本规则:
abs: 搜索摘要字段(最常用)
ti: 搜索标题字段
+AND+ 连接多个条件(交集)
+OR+ 连接多个条件(并集)
%22 用于包裹精确短语(URL 编码的双引号)
- 单词间用
+ 连接
Query 构造示例:
abs:%22data+center%22+AND+abs:cooling
abs:%22liquid+cooling%22+AND+abs:%22data+center%22
abs:%22immersion+cooling%22
ti:%22exact+phrase%22+AND+abs:keyword
cat:cs.AI+AND+abs:%22large+language+model%22
生成 search_config.json 并执行
import json
config = {
"question": "用户原始问题",
"queries": [
{"arxiv_query": "abs:%22keyword%22+AND+abs:topic", "label": "描述"},
],
"target_total": 50,
"top_k": 15,
"output_dir": "/home/scienceclaw/sessionid/research_papers",
"relevance_phrases": ["phrase1", "phrase2"],
"min_score": 4
}
with open("/home/scienceclaw/sessionid/search_config.json", "w", encoding="utf-8") as f:
json.dump(config, f, ensure_ascii=False, indent=2)
python3 /skills/deep-research/scripts/arxiv_paper_finder.py /home/scienceclaw/sessionid/search_config.json
脚本工作流程:多 Query 搜索 → 去重 → 相关性评分 → 筛选 TOP-K → 下载 PDF
评分规则:标题命中 +5 分/短语,摘要命中 +2 分/短语,多 query 命中 +3 分/额外命中,2025年+ +3分,2024年 +2分,2023年 +1分。
执行后检查:确认 all_candidates.json(40-60 篇)、selected_papers.json 质量、PDF 文件完整性。
2B: ToolUniverse 数据采集(⚠️ 必选)
使用 tooluniverse_search → tooluniverse_info → tooluniverse_run 三步流程采集专业数据。
此步骤包含两个必须完成的子任务:
- 专业数据库采集:获取领域特定的结构化数据
- 学术文献检索:通过 ToolUniverse 中的文献检索工具获取相关论文(此步骤必须执行,与 2A 的 arXiv 互补)
工作流程:
- 搜索工具:对每个任务维度,用
tooluniverse_search 找到合适的工具
- 查看规格:用
tooluniverse_info 确认参数要求
- 执行采集:用
tooluniverse_run 获取数据
- 保存结果:将每次调用结果保存到
research_data/ 目录
# ── 子任务 1: 专业数据库采集 ──
# 示例:蛋白功能调研
tooluniverse_search(query="protein function analysis", limit=5)
tooluniverse_info(tool_name="UniProt_get_function_by_accession")
tooluniverse_run(tool_name="UniProt_get_function_by_accession", arguments='{"accession": "P38398"}')
→ write_file("research_data/uniprot_P38398_function.json", result)
# 示例:疾病靶点
tooluniverse_search(query="disease drug targets", limit=5)
tooluniverse_run(tool_name="OpenTargets_get_associated_targets_by_disease_efoId", arguments='{"efoId": "EFO_0000305"}')
→ write_file("research_data/opentargets_breast_cancer_targets.json", result)
# ── 子任务 2: 学术文献检索(⚠️ 必须执行) ──
# 无论什么领域,都必须执行以下至少一种文献检索:
# 生物医药领域 → PubMed/PubTator
tooluniverse_run(tool_name="PubTator_search_publications", arguments='{"query": "BRCA1 mutation breast cancer", "limit": 20}')
→ write_file("research_data/pubmed_brca1_publications.json", result)
# 生物医药领域 → EuropePMC
tooluniverse_run(tool_name="EuropePMC_search", arguments='{"query": "BRCA1 PARP inhibitor", "limit": 20}')
→ write_file("research_data/europepmc_brca1_parp.json", result)
# 通用学术 → OpenAlex(覆盖所有学科)
tooluniverse_search(query="academic paper search", limit=5)
tooluniverse_run(tool_name="OpenAlex_search_works", arguments='{"query": "topic keywords", "limit": 20}')
→ write_file("research_data/openalex_results.json", result)
# CS/AI 领域 → DBLP
tooluniverse_run(tool_name="DBLP_search_publications", arguments='{"query": "large language model", "limit": 20}')
→ write_file("research_data/dblp_results.json", result)
常用 ToolUniverse 工具类别:
| 类别 | 典型工具 | 用途 |
|---|
| ⚠️ 文献检索(必选) | PubTator_search_publications, EuropePMC_search, OpenAlex_search_works, SemanticScholar_search_papers, DBLP_search_publications | 每次调研都必须检索学术文献 |
| 蛋白分析 | UniProt_get_entry_by_accession, UniProt_get_function_by_accession | 蛋白结构、功能、修饰位点 |
| 疾病靶点 | OpenTargets_get_associated_targets_by_disease_efoId | 疾病相关靶点排名 |
| 药物安全 | FAERS_count_reactions_by_drug_event | 不良反应统计 |
| 基因变异 | ClinVar_*, GWAS_* | 临床变异、GWAS 关联 |
| ADMET | ADMETAI_predict_* | 药物动力学预测 |
| 分子对接 | boltz2_docking | 蛋白-配体对接 |
| 天文学 | Simbad_*, SDSS_*, NASAExoplanet_* | 天体数据、巡天数据 |
| 地球科学 | USGS_*, ERDDAP_*, SoilGrids_* | 地震、水文、海洋气候 |
| 化学材料 | COD_* | 晶体结构 |
| 社会统计 | WorldBank_*, Eurostat_* | 经济社会指标 |
关键原则:
- 每个 ToolUniverse 调用结果都
write_file 保存到 research_data/ 目录
- 大型结果先保存原始 JSON,再写一个清洁版的摘要文件
- 对未知工具名称,先
tooluniverse_search 发现,再 tooluniverse_info 确认参数
2C: Web 搜索补充采集(如已启用)
使用 web_search + web_crawl 获取非学术来源的补充数据:
web_search("BRCA1 PARP inhibitor clinical trials 2024")
→ write_file("research_data/web_parp_trials.md", result)
web_crawl("https://specific-url.com/report")
→ write_file("research_data/web_industry_report.md", result)
Phase 3: 数据提取与整理
3.1 论文文本提取(如有 arXiv 论文)
对每篇已下载的 PDF 提取全文。优先用 pdftotext -layout,不可用时回退 PyMuPDF。
which pdftotext && echo "pdftotext OK" || echo "pdftotext NOT FOUND"
python3 -c "import fitz; print('PyMuPDF OK')" 2>/dev/null || python3 -m pip install --user pymupdf
方案 A(首选)—— pdftotext:
cd /home/scienceclaw/sessionid/research_papers
for pdf in *.pdf; do
txt="${pdf%.pdf}.txt"
if [ ! -f "$txt" ]; then
pdftotext -layout "$pdf" "$txt"
echo "Extracted: $pdf -> $txt"
fi
done
方案 B(回退)—— PyMuPDF:
import fitz, os, glob
pdf_dir = "/home/scienceclaw/sessionid/research_papers"
for pdf_path in sorted(glob.glob(os.path.join(pdf_dir, "*.pdf"))):
txt_path = pdf_path.replace(".pdf", ".txt")
if os.path.exists(txt_path) and os.path.getsize(txt_path) > 100:
continue
doc = fitz.open(pdf_path)
text = ""
for page in doc:
text += page.get_text("text", sort=True)
with open(txt_path, "w", encoding="utf-8") as f:
f.write(text)
print(f"[OK] {os.path.basename(pdf_path)} -> {os.path.basename(txt_path)} ({len(text)} chars)")
doc.close()
3.2 ToolUniverse 数据整理
读取 research_data/ 下的所有 JSON/MD 文件,用 read_file 逐个检查数据质量,提取关键信息写入摘要文件:
write_file("research_data/data_summary.md", """
## 采集数据概览
- UniProt P38398: BRCA1 蛋白功能数据 ✓(含 RING/BRCT 结构域信息)
- OpenTargets EFO_0000305: 乳腺癌靶点排名 ✓(Top 20 靶点)
- PubTator 文献: 20 篇相关论文摘要 ✓
- Web 搜索: 最新临床试验数据 ✓
- arXiv: 15 篇精选论文 ✓
""")
Phase 4: 逐源深度解读
4.1 论文深度解读(如有)
对每篇论文进行结构化深度解读,采用两轮阅读策略:
第一轮(快速扫描):从 selected_papers.json 读取 abstract,建立初步印象。
第二轮(深度阅读):用 read_file 的 offset/limit 参数按段读取 .txt 文件,重点关注 Introduction(前 100-150 行)和 Results/Conclusion(后 1/3 部分)。
为每篇论文写入结构化摘要:
write_file("paper_summaries/summary_{paper_id}.txt", """
【论文标题】{英文原标题}
【arXiv ID】{paper_id}
【作者】{前3位作者}, et al.
【发表日期】{年-月-日}
【研究问题】
该论文要解决什么问题?1-2 句话。
【核心方法】
提出了什么技术方案/方法?关键创新点是什么?3-5 句话。
【关键发现/实验结果】
- 具体数据点 1(必须包含量化数据)
- 具体数据点 2
- 具体数据点 3
【与用户问题的关联】
这篇论文回答了用户问题的哪个方面?1-2 句话。
【局限性与未来方向】
1-2 句话。
""")
4.2 ToolUniverse 数据解读
对每个 ToolUniverse 采集的数据文件,read_file 并提取关键发现,写入摘要:
write_file("data_summaries/summary_uniprot_brca1.txt", """
【数据来源】UniProt P38398 (BRCA1_HUMAN)
【关键发现】
- BRCA1 蛋白含 1863 个氨基酸,包含 RING 结构域(1-109)和 BRCT 结构域(1646-1859)
- 参与同源重组修复(HR)、细胞周期 G2/M 检查点调控
- 已知致病突变 > 1800 个,185delAG 和 5382insC 为 founder mutations
【与用户问题的关联】
直接回答了 BRCA1 蛋白功能机制部分的需求。
""")
4.3 Web 数据解读
对 Web 搜索结果同样提取关键信息,写入摘要文件。
Phase 5: 围绕用户问题的交叉分析与报告撰写
此阶段是从「逐源阅读」到「综合洞察」的质变。 不再逐源叙述,而是以用户的原始问题为轴心,跨数据源提取、对比、归纳。
5.1 确定报告章节
阅读完所有 Phase 4 摘要后,动态决定章节结构(选择 4-7 个最适合用户问题的维度):
| 分析维度 | 适用条件 | 文件名示例 |
|---|
| 研究背景与意义 | 所有调研 | sec_01_background.txt |
| 技术路线/方法分类与对比 | 多种方案可比较 | sec_02_methods.txt |
| 关键数据与实验发现 | 有量化数据 | sec_03_findings.txt |
| 蛋白/基因功能机制 | 涉及分子生物学 | sec_04_mechanism.txt |
| 靶向治疗/药物进展 | 涉及药物研发 | sec_05_therapeutics.txt |
| 应用场景分析 | 有明确场景差异 | sec_06_applications.txt |
| 挑战与展望 | 多源指出共同问题 | sec_07_challenges.txt |
5.2 撰写各章节
每个章节写入独立文件,每个章节 不少于 1500 字:
write_file("sections/sec_01_background.txt", content)
write_file("sections/sec_02_methods.txt", content)
...
写作风格 — 学术研究报告(CRITICAL):
- 连续流畅的散文段落。每段 8-10 句,遵循:主题句 → 具体数据支撑的证据 → 分析/对比 → 过渡到下一个论点。
- 跨来源综合:将论文数据、ToolUniverse 数据、Web 数据交织在一起叙述。例如:"UniProt 数据显示 BRCA1 蛋白的 RING 结构域(残基 1-109)具有 E3 泛素连接酶活性 [1],而 Zhang 等人的研究进一步表明该结构域的 C61G 突变会完全消除其泛素化功能 [2],OpenTargets 平台的靶点关联分析将 BRCA1 列为乳腺癌排名第 3 的治疗靶点,这一排名与近年 PARP 抑制剂临床试验的成功密切相关 [3]。"
- 行内引用
[1], [2],引用编号对应最终参考文献列表。不要在每章末尾加"参考文献"列表——所有引用统一放在报告最后的 references section。
- 学术连接词:"Furthermore"、"In contrast"、"These findings indicate"、"Notably"、"Taken together"、"此外"、"与之对比"、"上述结果表明"。
- 绝对禁止编号要点结构(如 "1. 标题\n\n段落. 2. 标题\n\n段落.")。使用
## 子标题作为结构,散文段落作为内容。
- 要点列表不超过 5%,仅用于简短枚举(如 4-5 个药物名称)。
- 必须包含具体数据:数字、百分比、p 值、置信区间、对比结果。
⚠️ 语言要求(CRITICAL):
- 所有报告内容(标题、副标题、章节标题、正文、图表标签、封面信息)必须使用用户在系统提示词
## Language 中配置的语言。
- 用户语言为中文(
zh)时,整篇报告用中文撰写;用户语言为英文(en)时,整篇报告用英文撰写。
- 除专有名词或无标准翻译的技术术语外,不要混用语言。
5.3 撰写执行摘要和结论
write_file("sections/executive_summary.txt", ...)
write_file("sections/conclusion.txt", ...)
执行摘要(400-600 字散文段落):用户问题的核心回答 + 最重要的 3-5 个发现 + 建议。
结论与展望(600-1000 字散文段落):综合各来源的关键结论 + 技术/领域成熟度评估 + 最有前景的方向 + 尚待解决的关键问题。
5.4 验证
python3 -c "import os,glob; [print(f'{f}: {len(open(f).read())} chars') for f in sorted(glob.glob('sections/*.txt'))]; total=sum(len(open(f).read()) for f in glob.glob('sections/*.txt')); print(f'TOTAL: {total} chars, ~{total//500} pages')"
如果总字数不足目标,做 一次修订:read_file 数据再看一遍,然后 write_file 重写最薄的 1-2 个章节。不要循环修订。
Phase 6: 生成研究报告
使用 pdf 或 docx skill 的模板生成专业报告。默认生成 PDF,用户要求 Word 时生成 DOCX。
6.1 复制报告生成器
cp /builtin-skills/pdf/scripts/generate_report.py /home/scienceclaw/sessionid/generate_report.py
cp /builtin-skills/docx/scripts/generate_report.js /home/scienceclaw/sessionid/generate_report.js
关键:必须用 shell cp 复制,不要自己写报告生成代码。
6.2 组装 report_data.json
编写 Python 脚本,将 sections 目录下的各章节文件 + 参考文献组装为 report_data.json:
import json, glob, os
BASE = "/home/scienceclaw/sessionid"
SECTIONS_DIR = f"{BASE}/sections"
references = []
papers_file = f"{BASE}/research_papers/selected_papers.json"
if os.path.exists(papers_file):
selected = json.load(open(papers_file, encoding="utf-8"))
for p in selected:
authors = ", ".join(p["authors"][:3])
if len(p["authors"]) > 3:
authors += " et al."
references.append(f'{authors}. {p["title"]}. arXiv:{p["id"]}, {p["published"]}. https://arxiv.org/abs/{p["id"]}')
SECTION_MAP = [
("executive_summary.txt", "1.", "执行摘要", None),
("sec_01_*.txt", "2.", "研究背景与意义", None),
("sec_02_*.txt", "3.", "方法与技术路线", {
"type": "chart_pie",
"title": "研究方法分布",
"labels": ["方法A", "方法B", "方法C", "其他"],
"values": [35, 30, 20, 15]
}),
("sec_03_*.txt", "4.", "关键发现与数据分析", {
"type": "chart_bar",
"title": "关键指标对比",
"categories": ["指标1", "指标2", "指标3"],
"series": [{"name": "数值", "values": [85, 72, 91]}]
}),
("sec_04_*.txt", "5.", "机制/原理深度解析", None),
("sec_05_*.txt", "6.", "应用与治疗进展", {
"type": "chart_line",
"title": "趋势分析",
"x_labels": ["2020", "2021", "2022", "2023", "2024"],
"series": [{"name": "指标", "values": [40, 55, 62, 70, 78]}]
}),
("sec_06_*.txt", "7.", "挑战与展望", None),
("conclusion.txt", "8.", "结论", None),
]
data = {
"title": "根据用户问题生成的报告标题",
"subtitle": "深度调研报告",
"short_title": "调研报告",
"report_type": "深度调研报告",
"toc": True,
"cover_meta": [
["报告类型", "多源深度调研报告"],
["生成日期", "YYYY-MM-DD"],
["数据来源", "arXiv / ToolUniverse / Web"],
["研究问题", "用户原始问题"],
],
"disclaimer": "本报告由 AI 基于多源数据自动生成,包括学术论文、专业数据库和公开资料。请结合实际情况参考使用。",
"sections": [],
}
for pattern, num, heading, chart in SECTION_MAP:
matches = sorted(glob.glob(os.path.join(SECTIONS_DIR, pattern)))
if not matches:
continue
body = open(matches[0], encoding="utf-8").read().strip()
data["sections"].append({"type": "heading", "level": 1, "number": num, "text": heading})
data["sections"].append({"type": "text", "body": body})
if chart:
data["sections"].append(chart)
data["sections"].append({"type": "heading", "level": 1, "number": f"{len([s for s in SECTION_MAP if glob.glob(os.path.join(SECTIONS_DIR, s[0]))])+1}.", "text": "参考文献"})
data["sections"].append({"type": "references", "items": references})
with open(f"{BASE}/report_data.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
print(f"Generated report_data.json ({len(data['sections'])} section blocks)")
注意:
- 根据实际分析内容调整
SECTION_MAP,可增减章节
- 图表数据必须来自实际采集的数据,不要编造
- chart 类型:
chart_pie(分布)、chart_bar(对比)、chart_line(趋势)
- 也可以在 text body 中嵌入 Markdown 表格(
| col1 | col2 |),模板会自动渲染
⚠️ 图表维度约束(CRITICAL — 不遵守会导致 PDF 生成崩溃):
chart_bar:categories 数组长度必须 == 每个 series[i].values 数组长度。例如 3 个 categories 则每个 series 必须恰好 3 个 values
chart_pie:labels 数组长度必须 == values 数组长度
chart_line:x_labels 数组长度必须 == 每个 series[i].values 数组长度
- 构造图表数据后,必须人工核查数组长度一致再写入 SECTION_MAP
⚠️ 引用一致性约束(CRITICAL — 不遵守会导致 PDF 生成崩溃):
- 正文
[n] 标记中的最大数字 n 不得超过 references 列表的条目数。例如正文用了 [1] 到 [15],则 references 列表必须至少有 15 条
- 如果
references 为空(0 条),则正文中禁止使用任何 [n] 引用标记
- 组装完成后运行下方校验脚本检查一致性
6.3 生成最终报告
cd /home/scienceclaw/sessionid
python3 generate_report.py report_data.json final_report.pdf
node generate_report.js report_data.json final_report.docx
6.4 质量校验
python3 -c "
import json, re
data = json.load(open('/home/scienceclaw/sessionid/report_data.json'))
total = sum(len(s.get('body', '')) for s in data['sections'])
secs = sum(1 for s in data['sections'] if s['type'] == 'heading')
refs = sum(len(s.get('items', [])) for s in data['sections'] if s['type'] == 'references')
print(f'总字数: {total}')
print(f'章节数: {secs}')
print(f'参考文献: {refs}')
print(f'预估页数: {total // 500}')
# ── 引用一致性检查 ──
all_text = ' '.join(s.get('body', '') for s in data['sections'] if s.get('type') == 'text')
cited = set()
for m in re.finditer(r'\[(\d+)\]', all_text):
cited.add(int(m.group(1)))
max_cite = max(cited) if cited else 0
if max_cite > refs:
print(f'⚠️ ERROR: 正文引用了 [1]-[{max_cite}] 但只有 {refs} 条参考文献!需补齐至少 {max_cite} 条')
elif refs == 0 and cited:
print(f'⚠️ ERROR: 参考文献为空但正文使用了 {len(cited)} 个引用标记!')
else:
print(f'✅ 引用一致性: OK (最大引用 [{max_cite}], 参考文献 {refs} 条)')
# ── 图表维度检查 ──
ok = True
for i, s in enumerate(data['sections']):
t = s.get('type', '')
if t == 'chart_bar':
nc = len(s.get('categories', []))
for j, sr in enumerate(s.get('series', [])):
nv = len(sr.get('values', []))
if nv != nc:
print(f'⚠️ ERROR: sections[{i}] chart_bar categories={nc} 但 series[{j}].values={nv}')
ok = False
elif t == 'chart_pie':
nl = len(s.get('labels', []))
nv = len(s.get('values', []))
if nl != nv:
print(f'⚠️ ERROR: sections[{i}] chart_pie labels={nl} 但 values={nv}')
ok = False
elif t == 'chart_line':
nx = len(s.get('x_labels', []))
for j, sr in enumerate(s.get('series', [])):
nv = len(sr.get('values', []))
if nv != nx:
print(f'⚠️ ERROR: sections[{i}] chart_line x_labels={nx} 但 series[{j}].values={nv}')
ok = False
if ok:
print('✅ 图表维度: OK')
"
⚠️ 必须在 PDF 生成前运行上述校验。如果输出包含 ERROR,必须先修复再生成 PDF。
质量阈值:
- 总字数 < 5000 → 内容不足,回到 Phase 5 补充
- 任何章节 < 400 字 → 需要扩充
- 参考文献 < 10 → 检查引用是否遗漏
- 引用一致性检查有 ERROR → 必须补齐参考文献或移除多余引用标记
- 图表维度检查有 ERROR → 必须修正数组长度使其一致
注意:预估页数仅用于判断内容充足度,绝对不要把页码/页数写进 cover_meta 或报告封面——实际页数在组装时未知,写入会产生不准确信息。
arXiv API Query 速查
搜索字段
| 前缀 | 搜索范围 |
|---|
abs: | 摘要 |
ti: | 标题 |
au: | 作者 |
all: | 所有字段 |
cat: | 分类(如 cs.AI, cs.LG) |
组合语法
abs:%22liquid+cooling%22+AND+abs:%22data+center%22 # 精确短语 + AND
abs:%22term+A%22+OR+abs:%22term+B%22 # OR 并集
ti:%22exact+phrase%22+AND+abs:keyword # 标题+摘要组合
cat:cs.AI+AND+abs:%22large+language+model%22 # 限定分类
常用分类代码
| 代码 | 领域 | 代码 | 领域 |
|---|
| cs.AI | 人工智能 | cs.LG | 机器学习 |
| cs.CL | NLP/计算语言学 | cs.CV | 计算机视觉 |
| cs.DC | 分布式计算 | cs.PF | 性能 |
| cs.AR | 体系结构 | cs.SE | 软件工程 |
| eess.SP | 信号处理 | physics.app-ph | 应用物理 |
质量标准
| 维度 | 要求 |
|---|
| 数据源覆盖 | 必须包含文献检索 + ToolUniverse,Web 搜索推荐启用 |
| 文献检索(必选) | arXiv(如适用)候选 40-60 篇精选 12-15 篇;且通过 ToolUniverse 调用 PubMed/EuropePMC/OpenAlex 等检索 ≥ 20 篇相关论文 |
| ToolUniverse(必选) | 文献检索工具 + 领域专业工具,合计 5-12 次工具调用,数据全部保存 |
| 单篇/单源摘要 | 每个数据源生成结构化摘要 |
| 章节字数 | 每个分析章节 ≥ 1500 字散文段落 |
| 写作风格 | 学术散文,段落 8-10 句,bullet ≤ 5% |
| 引用标注 | 所有事实性陈述标注 [n] |
| 数据支撑 | 每章至少 3-5 组量化数据 |
| 报告总字数 | ≥ 8000 字(不含参考文献) |
| 报告格式 | PDF/DOCX,含封面+目录+图表+参考文献 |
文件组织
/home/scienceclaw/sessionid/
├── research_plan.json # Phase 1 调研计划
├── search_config.json # Phase 2A arXiv 搜索配置
├── research_papers/ # Phase 2A arXiv 输出
│ ├── all_candidates.json
│ ├── selected_papers.json
│ ├── {paper_id}.pdf
│ └── {paper_id}.txt
├── research_data/ # Phase 2B/2C 采集数据
│ ├── uniprot_*.json
│ ├── opentargets_*.json
│ ├── pubmed_*.json
│ ├── web_*.md
│ └── data_summary.md
├── paper_summaries/ # Phase 4 论文摘要
│ └── summary_{paper_id}.txt
├── data_summaries/ # Phase 4 数据摘要
│ └── summary_*.txt
├── sections/ # Phase 5 报告章节
│ ├── executive_summary.txt
│ ├── sec_01_background.txt
│ ├── sec_02_methods.txt
│ ├── ...
│ └── conclusion.txt
├── generate_report.py # Phase 6 PDF 生成器(从 pdf skill 复制)
├── generate_report.js # Phase 6 DOCX 生成器(从 docx skill 复制,按需)
├── report_data.json # Phase 6 组装后的报告数据
└── final_report.pdf / .docx # 最终报告