Parcourir la source

feat(M2): Phase F — 3 built-in research agent packs (FR-008)

CR-20260607-001 rev.2 §6.3 FR-008。3 个内置科研 agent pack, 各含 manifest
+ 独立 entrypoint + README。175 test 全过 (含 4 个 bundled-pack regression
guard)。

## 设计决策: 独立 agent, 不是 symlink 流水线 sub-agent

physics67 的 reviewer.yml 是流水线 sub-agent — 读 {workspace}/02_sim/...
上游产物, 不能独立跑 ("审我的论文" 场景没有 sim 结果)。research67 的
agents/ 同理是 orchestrator 的子节点。

CR §F "基于 physics67 reviewer 改造" = 改造成独立单 agent: 用户直接给
论文/方向/材料作为输入, 不依赖流水线上游, KBSearch 取本地资料库做对照。
因此 Phase F 是新写 3 个 self-contained react config, 复用专家级 prompt
但换成 standalone 输入契约。

## 3 个 pack (agentexample/agentpacks/)

research.top-journal-reviewer — 顶刊审稿助手
  论文 → review_report.md (贡献/创新性/技术正确性/实验充分性/写作/中稿
  概率区间/可执行修改清单) + review_result.json

research.literature-mapper — 文献地图助手
  方向 + 本地论文 → literature_map.md (主题分类/方法谱系/代表论文表/
  open problems/可切入方向) + references.md

research.grant-planner — 基金写作助手
  方向 + 前期材料 → grant_proposal.md (立项依据/科学问题/创新点/技术
  路线/可行性/风险替代) + reviewer_concerns.md (评审质疑预案)

## 三者共性 (local-first 安全姿态)

- permissions: read_knowledge:true, file_write:workspace, network:false,
  shell:false (纯写作/分析, 不需要联网或跑代码)
- 强制"基于检索到的真实内容, 禁止编造", 缺依据处显式标注 (需补充文献 /
  待 PI 补充前期工作)
- 路径用绝对 {workspace}/..., 避免 M1 修过的 cd-空参 escape
- entrypoint 全部 from_config 编译通过 → Memory(...) term

## 测试 (tests/test_agentpack.py +4 → 23)
- test_bundled_packs_present: 3 个 id 都在
- test_bundled_pack_valid_and_compiles (×3 parametrized): manifest 校验 +
  entrypoint 存在 + shell/network=false + from_config 编译成功

## 验证
  $ pytest tests/ -q  →  175 passed
  3 packs load + compile; 不被 .gitignore 误伤

下一步 Phase E: PDF 页码引用追踪 (pdfplumber) + Obsidian 导入, 让这些
pack 的 KBSearch 能拿到带页码的引用。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
kenny67nju il y a 3 mois
Parent
commit
0db8d9a975

+ 28 - 0
agentexample/agentpacks/research.grant-planner/README.md

@@ -0,0 +1,28 @@
+# 基金写作助手 (research.grant-planner)
+
+辅助生成基金/项目申请书的核心部分。
+
+## 用法
+
+1. 把前期工作、已发论文、初稿导入本地资料库。
+2. 安装本包,输入研究方向 + 申请类型,例如:
+   「青年基金,方向是非互易非厄米系统的量子几何张量」。
+
+## 输出
+
+`{workspace}/grant_proposal.md` + `reviewer_concerns.md`:
+
+- 立项依据 / 关键科学问题 / 创新点
+- 研究内容与技术路线 + 里程碑
+- 可行性(基于真实前期工作)
+- 风险与替代方案
+- 评审人质疑点预案
+
+## 权限
+
+只读资料库、写 workspace、不联网、不执行 shell。
+
+## 不做
+
+- 不编造前期成果;缺依据处标注「(待 PI 补充前期工作)」
+- 产出是草稿,需 PI 审核打磨后提交

+ 74 - 0
agentexample/agentpacks/research.grant-planner/agents/planner.yml

@@ -0,0 +1,74 @@
+agentId: research-grant-planner
+name: 基金写作助手
+description: >
+  独立基金/项目申请书写作智能体。用户给研究方向 + 已有材料(论文/初稿/
+  前期工作,在本地资料库),输出申请书核心部分草稿:立项依据、科学问题、
+  创新点、研究内容与技术路线、风险与替代方案、评审人质疑点预案。
+
+type: react
+
+model:
+  provider: claude-code
+  name: sonnet
+  temperature: 0.3
+  maxTokens: 8192
+
+systemPrompt: |
+  你是一位经验丰富、拿过多项基金的 PI,擅长把研究想法写成有竞争力的
+  申请书。用户给你研究方向和已有材料,你产出申请书的核心部分草稿。
+
+  ## 输入
+  用户输入是研究方向 + 申请类型(如青年/面上/重点)。前期工作、已有论文、
+  初稿在本地资料库里,用 KBSearch 取回作为「研究基础」和创新点的依据。
+  - 先 KBList + KBSearch 了解用户已有什么工作。
+  - 创新点和研究基础必须基于检索到的真实材料,**禁止编造前期成果**;
+    没有依据的地方写「(待 PI 补充前期工作)」。
+
+  ## 强制工作流程
+  1. KBList + KBSearch 取回用户的前期工作 / 相关论文。
+  2. 起草申请书核心部分。
+  3. 写到 `{workspace}/grant_proposal.md`(绝对路径)。
+  4. 写评审预案到 `{workspace}/reviewer_concerns.md`。
+  5. 读回确认后 terminate。
+
+  ## grant_proposal.md 必须包含
+  - 立项依据(研究背景 + 国内外现状 + 本项目必要性,引用资料库材料)
+  - 拟解决的关键科学问题(提炼成 2-3 个清晰、可证伪的问题)
+  - 创新点(逐条,区分「方法创新」「问题创新」「应用创新」,每条说明
+    与已有工作的差异 — 基于资料库)
+  - 研究内容与技术路线(分任务 + 任务间逻辑 + 里程碑;可配文字版流程)
+  - 可行性分析(研究基础 / 团队 / 条件 — 基于真实前期工作)
+  - 风险与替代方案(识别 2-3 个主要风险,每个给 plan B)
+
+  ## reviewer_concerns.md
+  站在评审人角度列出最可能被质疑的 5 个点,每个给「如何在正文中预先回应」。
+
+  ## 路径规范
+  workspace 绝对路径,写 `{workspace}/grant_proposal.md`。
+
+  ## 风格
+  中文,申请书书面语,逻辑紧、有说服力,但不浮夸不空话。创新点要具体。
+
+react:
+  maxSteps: 50
+  observationEnabled: true
+  toolTimeout: 120
+  thinkTimeout: 300
+
+memory:
+  enabled: true
+  strategy: local
+  size: 40
+
+mcp:
+  localTools:
+    - ReadFile
+    - WriteFile
+    - ListFiles
+    - SearchContent
+    - KBSearch
+    - KBList
+    - terminate
+  policy:
+    mode: auto
+    maxConcurrent: 1

+ 27 - 0
agentexample/agentpacks/research.grant-planner/manifest.yml

@@ -0,0 +1,27 @@
+id: research.grant-planner
+name: 基金写作助手
+version: 0.1.0
+domain: research
+entrypoint: agents/planner.yml
+description: >
+  辅助生成基金/项目申请书的核心部分:立项依据、科学问题、创新点、
+  研究内容与技术路线、风险与替代方案、评审人可能质疑点。基于研究方向
+  + 已有论文/初稿/项目材料(本地资料库)。
+audience:
+  - professor
+  - postdoc
+  - phd_student
+permissions:
+  network: false
+  shell: false
+  file_write: workspace
+  read_knowledge: true
+  read_filesystem: false
+model:
+  recommended:
+    - claude-code/sonnet
+    - anthropic/claude-sonnet
+    - ollama/qwen
+author: kenny67nju
+homepage: https://github.com/kenny67nju/lambdagentpaas
+license: BUSL-1.1

+ 27 - 0
agentexample/agentpacks/research.literature-mapper/README.md

@@ -0,0 +1,27 @@
+# 文献地图助手 (research.literature-mapper)
+
+对一个研究方向 + 一组本地论文,生成结构化文献地图。
+
+## 用法
+
+1. 把该方向的论文导入本地资料库(PDF/Markdown)。
+2. 安装本包,输入研究方向,例如:「帮我梳理'非厄米拓扑'方向的文献地图」。
+
+## 输出
+
+`{workspace}/literature_map.md` + `references.md`:
+
+- 主题分类 + 方法谱系
+- 代表论文表格
+- 尚未解决的问题(open problems)
+- 3-5 个可切入的研究方向
+- 引用清单(含来源定位)
+
+## 权限
+
+只读资料库、写 workspace、不联网、不执行 shell。
+
+## 不做
+
+- 不编造论文;没有资料库支撑的判断会标注「(需补充文献)」
+- 不替代真正的全面文献调研,是加速整理的工具

+ 72 - 0
agentexample/agentpacks/research.literature-mapper/agents/mapper.yml

@@ -0,0 +1,72 @@
+agentId: research-literature-mapper
+name: 文献地图助手
+description: >
+  独立文献综述/地图智能体。用户给一个研究方向(+ 已导入本地资料库的一组
+  论文),输出结构化文献地图:主题分类、方法谱系、代表论文、open problems、
+  可切入方向、引用清单。基于本地资料库检索,不联网。
+
+type: react
+
+model:
+  provider: claude-code
+  name: sonnet
+  temperature: 0.2
+  maxTokens: 8192
+
+systemPrompt: |
+  你是一位资深科研工作者,擅长把一堆论文梳理成清晰的文献地图。
+  用户会给你一个研究方向(和一个已导入的本地论文库),你要产出一份
+  能直接用于综述写作或开题的文献地图。
+
+  ## 输入
+  用户输入通常是研究方向 / 研究问题。论文在本地资料库里,用 KBSearch
+  按主题、方法、关键概念多次检索取回原文片段。
+  - 先 KBList 看有哪些资料库,再 KBSearch 取相关论文。
+  - 检索要覆盖不同角度(按主题词、按方法名、按问题),不要只搜一次。
+  - 只基于检索到的真实内容归纳,**禁止编造论文或结论**;某个判断没有
+    资料库支撑就标注「(需补充文献)」。
+
+  ## 强制工作流程
+  1. KBList + 多轮 KBSearch,取回方向相关的论文片段。
+  2. 归纳主题分类与方法谱系。
+  3. 写文献地图到 `{workspace}/literature_map.md`(绝对路径)。
+  4. 写引用清单到 `{workspace}/references.md`(尽量含来源文件名/可定位信息)。
+  5. 读回确认后 terminate。
+
+  ## literature_map.md 必须包含
+  - 研究方向概述(1 段)
+  - 主题分类(每类:定义 + 代表工作 + 该类的核心思路)
+  - 方法谱系(方法之间的演进/对比关系,可用列表或表格)
+  - 代表论文表格(标题 / 主要贡献 / 方法 / 来源)
+  - 尚未解决的问题(open problems,逐条 + 为什么难)
+  - 可切入的研究方向(3-5 个,每个注明切入点与所需条件)
+
+  ## 路径规范
+  workspace 是绝对路径,写文件用 `{workspace}/literature_map.md`。
+
+  ## 风格
+  中文回复,综述式但有判断力。区分「论文声称」与「你的归纳」。
+
+react:
+  maxSteps: 50
+  observationEnabled: true
+  toolTimeout: 120
+  thinkTimeout: 300
+
+memory:
+  enabled: true
+  strategy: local
+  size: 40
+
+mcp:
+  localTools:
+    - ReadFile
+    - WriteFile
+    - ListFiles
+    - SearchContent
+    - KBSearch
+    - KBList
+    - terminate
+  policy:
+    mode: auto
+    maxConcurrent: 1

+ 28 - 0
agentexample/agentpacks/research.literature-mapper/manifest.yml

@@ -0,0 +1,28 @@
+id: research.literature-mapper
+name: 文献地图助手
+version: 0.1.0
+domain: research
+entrypoint: agents/mapper.yml
+description: >
+  对一个研究方向的一组本地论文,生成文献地图:研究主题分类、方法谱系、
+  代表论文表格、尚未解决的问题、可切入的研究方向,以及引用清单。
+  全程基于本地资料库,不需要联网。
+audience:
+  - professor
+  - phd_student
+  - postdoc
+  - research_assistant
+permissions:
+  network: false
+  shell: false
+  file_write: workspace
+  read_knowledge: true
+  read_filesystem: false
+model:
+  recommended:
+    - claude-code/sonnet
+    - anthropic/claude-sonnet
+    - ollama/qwen
+author: kenny67nju
+homepage: https://github.com/kenny67nju/lambdagentpaas
+license: BUSL-1.1

+ 27 - 0
agentexample/agentpacks/research.top-journal-reviewer/README.md

@@ -0,0 +1,27 @@
+# 顶刊审稿助手 (research.top-journal-reviewer)
+
+对一篇论文生成顶级期刊水准的审稿报告。
+
+## 用法
+
+1. 在 ResearchAgent Desktop 安装本包。
+2. 把论文导入本地资料库(PDF/Markdown),或直接在对话里粘贴论文正文。
+3. 输入例如:「审一下这篇论文,目标 PRL」。
+
+## 输出
+
+`{workspace}/review_report.md`(人读)+ `review_result.json`(机读):
+
+- 主要贡献 / 创新性 / 技术正确性 / 实验充分性 / 写作问题
+- 中稿概率区间 + 理由
+- 编号的可执行修改清单(major/minor)
+
+## 权限
+
+只读资料库、写 workspace、不联网、不执行 shell。论文内容只有在你选择
+云端模型时才会发送给模型服务商(见「模型与隐私」)。
+
+## 不做
+
+- 不替你投稿、不联系编辑
+- 不编造论文里没有的内容;信息不足会要你补充

+ 81 - 0
agentexample/agentpacks/research.top-journal-reviewer/agents/reviewer.yml

@@ -0,0 +1,81 @@
+agentId: research-top-journal-reviewer
+name: 顶刊审稿助手
+description: >
+  独立论文审稿智能体。用户直接提供论文(粘贴正文 / 指向本地 PDF / 给出
+  workspace 内的论文文件),输出顶刊水准的结构化审稿报告 + 修改清单。
+  与流水线 reviewer 不同:不依赖上游 sim/analysis 产物,论文本身就是输入。
+
+type: react
+
+model:
+  provider: claude-code
+  name: sonnet
+  temperature: 0.1
+  maxTokens: 8192
+
+systemPrompt: |
+  你是一位经验丰富的顶级期刊(Nature/Science/PRL/顶会)审稿人。
+  用户会直接给你一篇论文,你的目标是产出一份既严格又建设性的审稿报告:
+  发现会影响科学结论、可复现性、发表质量的问题,并转成作者可执行的修订项。
+
+  ## 输入
+  用户输入可能是以下任意一种,先判断再处理:
+  - 直接粘贴的论文正文 / 摘要
+  - 指向本地资料库的检索线索(用 KBSearch 取回相关原文)
+  - workspace 里的论文文件路径(用 ReadFile 读取)
+  如果信息不足以审稿(例如只有标题),先用 KBSearch 在本地资料库找全文;
+  仍不足则明确告诉用户还需要什么,不要凭空编造内容。
+
+  ## 强制工作流程
+  1. 取得论文全文或足够的内容(ReadFile / KBSearch)。
+  2. 通读,定位:研究问题、主要贡献、方法、实验/证据、结论。
+  3. 如需对照已有工作,用 KBSearch 在用户本地资料库检索相关论文。
+  4. 写报告到 `{workspace}/review_report.md`(用绝对路径,见下)。
+  5. 写机读结论到 `{workspace}/review_result.json`。
+  6. 读回两个文件确认存在后 terminate。
+
+  ## review_report.md 必须包含
+  - 摘要与定位评价
+  - 主要贡献判断(是否如作者声称的新颖/重要)
+  - 创新性评价(与最接近的已有工作的差异)
+  - 技术正确性风险(推导/证明/统计/实现层面)
+  - 实验或论证充分性(baseline、消融、误差、可复现性)
+  - 写作与结构问题(清晰度、图表、记号、参考文献)
+  - 中稿概率区间(给区间 + 理由,例如 "30-45%,主因创新性边际")
+  - 可执行修改清单(编号,每条注明 major/minor + 预计工作量)
+  每条尽量引用论文里的具体位置(章节/图/式号),有对照时引用资料库来源。
+
+  ## review_result.json 结构
+  {"verdict":"accept|minor|major|reject","accept_probability":[low,high],
+   "major_issues":[...],"minor_issues":[...],"top_3_fixes":[...]}
+
+  ## 路径规范
+  workspace 是绝对路径。写文件用 `{workspace}/review_report.md` 这样的绝对
+  路径;如需 Bash,先 `test -d "{workspace}"` 再操作,禁止 `cd` 到空参数。
+
+  ## 风格
+  中文回复,学术严谨但具体可执行。不空泛夸奖,也不无依据贬低。
+
+react:
+  maxSteps: 40
+  observationEnabled: true
+  toolTimeout: 120
+  thinkTimeout: 300
+
+memory:
+  enabled: true
+  strategy: local
+  size: 30
+
+mcp:
+  localTools:
+    - ReadFile
+    - WriteFile
+    - ListFiles
+    - SearchContent
+    - KBSearch
+    - KBList
+    - terminate
+  policy:
+    mode: auto
+    maxConcurrent: 1

+ 27 - 0
agentexample/agentpacks/research.top-journal-reviewer/manifest.yml

@@ -0,0 +1,27 @@
+id: research.top-journal-reviewer
+name: 顶刊审稿助手
+version: 0.1.0
+domain: research
+entrypoint: agents/reviewer.yml
+description: >
+  对一篇论文生成顶级期刊水准的审稿意见:主要贡献判断、创新性评价、
+  技术正确性风险、实验充分性、写作问题、中稿概率区间,以及可执行的
+  修改清单。基于本地资料库做对照,引用保留出处。
+audience:
+  - professor
+  - phd_student
+  - postdoc
+permissions:
+  network: false
+  shell: false
+  file_write: workspace
+  read_knowledge: true
+  read_filesystem: false
+model:
+  recommended:
+    - claude-code/sonnet
+    - anthropic/claude-sonnet
+    - ollama/qwen
+author: kenny67nju
+homepage: https://github.com/kenny67nju/lambdagentpaas
+license: BUSL-1.1

+ 40 - 0
tests/test_agentpack.py

@@ -211,3 +211,43 @@ def test_uninstall_nonexistent_returns_zero(tmp_path):
     packs_dir = tmp_path / "agentpacks"
     packs_dir.mkdir()
     assert uninstall(str(packs_dir), "does.not.exist") == 0
+
+
+# ─────────────────────────────────────────────────────────────────────────────
+# Built-in packs (FR-008) — regression guard: the 3 bundled research packs
+# must always load, validate, and compile.
+# ─────────────────────────────────────────────────────────────────────────────
+
+_BUNDLED_IDS = {
+    "research.top-journal-reviewer",
+    "research.literature-mapper",
+    "research.grant-planner",
+}
+
+
+def _bundled_pack_dirs():
+    import glob
+    repo_root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+    return sorted(glob.glob(os.path.join(repo_root, "agentexample", "agentpacks", "*", "manifest.yml")))
+
+
+def test_bundled_packs_present():
+    found = {load_manifest(os.path.dirname(p)).id for p in _bundled_pack_dirs()}
+    assert _BUNDLED_IDS.issubset(found), f"missing bundled packs: {_BUNDLED_IDS - found}"
+
+
+@pytest.mark.parametrize("manifest_path", _bundled_pack_dirs())
+def test_bundled_pack_valid_and_compiles(manifest_path):
+    """Each bundled pack: manifest validates, entrypoint exists, and the
+    entrypoint config compiles via from_config (it's a real runnable agent)."""
+    from lambdagent import from_config
+
+    pack_dir = os.path.dirname(manifest_path)
+    m = load_manifest(pack_dir)
+    assert os.path.isfile(m.entrypoint_path()), m.entrypoint
+    # Built-in research packs are local-first: no shell, no network.
+    assert m.permissions.shell is False
+    assert m.permissions.network is False
+    # The entrypoint must compile to a runnable term.
+    term = from_config(m.entrypoint_path())
+    assert term is not None