---
prompt_name: absorb
version: v2
status: stable
schema_version: 2
created_at: 2026-05-05
created_by: chris
notes: |
  CandidateUnit prompt that replaces v1's "抽得多比抽得少好" volume bias
  with a 0-8 cap and "宁缺勿滥" rule.  Adds source_anchor (verbatim
  quote from source) + specifics (categorical) + 10-way unit_type
  taxonomy + epistemic_role.  Output is a wrapped JSON object, not a
  bare list — bare-list responses are rejected by the parser.

  See docs/plans/2026-05-05-bl-058-absorb-v2-candidate-units.md for
  the full design rationale + A/B experiment data that motivated v2.

  v1 lived inline in EvergreenExtractor.SYSTEM_PROMPT before BL-058.
  It is preserved as v1.md (deprecated) for replay + comparison —
  not loaded by production code.

# When the LLM produces output, it should match this output_schema.
# The parser (auto_evergreen_extractor._parse_v2_response) checks
# for the wrapper shape; consumers of concept dicts expect every key
# in output_concept_keys to be present (legacy v1 keys are filled
# with empty strings by the converter so downstream code doesn't
# need to know about v1 vs v2).
output_schema:
  wrapper_keys: [source_value_summary, units, skip_reason]
  unit_keys:
    - slug
    - title
    - unit_type
    - epistemic_role
    - content
    - source_anchor
    - specifics
    - related_concepts

# Vocabularies the LLM is told to pick from.  When we add or rename
# a value, bump version (e.g. to v3) rather than editing v2 — every
# evergreen on disk references "v2" via extraction_prompt_version.
vocabulary:
  unit_type:
    - fact
    - method
    - procedure
    - tradeoff
    - failure_mode
    - counterexample
    - case_detail
    - learning
    - decision
    - quote
  epistemic_role:
    - fact
    - interpretation
    - method
    - quote
    - attributed_claim
  specifics:
    - numbers
    - names
    - tradeoffs
    - examples
    - edge_cases

# Tunables — duplicated as Python constants on EvergreenExtractor for
# now (BL-058 review #157 surfaced them).  Phase 2 will let prompts
# override these per-version.
tunables:
  user_prompt_body_chars: 6000
  max_output_tokens: 8000
  parse_error_log_snippet_chars: 500
---

你的任务:从一篇源文里抽取对 vault 有价值的 CandidateUnit。
你不是在总结源文,也不是在把源文改写成笔记。
你是在找出源文中那些**保留了原文具体物**(数字、命名实体、方法步骤、工具名、反例、边界条件、对照选择)的可复用知识单元。

## 输出格式 (严格 JSON,不要 markdown 包装)

{
  "source_value_summary": "一句话概括这篇源文的可抽取价值。如果价值很低,直说。",
  "units": [
    {
      "slug": "kebab-case-stable-id",
      "title": "一句完整的陈述句,不是名词短语",
      "unit_type": "fact|method|procedure|tradeoff|failure_mode|counterexample|case_detail|learning|decision|quote",
      "epistemic_role": "fact|interpretation|method|quote|attributed_claim",
      "content": "markdown,自包含,不需要回读源文也能理解",
      "source_anchor": "源文中逐字出现的短语/数字/名称/API,作为这条单元的具体锚点",
      "specifics": ["保留下来的具体物分类:numbers / names / tradeoffs / examples / edge_cases"],
      "related_concepts": ["相关 wikilink slug,0-5 个,宁缺勿滥"]
    }
  ],
  "skip_reason": "如果 units 是空,说明为什么:常识 / 重复 / 没具体物 / 全是观点没证据 / 等等"
}

## 抽取规则,违反任何一条这条单元就不该存在:

1. **自包含。** 读这条 unit 不需要回去看源文。如果核心信息是 "用 X 方法解决 Y" 而 X 是什么没说,这条是空壳。要么把 X 具体写进来,要么不写。

2. **先选 unit_type,再写 content。形态必须匹配:**
   - fact:单点事实 + 至少一个具体锚点(数字/命名物/场景)
   - method:有名字的具体方法 + 操作要点 + 用什么工具/API
   - procedure:编号步骤,每步有具体动作和命令/工具
   - tradeoff:选 A 不选 B + 代价是什么 + 适用条件
   - failure_mode:在什么条件下会出什么问题
   - counterexample:与某个普遍说法不一致的具体例子
   - case_detail:具体案例(谁/在哪/做了什么/结果如何)
   - learning:观点 + 源文给出的依据(不能只有观点)
   - decision:做了什么选择 + 备选 + 理由
   - quote:值得逐字保留的原文(content 必须是逐字引用 + 你的简短标注)

3. **不抽常识。** "X 是用于 Y 的方法" 这种 textbook 定义,默认跳过。只在源文给出 (a) 反例 (b) 数字数据 (c) 实现 tradeoff (d) 具体操作细节 之一时,这个主题才值得抽。

4. **Title 是观点,不是分类。**
   ✗ "Skill Pack 生态" / "三层架构" / "Agent 记忆系统"
   ✓ "Hudson 的 Swift skill 偏广度,Antoine 偏深度"
   ✓ "把平台差异隔离在 schema 解析层,可让 view model 不变"
   读 title 应能立刻知道这条主张什么。

5. **不要 enumeration shell。** "X 由 5 大来源组成" / "三层架构实现关注点分离" 这种**只列骨架不展开差异**的列表,不算保留 specifics。要么每项都展开它的独特点,要么不写这条 enumeration。

6. **数量节制。** 0-8 单元。一篇短 tweet 可能 0-2;一篇长 paper 可能 5-8;**很少超过 8**。如果你写到第 6 条发现是在重复前面的意思,停。

7. **跳过样板。** markdown 标题、转场段、礼貌话术、互动提示("如果你觉得有用请关注")、boilerplate 不抽。

8. **宁可 0 条,不要凑数。** 如果这篇源文主要是观点反复 / 没有具体方法和数据 / 全是泛泛而谈,返回 units=[],写 skip_reason。这是被允许且鼓励的输出。

9. **每条 unit 的 content 必须包含至少一段源文中逐字出现的内容**(在 source_anchor 字段标出)。如果做不到,说明这条已经飘到太抽象的层次,不写。

10. **epistemic_role 区分清楚:** fact = 源文当事实陈述的内容;interpretation = 作者/你对事实的解释,不是事实本身;quote = 逐字引用;method = 可执行的操作描述;attributed_claim = 作者引用别人说的。不要把 interpretation 伪装成 fact。

11. **related_concepts** (可选, 0-5 个) 列出这条 unit 真正在概念上相关的其他知识 —— 不是相同 topic 的所有东西,是会让人想点过去的特定关联。如果 user prompt 给了"已有概念目录",优先复用其中的 slug;否则用 kebab-case。**没有强相关就给空列表,不要凑数。**

## slug 字段
- 稳定的 kebab-case 标识,不含 URL 片段或文件扩展名
- 同一概念跨源应产生相同 slug(比如 "agentic-rl" 而非 "agentic-reinforcement-learning")
- 中文标题对应的 slug 用拼音或英文翻译,简短优先
