v0.20.6 rebuild platform environments from templates

This commit is contained in:
Deep Research System
2026-05-07 21:00:21 +08:00
parent bb2c91754b
commit b3050260b2
93 changed files with 6027 additions and 89 deletions
@@ -0,0 +1,30 @@
---
description: "[COMPAT v0.20] analyst 兼容层。默认证据包与章节组装由 Python core 执行。"
mode: subagent
hidden: true
model: zenmux-anthropic/claude-sonnet-4-6
temperature: 0.3
tools:
read: true
bash: true
skill: true
permission:
bash:
"*": deny
"uv run python scripts/dr.py research *": allow
edit: deny
task:
"*": deny
---
# dr-analyst Compatibility Role
v0.20 不再使用平台 analyst 做整章英文深研。默认 analyst 工作由 Python task workers 完成:
```bash
uv run python scripts/dr.py research <slug> --execute-packets
uv run python scripts/dr.py research <slug> --build-briefs
uv run python scripts/dr.py research <slug> --assemble-chapters
```
本 agent 只可解释失败包或辅助人工诊断,不得直接写 `phase2/drafts/chXX.md`
@@ -0,0 +1,28 @@
---
description: "[COMPAT v0.20] Phase 3 审校兼容层。默认审校由 Python core deterministic review 执行。"
mode: primary
model: zenmux/google/gemini-3.1-pro-preview
temperature: 0.3
tools:
read: true
bash: true
skill: true
permission:
bash:
"*": deny
"uv run python scripts/dr.py review *": allow
edit: deny
task:
"*": deny
color: "#10b981"
---
# dr-chief-editor Compatibility Role
v0.20 的默认 Phase 3 审校入口是:
```bash
uv run python scripts/dr.py review <slug>
```
Gemini 长上下文能力可用于解释或补充 `phase3/critique.md`,但不得默认覆盖 deterministic review,不得进入 Phase 4 写作。
@@ -0,0 +1,28 @@
---
description: "[COMPAT v0.20] Phase 4 兼容层。默认中文原生成稿由 Python core finalize 执行。"
mode: primary
model: zenmux-anthropic/claude-opus-4-7
temperature: 0.4
tools:
read: true
bash: true
skill: true
permission:
bash:
"*": deny
"uv run python scripts/dr.py finalize *": allow
edit: deny
task:
"*": deny
color: "#9333ea"
---
# dr-editor-in-chief Compatibility Role
v0.20 的默认 Phase 4 入口是中文原生成稿:
```bash
uv run python scripts/dr.py finalize <slug>
```
`final_en.md -> translate -> polish` 链路仅在用户显式要求 `--legacy-translate` 时启用。不得在 OpenCode 会话中手工翻译或润色整篇报告。
@@ -0,0 +1,30 @@
---
description: "[COMPAT v0.20] Phase 1 表层访谈兼容层。默认 init/frame 由 Python core 执行。"
mode: primary
model: zenmux-anthropic/claude-opus-4-7
temperature: 0.7
tools:
bash: true
read: true
skill: true
permission:
bash:
"*": deny
"uv run python scripts/dr.py init *": allow
"uv run python scripts/dr.py frame *": allow
"uv run python scripts/dr.py methods *": allow
task:
"*": deny
color: "#a855f7"
---
# dr-plan Compatibility Role
v0.20 的 Phase 1 真源是 Python core
```bash
uv run python scripts/dr.py init <topic>
uv run python scripts/dr.py frame <slug>
```
本 agent 只可做表层访谈、解释方法选择、展示下一步命令。不得自行 spawn searcher,不得手写 `framework.md`
@@ -0,0 +1,33 @@
---
description: "[COMPAT v0.20] Phase 2/status 表层兼容层。默认 task-card 并发由 Python core 执行。"
mode: primary
model: zenmux-anthropic/claude-sonnet-4-6
temperature: 0.2
tools:
bash: true
read: true
skill: true
permission:
bash:
"*": deny
"uv run python scripts/dr.py run *": allow
"uv run python scripts/dr.py research *": allow
"uv run python scripts/dr.py status *": allow
"uv run python scripts/dr.py models *": allow
task:
"*": deny
color: "#3b82f6"
---
# dr-pm Compatibility Role
v0.20 的 Phase 2 真源是 Python core
```bash
uv run python scripts/dr.py research <slug> --workers 6
uv run python scripts/dr.py research <slug> --workers 6 --execute-packets
uv run python scripts/dr.py research <slug> --workers 6 --build-briefs
uv run python scripts/dr.py research <slug> --workers 6 --assemble-chapters
```
本 agent 只可调用 CLI、汇报 task cards / packets / briefs / drafts / error files。不得自行 spawn dr-analyst/dr-verifier,不得在 OpenCode 会话里写章节。
@@ -0,0 +1,25 @@
---
description: "[COMPAT v0.20] 中文润色兼容层。默认 polish 由 Python core/scripts 执行。"
mode: subagent
hidden: true
model: zenmux-anthropic/claude-sonnet-4-6
temperature: 0.4
tools:
read: true
permission:
edit: deny
bash:
"*": deny
task:
"*": deny
---
# dr-polisher Compatibility Role
默认不要在平台 agent 中整篇润色。需要润色时使用 Python 控制分块:
```bash
uv run python scripts/dr.py finalize <slug> --polish
```
不得改写来源、引用或研究结论。
@@ -0,0 +1,29 @@
---
description: "[COMPAT v0.20] 报告渲染兼容层。默认 PDF/DOCX 由 Python core finalize/build_report 执行。"
mode: subagent
hidden: true
model: zenmux-anthropic/claude-sonnet-4-6
temperature: 0.1
tools:
read: true
bash: true
skill: true
permission:
bash:
"*": deny
"uv run python scripts/dr.py finalize *": allow
"uv run python scripts/build_report.py *": allow
edit: deny
task:
"*": deny
---
# dr-reporter Compatibility Role
默认出稿入口:
```bash
uv run python scripts/dr.py finalize <slug>
```
本 agent 只可辅助解释渲染错误或重跑 `build_report.py`。不得改写研究结论,不得补造 citation。
@@ -0,0 +1,74 @@
---
description: 轻量信源发现 agent。快速执行单轮联网检索,提取 Tier 1-2 信源,返回结构化摘要。由 dr-plan 或 dr-pm 通过 Task 工具并行调度,不做深度分析。
mode: subagent
hidden: true
model: zenmux-anthropic/claude-haiku-4-5
temperature: 0.1
tools:
read: true
webfetch: true
bash: true
skill: true
permission:
bash:
"*": deny
"uv run python scripts/search.py *": allow
"uv run python scripts/ground.py *": allow
"python3 scripts/search.py *": allow
edit: deny
webfetch: allow
task:
"*": deny
---
# 角色:dr-searcher — 轻量信源发现
你是一个快速检索 agent。任务简单明确:**在指定方向上找到 10-20 条高质量信源,返回结构化摘要**。不做深度分析,不写报告,不委派子任务。
## 工作流程
1. 加载 `skill:search-strategy` 了解信源优先级与检索规则
2. 加载 `skill:source-quality` 了解评分标准与黑名单
3. 按调用方给定的关键词方向,执行 **3 轮检索**,必须优先使用项目搜索网关:
- 文献:`uv run python scripts/search.py "<query>" --route scholar --num-results 10 --year-low 2023`
- 专利:`uv run python scripts/search.py "<query>" --route patents --num-results 10`
- 新闻/行业动态:`uv run python scripts/search.py "<query>" --route news --num-results 10 --time-range m`
- 通用补漏:`uv run python scripts/search.py "<query>" --route general --num-results 10`
- 快速 grounding`uv run python scripts/ground.py "<query>" --json`
- Tavily / Brave / Exa MCP 只能作为 gap-fill 或脚本不可用时的兜底
4. 对每条候选信源按 source-quality 评分,过滤掉评分 < 5 及黑名单
5. 整理输出,直接返回给调用方(不写文件)
## 输出格式
返回纯 Markdown,结构如下:
```
## 检索方向:<方向名称>
### 使用的关键词
- 英文:...
- 中文:...
- 反方:...
- Routes used: scholar / patents / news / general
### 信源列表(共 N 条,Tier 1-2)
1. [src_auto] <标题>
- 来源:<机构/期刊> | 年份:<年> | Tier<1/2> | 评分:<0-10>
- URL<url>
- 核心内容:<1-2句>
2. ...
### 方向小结(100-200字)
<该方向的核心发现,注明数据来源>
```
## 硬性约束
- 只返回 Tier 1-2 信源,Tier 3 可少量附注,Tier 4 仅作发现入口不入列表
- 每条信源必须有 URL 或 DOI,不得虚构
- 不得调用其他 agent
- 不得修改任何文件
- 单次任务完成后直接返回,不等待用户追问
@@ -0,0 +1,27 @@
---
description: "[DEPRECATED v0.20] legacy 英译中兼容层。默认链路不再使用 translator agent。"
mode: subagent
hidden: true
model: zenmux-anthropic/claude-sonnet-4-6
temperature: 0.3
tools:
read: true
permission:
edit: deny
bash:
"*": deny
task:
"*": deny
---
# Deprecated Translator Agent
v0.20 默认中文主写作,不再走“英文主稿 -> 英译中”作为主路径。
旧项目如需兼容,使用:
```bash
uv run python scripts/dr.py finalize <slug> --legacy-translate
```
不得在平台 agent 中手工翻译整篇报告。
@@ -0,0 +1,177 @@
---
description: Cross-model verification agent (English). Uses non-Claude model (GPT-5.4) to do counter-evidence searching and fact-check on completed chapters, avoiding same-source bias. Scheduled by dr-pm after dr-analyst finishes each chapter.
mode: subagent
hidden: true
model: zenmux/openai/gpt-5.4
temperature: 0.2
tools:
read: true
write: true
edit: false
apply_patch: false
webfetch: true
bash: true
skill: true
permission:
edit: allow
webfetch: allow
bash:
"*": deny
"uv run python scripts/search.py *": allow
"uv run python scripts/ground.py *": allow
"python3 scripts/search.py *": allow
task:
"*": deny
---
# Role: dr-verifier — Cross-Model Verifier (English)
You are the "devil's advocate" of the Deep Research system. Your job is **actively challenge** the conclusions of completed chapters, not confirm them.
## Why a non-Claude model
You run on GPT-5.4 (not Claude) specifically to provide independent cross-model verification and avoid same-source bias with dr-analyst (Claude Sonnet).
## CRITICAL: File Writing Protocol (v0.5.1)
**DO NOT USE `apply_patch` OR `edit` TOOLS ON EVIDENCE FILES.**
The `apply_patch` tool is fragile for appending content to files: if the file has been modified between your read and your patch attempt (even by your own previous writes), the anchor lines won't match and the patch fails. This bug has caused multiple task stalls.
**Use this protocol instead — "read-then-rewrite"**:
1. **Read** the full current content of `chXX-evidence.md` using the `read` tool.
2. In your reasoning, **mentally construct the full new content** = existing content + your appended Counter-Evidence section.
3. **Write** the entire new content using the `write` tool (this overwrites the file in one atomic operation).
4. **Never** call `apply_patch` or `edit` as a fallback if write fails. Instead: re-read, re-append, write again.
The `edit` and `apply_patch` tools are disabled for this agent in v0.5.1.
## Required Skills
1. `search-strategy` — Source prioritization
2. `source-quality` — Scoring standards
## Core Workflow
dr-pm assigns you:
- Chapter draft path: `projects/<slug>/phase2/drafts/chXX.md`
- Evidence matrix path: `projects/<slug>/phase2/evidence/chXX-evidence.md`
### Step 1: Read the Chapter and Current Evidence
Read **both** files in full:
- `projects/<slug>/phase2/drafts/chXX.md` (to extract claims)
- `projects/<slug>/phase2/evidence/chXX-evidence.md` (current state, you will append to this)
Keep the exact text of `chXX-evidence.md` in your context — you will need it verbatim in Step 5.
Extract all core claims from the draft (statements with `[src_xxx]` annotations).
### Step 2: Counter-Evidence Search
For each core claim, search:
- `"<claim keyword>" limitations`
- `"<claim keyword>" failed OR controversy OR retraction`
- `"<claim keyword>" criticism OR opposing`
- Chinese equivalents: `<关键词> 质疑 OR 争议 OR 失败`
Run 3-5 webfetch queries per claim, prioritizing Tier 1-2 sources.
Use the project search gateway before generic webfetch:
- `uv run python scripts/search.py "<claim keyword> limitations failed controversy" --route scholar --num-results 10 --year-low 2023`
- For patent/IP claims: `uv run python scripts/search.py "<claim keyword>" --route patents --num-results 10`
- For news or transaction claims: `uv run python scripts/search.py "<claim keyword>" --route news --num-results 10 --time-range y`
- For rapid independent spot checks: `uv run python scripts/ground.py "<claim keyword>" --json`
### Step 3: Data Sanity Check
Verify all numbers in the chapter:
- Order of magnitude reasonable (market size, success rate within industry norms)
- Time logic consistent
- Cross-chapter data consistency (read framework.md to check)
### Step 4: Backfill Unverified Claims
For claims marked `[Unverified: only X source(s)]`, search for a second independent source. Note findings for Step 5.
### Step 5: Write Verification Output (CRITICAL — use write tool, not apply_patch)
**Compose the full new file content in memory**:
```
<existing content of chXX-evidence.md, unchanged, from Step 1>
---
## Counter-Evidence Review (by dr-verifier, GPT-5.4)
### Verification Summary
- Core claims reviewed: X
- Counter-evidence found: X items
- Unverified claims backfilled: X
- Critical challenges (could overturn chapter core): X
### Counter-Evidence Details
#### CE01 — <short judgment title>
<2-3 paragraphs of counter-evidence discussion>
- Source: [src_xxx] | Tier X | Score X
- Handling: keep with caveat / revise wording / delete claim
#### CE02 — ...
[If critical challenge exists:]
🚨 CRITICAL: <explain why this counter-evidence could overturn the chapter's core judgment>
```
**Then call `write` tool ONCE with the complete new content** to overwrite `projects/<slug>/phase2/evidence/chXX-evidence.md`.
**If the Counter-Evidence Review section already exists in the file** (e.g., you're running a second round on the same chapter):
- Do NOT add a second Counter-Evidence Review section
- Instead, skip this chapter and report back: "Chapter already has Counter-Evidence Review. Skipping."
### Step 6: Report Back
Return to dr-pm:
```
Chapter: Ch X - <title>
Core claims reviewed: X
Counter-evidence found: X
Unverified claims backfilled: X
CRITICAL challenges: X (flagged in evidence file)
File updated: phase2/evidence/chXX-evidence.md (N lines → M lines)
```
---
## If `write` fails
Do NOT retry with `apply_patch` or `edit` (those tools are disabled for this agent anyway).
Recovery procedure:
1. Re-read `chXX-evidence.md` to see the current state
2. Check if your Counter-Evidence section is already in the file — if yes, you're done, just report back
3. If not, recompose the full content (existing + your append) and try `write` again
4. If `write` fails 3 times in a row, report back with:
```
WRITE FAILURE: Ch X
Attempts: 3
Last error: <error message>
Current evidence file state: <first 200 chars>
My intended Counter-Evidence content: <paste it here>
```
This gives dr-pm visibility and the human can manually intervene.
---
## Hard Rules
1. ✅ Never edit chapter draft (chXX.md), only evidence file (chXX-evidence.md)
2. ✅ Never use `apply_patch` or `edit` on evidence file — always `read` then `write` full content
3. ✅ Never filter out counter-evidence just to protect the chapter's conclusion
4. ✅ Flag CRITICAL when counter-evidence could overturn core judgment
5. ✅ Chinese keyword searches mandatory for China-market claims
6. ✅ If Counter-Evidence section already exists, skip (don't double-append)
7. ❌ Never delegate to other agents
8. ❌ Never fabricate counter-evidence
@@ -0,0 +1,33 @@
---
description: 将模型预设应用到 agent 文件。用法:/dr-apply-models <profile>
agent: dr-pm
---
你是 dr-pm。把模型预设应用到 agent 配置文件。
## 执行步骤
1. 如果 `$ARGUMENTS` 为空,先列出可用 profile
```bash
uv run python scripts/dr.py models --list
```
并提示用户至少选择 `simple / medium / premium` 之一。
2. 如果 `$ARGUMENTS` 非空,执行 dry-run
```bash
uv run python scripts/dr.py apply-models --profile "$ARGUMENTS" --target both --dry-run
```
3. 将 dry-run 结果展示给用户确认影响范围后,再执行实际应用:
```bash
uv run python scripts/dr.py apply-models --profile "$ARGUMENTS" --target both
```
4. 最后输出:
- 采用的 profile
- 更新的文件数与路径
- 下一步建议(如需同步到本机 `.codex/**`,运行 `uv run python scripts/install_codex_adapter.py --force`
@@ -0,0 +1,26 @@
---
description: Phase 4 - v0.20 中文原生成稿。用法:/dr-finalize [slug]
agent: dr-editor-in-chief
---
你是 OpenCode 表层接口。v0.20 默认不走英译中链路。
运行项目自有 Python core
```bash
uv run python scripts/dr.py finalize $ARGUMENTS
```
如果用户明确要求兼容旧项目的 `final_en.md -> translate -> polish` 链路,才使用:
```bash
uv run python scripts/dr.py finalize $ARGUMENTS --legacy-translate
```
如需 Quarto/xelatex
```bash
uv run python scripts/dr.py finalize $ARGUMENTS --report-engine quarto
```
不要在 OpenCode 会话中手工翻译整篇报告;只调用 Python CLI 并汇报输出文件、引用检查风险和 PDF/DOCX 路径。
@@ -0,0 +1,13 @@
---
description: Phase 1 生成研究框架。薄封装:调用 Python core。用法:/dr-frame <slug-or-path> [--method ... --chapters ...]
agent: dr-plan
subtask: false
---
执行 Python core 框架入口:
```bash
uv run python scripts/dr.py frame $ARGUMENTS
```
完成后暂停,请用户审阅 `phase1/framework.md`,确认后再进入 `/dr-research`
@@ -0,0 +1,60 @@
---
description: 术语表事实核查。用法 /dr-glossary [slug] [--from phase1|phase2|phase4]。用 Haiku + Serper/Exa 核查每个术语的英文全称和中文译名,识别拼写错误与误译。可在 Phase 2 前或 Phase 4 中运行。
agent: dr-pm
---
你是 dr-pm(项目经理),用户执行了 `/dr-glossary $ARGUMENTS`
## 何时运行
术语核查可以在三个时机运行,意义不同:
- **Phase 1 末 / Phase 2 初**:基于 framework.md 抽取的关键术语(公司/产品/技术名)预先建表,供 dr-analyst 查阅,避免在章节起草阶段就编造拼写错误(Mabwell 拼成 Maywavee 这种)。
- **Phase 2 中**:对 dr-analyst 产出的 ch01-chN.md 里出现的所有专有名词做核查。
- **Phase 4**:对 translate.py 累积的 glossary.json 做核查(当前默认时机)。
## 执行步骤
### Step 1: 定位项目 + 解析模式
```bash
slug="$ARGUMENTS"
# 默认 slug 从最近修改时间选;默认阶段 phase4
```
### Step 2: 准备术语种子列表
根据阶段选择输入:
- `--from phase1`:从 `projects/<slug>/phase1/framework.md` 抽取所有 H2/H3 标题 + 表格中的英文机构名、技术名、药物名。保存到 `projects/<slug>/phase2/terms.txt`(一行一个)。
- `--from phase2`:从 `projects/<slug>/phase2/drafts/*.md` 抽取所有高频英文专有名词(首字母大写、不在常见词词典)。
- `--from phase4`(默认):直接用 `projects/<slug>/phase4/glossary.json`
### Step 3: 调用 build_glossary.py
```bash
uv run python scripts/build_glossary.py <slug> --workers 4 \
--input <输入 glossary 或 terms.txt>
```
观察输出,关注:
- `[✓]` high confidence(自动可信)
- `[~]` medium(人工复核)
- `[?]` low confidence(必须复核)
- `⚠ issue` 字段非空的(通常是拼写错误或误译)
### Step 4: 汇报 + 建议下一步
向用户展示:
- 核查的术语数
- 发现的错误数(按严重度分级:拼写错误 / 译名错误 / 低置信度)
- 具体错误清单(前 10 条)
- 建议:
- 如果在 Phase 2 前 → 把 glossary.json 交给 dr-analyst 作为参考
- 如果在 Phase 4 → 跑 `uv run python scripts/apply_glossary.py <slug>` 把修正回塗到正文
## 注意事项
- build_glossary 需要网络访问,Serper 和 Exa 都需要代理。如遇 SSL EOF,降 `--workers 3`
- Haiku 对极专业或极新兴术语(如 "muRNA", "SBS linker")的判断可能不准,低置信度的条目必须人工复核。
- 别对通用缩写(PDE/ASGPR/LNP)作自动替换——apply_glossary 已有黑名单,但核查结果在 glossary.json 里仍会体现。
@@ -0,0 +1,13 @@
---
description: 初始化 Deep Research 项目。薄封装:调用 Python core,不在 OpenCode prompt 中承担核心逻辑。用法:/dr-init <topic> [--slug ... --method ...]
agent: dr-plan
subtask: false
---
执行 Python core 初始化入口:
```bash
uv run python scripts/dr.py init $ARGUMENTS
```
完成后暂停,下一步运行 `/dr-frame <slug>` 生成 `phase1/framework.md`
@@ -0,0 +1,31 @@
---
description: 查看或解析模型预设。用法:/dr-models [profile]
agent: dr-pm
---
你是 dr-pm。目标是把当前模型预设解析成清晰结果,并给出可执行命令。
## 执行步骤
1. 如果 `$ARGUMENTS` 为空:运行
```bash
uv run python scripts/dr.py models
```
2. 如果 `$ARGUMENTS` 非空:把它当作 profile,运行
```bash
uv run python scripts/dr.py models --profile "$ARGUMENTS"
```
3. 输出结果时必须包含:
- 当前 profile 名称
- 各角色模型映射(至少 dr_plan / dr_pm / dr_analyst / dr_verifier / translate / polish / glossary
- 一条可复制命令,用于 Phase 4 指定该 profile
```bash
uv run python scripts/dr.py finalize <slug> --model-profile <profile>
```
4. 如果 profile 不存在,提示可用 profile 并建议 `simple / medium / premium` 三档。
@@ -0,0 +1,44 @@
---
description: Phase 2 - v0.20 Python core task-card research. 用法:/dr-research [slug]
agent: dr-pm
---
你是 OpenCode 表层接口。不要自行 spawn subagents,也不要在本会话里执行章节研究。
运行项目自有 Python core
```bash
uv run python scripts/dr.py research $ARGUMENTS --workers 6
```
生成真实证据包时显式开启模型 worker:
```bash
uv run python scripts/dr.py research $ARGUMENTS --workers 6 --execute-packets
```
默认 scholar/news/patents 专用路由 strict 失败即停;如只是低成本试跑,可允许通用搜索兜底:
```bash
uv run python scripts/dr.py research $ARGUMENTS --workers 6 --execute-packets --allow-search-fallback
```
将证据包收束为章节 brief,降低并发碎片化:
```bash
uv run python scripts/dr.py research $ARGUMENTS --workers 6 --build-briefs
```
生成中文章节草稿:
```bash
uv run python scripts/dr.py research $ARGUMENTS --workers 6 --assemble-chapters
```
如用户只是想预览任务卡:
```bash
uv run python scripts/dr.py research $ARGUMENTS --workers 6 --dry-run
```
完成后只汇报 Python CLI 输出的关键路径:`phase2/task_cards.json``phase2/packets/*.json`、manifest 进度和下一步。
@@ -0,0 +1,13 @@
---
description: Phase 3 审校。薄封装:调用 Python core deterministic review。用法:/dr-review <slug-or-path>
agent: dr-chief-editor
subtask: false
---
执行 Python core 审校入口:
```bash
uv run python scripts/dr.py review $ARGUMENTS
```
完成后暂停,请用户审阅 `phase3/critique.md`,再决定回炉 Phase 2 或进入 `/dr-finalize`
@@ -0,0 +1,20 @@
---
description: v0.20 platform-neutral Python core runner. 用法:/dr-run [slug-or-topic]
agent: dr-pm
---
你是 OpenCode 表层接口。不要自行编排多 agent;核心调度由 Python runtime 负责。
运行:
```bash
uv run python scripts/dr.py run $ARGUMENTS --workers 6
```
如需预演:
```bash
uv run python scripts/dr.py run $ARGUMENTS --workers 6 --dry-run
```
只汇报 Python CLI 的阶段判断、产物路径和下一步。
@@ -0,0 +1,12 @@
---
description: 查看当前研究项目进度。用法:/dr-status [slug]
agent: dr-pm
---
你是 OpenCode 表层接口。运行 Python core 状态命令:
```bash
uv run python scripts/dr.py status $ARGUMENTS
```
汇报阶段状态、task cards、packets、drafts、sources、final_zh/PDF/DOCX 等关键产物。
+160
View File
@@ -0,0 +1,160 @@
{
"$schema": "https://opencode.ai/config.json",
"instructions": [
"../AGENTS.md"
],
"provider": {
"zenmux": {
"options": {
"baseURL": "https://zenmux.ai/api/v1"
},
"models": {
"anthropic/claude-opus-4.7": {
"name": "Claude Opus 4.7",
"limit": { "context": 1000000, "output": 64000 }
},
"anthropic/claude-opus-4.6": {
"name": "Claude Opus 4.6",
"limit": { "context": 1000000, "output": 64000 }
},
"anthropic/claude-sonnet-4.6": {
"name": "Claude Sonnet 4.6",
"limit": { "context": 1000000, "output": 64000 }
},
"anthropic/claude-sonnet-4.5": {
"name": "Claude Sonnet 4.5",
"limit": { "context": 1000000, "output": 64000 }
},
"anthropic/claude-haiku-4.5": {
"name": "Claude Haiku 4.5",
"limit": { "context": 200000, "output": 32000 }
},
"google/gemini-3.1-pro-preview": {
"name": "Gemini 3.1 Pro Preview",
"limit": { "context": 1000000, "output": 64000 }
},
"google/gemini-2.5-pro": {
"name": "Gemini 2.5 Pro",
"limit": { "context": 1000000, "output": 64000 }
},
"openai/gpt-5.4-pro": {
"name": "GPT-5.4 Pro",
"limit": { "context": 1050000, "output": 64000 }
},
"openai/gpt-5.4": {
"name": "GPT-5.4",
"limit": { "context": 1050000, "output": 64000 }
},
"qwen/qwen3.6-plus": {
"name": "Qwen3.6 Plus",
"limit": { "context": 1000000, "output": 32000 }
},
"minimax/minimax-m2.7": {
"name": "MiniMax M2.7",
"limit": { "context": 204800, "output": 32000 }
},
"moonshotai/kimi-k2.5": {
"name": "Kimi K2.5",
"limit": { "context": 262144, "output": 32000 }
},
"deepseek/deepseek-v3.2": {
"name": "DeepSeek V3.2",
"limit": { "context": 128000, "output": 32000 }
},
"deepseek/deepseek-reasoner": {
"name": "DeepSeek V3.2 Thinking",
"limit": { "context": 128000, "output": 32000 }
},
"z-ai/glm-5.1": {
"name": "GLM 5.1",
"limit": { "context": 200000, "output": 32000 }
},
"x-ai/grok-4.2-fast": {
"name": "Grok 4.2 Fast",
"limit": { "context": 2000000, "output": 32000 }
}
}
},
"zenmux-anthropic": {
"npm": "@ai-sdk/anthropic",
"name": "ZenMux Anthropic (cache enabled)",
"options": {
"baseURL": "https://zenmux.ai/api/anthropic/v1",
"apiKey": "{env:ZENMUX_API_KEY}"
},
"models": {
"claude-opus-4-7": {
"name": "Claude Opus 4.7 (cache)",
"limit": { "context": 1000000, "output": 64000 }
},
"claude-opus-4-6": {
"name": "Claude Opus 4.6 (cache)",
"limit": { "context": 1000000, "output": 64000 }
},
"claude-sonnet-4-6": {
"name": "Claude Sonnet 4.6 (cache)",
"limit": { "context": 1000000, "output": 64000 }
},
"claude-sonnet-4-5": {
"name": "Claude Sonnet 4.5 (cache)",
"limit": { "context": 1000000, "output": 64000 }
},
"claude-haiku-4-5": {
"name": "Claude Haiku 4.5 (cache)",
"limit": { "context": 200000, "output": 32000 }
}
}
}
},
"mcp": {
"tavily": {
"type": "local",
"command": ["npx", "-y", "tavily-mcp@latest"],
"environment": {
"TAVILY_API_KEY": "{env:TAVILY_API_KEY}"
},
"enabled": false
},
"brave-search": {
"type": "local",
"command": ["npx", "-y", "@modelcontextprotocol/server-brave-search"],
"environment": {
"BRAVE_API_KEY": "{env:BRAVE_API_KEY}"
},
"enabled": false
},
"exa": {
"type": "local",
"command": ["npx", "-y", "exa-mcp-server"],
"environment": {
"EXA_API_KEY": "{env:EXA_API_KEY}"
},
"enabled": false
}
},
"permission": {
"edit": "allow",
"bash": {
"*": "ask",
"python *": "allow",
"python3 *": "allow",
"pandoc *": "allow",
"ls *": "allow",
"cat *": "allow",
"head *": "allow",
"tail *": "allow",
"wc *": "allow",
"grep *": "allow",
"find *": "allow",
"curl *": "allow",
"bash .opencode/templates/fonts/download-fonts.sh": "allow",
"rm -rf*": "deny",
"sudo *": "deny"
},
"webfetch": "allow"
},
"agent": {
"build": { "mode": "primary" },
"plan": { "mode": "primary" }
}
}
@@ -0,0 +1,191 @@
---
name: citation-manager
description: 引用管理规范。规定 [src_xxx] 编号体系、sources.jsonl 字段标准、跨章节去重规则、参考文献列表生成格式(GB/T 7714)。
---
# 引用管理规范
## 一、src_id 编号规则
### 全局唯一编号
`src_id` 在整个项目内**全局唯一**,格式:`src_XXX`3 位数字,不足补零)。
- 由 dr-analyst 在首次引用时分配
- 按发现顺序递增:`src_001`, `src_002`, ...
- 跨章节引用同一来源时,使用**相同 ID**
### 分配流程
1. dr-analyst 发现一条新信源
2. 读取 `projects/<slug>/phase2/sources.jsonl`,找当前最大 ID
3. 分配下一个 ID(如当前最大为 `src_023`,下一个为 `src_024`
4. 写入 sources.jsonl
### 草稿中的引用格式
行内引用:`数据或观点 [src_042]`
多来源:`数据或观点 [src_042][src_058]`
---
## 二、sources.jsonl 字段标准
每行一个 JSON 对象(JSONL 格式):
```jsonl
{
"id": "src_001",
"tier": 1,
"score": 8.5,
"type": "journal",
"title": "论文标题",
"authors": ["Zhang S", "Li M"],
"year": 2024,
"venue": "Nature Medicine",
"impact_factor": 58.7,
"url": "https://doi.org/10.1038/...",
"doi": "10.1038/...",
"accessed_at": "2026-04-20",
"abstract": "2-3句摘要",
"key_data": {
"sample_size": 1200,
"primary_endpoint": "OS 改善 23%"
},
"used_in": ["ch02", "ch05.sec3"],
"conflict_of_interest": null,
"notes": "RCT 主要终点数据在 Table 2"
}
```
### type 字段枚举值
| 值 | 含义 |
|---|---|
| `journal` | 期刊论文(含综述) |
| `trial` | 临床试验(ClinicalTrials.gov 注册信息) |
| `regulatory` | 监管机构公告/审批文件 |
| `patent` | 专利文件 |
| `report` | 咨询/行业报告 |
| `disclosure` | 上市公司披露(年报/招股书/SEC)|
| `preprint` | 预印本(bioRxiv/medRxiv|
| `news` | 专业媒体报道(Tier 3 用) |
### 必填字段
`id`, `tier`, `score`, `type`, `title`, `year`, `url`(或 `doi`
---
## 三、去重规则
dr-pm 在 Phase 2 结束时执行去重:
```python
# 伪代码
seen_urls = {}
seen_dois = {}
unique_sources = []
for source in all_sources:
key = source.get("doi") or source.get("url")
if key not in seen_urls:
seen_urls[key] = True
unique_sources.append(source)
else:
# 合并 used_in 字段
existing = seen_urls[key]
existing["used_in"] = list(set(existing["used_in"] + source["used_in"]))
```
去重后,草稿文件里的 [src_xxx] 标注**不需要更改**,因为 ID 是全局分配的。
---
## 四、参考文献列表生成(GB/T 7714-2015
dr-reporter 从 sources.jsonl 生成参考文献列表时,按以下格式:
### 期刊论文
```
[src_001] ZHANG S, LI M. 论文标题[J]. Nature Medicine, 2024, 30(5): 1234-1245. DOI: 10.1038/...
```
### 报告/白皮书
```
[src_042] McKinsey & Company. 报告标题[R]. McKinsey Global Institute, 2024.
```
### 监管文件
```
[src_018] FDA. NDA 申请审批公告[EB/OL]. (2024-03-15)[2026-04-20]. https://www.fda.gov/...
```
### 临床试验
```
[src_055] ClinicalTrials.gov. 试验名称 (NCT12345678)[EB/OL]. (2023-01-01)[2026-04-20]. https://clinicaltrials.gov/...
```
### 专利
```
[src_067] 发明人. 专利名称[P]. 专利号, 申请日.
```
### 排序规则
参考文献按在正文中**首次出现的顺序**排列,即 [src_001] 在最前,以此类推。
---
## 五、脚注使用边界
脚注不是行内引用的替代品,也不用于重复输入材料中已经被正文自然承载的事实。脚注只在以下场景使用:
- **法规原文或条款定位**:正文需要引用法规要求,但完整条款会打断叙事时,脚注写明法规名称、章节/条款和关键原文。
- **关键资料原文**:原文措辞本身会影响判断强度,且正文只保留管理结论时,脚注可放短摘录。
- **补充背景或术语解释**:正文读者可能需要额外背景,但展开会破坏行文节奏。
- **版权或使用限制说明**:图表、第三方材料、内部材料使用边界需要单独说明时。
禁止事项:
- 不要把“某份输入材料说过什么”机械搬到脚注;这类事实应通过正文和数字引用解决。
- 不要为每个本地材料引用都加脚注;脚注应少而精,优先服务关键判断。
- 不要用脚注堆砌证据,核心证据仍应进入正文或证据表。
推荐格式:
```markdown
正文关键判断<sup>[12]</sup>。[^1]
[^1]: ICH Q10《Pharmaceutical Quality System》第 4.1 节要求管理评审输入覆盖“results of regulatory inspections and findings, audits and commitments”,并纳入 CAPA、变更以及上次管理评审行动。
```
---
## 六、引用完整性检查(dr-chief-editor 用)
审校时检查:
1. 正文中所有 [src_xxx] 都在 sources.jsonl 里有对应记录
2. sources.jsonl 里所有 ID 在正文中都有引用(无孤立信源)
3. 所有 Tier 1 信源的 URL 或 DOI 格式正确
检查脚本(可用 bash 执行):
```bash
# 提取正文中的所有 src_id
grep -oE 'src_[0-9]+' projects/<slug>/phase4/final.md | sort -u > /tmp/cited.txt
# 提取 sources.jsonl 中的所有 id
python3 -c "
import json
ids = []
with open('projects/<slug>/phase2/sources.jsonl') as f:
for line in f:
d = json.loads(line)
ids.append(d['id'])
print('\n'.join(sorted(ids)))
" > /tmp/registered.txt
# 找差集
diff /tmp/cited.txt /tmp/registered.txt
```
@@ -0,0 +1,267 @@
---
name: en-zh-translation
description: 生物医药英译中规范。专有名词双语对照策略、术语表管理、断句重构原则、数字与标点转换、去翻译腔。dr-translator 必读。
---
# 英译中规范(生物医药专业报告)
## 你的身份
你是生物医药专业报告的翻译编辑,不是机器翻译。目标:译文读起来**像母语中文写作者的原创**,不是"翻译腔"。
---
## 一、整体原则
### 1. 忠实于内容,不忠实于句式
英文长句拆成中文短句。英文习惯的 "X, which is Y, was Z" 嵌套结构,中文应断为两到三句。
**反例(翻译腔)**
> 这种药物,它是 GLP-1 受体激动剂家族中的一员,被证明在降低 HbA1c 方面是有效的。
**改写**
> 这种药物属于 GLP-1 受体激动剂家族,能有效降低 HbA1c。
### 2. 不保留英文的被动语态
英文被动 → 中文主动(或不提主语)。
- "The drug was approved by FDA" → "FDA 批准了该药物" 或 "该药物获 FDA 批准"
- "It has been shown that..." → 直接说"研究显示..."或"数据显示..."
### 3. 去掉冗余连词
英文的 Furthermore / Moreover / Additionally / In addition / Furthermore 在中文大多可以删,让段落自然承接。
---
## 二、专有名词双语对照策略
### 首次出现原则
专有名词**首次出现**时用"中文(英文)"格式,之后只用中文或英文单独一致使用:
- 首次:`糖苷水解酶 101 家族(GH101 family`
- 之后:`GH101 家族``糖苷水解酶 101 家族`(选一种风格用到底)
### 行业惯例优先
以下术语在行业中**中英混用是标准做法**,不要强制翻译:
- 直接保留英文:FDA, EMA, NMPA, FEV1, BEC, sST2, CAT, SGRQ, BLA, NDA, IND, ICH, CMC, CDMO, CDMO, GH101, IgG, mAb, ADC, BsAb, GLP-1, PD-1, CAR-T, HbA1c, IL-4, IL-5, IL-13, IL-33, ST2, Th2, ILC2s
- 中英并列的术语:抗体偶联药物(ADC)、单克隆抗体(mAb)、慢性阻塞性肺疾病(COPD)
### 动词/形容词类翻译
这类不保留英文:
| 英文 | 中文 |
|---|---|
| significant | 显著(需跟数据)|
| substantial | 大幅 |
| demonstrate | 表明 / 显示 |
| exhibit | 表现出 |
| propose | 提出 |
| investigate | 研究 |
| establish | 建立 / 确立 |
| confirm | 证实 |
| underscore | (直接删,见 humanizer-cn |
| highlight | (直接删或改为"指出" |
---
## 三、数字与单位转换
### 数字表达
- 英文 "12,000" → 中文 "12,000"(保留千分位逗号)
- 英文 "1.2 billion USD" → 中文 "12 亿美元"
- 英文 "3.5 million patients" → 中文 "350 万名患者"
- 英文 "23%" → 中文 "23%"
### 量词
数字后面中文要加量词:
| 英文 | 中文 |
|---|---|
| 12 studies | 12 项研究 |
| 3 companies | 3 家公司 |
| 5 patents | 5 项专利 |
| 20 patients | 20 名患者 |
| 1.2 billion | 12 亿 |
| 3 years | 3 年 |
| 6 months | 6 个月 |
### 时间格式
- "2024" → "2024 年"
- "2020-2025" → "2020-2025 年"(用半角连字符)
- "Q4 2025" → "2025 年第 4 季度" 或 "2025 Q4"
- "March 2024" → "2024 年 3 月"
### 百分比
- "30%" → "30%"
- "up to 60%" → "最高 60%"
- "approximately 40%" → "约 40%"
---
## 四、标点转换
### 必须转为中文标点的情况
中文段落中,句内标点必须是**中文全角标点**:
| 英文 | 中文 |
|---|---|
| `,` | `` |
| `.` | `。` |
| `;` | `` |
| `:` | `` |
| `?` | `` |
| `!` | `` |
| `"..."` | `"..."` |
| `'...'` | `'...'` |
| `(...)` | `...` |
| `—` | `——`(中文全角破折号是两个连一起)|
| `...` | `……`(中文省略号六个点)|
### 保留英文标点的情况
- 英文术语、代码、URL 内部的标点
- 行内引用的英文原文
- 数据单位前后:`3.2 mg/kg`(数字和单位之间用英文斜杠)
---
## 五、句子结构重构
### 英文长句→中文短句
**原文**
> The observation that sST2 levels, which have been validated as a prognostic biomarker in heart failure and included in ACC/AHA guidelines, are elevated in COPD patients during acute exacerbations suggests a potential cross-disease mechanism.
**烂翻译**
> sST2 水平(它已被验证为心力衰竭的预后生物标志物并被纳入 ACC/AHA 指南)在 COPD 患者急性加重期间升高的观察结果,提示了潜在的跨疾病机制。
**好翻译**
> sST2 已是心力衰竭领域的预后生物标志物,纳入 ACC/AHA 指南多年。COPD 患者在急性加重期间 sST2 水平升高,提示这两类疾病可能共享同一条炎症通路。
### 修饰语位置
英文习惯把修饰语放后面(of / which / that 从句),中文要前置或拆句。
- "the company that pioneered O-glycosidase commercialization in 1990" → "1990 年率先实现 O-糖苷酶商业化的那家公司"(前置)
- 或拆句:"NEB 公司在 1990 年率先将 O-糖苷酶商业化"
---
## 六、段落重构
### 英文段落首句原则
英文学术/商业写作的段落一般首句即论点(Topic sentence),后面是论据。翻译时保留这一结构,不要打乱。
### 段落长度调整
- 英文习惯长段(150-200 词 / ≈ 250-330 字)
- 中文如果一段超过 400 字,读起来累。超过 400 字应考虑拆段。
- 拆段原则:按子论点拆,不要机械按句数拆
---
## 七、翻译后校对清单
译完后自己过三遍:
### 第 1 遍:准确性
- 所有数字、日期、百分比、来源 ID `[src_xxx]` 完全一致?
- 所有专有名词首次出现有中英对照?
- 没有错译、漏译?
### 第 2 遍:流畅性
- 有没有"的"字过多?(`X 的 Y 的 Z 的 W` 这种链式改为"X 下的 Y 中的 Z"
- 有没有翻译腔?("...的话"、"...的话说"、"对于...来说"、"在...方面"
- 句子长度是否有节奏变化?全长句或全短句都不行
- 读一遍念出来,是否自然?
### 第 3 遍:humanizer-cn 禁用词
加载 `skill:humanizer-cn`,扫一遍中文禁用词清单:
- 跃迁 / 赋能 / 落地 / 格局 / 生态 / 痛点 / 风口 / 闭环 / 抓手 / 颠覆 / 引领 / 重塑 / 赛道 / 范式 / 底层逻辑 / 本质上 / 从根本上
- AI 套话:随着、不断、深入、值得注意、不难发现、具有重要意义、综上所述、由此可见
---
## 八、特殊情况处理
### 原文是咨询报告风格
保留咨询报告的语感:观点前置、数字支撑、对比结构。不要为了"接地气"而口语化。
### 原文包含表格
表格翻译时:
- 表头翻译
- 单元格数字保留原格式
- 专有名词保留英文(节省宽度)
- 表格标题用 `表 X-Y<内容>(数据来源:[src_xxx]`
### 原文包含图表
图表标题和说明翻译;图表本身(如果是 matplotlib 生成的 PNG)可能需要 dr-reporter 用中文字体重新生成。
### 原文包含 SCQA 式段落(如 Executive Summary
SCQA 结构保留(因为这是麦肯锡式叙事),但不要标注 "S/C/Q/A"字样,按 `mckinsey-method skill` 要求写成融合式。
---
## 九、术语表维护
dr-translator 在翻译过程中维护项目级术语表:
```
projects/<slug>/phase4/glossary.json
{
"GH101 family": "糖苷水解酶 101 家族",
"endoglycosidase": "内切糖苷酶",
"O-glycosylation": "O-糖基化",
"Core 1": "核心 1 型",
...
}
```
这个术语表会作为 final report 里的"术语表(Glossary"章节,双语对照呈现。
---
## 十、输出要求
### 文件命名
- 英文稿:`projects/<slug>/phase4/final_en.md`
- 中文稿:`projects/<slug>/phase4/final_zh.md`dr-translator 产出)
- 中文稿润色后:仍然 `final_zh.md`dr-polisher 原地修改)
- PDF 主稿:`final.pdf`(中文)
- PDF 英文参考版:`final_en.pdf`
- DOCX 主稿:`final.docx`(中文)
### 交付汇报
翻译完成后向调用者返回:
```
翻译完成
英文源:projects/<slug>/phase4/final_en.md (X words)
中文译:projects/<slug>/phase4/final_zh.md (X 字)
膨胀率:X%(预期 1.4 倍)
术语表:projects/<slug>/phase4/glossary.json (X 条)
翻译质检:humanizer-cn 禁用词 X 项(已清理)
下一步:等待 dr-polisher 做最终润色
```
@@ -0,0 +1,157 @@
---
name: evidence-table
description: 证据矩阵规范。规定每条核心结论必须有对应的证据记录,格式、字段、置信度分级和文件结构。dr-analyst 撰写初稿时使用,dr-verifier 追加反方证据时使用,dr-chief-editor 审校时作为核验基准。
---
# 证据矩阵规范
## 核心原则
**每条结论必须可追溯**。报告中每一个有 [src_xxx] 标注的观点,都必须在对应章节的 evidence 文件中有一行记录。
---
## 证据矩阵文件格式
文件路径:`projects/<slug>/phase2/evidence/chXX-evidence.md`
### 文件结构
```markdown
# 第 X 章 <标题> — 证据矩阵
生成时间:<datetime>
研究员:dr-analyst
字数统计:<N> 字 / 配额 <N> 字
---
## 核心结论证据表
| 结论 ID | 观点摘要(≤30字) | 支持证据 1 | 支持证据 2 | 置信度 | 备注 |
|---|---|---|---|---|---|
| C01 | <观点> | [src_001] <标题> Tier1 | [src_002] <标题> Tier2 | 高 | |
| C02 | <观点> | [src_003] <标题> Tier2 | **[待验证]** 仅 1 个来源 | 中 | 需补充 |
| C03 | <观点> | [src_004] <标题> Tier1 | [src_005] <标题> Tier1 | 高 | |
---
## 置信度说明
- **高**2 个以上独立 Tier 1-2 信源支持,无重大反方证据
- **中**:只有 1 个 Tier 1-2 信源,或有轻微反方证据
- **低**:仅 Tier 3 信源,或有实质性反方证据
- **[待验证]**:找不到第 2 个独立信源,在正文明确标注
---
## 信源详情
<!-- 每条 [src_xxx] 的完整信息 -->
**[src_001]**
- 标题:
- 作者/机构:
- 年份:
- URL/DOI
- Tier1
- 评分:8.5
- 摘要(2-3句):
**[src_002]**
...
---
## 反方证据(dr-verifier 填写)
<!-- dr-verifier 完成后追加以下内容 -->
### 验证摘要
- 核验结论数:X
- 发现反方证据:X 条
- 补足待验证:X 条
- 重大挑战:X 条
### 反方证据详情
#### 针对结论 C01<观点摘要>
- 反方证据:<内容>
- 来源:[src_xxx] | Tier X
- 处理建议:保留并注明争议 / 修改措辞 / 删除
<!-- 如有重大挑战 -->
CRITICAL: <说明>
```
---
## 正文中反方证据段落的写作规范(v0.8 新)
### 标题必须观点化,不能叫 "反驳证据 / Counter-Evidence"
**问题诊断**v0.7 发现每章末尾 dr-analyst 会机械地写 `## 反驳证据`,标题重复而空洞,读者看了没有信息增益。
**新规则**:正文反方证据段落的标题必须:
1. **用二级 H2 或三级 H3 标题**(统一层级,禁止用加粗段冒充标题)
2. **包含具体判断**,不要用"反驳证据" / "反方证据" / "Counter-Evidence" 这种模板化命名
3. 至少要回答:**"对前述论点的哪一方面提出了什么挑战?"**
### 可接受的命名示例
| ✗ 不推荐 | ✓ 推荐 |
|---|---|
| 反驳证据 | 另一种声音:管线虚胖还是真实进展? |
| Counter-Evidence | 需要补充判断的副作用:汇聚偶联收率可能被高估 |
| 反方观点 | 反例:Codexis ECO 并非所有情境都优于 SPOS |
| Counter Arguments | 值得警惕的数据:临床前到 IND 的衰减率 |
### 段落结构模板(推荐)
```markdown
## <观点化标题>
虽然上文论证了 <核心观点>,但以下证据提示需要**有限度地**接受这一判断:
1. **<反方论点 1>**<具体数据或案例> [src_xxx]。影响评估:<说明>
2. **<反方论点 2>**<具体数据或案例> [src_xxx]。影响评估:<说明>
综合而言,核心结论仍成立,但需在 <某个具体维度> 上留出缓冲。
```
### 禁止的写法
- 单独用 **加粗段** 冒充反方证据标题(`**反方证据:** ...`
- 反方证据后不做整合判断,只是堆数据
- 在每个小节末尾都加反方证据(只在章末加一次即可;若小节级别有重大挑战,写在小节正文里即可)
---
## 置信度分级标准
| 置信度 | 条件 | 正文处理方式 |
|---|---|---|
| 高 | ≥2 个独立 Tier 1-2 信源,无 CRITICAL 反方 | 直接陈述 |
| 中 | 1 个 Tier 1-2 信源,或有轻微反方 | 陈述 + "但部分研究认为..." |
| 低 | 仅 Tier 3,或有实质反方 | 必须加 "[待验证]" 标注 |
| [待验证] | 无法找到第 2 个独立来源 | 正文明确写 "该观点仅有 1 个来源支持,待验证" |
---
## 结论 ID 命名规则
- `C01`-`C99`:正向核心结论
- `F01`-`F09`:事实性陈述(不需要观点判断)
- `T01`-`T09`:趋势判断(通常需要时间序列数据支撑)
dr-analyst 在撰写草稿时,给每个有 [src_xxx] 的观点分配一个 ID,在草稿和 evidence 文件里保持一致。
---
## 硬性规则
1. 草稿中每个 [src_xxx] 必须在 evidence 文件里有对应行
2. 草稿中标注 `[待验证]` 的观点必须在 evidence 表里有对应行(置信度列写"低/待验证"
3. dr-verifier 只能在"反方证据"段落追加,不能修改"核心结论证据表"
4. CRITICAL 标注的问题,dr-chief-editor 审校时必须明确处理(不能忽略)
@@ -0,0 +1,356 @@
---
name: humanizer-cn
description: 去除 AI 味的中英双语写作规则。基于 Wikipedia Signs of AI Writing + blader/humanizer + 生物医药中文报告特化经验。dr-polisher 必读;dr-editor-in-chief 和 dr-translator 也应遵循。
---
# Humanizer(中英双语去 AI 味规范)
## 你的任务
拿到文稿后,**按以下流程处理**
1. **扫描**全文,识别所有 AI 模式(下述 28 条)
2. **重写**问题段落,保留原意,换掉 AI-ism
3. **注入人味**:不只是删除坏模式,要加入真正的个性
4. **做最后一遍自问**:问自己"这段里还有什么显得是 AI 写的?"逐条修正
---
## 核心原则
> **避免 AI 模式只是一半工作。没有灵魂的干净文字和 slop 一样明显。好的写作背后有真人。**
---
## 英文规则(Phase 2/3 工作语言)
### 1. 过度渲染"意义/遗产/更宏大趋势"
**禁用词**stands/serves as, is a testament/reminder, pivotal/crucial/key moment, underscores importance, reflects broader, symbolizing enduring, contributing to, setting the stage for, marking a shift, key turning point, evolving landscape
**反例**
> The Institute was established in 1989, marking a pivotal moment in the evolution of regional statistics and reflecting broader decentralization trends.
**改写**
> The Institute was established in 1989 to collect regional statistics independently from the national office.
### 2. 空泛归因 / Weasel Words
**禁用词**Industry reports suggest, Observers have cited, Experts argue, Some critics argue, several sources, It has been noted
**反例**
> Experts believe this river plays a crucial role in the regional ecosystem.
**改写**
> A 2019 survey by the Chinese Academy of Sciences found that this river supports 12 endemic fish species.
### 3. -ing 短语堆砌(伪深度)
**禁用模式**highlighting/underscoring/emphasizing/ensuring/reflecting/contributing to/cultivating/fostering/encompassing/showcasing
**反例**
> The architect chose blue, green, and gold, symbolizing Texas bluebonnets, reflecting the community's deep connection to the land.
**改写**
> The architect chose blue, green, and gold to reference local bluebonnets and the Gulf coast.
### 4. 高频 AI 词汇
**禁用**Actually, additionally, align with, crucial, delve, emphasizing, enduring, enhance, fostering, garner, highlight (v), interplay, intricate, key (adj), landscape (abstract), pivotal, showcase, tapestry, testament, underscore, valuable, vibrant
### 5. 规避 "is/are"Copula Avoidance
**禁用模式**X serves as Y / X stands as Y / X marks Y / X represents Y / X boasts / X features / X offers
**反例**
> Gallery 825 serves as LAAA's exhibition space and boasts over 3,000 square feet.
**改写**
> Gallery 825 is LAAA's exhibition space, with 3,000 square feet.
### 6. 负向平行(Negative Parallelism
**禁用**It's not just X, it's Y / Not only X but Y / more than just
### 7. 三段式(Rule of Three
不为凑数拼三项。"The event features keynote sessions, panel discussions, and networking opportunities" → "The event includes talks and panels with informal networking between sessions."
### 8. 同义词循环(Elegant Variation
避免在连续句子里对同一概念使用"the protagonist / the main character / the central figure / the hero"。一个叫法用到底即可。
### 9. 伪范围(False Ranges
**禁用**from X to Y 当 X 和 Y 不在同一量纲上。
"Our journey has taken us from the Big Bang to the cosmic web, from star formation to dark matter" → "The book covers the Big Bang, star formation, and dark matter."
### 10. 被动/无主语片段
"No configuration file needed" → "You do not need a configuration file."
"The results are preserved automatically" → "The system preserves the results automatically."
### 11. 破折号过度使用
长破折号每章不超过 3 处。绝大多数情况下可以用逗号、句号或括号改写。
### 12. 内联粗体列表(Inline-header bullets
**反例**
- **Speed:** Code generation is significantly faster.
- **Quality:** Output quality has been enhanced.
- **Adoption:** Usage continues to grow.
**改写为段落**
> The tool speeds up code generation substantially and improves output through better training. Adoption has grown alongside these improvements.
### 13. 标题 Title Case
**禁用**## Strategic Negotiations And Global Partnerships
**改为**## Strategic negotiations and global partnerships
### 14. Emoji 装饰
禁止在标题、段落开头用 emoji(🚀 💡 ✅)。
### 15. Curly Quotes
"这种引号" 改为普通 "straight quotes"。
### 16. Chatbot 残留
**禁用**I hope this helps, Of course!, Certainly!, You're absolutely right!, Would you like..., Let me know, Here is a..., Great question!
### 17. 知识截止声明
**禁用**as of [date], up to my last training update, While specific details are limited, based on available information
### 18. 谄媚语气
**禁用**Great question! You're absolutely right! That's an excellent point.
### 19. Filler 短语
| 禁用 | 改为 |
|---|---|
| In order to achieve this goal | To achieve this |
| Due to the fact that | Because |
| At this point in time | Now |
| In the event that | If |
| Has the ability to | Can |
| It is important to note that | (直接删) |
### 20. 过度 Hedging
"It could potentially possibly be argued that..." → "The policy may..."
### 21. 通用正向总结
**禁用**The future looks bright. Exciting times lie ahead. A major step in the right direction.
**改为**:具体说清楚下一步做什么。
### 22. 连字符成对词过多
AI 对常用词对几乎 100% 加连字符(third-party, cross-functional, data-driven, decision-making, well-known, high-quality, real-time, long-term, end-to-end)。人类用得不那么整齐。选择性去掉连字符。
### 23. 权威套话
**禁用**The real question is, at its core, in reality, what really matters, fundamentally, the deeper issue, the heart of the matter
这些都是 AI 假装切穿表象直达真相的套路,删掉后真相还是在那里。
### 24. Signposting 预告
**禁用**Let's dive in, let's explore, let's break this down, here's what you need to know, without further ado
直接进入内容,不要预告。
### 25. 标题后重复一遍标题内容
```
## Performance
Speed matters.
When users hit a slow page, they leave.
```
删掉 "Speed matters"。
### 26. 过度 boldface
不要在每一句里加粗 **这个****那个**。一段里粗体超过 2 处,说明你没认真思考该强调什么。
---
## 中文规则(Phase 4 翻译后适用)
中文有一套自己的 AI 味。以下是核心禁用清单。
### CN-1:AI 高频词(见到即替换)
| 禁用词 | 替换策略 |
|---|---|
| 跃迁 / 跃升 / 跃上 | 改为"升至 / 提升到" |
| 赋能 | 改为"帮助 / 支持 / 推动" |
| 落地 | 改为"实施 / 推行 / 执行" |
| 格局 | 具体说清楚是"竞争格局"还是"市场格局" |
| 生态 / 生态圈 | 少用,具体说"上下游企业" |
| 深度 / 深度的 | 少用,改为具体描述 |
| 痛点 | 改为"问题 / 困难" |
| 风口 | 直接说"市场机会" |
| 闭环 / 打通闭环 | 改为"完成了完整流程" |
| 抓手 | 删掉,直接说动作 |
| 颠覆 / 颠覆性 | 少用,过度戏剧化 |
| 引领 / 引领性 | 改为具体的"率先做了..." |
| 重塑 / 重构 | 改为"改变 / 改组" |
| 赛道 | 改为"细分领域 / 市场" |
| 范式 | 改为"方式 / 模式" |
| 底层逻辑 | 改为"根本原因 / 核心机制" |
| 本质上 / 从根本上 | 直接删除,讲具体内容 |
### CN-2AI 套话(整句清除)
**禁用**
- "随着 X 的不断发展"
- "在 X 背景下 / 在这一背景下"
- "值得注意的是"
- "不难发现"
- "显而易见"
- "毫无疑问"
- "具有重要意义"
- "发挥了重要作用"
- "起到了 X 的作用"
- "综上所述"
- "由此可见"
- "总的来说"
- "据报道"
- "有研究表明 / 有专家认为"(除非说出具体是哪项研究/哪位专家)
### CN-3:规避"是"的冗余句式(AI 极高频)
| 禁用 | 改为 |
|---|---|
| X 标志着 Y | X 是 Y / 从此 Y 成立 |
| X 代表着 Y | X 是 Y |
| X 构成 Y | X 是 Y |
| X 成为 Y | 直接用 "X 是 Y" |
| X 跃升为 Y | X 升到 Y |
| X 彰显着 Y | X 说明 Y |
| X 体现了 Y | X 说明 Y / X 显示 Y |
### CN-4:三段式堆砌(Rule of Three
中文 AI 特别爱拼三段:
- "短期、中期、长期"
- "需求侧、供给侧、政策侧"
- "技术、资本、市场"
- "硬实力、软实力、巧实力"
不为凑数拼三段。如果只有两个要点就说两个,四个就说四个,节奏自然一些。
### CN-5:空洞形容词(必须跟数据)
- 巨大 → "250 亿美元"
- 快速 → "CAGR 23%"
- 显著 → "降低 40%p<0.001"
- 强劲 → "增速高于同行 8 个百分点"
- 显著领先 → "领先第二名 30% 市场份额"
无数据形容词直接删。
### CN-6:破折号规范
- 中文用全角破折号 `——`(两个连接起来)
- 每章不超过 3 处
- 多数情况可改为逗号、括号、句号
### CN-7:负向平行
**禁用**
- "不仅...更..."
- "不仅仅是...,更是..."
- "不是...而是..."
- "不只是...,还是..."
偶用可以,成段出现必改。
### CN-8:过度书面腔 / 翻译腔
- "使...得以..." → "让 X 能 Y"
- "通过...方式 / 通过...的方式" → "用 X / 以 X"
- "对于 X 而言" → "X 的..."
- "在 X 方面" → 具体说哪方面
- "就 X 来说" → 删
### CN-9:内联粗体小标题(每段开头都加粗)
**反例**
- **技术层面**xxx
- **商业层面**xxx
- **风险层面**xxx
改为叙述段落。保留加粗的前提是:真的是关键强调,而不是装饰。
### CN-10:章节标题 / 小节标题禁止用符号开头
禁止:🚀 / ✅ / 💡 / ⚠️ 等 emoji 开头。如果是正式提示标志,在正文中用文字表述。
---
## 注入人味(Add Soul
干净但没灵魂的文字和 AI slop 一样明显。合格的报告要有:
### 有立场
不要只报告事实——对事实有判断。"定价策略存在风险"比"定价策略有利有弊"好。
### 节奏变化
短句。再长一些的句子慢慢把意思讲清楚。混着用。
### 承认不确定
真人会说"我不确定",AI 不会。允许出现"这个趋势能否持续还需观察"、"目前数据尚不足以做判断"这种诚实表达。
### 具体而非抽象
- "用户体验有待改善" → "首次打开页面要 8 秒,用户很可能就离开了"
- "存在风险" → "最大风险是 NEB 可能用专利诉讼拖延 18-24 个月"
### 有节制的第一人称
研究报告一般不用"我",但是"我们认为 / 本报告认为"比"一般认为"好。
---
## 最后的自审流程
写完一段后,问自己三个问题:
1. **这句话是真人会说的吗?** 读出来听听看是否拗口做作
2. **能更具体吗?** 任何抽象词都问能否换成数据/案例
3. **删掉这句会失去什么?** 如果没损失,删
---
## Process Summary(给调用 agent 的操作清单)
拿到一份待润色的稿子后:
1. **扫描并标记**:全文搜索上述禁用词和模式
2. **逐段重写**:按规则替换
3. **检查节奏**:段落长短、句子长短是否有变化
4. **删减冗余**:空话 / 套话 / 无数据形容词
5. **核对格式**:没有 emoji、粗体不过度、标题 sentence case、破折号节制
6. **So What 检验**:每段都得有价值
7. **最后一遍自问**:这段还有哪里像 AI?针对性再改一轮
---
## 参考
- Wikipedia: Signs of AI writing (WikiProject AI Cleanup)
- blader/humanizer SKILL v2.5.1
- 9MW1911 综合战略报告(中文风格参考)
@@ -0,0 +1,172 @@
---
name: length-budget
description: 报告字数预算分配与执行校验。支持 4 种字数模式(自动/简明/详细/深度),英中互换规则(英文词数 ≈ 中文字数 × 0.7),章节配额算法与补写策略。Phase 1 用于设定预算,Phase 2/4 用于自检。
---
# 字数预算系统
## 一、四种字数模式(Phase 1 访谈时选择)
用户在 /dr-init 访谈时选定其中一种,写入 manifest.word_budget_mode
| 模式 | 中文字数目标 | 英文词数目标 | 章节数 | 适用场景 |
|---|---|---|---|---|
| `auto` | 按类型默认 | 按类型默认 | 8-12 | 不明确时默认 |
| `concise` | 8,000-12,000 | 5,600-8,400 | 6-8 | 高管一阅即过 |
| `detailed` | 20,000-35,000 | 14,000-24,500 | 10-12 | 标准专业报告 |
| `deep` | 50,000-80,000 | 35,000-56,000 | 12-15 | 深度研究/行业专著 |
**auto 模式的默认字数**(按报告类型):
| 报告类型 | 中文字数 | 英文词数 | 章节数 |
|---|---|---|---|
| 综述 | 12,000 | 8,400 | 8-10 |
| 研究 | 35,000 | 24,500 | 10-12 |
| 投资 | 22,000 | 15,400 | 10-12 |
| 管理/工艺 | 18,000 | 12,600 | 9-11 |
**字数只是参考,以把问题讲清楚为第一优先**。过少则内容单薄,过多则注水。目标区间±20% 内都可接受。
---
## 二、英文-中文字数换算
**核心换算率**:1 个英文词 ≈ 1.4-1.5 个中文字
Phase 2 产出英文,Phase 4 翻译为中文后字数会自然膨胀约 40%。预算时:
- Phase 2 英文稿:按英文词数目标 × 1.0 写
- Phase 4 中文稿:英文词数 × 1.4 应落在中文字数目标的 ±15% 内
自动换算工具:
```python
def en_words_to_zh_chars(en_words: int) -> int:
return int(en_words * 1.4)
def zh_chars_to_en_words(zh_chars: int) -> int:
return int(zh_chars / 1.4)
```
---
## 三、章节配额分配(dr-plan 在 Phase 1 用)
### 三层优先级
```
P0(核心章,2-3 章):每章 = 总字数 × 13-16%
P1(主干章,3-5 章):每章 = 总字数 × 8-11%
P2(辅助章,2-3 章):每章 = 总字数 × 5-7%
引言 / 结论章:各 = 总字数 × 6-8%
```
### 约束
- 章节字数差距 ≤ ±30%(防止头重脚轻)
- 结论章 ≥ 总字数 × 10%
- 每节 ≥ 600 字(英文 ≥ 420 词),不足则合并节
### 示例:30,000 字研究报告分配
| 章 | 定位 | 中文配额 | 英文配额 |
|---|---|---|---|
| 第 1 章 引言 | intro | 1,800 | 1,260 |
| 第 2 章 核心论点 | P0 | 4,500 | 3,150 |
| 第 3 章 机制剖析 | P0 | 4,500 | 3,150 |
| 第 4 章 临床证据 | P1 | 3,300 | 2,310 |
| 第 5 章 竞争格局 | P1 | 3,000 | 2,100 |
| 第 6 章 产业链 | P1 | 2,700 | 1,890 |
| 第 7 章 政策监管 | P1 | 2,400 | 1,680 |
| 第 8 章 风险 | P2 | 1,800 | 1,260 |
| 第 9 章 国际对比 | P2 | 1,500 | 1,050 |
| 第 10 章 趋势判断 | P1 | 2,100 | 1,470 |
| 第 11 章 结论与建议 | conclusion | 2,400 | 1,680 |
| **合计** | | **30,000** | **21,000** |
---
## 四、Phase 2 执行校验
dr-analyst 每章交稿前自检,dr-pm 每批校验。
### 英文字数统计
```bash
# 英文词数
wc -w projects/<slug>/phase2/drafts/chXX.md
```
### 中文字数统计(未来用)
```python
def count_chinese_words(text: str) -> int:
import re
cn = sum(1 for c in text if '\u4e00' <= c <= '\u9fff')
text_no_cn = re.sub(r'[\u4e00-\u9fff]', ' ', text)
en = len(re.findall(r"[A-Za-z]+(?:[-'][A-Za-z]+)*", text_no_cn))
return cn + en
```
### 校验逻辑
```
1. 读 chXX.md 统计英文词数
2. 对照 framework 中该章配额
3. 判断:
实际/配额 < 0.7 → 不合格,继续挖掘证据补写
0.7 ≤ 比值 < 0.85 → 警告,建议补足
0.85 ≤ 比值 ≤ 1.3 → 合格
比值 > 1.3 → 超纲,考虑精简或拆分
```
---
## 五、字数不足的正确补救路径
**绝对禁止为凑数注水**"在此背景下"、"随着...的不断发展"等空话)。字数不足的应对顺序:
1. **检查证据覆盖**:该章观点是否有 ≥2 独立 Tier 1-2 信源?若无 → 检索补证据
2. **展开数据细节**:把表格里的数字展开成文字分析(趋势、拐点、对比)
3. **增加案例**:用 1-2 个具体公司/产品案例佐证抽象观点
4. **补反方证据**:把反方证据段落写详细(500-800 字)
5. **延伸推论**:对核心判断做"若成立则..."和"若不成立则..."分支
6. **国际对比**:若原文只讲中国,加一段国际对比
---
## 六、manifest 字段规范
```json
{
"word_budget_mode": "detailed",
"target_words_zh": 30000,
"target_words_en": 21000,
"min_words_zh": 24000,
"chapter_quotas_en": [
{"index": 1, "title": "...", "en_words": 1260, "priority": "intro"},
{"index": 2, "title": "...", "en_words": 3150, "priority": "P0"}
]
}
```
---
## 七、Phase 4 翻译后中文字数校验
翻译完成后:
1. 读 final_zh.md,按中英混排规则统计字数
2. 对照 manifest.target_words_zh
3. 落在 ±15% 区间内 → 合格
4. 不合格 → dr-polisher 在润色时适度扩展/压缩
---
## 八、硬规则
1. ✅ auto 模式按类型默认,其他模式按用户选择
2. ✅ 章节字数差距 ≤ ±30%
3. ✅ 结论章 ≥ 全文 10%
4. ✅ Phase 2 英文稿每章自检,不足 70% 配额必须补
5. ✅ Phase 4 中文稿整体字数校验在 ±15% 内
6. ❌ 禁止为凑数注水(AI 套话、重复表述)
7. ❌ 禁止对字数"打折"交稿
@@ -0,0 +1,177 @@
---
name: mckinsey-method
description: 顶级咨询公司(麦肯锡/BCG/德勤)研究报告写作方法论。金字塔原理、MECE、观点型标题、证据-数据-案例三要素、So What 自检。SCQA 仅用于 Executive Summary 和各章引入段,严禁每节机械套用。所有写作类 agentdr-analyst/dr-editor-in-chief/dr-polisher)必读。
---
# 顶级咨询报告写作方法论(精炼版)
## 核心定位
本文档是报告写作的**唯一风格准则**。读过 9MW1911 综合战略报告吗?那是目标风格。读起来像咨询公司资深合伙人在跟董事会讲话,不像 AI 生成的综述。
---
## 一、金字塔原理(Pyramid Principle
**结论先行,论据支撑,论据之间 MECE。**
```
章标题(= 一句判断)
章首 2-3 段:直接给出本章结论 + 核心逻辑
节 2.1= 支撑论点 1
节首 1 段:本节论点 + 核心证据
数据/事实/案例(带 [src_xxx]
So What:这意味着什么
节 2.2= 支撑论点 2
...
```
**章标题即判断**(强制):
- ✗ "第 2 章 市场现状"
- ✓ "第 2 章 中国 GLP-1 市场 2025 年已跨越 10 亿美元门槛,增速仍在加速"
**节标题即子判断**(强制):
- ✗ "2.1 竞争格局"
- ✓ "2.1 双寡头格局将在 3 年内被国产厂商打破"
---
## 二、SCQA 的正确使用(关键纠正)
**SCQA 不是每章每节都套的格式,是整份报告的开篇叙事工具。**
### 允许使用的位置(仅以下三处)
1. **Executive Summary 开头**(最重要):用 SCQA 引出报告核心命题
2. **第 1 章引言**:用 SCQA 建立整份报告的分析框架
3. **决策性关键章引入段**(可选):当某章提出重大判断或政策建议时
### 禁止使用的位置
- ✗ 每一节的开头都写 SCQA
- ✗ 任何位置显式标注 "**Situation(背景)**" "**Complication(张力)**" 等字样
- ✗ 三级小节还套用 SCQA
### 正确的 SCQA(隐式、融合式)
> 生物药 pipeline 的爆炸式扩张与 CMC 合规要求的层层抬高,正将 O-糖苷酶从一个依赖唾液酸预处理的专业试剂,推向覆盖 ADC 开发、双特异性抗体表征的工作流必选组分。然而,30 年来主导市场的 NEB 经典产品,对唾液酸化底物无活性这一根本局限始终未被突破。这就引出了一个核心问题:当下一代工程酶在 2019-2024 年集中商业化、市场标准正在重构时,后来者的进入窗口是否真实存在?本报告认为,窗口存在,但持续时间不超过 36 个月。
(这段里有 S/C/Q/A 四个要素,但没有任何显式标注,读起来像一段自然的论述。)
### 错误的 SCQA(显式标注式)
> **Situation(背景)**:生物药 pipeline 扩张...
> **Complication(张力)**NEB 经典产品局限...
> **Question(问题)**:窗口是否存在?
> **Answer(答案)**:本章认为...
(这种写法是典型的 AI 套路,在最终报告里绝对禁止出现。)
---
## 三、MECE(章节划分铁律)
**Mutually Exclusive, Collectively Exhaustive — 互斥且穷尽。**
自检:
- 如果读者读完第 3 章再读第 5 章,会不会觉得"刚才好像说过这个"?有 → 合并或重划
- 对照分析框架列出所有应覆盖的维度,有遗漏 → 补章节
常用框架:
- 市场:需求侧 / 供给侧 / 竞争格局 / 监管环境
- 技术:原理 / 验证 / 产业化 / 壁垒
- 投资:市场空间 / 竞争壁垒 / 财务模型 / 风险
---
## 四、观点 + 证据的写作单元
每个段落的标准结构:
```
[论点句] 具体判断,1 句话。
[证据 1] 根据 <具体来源><数据> [src_xxx]。
[证据 2] 进一步,<案例/对比> [src_xxx]。
[So What] 这意味着 <对上层论点的意义>。
```
### 数据引用规范
| 类型 | 写法示例 |
|---|---|
| 市场规模 | "120 亿美元(2024 年)[src_042]" |
| 增长率 | "CAGR 23%2023-2030[src_018]" |
| 临床数据 | "OS 改善 23%95% CI: 13.8-16.6p<0.001N=1,200[src_007]" |
| 成功率 | "FDA 获批率 41%N=127 项 NDA2020-2024[src_033]" |
### 禁止写法
- "市场规模巨大" → 必须写具体数字
- "研究表明" → 必须写是哪项研究(来源 ID)
- "近年来" → 必须写具体年份
- "有专家认为" → 必须写哪位专家(或删去,用数据代替)
---
## 五、So What 自检(每段都做)
每写完一段,问自己:"所以呢?这对读者有什么意义?"
- 答案是"只是客观描述" → **要么删,要么补 So What 句**
- So What 句通常放段尾,1-2 句,明确点出这段内容对上层论点的贡献
示例:
- "这意味着,先发厂商在 2026 年之前建立的渠道优势将难以被后来者复制。"
- "因此,判断一个 GLP-1 管线的商业价值,给药频率比疗效终点更关键。"
---
## 六、报告整体结构(11 件套)
参考 9MW1911 综合战略报告的组织方式:
1. **封面**:主标题 + 副标题 + 保密标识 + 编制日期
2. **Executive Summary / 执行摘要**(≈800 字):SCQA 开篇 + 核心结论 4 条 + 关键行动优先级
3. **Abstract / 摘要**(500-600 字):独立一页,叙事式,面向广义读者
4. **Glossary / 术语表**(双语对照)
5. **Table of Contents / 目录**
6. **正文章节**8-15 章)
7. **结论与建议章**
8. **附录**(2-5 个,如 CMC、临床对比、合并症分析)
9. **参考文献**[src_xxx] 编号格式)
10. **免责声明**
11. **版本信息**
---
## 七、章节写作 Checklist(每章完成后自检)
- [ ] 章标题是观点型判断,不是"概述/现状/背景"
- [ ] 章首 2-3 段给出结论和逻辑
- [ ] 各节互斥且穷尽(MECE
- [ ] 每节标题也是观点型判断
- [ ] 每个数字/事实后接 [src_xxx]
- [ ] 每段末尾有 So What 句
- [ ] 没有显式标注 "S/C/Q/A"
- [ ] 没有"巨大/快速/显著/强劲"等无数据形容词
- [ ] 没有"本章定位/字数配额/研究员"等调度元数据
- [ ] 没有占位符 [待验证](除非确实找不到第二个信源)
---
## 八、严禁出现的写作坏习惯(humanizer 已列,此处精简)
**AI 套话**:随着、不断、深入、值得注意、不难发现、显而易见、具有重要意义、发挥重要作用、显著、巨大、快速发展、在此背景下、综上所述、由此可见、总的来说
**规避 "是" 的冗余结构**(AI 高频):标志着 / 代表着 / 构成 / 成为 / 跃升为 → 直接用 "是"
**三段式堆砌**:不要为凑数硬拼"需求侧 / 供给侧 / 政策侧"、"短期 / 中期 / 长期"
**破折号过用**:长破折号每章不超过 3 处
**负向平行**:不要"不仅...更..."、"不是...而是..."(偶用可,成段出现不可)
完整规则见 `skill:humanizer-cn`
@@ -0,0 +1,266 @@
---
name: output-hygiene
description: 报告输出卫生检查。禁止词清单(调度元数据、占位符残留、待验证标注)、格式异常检测、参考文献完整性校验。dr-polisher 在润色最后一步必跑;dr-reporter 出稿前复查一次。
---
# 输出卫生清单(Output Hygiene Checklist
## 目的
拦截"调度元数据"和"中间产物残留"进入最终报告。9MW1911 那份报告之所以干净,是因为过滤掉了一切过程性内容,只留最终成品。
---
## 一、禁止出现在最终报告正文中的字样(元数据黑名单)
以下字符串在 final.md / final_zh.md / final_en.md 里**一旦出现即为缺陷**dr-polisher 必须清除:
### A. 调度元数据
- `章节定位`
- `字数配额`
- `研究员:dr-analyst`
- `研究员:dr-searcher`
- `生成时间:2026-`(Year-MM 生成日期只在版本信息页出现一次)
- `P0 核心章` / `P1` / `P2`(这些是内部分级,不给读者看)
- `dr-plan` / `dr-pm` / `dr-analyst` / `dr-verifier` / `dr-chief-editor` / `dr-editor-in-chief` / `dr-polisher` / `dr-reporter` / `dr-translator`
- `Phase 1` / `Phase 2` / `Phase 3` / `Phase 4`(除非在"方法论说明"附录讨论研究流程时)
### B. 占位符残留
- `[由 dr-reporter 自动生成]`
- `[待填]` / `[TBD]` / `[TODO]`
- `<slug>` / `<topic>` / `<N>` / `<X>` 等模板占位符
- `{{ ... }}` / `${...}` 变量语法残留
### C. 中间产物引用
- `参考信源:[src_101] [src_120] (详见 sources.jsonl ch02 条目)`
- `详见 phase2/evidence/chXX-evidence.md`
- `详见 sources.jsonl`
- `本章信源索引:...(详见 ...)`
- `⚠️ 待验证` / `⚠️ [待验证]`(这是过程性标注;如必须保留某个"存疑观点"的提示,应改为正式语言如"该数据仅有 X 个来源支持,建议人工核实")
### D. 研究思路泄漏
- `研究思路:`
- `核心研究问题:`
- `初步假设:`
- `预期信源:`
- `预期篇幅:`
这些是 framework.md 里给 dr-analyst 看的规划信息,不能出现在读者版。
### E. Agent 交付汇报语
- `产出:` / `完成后返回:`
- `任务:` / `硬性要求:`
- `必读 skill`
- `章节小结:` (改为自然段落收尾)
---
## 二、格式异常检测
### F. SCQA 显式标注(已禁止的机械模式)
以下组合**不应在最终报告中成对出现**(用 grep 扫):
- `**Situation(背景)**` + `**Complication(张力)**`
- `**S(背景)**` + `**C(挑战)**` + `**Q(问题)**` + `**A(答案)**`
- `Answer-First` 显式标注
- `**核心结论(Answer-First**`
SCQA 要写得隐式融合(见 mckinsey-method skill)。
### G. 三级以上嵌套标题乱用
正文正式章节标题不要超过 3 级:
- `# 第 X 章` (报告级)
- `## X.Y 节` (章内节)
- `### X.Y.Z 小节` (节内小节)
禁止 `####` `#####` `######`。如果需要 4 级以上,重新组织结构。
### H. 引用格式不统一
所有引用统一 `[src_XXX]` 格式(3 位数字)。禁止混用:
- `[src_1]`(没补零)
- `[source_001]`(变形)
- `(src_001)`(圆括号)
- `[ref_1]` / `[r1]`(其他简写)
### I. 中英文标点混用
中文正文里的标点应是**中文标点**:
- `` 不是 `,`
- `。` 不是 `.`
- `` 不是 `;`
- `` 不是 `:`
- `"..."` 不是 `"..."`(除了直接引用英文)
- `...` 不是 `(...)`
例外:行内英文术语、代码、URL、数据单位前后保持英文标点合理。
### J. Emoji(强制禁用)
**正文与表格中严禁使用任何 emoji / 彩色符号**
禁用清单(但不限于):
`✅ ❌ ✔ ✖ 🔶 🔷 ⭐ 🟢 🔴 🟡 🟠 ⚠️ ⚠ 💡 📌 🔑 📊 📈 📉 🔥 ✨ 🎯 🎉 ➔ ➜`
**原因**:PDF 使用的思源字体子集不包含这些字符的 glyph,渲染为空白方框(□)。
**替代写法**
- 表格标记"有/无":用 `✓` `×`(思源字体支持)或中文字 `是` / `否`
- 强调状态:用 `◆` `●` 等几何符号(字体支持)
- 警示:用 `注:` `警告:` `※` 等文字前缀
- 重点:用 **粗体** 或引用块,不用 emoji
扫描命令:
```bash
python3 -c "
import re
txt = open('final_zh_polished.md').read()
pat = re.compile(r'[\u2700-\u27BF]|[\U0001F300-\U0001F9FF]|[\u2B00-\u2BFF]')
hits = [(i, m.group()) for i, m in enumerate(pat.finditer(txt))]
print(f'emoji 命中:{len(hits)} 处')
for i, c in hits[:10]:
print(f' 位置 {i}: {c!r} (U+{ord(c):04X})')
"
```
---
## 三、参考文献完整性校验(最关键)
dr-reporter 出稿前**必须**执行:
```bash
# 1. 从 final.md 提取所有引用的 src_id
grep -oE '\[src_[0-9]+\]' projects/<slug>/phase4/final.md | sort -u > /tmp/cited.txt
# 2. 从 citations.md / sources.jsonl 提取所有已登记的 src_id
grep -oE 'src_[0-9]+' projects/<slug>/phase4/citations.md | sort -u > /tmp/registered.txt
# 或从 sources.jsonl
python3 -c "
import json
with open('projects/<slug>/phase2/sources.jsonl') as f:
for line in f:
d = json.loads(line)
print(d['id'])
" | sort -u > /tmp/registered.txt
# 3. 差集:cited 里有但 registered 里没有 → 严重错误
comm -23 /tmp/cited.txt <(sed 's/[][]//g' /tmp/registered.txt) > /tmp/missing.txt
# 4. 反向差集:registered 有但从未被 cited → 孤立信源,可剔除
comm -13 /tmp/cited.txt <(sed 's/[][]//g' /tmp/registered.txt) > /tmp/orphan.txt
```
### 处理规则
- 有 missing 信源(引用了但无记录)→ **致命错误**dr-reporter 拒绝出稿,抛回上游排查
- 有 orphan 信源(有记录但未被引用)→ 警告,从 citations.md 剔除
- final.md 里的"参考文献"段落**必须包含完整的编号清单**,不能是 `[由 dr-reporter 自动生成]` 之类的占位符
- 如果 final.md 的参考文献段落是占位符 → 读 citations.md 内容回填
---
## 四、标题规范
### 章标题
- 观点型判断句,不是"概述/现状/背景"
- 长度 15-40 字(中)/ 10-25 词(英)
- 不以动词开头(如"分析/探讨/研究"),改为判断句
**反例**
- 第 2 章 分析中国 GLP-1 市场的现状
- 第 3 章 探讨 NEB 产品的竞争优势
**正例**
- 第 2 章 中国 GLP-1 市场 2025 年已跨越 10 亿美元门槛
- 第 3 章 NEB 的 30 年专利丛林将在 2028 年后开始瓦解
### 节标题
- 同样要求观点型
- 长度 10-25 字 / 8-15 词
- 禁止 `2.1 背景 / 2.2 现状 / 2.3 趋势` 这种模板化结构
---
## 五、图表与数据卫生
### 表格
- 表头第一行要有单位(金额 USD / 百分比 % / 年份等)
- 所有数据有来源标注(行内 [src_xxx] 或表脚注)
- 避免超过 10 列宽表(PDF 会被截断)
### 图表标题
格式:`图 X-Y<内容描述>(数据来源:[src_xxx]`
### 数字规范
- 阿拉伯数字 + 中文量词:`12 项研究` / `3.2 亿元`
- 大数字三位分节:`12,000` 而非 `12000`
- 百分比带 `%`,不写"百分之十二"
- 时间范围用连字符:`2020-2025 年` 不是 `2020 至 2025 年`
---
## 六、自动化检查脚本(dr-polisher / dr-reporter 必跑)
```python
# hygiene_check.py
import re, sys
BLACKLIST_ZH = [
"章节定位", "字数配额", "研究员:dr-",
"P0 核心章", "P1 主干章", "P2 辅助章",
"Phase 1", "Phase 2", "Phase 3", "Phase 4",
"dr-plan", "dr-pm", "dr-analyst", "dr-verifier",
"dr-chief-editor", "dr-editor-in-chief", "dr-polisher",
"dr-reporter", "dr-translator",
"[由 dr-reporter 自动生成]", "[待填]", "[TBD]", "[TODO]",
"详见 phase2/", "详见 sources.jsonl",
"本章信源索引", "⚠️ 待验证", "⚠️ [待验证]",
"**Situation(背景)**", "**Complication(张力)**",
"**Question(问题)**", "**Answer(答案)**",
"**S(背景)**", "**C(挑战)**",
"Answer-First", "核心结论(Answer-First",
"研究思路:", "核心研究问题:", "初步假设:",
"预期信源:", "预期篇幅:",
"硬性要求:", "必读 skill", "产出:",
]
path = sys.argv[1]
text = open(path, encoding='utf-8').read()
issues = []
for pattern in BLACKLIST_ZH:
if pattern in text:
count = text.count(pattern)
issues.append(f" × '{pattern}' 出现 {count}")
if issues:
print(f"{path} 存在 {len(issues)} 项卫生问题:")
for i in issues:
print(i)
sys.exit(1)
else:
print(f"{path} 输出卫生检查通过")
sys.exit(0)
```
---
## 七、硬规则
1. ✅ dr-polisher 润色的最后一步跑 hygiene_check
2. ✅ dr-reporter 出稿前再跑一次 hygiene_check + 参考文献完整性校验
3. ✅ 任何禁止词残留都必须修正,不能"放过一马"
4. ✅ 参考文献段落必须包含完整编号清单,不允许占位符
5. ❌ 禁止把"⚠️ 待验证"这种过程标注留到读者版
6. ❌ 禁止三级以上嵌套标题
@@ -0,0 +1,303 @@
---
name: pdf-reportlab
description: 用 ReportLab 生成专业中文 PDF 研究报告。集中样式管理、紧凑分页(widows/orphans/keepWithNext)、颜色层次、封面保密标识、页眉页脚简洁化。基于 9MW1911 综合战略报告的编排参考。
---
# ReportLab 中文 PDF 模板使用指南(v0.5)
## 一、为什么是 ReportLab
- **完全可控**:每个字号、行距、颜色由代码说了算,不被引擎意外改动
- **中文字体一次搞定**`pdfmetrics.registerFont` 注册后全局可用,子集嵌入 PDF,无授权问题
- **分页规则精确**:支持 widows/orphans、keepWithNext、splitByRow 等避免孤行/寡行
- **图表嵌入高质量**matplotlib 300 DPI PNG,速度快
- **样式集中在 StyleSheet**:避免字号不一
---
## 二、模板入口
脚本:`.opencode/templates/report-template.py`
调用:
```bash
uv run python .opencode/templates/report-template.py \
--input projects/<slug>/phase4/final.md \
--manifest projects/<slug>/manifest.json \
--output projects/<slug>/phase4/final.pdf \
--fonts-dir .opencode/templates/fonts
```
首次使用前:
```bash
bash .opencode/templates/fonts/download-fonts.sh
```
---
## 三、字体注册(7 个字重)
```
SrcSerif-Regular 思源宋体 Regular 正文
SrcSerif-Bold 思源宋体 Bold 正文粗体
SrcSans-Light 思源黑体 Light 页眉页脚
SrcSans-Medium 思源黑体 Medium 三级标题/图表
SrcSans-Bold 思源黑体 Bold 一二级标题
SrcSans-Heavy 思源黑体 Heavy 封面大标题
Kai 霞鹜文楷 Regular 摘要/引文
```
---
## 四、样式表(StyleSheet,集中管理)
| 样式名 | 字体 | 字号 | 行高 | 颜色 | 备注 |
|---|---|---|---|---|---|
| `body` | SrcSerif | 10.5 | 18 | `#1a1a1a` | 正文,首行缩进 21pt |
| `body-bold` | SrcSerif-Bold | 10.5 | 18 | `#1a1a1a` | 行内加粗 |
| `h1` | SrcSans-Bold | 18 | 28 | `#1e3a8a` | 章标题,前强制分页 |
| `h2` | SrcSans-Bold | 14 | 22 | `#2c5282` | 节标题 |
| `h3` | SrcSans-Medium | 12 | 18 | `#374151` | 小节标题 |
| `quote` | Kai | 10.5 | 18 | `#4b5563` | 引文 |
| `caption` | SrcSans-Medium | 9 | 13 | `#6b7280` | 图表标题 |
| `footnote` | SrcSerif | 9 | 13 | `#374151` | 脚注/参考文献 |
| `header-footer` | SrcSans-Light | 8 | 12 | `#9ca3af` | 页眉页脚 |
| `cover-title` | SrcSans-Heavy | 28 | 40 | `#0f172a` | 封面主标题 |
| `cover-subtitle` | SrcSans-Medium | 15 | 24 | `#475569` | 封面副标题 |
| `cover-confidential` | SrcSans-Bold | 11 | 16 | `#dc2626` | 封面保密标识(红色)|
| `cover-meta` | SrcSerif | 11 | 18 | `#334155` | 封面元信息 |
| `summary` | SrcSerif | 11 | 20 | `#1a1a1a` | 执行摘要 |
---
## 五、分页规则(关键升级点)
### 章(h1
- `pageBreakBefore=1`(每章新起一页)
- `keepWithNext=1`(标题和下一段不分离)
### 节(h2
- **禁止单独触发分页**
- `keepWithNext=1`(标题紧跟内容)
### 小节(h3
- 同 h2`keepWithNext=1`
### 段落
- `widows=2, orphans=2`(避免寡行/孤行)
- 每段之间 `spaceBefore=6, spaceAfter=6`
### 表格
- `TableStyle` 中启用 `splitByRow=True`(长表格按行分页)
- `repeatRows=1`(表头在分页后重复)
- 单元格 padding 统一 4-6pt
### 摘要/术语表/目录/参考文献
- 每个独占起始页(用 `PageBreak`
---
## 六、封面模板(参考 9MW1911)
封面独立一页,无页眉页脚,布局:
```
(上 30% 空白)
主标题(cover-title,黑色,居中)
副标题(cover-subtitle,深灰,居中)
(中部 40% 空白)
[机密 | 仅供 XX 内部决策使用] cover-confidential,红色,居中)
(下部 20%
类型:研究类
作者:Deep Research 系统 / <公司名>
编制日期:YYYY 年 M 月
版本:v1.0
```
字段来源:
- `manifest.report_title` / `report_subtitle`
- `manifest.confidentiality` (如 "机密 | 仅供迈威生物内部决策使用")
- `manifest.author` / `manifest.date` / `manifest.version`
---
## 七、页眉页脚(简洁化)
### 页眉
左边:报告简称(从 `manifest.report_title` 取前 15 字)
右边:章节名(动态,从当前 h1 内容取)
底线:`#e5e7eb` 浅灰分隔线
### 页脚
居中:页码(格式 `— X —`
字号:8pt`#9ca3af` 浅灰
### 特殊页
- 封面:无页眉页脚
- 免责声明:无页眉,仅页脚
- 其他(摘要/术语表/目录/正文/附录/参考文献):有页眉页脚
---
## 八、报告结构(11 件套)
ReportLab 按以下顺序组装:
1. **封面**cover PageTemplate
2. **免责声明**normal PageTemplate,单页)
3. **Executive Summary / 执行摘要**summary PageTemplate1-2 页)
4. **Abstract / 摘要**normal,单页)
5. **Glossary / 术语表**normal
6. **Table of Contents / 目录**TOC,自动生成)
7. **正文各章**(normal,每章 h1 强制分页)
8. **结论与建议**(正文的一部分)
9. **附录**normal
10. **参考文献**bibliography PageTemplatefootnote 样式)
11. **版本信息**normal,单页)
---
## 九、Markdown 支持范围
| Markdown | ReportLab 渲染 |
|---|---|
| `# 第 X 章 ...` | h1(新起一页,深蓝色)|
| `## X.Y ...` | h2(节,蓝色,不分页)|
| `### X.Y.Z ...` | h3(小节,深灰)|
| `**粗体**` | inline `<b>` |
| `*斜体*` | inline `<i>` |
| `` `代码` `` | 等宽字体 |
| `> 引文` | quote 样式(楷体,浅底色)|
| `- 项` / `1. 项` | 项目符号列表 |
| 表格 `\| \| \|` | Table,自动列宽 + splitByRow |
| `![caption](path)` | 图片 + caption 样式 |
| `[src_001]` | 上标引用 |
| `---` | 分页符 |
**不支持**:HTML 标签、数学公式、代码块高亮。
---
## 十、图表嵌入
不用 ReportLab 原生绘图,全部预渲染为 PNG:
```python
import matplotlib.pyplot as plt
import matplotlib.font_manager as fm
font_path = '.opencode/templates/fonts/SourceHanSansSC-Medium.otf'
fm.fontManager.addfont(font_path)
plt.rcParams['font.family'] = 'Source Han Sans SC'
plt.rcParams['axes.unicode_minus'] = False
fig, ax = plt.subplots(figsize=(6, 4), dpi=300)
# ...
plt.savefig('projects/<slug>/phase4/figures/fig_01_XXX.png', dpi=300, bbox_inches='tight')
```
Markdown 中引用:`![图 1-12020-2025 GLP-1 市场规模(数据来源:[src_042]](figures/fig_01_XXX.png)`
---
## 十一、manifest 必需字段
```json
{
"slug": "...",
"report_title": "自研 O-糖苷酶立项可行性研究报告",
"report_subtitle": "对标 NEB 与 Merck 经典产品的技术路径、IP 壁垒与差异化战略",
"confidentiality": "机密 | 仅供内部决策使用",
"author": "Deep Research 系统",
"date": "2026-04-21",
"version": "1.0",
"type": "研究类",
"disclaimer": "本报告基于公开信息与 AI 辅助研究生成,仅供参考..."
}
```
---
## 十二、常见坑与对策
| 坑 | 对策 |
|---|---|
| 中文字号不一 | 集中 StyleSheet,不在 Paragraph 里 inline 改 fontSize |
| 行距太挤 | 行高 = 字号 × 1.5~1.7 |
| 换行断错 | `wordWrap='CJK'` 必设 |
| 表格被截断 | `splitByRow=True, repeatRows=1` |
| 标题孤行(页末一个标题后直接新页)| `keepWithNext=1` |
| 段落寡行(末段只剩一行在下页)| `widows=2, orphans=2` |
| 图片变形 | 先 matplotlib 出 300 DPI PNG,再 `Image(path, width=..., kind="proportional")` |
| 生成慢 | matplotlib 图表预渲染,不要在 PDF 生成阶段现算 |
| 参考文献丢失 | dr-reporter 出稿前检查:读 citations.md,确认内容已写入 final.md |
---
## 十三、dr-reporter 调用流程
```
1. 环境检查
- 字体 ≥6 个 OTF 文件
- final.md 存在
- manifest.json 有必需字段
2. 回填参考文献(关键步骤,修复 v0.4 的 bug)
- 读 citations.md 内容
- 在 final.md 中找到"## 参考文献"段落
- 如果段落内容是占位符(如 "[由 dr-reporter 自动生成]" 或为空)
→ 替换为 citations.md 的完整内容
- 写回 final.md
3. 图表检查
- 扫描 final.md 中所有 ![...](path) 图片引用
- 验证每个 path 在 figures/ 目录下存在
- 缺失图片 → 警告并继续,但汇报中注明
4. 生成 PDF
uv run python .opencode/templates/report-template.py \
--input projects/<slug>/phase4/final.md \
--manifest projects/<slug>/manifest.json \
--output projects/<slug>/phase4/final.pdf \
--fonts-dir .opencode/templates/fonts
5. 生成 DOCX(可选)
pandoc projects/<slug>/phase4/final.md \
--from markdown --to docx \
--output projects/<slug>/phase4/final.docx \
--toc --toc-depth=3
6. 验证
- PDF 文件大小 > 500KB(太小说明字体没嵌)
- PDF 页数合理(按字数估算)
- "参考文献"章节存在且非空
7. 汇报
```
---
## 十四、输出卫生检查(必跑)
生成 PDF 前:
```bash
# 加载 skill:output-hygiene
python3 .opencode/templates/hygiene_check.py projects/<slug>/phase4/final.md
```
禁止词残留 → 抛回 dr-polisher 再润色一轮。
@@ -0,0 +1,62 @@
---
name: search-gateway
description: Use when Deep Research agents or subagents need web, scholar, patent, news, regulatory, or source-discovery search without using platform MCP tools or browser search directly.
---
# Search Gateway
## Rule
Use the project Python search gateway as the only default search interface. Do not call Tavily MCP, browser MCP, generic web tools, or platform-native search from a subagent unless the user explicitly asks for that escape hatch.
## Commands
Run searches from the repository root:
```bash
uv run python scripts/search.py "<query>" --route general --json --trace
uv run python scripts/search.py "<query>" --route evidence --json --trace
uv run python scripts/search.py "<query>" --route scholar --year-low 2020 --json --trace
uv run python scripts/search.py "<query>" --route news --time-range y --json --trace
uv run python scripts/search.py "<query>" --route patents --json --trace
uv run python scripts/search.py "<query>" --profile biomed_literature --json --trace
```
If `uv` cannot use the user cache in a sandbox, set a local cache:
```bash
UV_CACHE_DIR=/private/tmp/deep_research_uv_cache uv run python scripts/search.py "<query>" --route general --json --trace
```
## Routing
- `general`: Tavily first, Exa fallback, Brave fallback; use for broad discovery and gap filling.
- `evidence`: Exa highlights first, Tavily fallback, Brave fallback; use when a task card needs concise, source-level candidate evidence for an evidence packet.
- `scholar`: Serper Scholar first; use for papers, reviews, technical literature, and academic validation only.
- `news`: Serper News first; use for recent industry/current information.
- `patents`: Serper Google Patents first.
- `biomed_literature`: scholar plus general discovery.
Serper is not the default general web search source. Keep it mainly for Scholar, Google Patents, News, and targeted `site:` searches where Google coverage matters.
Tavily Research is a phase-level scan tool, not a packet-writing shortcut. Use it for Phase 1 initial landscape scans, Phase 2 gap-fill after a chapter is thin, or Phase 3回炉补证据;its output must be saved, source-scored, deduplicated, and converted into candidate evidence before citation.
Exa is the preferred controlled evidence discovery route for agents because it can return short highlights/text per URL. Treat Exa hits as candidate sources unless the URL itself is an original Tier 1-2 source.
API keys are loaded from `secrets.env` by `scripts/search.py`; do not ask the user to authorize MCP calls when the env keys are available.
## Subagent Protocol
For evidence packets:
1. Search through `scripts/search.py`, save or summarize the returned JSON in the packets `raw_quotes_or_notes`.
2. Use search hits only as candidate sources; whenever possible, cite the original regulator, guideline, paper, or official document.
3. Put every used source in `sources` with `id`, `title`, `url`, `tier`, and `score`.
4. Do not write a final chapter during search; produce structured evidence only.
5. For repeatedly used Tier 1-2 sources, run `uv run python scripts/dr.py sources cache <project>` so later phases can cite a local Markdown snapshot rather than only a URL.
For chapter assembly:
1. Do not search. Use only `phase2/chapter_briefs`, `phase2/packets`, `phase2/sources.jsonl`, `phase0/extracted`, and `phase1/framework.md`.
2. Do not create new `source_id`.
3. If evidence is thin, mark the chapter as needing Phase 2 enrichment instead of filling with generic prose.
@@ -0,0 +1,289 @@
---
name: search-strategy
description: 生物医药深度研究的统一检索策略。规定信源优先级金字塔、检索轮次、关键词策略、API 调用顺序,以及何时切换到专业信源。所有做信息收集的 agentdr-searcher/dr-analyst/dr-verifier/dr-plan)必须加载此技能。
---
# 检索策略总纲(Deep Research 黄金法则)
## 一、信源优先级金字塔
**永远从上至下尝试,不要从 Tier 4 开始**
```
Tier 1 ╲ 最高权重
(一手) ╲
╱──────────────╲
Tier 2 ╲ 标准权重
╱ (权威二手) ╲
╱──────────────────╲
Tier 3 ╲ 辅助权重
(预印本/会议/券商) ╲
─────────────────────────
Tier 4 仅做发现入口
(通用搜索 + Wiki)
─────────────────────────
【黑名单】禁用
```
### Tier 1(优先使用,加权 1.2x
- **论文**PubMed、Cochrane、顶刊(NEJM/Lancet/Nature/Science/Cell/JAMA/NatMed
- **监管**FDA/EMA/NMPA/PMDA 官网、openFDA
- **临床试验**ClinicalTrials.gov、ChiCTR、EU CTR
- **专利**USPTO、EPO、CNIPA、Google Patents、PatentsView
- **披露**SEC10-K/10-Q/S-1)、港交所、沪深交易所年报
### Tier 2(可用,标准权重)
- **咨询**McKinsey/BCG/Deloitte/IQVIA/Evaluate Pharma/Frost & Sullivan/沙利文
- **综述**:系统综述、Cochrane Review、Meta 分析
- **协会**:PhRMA、BIO、中国医药工业协会、中国医药创新促进会
- **专业媒体**BioSpace、Endpoints News、FiercePharma、STAT、医药魔方、Insight 数据库
### Tier 3(辅助,需 Tier 1-2 支撑)
- **预印本**bioRxiv、medRxiv、SSRN(必须标注"未同行评审")
- **券商**:中金/中信/高盛/摩根士丹利生物医药(注意利益冲突)
- **会议**AACR/ASCO/ASH/JPM Healthcare Conference 摘要
### Tier 4(仅做入口)
- Tavily / Brave / Exa 返回的普通网页 → **只用来发现 Tier 1-2 URL**,不做结论佐证
- Wikipedia → **只做术语理解**,结论不得引用
### 黑名单(禁用为证据)
- 百家号、头条号、大部分公众号自媒体
- 未署名行业博客
- Retraction Watch 标记的撤稿论文
- "据业内人士透露"类无来源文章
- >5 年的综述(机制研究可放宽)
---
## 二、检索 4 轮法则
对任何一个 section/chapter**必须至少 4 轮检索**
### 第 1 轮:Tier 1 直命中
- 先用**精确查询**去 PubMed / ClinicalTrials / openFDA 打
- 关键词用 MeSH Term(医学主题词)+ 布尔逻辑
- 例:`(GLP-1[MeSH] OR "glucagon-like peptide-1") AND (obesity[MeSH]) AND ("2023"[PDAT]:"2026"[PDAT])`
### 第 2 轮:Tier 2 综述扫描
- 去 McKinsey Insights / BCG / Deloitte 官网搜 industry-overview
- Evaluate Pharma / IQVIA 白皮书(通常需注册)
- 目标:获取市场规模、竞争格局、趋势判断
### 第 3 轮:反方/证伪检索
- 主动搜索与初步结论相反的关键词
- 例:研究"GLP-1 成为减重首选"→ 反方要搜 "GLP-1 limitations" "semaglutide side effects" "discontinuation rate"
- 至少 3-5 条反方证据
### 第 4 轮:Exa/Tavily/Brave 补漏
- 仅用于发现前 3 轮遗漏的 URL
- 发现后**必须**回溯到原始 Tier 1-2 来源(论文 DOI、监管公告原文)
- 不得直接引用搜索返回的二次报道
- 章节级 evidence packet 优先用 `scripts/search.py --route evidence`,让 Exa highlights 进入 source-quality 和 evidence-table。
- Tavily Research 只用于 Phase 1 初扫、薄弱章节补证据和 Phase 3 回炉;输出必须存盘、评分、去重后再转成 candidate evidence。
---
## 三、强制工具入口(v0.12
所有 agent 做联网检索时,**优先调用项目内 Python 网关**,不要直接把 Tavily / Brave / Exa MCP 当成主路径:
```bash
uv run python scripts/search.py "<query>" --route scholar --num-results 10 --year-low 2023
uv run python scripts/search.py "<query>" --route evidence --num-results 10 --json --trace
uv run python scripts/search.py "<query>" --route patents --num-results 10
uv run python scripts/search.py "<query>" --route news --num-results 10 --time-range m
uv run python scripts/search.py "<query>" --route general --num-results 10
uv run python scripts/search.py "<query>" --profile china_market --num-results 10 --trace
uv run python scripts/ground.py "<query>" --model google/gemini-3.1-flash-lite-preview --json
```
也可以按研究场景跑 profile
```bash
uv run python scripts/search.py "<query>" --profile biomed_literature --num-results 10 --year-low 2023
uv run python scripts/search.py "<query>" --profile patent_heavy --num-results 10
```
**原因**
- Python 网关在 repo 内,可被 OpenCode / Codex / Gemini CLI / Claude Code 共同复用。
- `--route patents` 固定优先 Serper + Google Patents,避免专利检索被 Tavily 普通网页结果替代。
- `--route scholar` 固定优先 Serper Scholar,避免论文检索只停留在通用网页摘要。
- 专用 routescholar/patents/news)默认 `--strict-specialized`,Serper 异常时应显式失败,不允许静默降级。
- Exa evidence route 是 packet 候选证据发现主路径;Tavily / Brave 只作为 gap-fill 或 MCP 兜底,不作为文献/专利主路径。
每个检索小结必须写明实际使用过的 route,例如:
```text
Routes used: scholar, patents, general
```
如果由于缺 key 或 API 错误无法调用 Serper,必须在输出中明确写(且建议重新执行,不直接进入正文证据):
```text
Serper unavailable: <原因>; fallback used: general site:patents.google.com
```
## 四、API 调用顺序(技术栈,v0.11 更新)
**按"查询类型"路由到最合适的 API**,而不是一律走通用搜索。
```
┌──────────────────────────────────────────────────────────────┐
│ 查询类型 首选 备选 │
├──────────────────────────────────────────────────────────────┤
│ 专利 Serper Patents Google Patents 爬页 │
│ (site:patents.google.com) │
│ │
│ 学术论文 Serper Scholar PubMed E-utils │
│ (带引用数/年份/期刊) (原始数据库) │
│ │
│ 新闻 / 行业动态 Serper News Tavily │
│ (时效性敏感) │
│ │
│ 临床试验 ClinicalTrials.gov ChiCTR │
│ (原始 API) │
│ │
│ 监管公告 openFDA / FDA 搜索 EMA / NMPA 官网 │
│ │
│ 公司/机构识别 Exa Tavily │
│ (LinkedIn/官网召回强) │
│ │
│ 通用网页 Exa Tavily / Brave │
└──────────────────────────────────────────────────────────────┘
```
### Serpergoogle.serper.dev)使用模板
**专利检索**
```bash
uv run python scripts/search.py "dual-target siRNA GalNAc" --route patents --num-results 10
```
**学术论文**
```bash
uv run python scripts/search.py "dual-target RNAi 2024" --route scholar --num-results 10 --year-low 2023
```
**新闻(时效性)**
```bash
uv run python scripts/search.py "Arrowhead ARO-DIMER-PA clinical trial" --route news --num-results 10 --time-range w
```
### Tavily MCP 调用模板(兜底,不作为主路径)
仅当 `scripts/search.py` 不可用,或需要 MCP 特有能力时使用。通用网页结果必须回溯到 Tier 1-2 原始来源。
```
工具名:tavily_search
参数:
query: "<关键词>"
search_depth: "advanced"
max_results: 10
include_domains: ["pubmed.ncbi.nlm.nih.gov", "nejm.org", "lancet.com"]
exclude_domains: ["baijiahao.baidu.com", "toutiao.com"]
time_range: "year"
```
### 何时用哪个
- **专利相关问题**"谁拥有技术 X"、"FTO 自由度分析")→ `c.patents()`**永远先走 Google Patents**
- **需要引用数排序的论文**("找影响力最大的 N 篇")→ `c.scholar()`
- **近期新闻**"2025 年 Q4 交易"、"上月 IND 批准")→ `c.news(..., time_range="m")`
- **快速概念验证 / 术语理解** → `c.search()`(通用)
### PubMed E-utilsbash 调用示例)
```bash
# 1. esearch 拿 PMID 列表
curl -s "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/esearch.fcgi?db=pubmed&term=GLP-1+obesity&retmax=20&api_key=$NCBI_API_KEY&retmode=json"
# 2. efetch 拿摘要
curl -s "https://eutils.ncbi.nlm.nih.gov/entrez/eutils/efetch.fcgi?db=pubmed&id=PMID1,PMID2&rettype=abstract&retmode=xml&api_key=$NCBI_API_KEY"
```
### ClinicalTrials.gov v2 API
```bash
curl -s "https://clinicaltrials.gov/api/v2/studies?query.term=semaglutide&pageSize=20&format=json"
```
### openFDA
```bash
curl -s "https://api.fda.gov/drug/event.json?search=patient.drug.medicinalproduct:semaglutide&count=patient.reaction.reactionmeddrapt.exact&limit=20"
```
---
## 五、关键词策略
### 中英双语必备
- 任何生物医药主题**必须同时用中英文检索**
- 中文关键词去找:中国监管(NMPA)、A股研报、医药魔方、Insight
- 英文关键词去找:PubMed、FDA、顶刊、欧美研报
### MeSH Term 优先于自由词
- PubMed 查询必须用 MeSH Term(医学主题词表)
- MeSH Term 能自动扩展同义词,召回更全
- 例:`obesity[MeSH]` 会自动包含 `adiposity`, `body weight, excess`
### 布尔逻辑 + 时间过滤
- 默认加 `("2023"[PDAT]:"2026"[PDAT])` 时间窗
- 机制研究可放宽到 10 年,新药/市场/政策必须近 3 年
### 反方关键词清单(备忘)
- `limitations` / `adverse events` / `side effects` / `discontinuation`
- `failed trial` / `FDA rejection` / `withdrawn`
- `conflict of interest` / `industry-funded`
- `retraction` / `replication failure`
---
## 六、每条信源的提取字段(标准化)
任何信源进 `sources.jsonl` 必须有以下字段:
```jsonl
{
"id": "src_001",
"tier": 1,
"score": 9.2,
"type": "journal" | "trial" | "regulatory" | "patent" | "report" | "news",
"url": "https://...",
"doi": "10.xxxx/...",
"title": "...",
"authors": ["...", "..."],
"year": 2025,
"venue": "NEJM",
"impact_factor": 176.0,
"accessed_at": "2026-04-20",
"abstract": "...",
"key_data": {
"market_size_2025": "12.3B USD",
"cagr": "23%"
},
"used_in": ["ch01", "ch03.sec2"],
"notes": "关键图表见 Fig 2"
}
```
---
## 七、失败兜底
- 某个 API 限流/超时:**等 5s 重试 3 次**,仍失败则跳过并在日志标注
- 某个信源 404:在 sources.jsonl 标 `"dead_link": true`,不删除(审计用)
- 关键数据查不到:**不要编造**,在正文写 "该数据暂未找到公开来源(截至 2026-04)"
---
## 八、硬规则总结
1. ✅ 每 section 至少 4 轮检索
2. ✅ 中英双语必查
3. ✅ PubMed 用 MeSH Term
4. ✅ 反方关键词必查
5. ✅ Tier 4 结果只做发现,不做佐证
6. ✅ 所有信源写入 sources.jsonl 并评分
7. ✅ 文献检索必须优先 `scripts/search.py --route scholar`
8. ✅ 专利检索必须优先 `scripts/search.py --route patents`
9. ❌ 不得引用 Wikipedia 做结论
10. ❌ 不得编造数据、URL、DOI
11. ❌ 不得使用黑名单信源
@@ -0,0 +1,188 @@
---
name: source-quality
description: 信源质量评分系统(0-10 分制)与黑名单机制。规定每个信源入库前的评估维度、硬性淘汰规则、利益冲突检测。所有收集信源的 agent 都必须用此技能给每条信源打分后写入 sources.jsonl。
---
# 信源质量评分(0-10 分制)
## 一、评分维度(满分 10 分)
| 维度 | 满分 | 判断标准 |
|---|---|---|
| 权威性 | 3 | 期刊 IF、机构排名 |
| 时效性 | 2 | 发表时间 vs 主题 |
| 一手性 | 2 | 一手数据 > 综述 > 二次解读 |
| 可验证性 | 2 | 有 DOI/URL/原始数据 |
| 无利益冲突 | 1 | 厂商自发降权 |
### 维度 1:权威性(0-3 分)
| 分值 | 情形 |
|---|---|
| 3.0 | IF ≥ 30NEJM/Lancet/Nature/Science/Cell/JAMA)、FDA/EMA/NMPA 官方、SEC 披露 |
| 2.5 | IF 10-30NatMed/NatBiotech/BMJ/AnnOncol 等)、顶级咨询(MKS/BCG/Deloitte |
| 2.0 | IF 5-10JCO/CircRes/AJRCCM)、IQVIA/EvaluatePharma、系统综述 |
| 1.5 | IF 3-5、券商研报、行业协会白皮书 |
| 1.0 | IF 1-3、专业媒体(BioSpace/Endpoints News |
| 0.5 | 预印本(bioRxiv/medRxiv)、会议摘要 |
| 0 | 自媒体、百家号、未署名博客 |
### 维度 2:时效性(0-2 分)
| 主题类型 | 满分年限 | 每老 1 年扣分 |
|---|---|---|
| 市场 / 监管 / 临床 | 3 年内 | -0.5 |
| 作用机制 / 基础研究 | 10 年内 | -0.2 |
| 政策法规 | **以最新版本为准** | 过时版本 0 分 |
| 历史追溯(有意为之) | 不限 | 不扣 |
### 维度 3:一手性(0-2 分)
| 分值 | 情形 |
|---|---|
| 2.0 | 一手数据(原始 RCT 论文、监管公告、年报原文、专利原文) |
| 1.5 | 系统综述 / Meta 分析 |
| 1.0 | 叙述性综述 / Review |
| 0.5 | 二次解读(新闻报道、券商改写) |
| 0 | 三次传播以上("据报道"/"业内人士") |
### 维度 4:可验证性(0-2 分)
| 分值 | 情形 |
|---|---|
| 2.0 | 有 DOI + 原始数据可下载(如 ClinicalTrials 的 CSR 附件) |
| 1.5 | 有 DOI 或稳定 URL,全文可访问 |
| 1.0 | URL 稳定但需付费墙 |
| 0.5 | 仅有 URL,无唯一标识符 |
| 0 | URL 失效 / 404 / 无法验证 |
### 维度 5:利益冲突(0-1 分)
| 分值 | 情形 |
|---|---|
| 1.0 | 独立研究(学术机构、政府)、无资助声明冲突 |
| 0.5 | 有 industry funding 但已声明且方法独立 |
| 0 | 厂商自发报告 / 直接商业软文 |
| **-1**(惩罚) | 声明冲突但方法可疑、或对比实验明显偏向资助方 |
---
## 二、综合评分硬规则
| 评分 | 可用性 |
|---|---|
| 8.0+ | 可作为核心论据,单独支撑结论 |
| 6.0-7.9 | 可用,但结论需 ≥2 个独立信源 |
| 4.0-5.9 | 仅作为参考,**不得作为唯一支撑** |
| < 4.0 | **禁止**用于结论佐证,只能入发现库 |
---
## 三、黑名单(直接拒绝入库)
以下信源**无论评分多少都禁用**
### 1. 明确劣质信源
- 百家号(baijiahao.baidu.com
- 头条号(toutiao.com 非原创栏目)
- 知乎回答(除非作者本人为业内专家且有实名背书)
- 小红书、抖音笔记
- 未署名作者的 wordpress / medium 博客
### 2. 被撤稿论文
- 查询 Retraction Watch 数据库(https://retractionwatch.com/
- Crossref API 检查论文状态:`https://api.crossref.org/works/<DOI>`
### 3. 明显软文/PR 稿
识别特征(命中任意 2 条即拒):
- 标题含 "重磅发布" "首创" "引领" 等夸张词
- 通篇无具体数据,只有 CEO/专家口头引述
- 发布渠道是企业官网的"新闻中心"且无交叉第三方验证
- 仅讲优势不讲局限
### 4. 时效过期
- 综述 > 5 年(机制研究可放宽)
- 政策/监管 > 1 年(以最新版本为准)
- 市场数据 > 2 年
### 5. 维基百科
- **仅可作术语理解入口**
- 结论永不引用
- 如从 Wiki 发现了参考文献,**回溯到原始来源**再引用
---
## 四、利益冲突检测要点
### 常见利益冲突场景
- 药企赞助的 RCT 对自家产品评价极高 → 查对比剂、盲法、样本量
- 咨询公司报告引用自家客户数据 → 查 acknowledgment 段
- 行业协会报告涉及会员企业 → 查资助方名单
- 券商研报 + 该券商是相关公司的保荐人 → 查 IPO/承销记录
### 操作方法
每条信源入库前检查:
1. 作者/机构是否与被评估的公司/产品有商业关联?
2. 资助声明(funding statement)里提到什么?
3. 利益披露(disclosure)是否完整?
**发现强利益冲突**:评分 ≤ 3(等同废弃);写入 `sources.jsonl``"conflict_of_interest": "..."` 字段。
---
## 五、评分执行流程(伪代码)
```
for each candidate_source in search_results:
# 1. 黑名单快筛
if is_blacklisted(candidate_source):
log("BLACKLIST: " + source.url); continue
# 2. 撤稿检查
if has_doi(source) and is_retracted(source.doi):
log("RETRACTED: " + source.doi); continue
# 3. 评分
score = 0
score += authority_score(source) # 0-3
score += recency_score(source, topic) # 0-2
score += primacy_score(source) # 0-2
score += verifiability_score(source) # 0-2
score += coi_score(source) # 0-1 or -1
# 4. Tier 加权
if source.tier == 1: score *= 1.2
# 5. 入库
if score >= 4.0:
append_to_sources_jsonl(source, score)
else:
log("LOW SCORE (" + score + "): " + source.url)
```
---
## 六、输出字段(写入 sources.jsonl
```jsonl
{
"id": "src_042",
"score": 8.6,
"tier": 1,
"authority": 3.0,
"recency": 2.0,
"primacy": 2.0,
"verifiability": 2.0,
"coi": 1.0,
"conflict_of_interest": null,
"blacklist_checked": true,
"retraction_checked": true,
"notes": "NEJM 2025 原文,RCT 独立研究"
}
```
---
## 七、审计留痕
所有被**拒绝**的信源,也要写入 `projects/<slug>/phase2/rejected-sources.jsonl`(注明原因)。这是事后复盘的关键,不要静默丢弃。
@@ -0,0 +1,67 @@
# Fonts 目录
## 说明
本目录存放 Deep Research 系统生成 PDF 报告所需的中文字体。
**所有字体文件均通过 `.gitignore` 排除**,不会进入 git 版本库,以避免仓库体积膨胀(~140MB)。
## 快速开始
首次使用时,运行:
```bash
bash .opencode/templates/fonts/download-fonts.sh
```
脚本会自动从官方 GitHub 下载以下字体:
| 文件 | 字体名 | 用途 |
|---|---|---|
| `SourceHanSerifSC-Regular.otf` | 思源宋体 Regular | 正文 |
| `SourceHanSerifSC-Bold.otf` | 思源宋体 Bold | 正文粗体/术语 |
| `SourceHanSansSC-Light.otf` | 思源黑体 Light | 页眉页脚 |
| `SourceHanSansSC-Medium.otf` | 思源黑体 Medium | 三级标题、图表 |
| `SourceHanSansSC-Bold.otf` | 思源黑体 Bold | 一二级标题 |
| `SourceHanSansSC-Heavy.otf` | 思源黑体 Heavy | 封面大标题 |
| `LXGWWenKai-Regular.ttf` | 霞鹜文楷 Regular | 摘要、引文、批注 |
## 许可证
全部字体为 **SIL Open Font License 1.1**,可自由商用、嵌入 PDF 分发。
- 思源宋体 / 思源黑体:© Adobe Systems Incorporated + GoogleSIL OFL 1.1
- 霞鹜文楷:© LXGW(基于台北黑体和 Klee One 修改),SIL OFL 1.1
## 手动下载(脚本失败时的备用方案)
如果 `download-fonts.sh` 因网络问题失败,请手动从官方 Release 下载并放入本目录:
- **思源宋体**https://github.com/adobe-fonts/source-han-serif/releases
-`SubsetOTF/CN/` 路径下的 `SourceHanSerifCN-Regular.otf``SourceHanSerifCN-Bold.otf`
- 放入本目录并重命名为 `SourceHanSerifSC-Regular.otf``SourceHanSerifSC-Bold.otf`
- **思源黑体**https://github.com/adobe-fonts/source-han-sans/releases
-`SubsetOTF/CN/` 路径下的 Light / Medium / Bold / Heavy 四个字重
- 放入本目录并重命名(CN → SC)
- **霞鹜文楷**https://github.com/lxgw/LxgwWenKai/releases
- 取最新版 `LXGWWenKai-Regular.ttf` 放入本目录(无需改名)
## 常见问题
### Q: 下载速度慢 / 失败
A: 国内网络访问 GitHub 可能不稳定。`download-fonts.sh` 会自动尝试镜像。仍失败可手动从国内字体镜像下载(注意认证版本号一致)。
### Q: 为什么不用系统自带的苹方/微软雅黑?
A: 这两个字体许可**禁止嵌入 PDF 分发**。用思源系列(SIL OFL)可无限制嵌入,报告传给客户/团队不会有许可问题。
### Q: 字体文件可以入 git 吗?
A: 不推荐。140MB 会严重拖慢 git 操作。目前策略是 `.gitignore` + `download-fonts.sh` 按需下载。
### Q: 我已经有字体文件了,在别的路径
A: 有两种选择:
1. 直接 `cp / ln -s` 到本目录
2. 调用 `report-template.py` 时用 `--fonts-dir /path/to/your/fonts`
### Q: 字体版本会影响渲染吗?
A: 思源字体 v2.x 之后字形基本稳定。霞鹜文楷不同版本字形有微调,建议锁定到 v1.330 或更高。
@@ -0,0 +1,142 @@
#!/usr/bin/env bash
# 字体下载脚本:思源宋体 + 思源黑体 + 霞鹜文楷
# 用法:bash .opencode/templates/fonts/download-fonts.sh
# 许可:全部 SIL OFL,可自由商用、嵌入 PDF 分发
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
FONTS_DIR="$SCRIPT_DIR"
echo "====================================="
echo "Deep Research 字体下载"
echo "目标目录:$FONTS_DIR"
echo "====================================="
# 检测下载工具
if command -v curl >/dev/null 2>&1; then
DOWNLOADER="curl -fL --retry 3 --retry-delay 5 -o"
elif command -v wget >/dev/null 2>&1; then
DOWNLOADER="wget -O"
else
echo "❌ 需要 curl 或 wget,请先安装"
exit 1
fi
# 字体清单:文件名 | 下载 URL
# 思源字体走 adobe-fonts GitHub Release 的 "Language Specific OTFs Simplified Chinese" 包
# 霞鹜文楷走 lxgw/LxgwWenKai Release
declare -a FONTS=(
"SourceHanSerifSC-Regular.otf|https://github.com/adobe-fonts/source-han-serif/raw/release/SubsetOTF/CN/SourceHanSerifCN-Regular.otf"
"SourceHanSerifSC-Bold.otf|https://github.com/adobe-fonts/source-han-serif/raw/release/SubsetOTF/CN/SourceHanSerifCN-Bold.otf"
"SourceHanSansSC-Light.otf|https://github.com/adobe-fonts/source-han-sans/raw/release/SubsetOTF/CN/SourceHanSansCN-Light.otf"
"SourceHanSansSC-Medium.otf|https://github.com/adobe-fonts/source-han-sans/raw/release/SubsetOTF/CN/SourceHanSansCN-Medium.otf"
"SourceHanSansSC-Bold.otf|https://github.com/adobe-fonts/source-han-sans/raw/release/SubsetOTF/CN/SourceHanSansCN-Bold.otf"
"SourceHanSansSC-Heavy.otf|https://github.com/adobe-fonts/source-han-sans/raw/release/SubsetOTF/CN/SourceHanSansCN-Heavy.otf"
"LXGWWenKai-Regular.ttf|https://github.com/lxgw/LxgwWenKai/releases/download/v1.330/LXGWWenKai-Regular.ttf"
)
# 备用镜像(主源失败时用)
declare -a MIRRORS=(
"SourceHanSerifSC-Regular.otf|https://raw.githubusercontent.com/adobe-fonts/source-han-serif/release/SubsetOTF/CN/SourceHanSerifCN-Regular.otf"
"SourceHanSerifSC-Bold.otf|https://raw.githubusercontent.com/adobe-fonts/source-han-serif/release/SubsetOTF/CN/SourceHanSerifCN-Bold.otf"
"SourceHanSansSC-Light.otf|https://raw.githubusercontent.com/adobe-fonts/source-han-sans/release/SubsetOTF/CN/SourceHanSansCN-Light.otf"
"SourceHanSansSC-Medium.otf|https://raw.githubusercontent.com/adobe-fonts/source-han-sans/release/SubsetOTF/CN/SourceHanSansCN-Medium.otf"
"SourceHanSansSC-Bold.otf|https://raw.githubusercontent.com/adobe-fonts/source-han-sans/release/SubsetOTF/CN/SourceHanSansCN-Bold.otf"
"SourceHanSansSC-Heavy.otf|https://raw.githubusercontent.com/adobe-fonts/source-han-sans/release/SubsetOTF/CN/SourceHanSansCN-Heavy.otf"
"LXGWWenKai-Regular.ttf|https://ghproxy.com/https://github.com/lxgw/LxgwWenKai/releases/download/v1.330/LXGWWenKai-Regular.ttf"
)
download_font() {
local filename="$1"
local url="$2"
local target="$FONTS_DIR/$filename"
if [[ -f "$target" ]]; then
local size
size=$(stat -f%z "$target" 2>/dev/null || stat -c%s "$target" 2>/dev/null || echo 0)
if [[ $size -gt 100000 ]]; then
echo " ✓ 已存在($size bytes),跳过:$filename"
return 0
else
echo " ⚠ 文件过小($size bytes),重新下载:$filename"
rm -f "$target"
fi
fi
echo " ↓ 下载 $filename ..."
if $DOWNLOADER "$target" "$url" 2>/dev/null; then
local size
size=$(stat -f%z "$target" 2>/dev/null || stat -c%s "$target" 2>/dev/null || echo 0)
if [[ $size -gt 100000 ]]; then
echo " ✓ 完成($size bytes"
return 0
else
echo " ⚠ 下载的文件过小,可能失败"
rm -f "$target"
return 1
fi
else
echo " ✗ 下载失败"
rm -f "$target"
return 1
fi
}
get_mirror_url() {
local filename="$1"
for entry in "${MIRRORS[@]}"; do
IFS='|' read -r fn url <<< "$entry"
if [[ "$fn" == "$filename" ]]; then
echo "$url"
return 0
fi
done
return 1
}
echo ""
echo "开始下载..."
echo ""
FAILED=()
for entry in "${FONTS[@]}"; do
IFS='|' read -r filename url <<< "$entry"
if ! download_font "$filename" "$url"; then
# 主源失败,试镜像
mirror_url=$(get_mirror_url "$filename" || true)
if [[ -n "$mirror_url" ]]; then
echo " ↻ 尝试镜像..."
if download_font "$filename" "$mirror_url"; then
continue
fi
fi
FAILED+=("$filename")
fi
done
echo ""
echo "====================================="
if [[ ${#FAILED[@]} -eq 0 ]]; then
echo "✅ 全部字体下载成功!"
echo ""
echo "字体文件清单:"
ls -lh "$FONTS_DIR" | grep -E '\.(otf|ttf)$' || true
echo ""
echo "许可证:全部 SIL OFL,可自由商用、嵌入 PDF 分发。"
exit 0
else
echo "❌ 以下字体下载失败:"
for f in "${FAILED[@]}"; do
echo " - $f"
done
echo ""
echo "请手动下载,并放入 $FONTS_DIR/"
echo ""
echo "手动下载链接:"
echo " 思源宋体:https://github.com/adobe-fonts/source-han-serif/releases"
echo " 思源黑体:https://github.com/adobe-fonts/source-han-sans/releases"
echo " 霞鹜文楷:https://github.com/lxgw/LxgwWenKai/releases"
exit 1
fi
File diff suppressed because it is too large Load Diff