| name | spark-science-knowledge-builder |
| version | 1.0.0 |
| description | 知识库构建者:摄入文献(PDF/文件夹批量摄入)、生成三层 Wiki 页面(论文页/概念页/话题页)、维护知识网络。
使用场景:(1) 将 PDF 或文档批量摄入知识库(说"摄入"/"ingest"/"读这篇论文"/"整理文献");
(2) 为论文提炼概念页、生成 Wiki;(3) 执行「lint wiki」/「检查知识库质量」;
(4) 查询知识库内容;(5) 生成/更新 HTML 可视化;(6) 更新/查看 open_questions 知识缺口。
NOT for: 提出研究假设、判断学术质量、撰写论文、搜寻网络资源。
|
| metadata | {"openclaw":{"homepage":"https://github.com/jingxiangljj/paper-skills"}} |
spark-science-knowledge-builder
角色
图书管理员兼知识蒸馏者:摄入文献 → 论文页(溯源)+ 概念页(LLM消费)+ 话题页(领域导航,≥5篇创建)+ 方法页(可复用方法库)
spark-science-knowledge-builder 维护的是用户级知识库,不是单个项目的临时知识库。用户上传文档实体文件、跨项目复用的网页 URL 和 Wiki 页面都属于用户级资产;项目目录只保存引用链接、证据关系和写作产物。
三层结构
| 层 | 文件 | 回答问题 | 消费者 | 创建时机 |
|---|
| 论文层 | paper_xxx.md | 这篇文章说了什么 | 人类(引用溯源) | 每次摄入 |
| 概念层 | concept_xxx.md | X 是什么 | LLM(推理消费) | 每次摄入 |
| 话题层 | topic_xxx.md | 这个领域有哪些研究 | 人类(导航) | 文献 ≥ 5 篇 |
| 构想层 | idea_xxx.md | 下一步研究什么 | 人类(决策) | 用户主动 / 自动提炼 |
| 方法层 | method_xxx.md | 这个方法怎么用 | LLM(方法检索) | 摄入时识别到命名方法 |
| 实验层 | experiment_xxx.md | 实验结果如何 | 人类(追踪) | 用户主动创建 |
| 图谱层 | graph/open_questions.md | 当前有哪些研究空白 | LLM(ideate) | 自动聚合 |
摄入流程(3步批处理)
路径说明
{ws} = skill 所在目录的上级(即 scripts/ 的父目录,由安装环境决定)
{base} = %USERPROFILE%\.research-assistant(Windows)/ ~/.research-assistant(macOS/Linux)
{user_kb} = {base}/user/wiki/
{user_raw} = {base}/user/raw/uploaded_documents/
- 调用脚本必须用绝对路径,禁止相对路径
Step A — prepare(exec,脚本完成锁/幂等/提取)
python {ws}/scripts/ingest_batch.py --project={id} prepare --folder="{源文件夹}"
python {ws}/scripts/ingest_batch.py --project={id} prepare --files="路径1||路径2||路径3"
⚠️ --folder 与 --files 互斥,不可同时传;禁止并行调用多次 prepare(锁不防并发竞争)。
--folder 使用 rglob 递归扫描,无论子文件夹嵌套多深均会纳入。
输出 {user_kb}/ingest_plan.json,含每篇的 paper_id、filename、text(前8000字)、quality、skipped,以及:
total_papers_after:本批摄入后知识库总篇数
trigger_topic:是否达到 ≥5 篇话题页阈值(true/false)
脚本已处理:锁检查(TTL 30分钟自动清过期锁)、幂等过滤、paper_id自增、source_index占位、文本提取。
📡 prepare 完成后同时写入两个文件:
{user_kb}/ingest_heartbeat.json:本批总篇数和等待写作状态
{user_kb}/ingest_results_manifest.json:本批应写入的所有 paper_id 列表(供 finalize 做完整性校验)
Step B — 写作(LLM,含概念存在性确认)
read {user_kb}/ingest_plan.json,对每篇 items[i] 逐篇生成内容,每篇单独 write 一个分片文件:
⚠️ 写作过程中需对每个概念 read 对应 concept_*.md 确认是否已存在(见写作要求)。
分片写法(推荐,每篇一个文件,体积小,不受 write 工具大小限制):
❌ 禁止:将分片内容嵌入 exec / python -c "..." 内联脚本写入——多行字符串和 Markdown 内容遇到引号/转义必然崩溃(SyntaxError: unterminated triple-quoted string literal)。
✅ 必须:每篇调用一次 write 工具,直接写到 {user_kb}/ingest_result_{paper_id}.json。即使只有 1 篇也要用 write 工具,不得改用 exec。
每篇写入 {user_kb}/ingest_result_{paper_id}.json,格式如下:
{
"paper_id": "paper_007",
"year": "2025",
"first_author": "Newsham et al.",
"paper_md": "---\ntype: paper\n...完整论文页 Markdown(status直接写complete)...",
"concepts": [
{"name": "概念名", "filename": "concept_xxx.md", "exists": false, "content": "...完整概念页..."},
{"name": "已有概念", "filename": "concept_yyy.md", "exists": true, "append_line": "paper_007(作者,年份)"}
],
"topics": [{"filename": "topic_xxx.md", "content": "..."}]
}
topics 字段:仅在该篇是本批最后一篇时写入(或任意一篇写入,finalize 自动去重),trigger_topic=false 时所有分片均不写 topics。
- 所有分片写完后,finalize 会读取
ingest_results_manifest.json 做完整性校验,缺少任何分片会报错而非静默跳过。
单文件写法(兼容旧方式,仅在分片写法不可用时使用):
write {user_kb}/ingest_results.json:
{
"project_id": "proj_001",
"skipped": [...原样复制 plan.skipped...],
"items": [
{
"paper_id": "paper_007",
"year": "2025",
"first_author": "Newsham et al.",
"paper_md": "---\ntype: paper\n...完整论文页 Markdown(status直接写complete)...",
"concepts": [
{"name": "概念名", "filename": "concept_xxx.md", "exists": false, "content": "...完整概念页..."},
{"name": "已有概念", "filename": "concept_yyy.md", "exists": true, "append_line": "paper_007(作者,年份)"}
]
}
]
}
写作要求:
paper_md:按论文页模板,status: complete,字数 ≤ 800
tldr(required):≤80字,优先写核心贡献/关键结论而非问题描述;主动句式,不加「本文/作者」主语(例:「引入 X 机制,在 Y 任务上提升 Z%」);若 frontmatter 缺失,HTML 生成器自动从「关键发现」首句回退
importance(论文星级 1–5):基于论文对当前研究项目的重要程度评定,不是论文绝对学术地位;标准见 references/templates.md
concepts[].exists:先 read 对应 concept_*.md 确认是否存在,不得凭记忆判断
exists=false:写完整概念页(正文 ≤ 400字,不含「来源文献」)
exists=true:只写 append_line(追加到来源文献),禁止写 content
- 话题页:当 plan 中
trigger_topic=true 时写入 topics;trigger_topic=false 时不写
- 模板详见
references/templates.md
Step C — finalize(exec,脚本完成写文件/索引/HTML/释放锁)
python {ws}/scripts/ingest_batch.py --project={id} finalize
自动完成:写所有 .md、patch source_index、更新 index.md、生成 HTML、写摄入报告、释放锁、清理临时 JSON。
📡 finalize 每写完一篇论文都会刷新 {user_kb}/ingest_heartbeat.json,包含进度百分比和预估剩余时间。
进度心跳查询(任意阶段可调用)
python {ws}/scripts/ingest_batch.py --project={id} heartbeat
输出 ingest_heartbeat.json 当前快照,字段:
stage:prepare | finalize | done
ok/total/pct:已完成篇数 / 本批总数 / 百分比
current:当前正在写入的 paper_id
elapsed_s / eta_s:已用秒数 / 预估剩余秒数
status_line:人类可读的一行摘要
写作阶段(Step B)卡顿处理:
- Step B(LLM 写作)是最耗时的环节,大批量时每篇约需 30–60 秒。
- 若超过 5 分钟无输出,可调用
heartbeat 检查 prepare 阶段是否已记录 total;若 total=0 或文件不存在,说明 prepare 未成功,需重新运行 Step A。
- finalize 执行中途如崩溃,可重新运行 finalize(幂等,已写的文件会被覆盖但不会重复计数)。
知识库问答优先级
index.md → concept_xxx.md → topic_xxx.md → paper_xxx.md → source_path 原文 → 告知路径不可访问
Wiki Lint
触发:「lint wiki」/ 「检查知识库质量」,或每批摄入后自动。
规则与输出格式详见 references/lint_rules.md。
结果写入 {user_kb}/lint_report.md(覆盖),聊天输出一行摘要。
规则编号说明:1–11 自动执行;12/13 语义级(仅显式触发);14–16 方法页专项(仅显式触发)。
路径与环境
用户级文档实体根:{base}/user/raw/uploaded_documents/
用户级知识库根:{base}/user/wiki/
项目级来源登记:{base}/projects/{project_id}/sources/
脚本目录:{ws}/scripts/(脱离具体用户路径,由 __file__ 自动推断)
关键脚本:ingest_batch.py generate_wiki_html.py progress.py
调用脚本必须用绝对路径,禁止相对路径。
手动重新生成 HTML 可视化
当需要单独刷新知识图谱页面时(不重新摄入):
python {ws}/scripts/generate_wiki_html.py --project {id}
输出路径:
{user_kb}/index.html(主文件)
%USERPROFILE%/.openclaw/canvas/documents/wiki_{id}/index.html(Canvas 预览副本)
⚠️ 旧参数 --wiki / --out 已废弃,必须使用 --project。
v5 新增:卡片与图谱节点交互
- 点击任意卡片(论文/概念/话题/构想/方法/实验)→ 打开全页详情,展示完整 Markdown 正文
- 点击知识图谱节点 → 在右侧抽屉展示卡片同款摘要内容,底部「查看详情」按钮才跳转全页详情
- 点击图谱空白区域或抽屉 × 按钮 → 关闭抽屉、清除高亮
- 详情页内
[[wikilink]] 可继续点击跳转,支持浏览器返回键回退
- 纯静态 SPA,无需后端,可直接部署到 CDN/静态托管
项目论文参考文献中的网页 URL 由项目级 sources/reference_registry.yaml 或 sources/web_urls.md 登记;用户通过“整理知识库”或定时任务触发时,spark-science-knowledge-builder 可以读取这些 URL,整理为用户级 Wiki 页面。整理完成后,项目仍只引用用户级 Wiki 或 URL,不复制实体文件。
工具
exec:运行 ingest_batch.py prepare / finalize;单独生成 HTML;读取 progress
read / write:读 ingest_plan.json,写 ingest_results.json;检查 concept 是否存在
- 禁止用
write 直接写 paper_.md / concept_.md / index.md——文件操作由 finalize 统一处理
- 禁止用
exec 做任何文件写入操作(写 .md、写索引、写 JSON 中间产物)——即使遇到工具异常也不得绕过,应报告异常后等待重试
- 禁止用
exec python -c "..." 内联脚本写入任何数据文件:python -c 内联代码无法安全包含多行字符串或 Markdown 内容,会因引号/转义问题崩溃。Step B 分片写作必须使用 write 工具,每篇一次 write 调用,目标路径 {user_kb}/ingest_result_{paper_id}.json。
工作原则(速查)
| # | 原则 | 关键约束 |
|---|
| 1 | 忠实原文 | 概念页不加个人解读 |
| 2 | 路径可溯 | source_path 必填,项目级只登记引用链接,不复制实体文件 |
| 3 | 概念优先 | 每篇必须提炼概念页 |
| 4 | 显式关系 | [[concept_xxx]] 写入正文 |
| 5 | 独立可读 | 每个概念页单独可理解 |
| 6 | 增量更新 | 写前必须 read 检查存在性 |
| 7 | 话题按需 | 文献 < 5 篇不建话题页 |
| 8 | 精简克制 | 论文≤800字,概念正文≤400字,话题≤600字 |
| 9 | 串行摄入 | 锁由脚本管理,LLM 不操作锁文件 |
| 10 | 编号读文件 | paper_id 由脚本分配,LLM 不自行推断 |
| 11 | 用户级沉淀 | Wiki 页面写入用户级知识库,供多个项目复用 |
| 12 | 字段完整 | concept 必含 maturity,idea 必含 origin_gaps,新摄入必填 contribution_type(英文枚举) |
安装说明
脚本位于 {ws}/scripts/,各脚本通过 __file__ 互相推断路径。新环境部署:将 scripts/*.py 复制到目标 scripts/ 目录即可。
方法页(method_xxx.md)写作要求
当摄入论文中识别到具体研究方法时(frontmatter methods 字段或正文描述),需生成对应的方法页。
方法页写入 ingest_result_{paper_id}.json 的 methods 数组(格式同 concepts)。
必填字段:
问题背景:该方法解决的核心问题或研究缺口,与已有方法的差异(≤150字)
机制:方法的核心工作原理、关键步骤或算法逻辑(≤200字)
method_type:从封闭枚举选取(architecture/training/inference/evaluation/data/benchmark/system/optimization/prompting/protocol/other)
可选字段:
写作原则:
- 问题背景:回答"为什么需要这个方法",不重复摘要
- 机制:主动句,技术方法写算法逻辑,研究方法写操作流程
- 正文(不含"关联论文")总字数 ≤ 500字
- 模板详见 references/templates.md → 方法页 method_xxx.md
研究构想(idea_xxx.md)写作要求
- status 初始固定为 proposed,不得预设结果
- priority 1-5,基于与当前项目研究方向的紧迫程度
- origin_papers / origin_concepts:必须引用知识库中实际存在的 paper_id / concept_id
- origin_gaps:填写触发此构想的知识缺口(concept_xxx / topic_xxx),可留 []
- pilot_result:初步验证结果,未验证时留空字符串
- failure_reason:status=failed 时必填,记录失败原因
- 核心假设节:必须可验证,应含可量化的预期效果
- 方法草图节:150字以内,用 [[]] 引用相关实体
- novelty_score 初始写 0,待人工评分后填写 1-5
- 构想页由用户主动触发或 LLM 在摄入后从知识缺口自动提炼(非强制每篇都生成)
- 模板详见 references/templates.md
不负责
提出研究假设 / 判断学术质量 / 撰写论文 / 搜寻网络资源