Skip to content

生命周期与进化 — 知识的生老病死

知识不是静态快照,它有诞生、成长、衰退和消亡 — 六态状态机管理整个旅程。

问题场景

你提取了一条 "所有网络请求必须通过 NetworkManager 单例" 的 Recipe。半年后,团队重构为 async/await 原生并发,NetworkManager 已经被弃用。但 Recipe 还在,AI 继续按旧模式生成代码——更糟的是,Guard 会对新代码报出 violation,因为它没有经过早已废弃的 NetworkManager

另一种场景:Agent 在冷启动时生成了两条几乎相同的 Recipe,描述同一个设计模式但措辞略有不同。搜索时两条都被命中,用户无法确定哪条是权威版本。

还有一种场景:某条 Recipe 的 reasoning.sources 引用了三个文件,其中两个在最近的重构中被删除了。这条知识的"证据链"已经断裂,但系统不会自动发现。

这三个场景指向同一个根本问题:代码在持续进化,知识库如果不跟上,就会从资产变成负债

一个知识引擎不能只解决"如何提取知识"的问题。它必须同时解决:知识什么时候生效?如何安全地更新?什么时候过时?怎样退出?

设计决策

六态状态机

传统知识库通常只有两种状态:active(有效)和 archived(归档)。这对于人工维护的文档也许够用——人可以在切换状态时完成所有必要的判断。但对于 AI 驱动的知识引擎,二态模型无法区分两种截然不同的情况:

  • 一条知识"正在被评估中"和"已经完全可用"——消费方(搜索、Guard)应该给予不同的权重
  • 一条知识"正在被修改"和"正在衰退"——前者只是暂时不稳定,后者可能需要永久退出

Alembic 设计了六态生命周期模型:

text
pending → staging → active → evolving → decaying → deprecated

每个状态有明确的语义和消费规则:

状态语义搜索可见Guard 参与权重
pending待审核,所有新条目的初始状态
staging暂存期,高置信度条目在此观察降权
active已发布,正式知识全权重
evolving进化中,有 Evolution Proposal 附着全权重
decaying衰退观察期,可能已过时✓(降权)✓(降级为 warning)降级
deprecated已废弃

状态分组在代码中定义为常量数组,供搜索、Guard、统计等模块直接引用:

typescript
// lib/domain/knowledge/Lifecycle.ts

/** 可消费状态(Guard/Search/Delivery 可使用的状态) */
export const CONSUMABLE_STATES = [
  Lifecycle.STAGING,
  Lifecycle.ACTIVE,
  Lifecycle.EVOLVING,
];

/** 降级消费状态(Guard violation 降为 warning,Search 降权) */
export const DEGRADED_STATES = [Lifecycle.DECAYING];

/** Guard 可消费状态(含降级 decaying)*/
export const GUARD_LIFECYCLES = [
  Lifecycle.STAGING,
  Lifecycle.ACTIVE,
  Lifecycle.EVOLVING,
  Lifecycle.DECAYING,
] as const;

注意 CONSUMABLE_STATESGUARD_LIFECYCLES 的区别:Guard 检查会遍历 GUARD_LIFECYCLES(包括 decaying),但 decaying 状态的规则产生的 violation 会被降级为 warning——提示开发者可能有问题,但不阻断工作流。这是一个刻意的设计:衰退期的知识仍然可能是有价值的,只是不够确定。

合法的状态转换定义在一张静态表中:

typescript
// lib/domain/knowledge/Lifecycle.ts
const VALID_TRANSITIONS: Record<string, string[]> = {
  [Lifecycle.PENDING]:    [Lifecycle.STAGING, Lifecycle.ACTIVE, Lifecycle.DEPRECATED],
  [Lifecycle.STAGING]:    [Lifecycle.ACTIVE, Lifecycle.PENDING],
  [Lifecycle.ACTIVE]:     [Lifecycle.EVOLVING, Lifecycle.DECAYING, Lifecycle.DEPRECATED],
  [Lifecycle.EVOLVING]:   [Lifecycle.STAGING, Lifecycle.ACTIVE, Lifecycle.DECAYING],
  [Lifecycle.DECAYING]:   [Lifecycle.ACTIVE, Lifecycle.DEPRECATED],
  [Lifecycle.DEPRECATED]: [Lifecycle.PENDING],
};

export function isValidTransition(from: string, to: string): boolean {
  const normalFrom = normalizeLifecycle(from);
  const normalTo = normalizeLifecycle(to);
  const allowed = VALID_TRANSITIONS[normalFrom];
  return Array.isArray(allowed) && allowed.includes(normalTo);
}

几个值得注意的转换路径:

  • deprecated → pending:已废弃的知识可以被"复活"——回到待审核状态重新走一遍晋升流程。这不是随意设计的,而是因为在实践中确实存在"某个被废弃的库重新被采用"的情况。
  • evolving → staging:进化后的知识不直接回到 active,而是进入 staging 重新观察。即使是对已有知识的修改,也要经过一个 grace period——这是 SOUL 原则中"永不覆盖"精神的体现。
  • staging → pending:暂存期的知识可以打回待审核。这发生在用户通过 Dashboard 发现某条自动晋升的候选存在问题时。

六态生命周期状态机

进化而非直接修改

知识库最危险的操作不是"删除一条知识"——而是"悄悄修改一条知识的内容"。

假设 Agent 在一次代码分析中"发现"某条 Recipe 的 coreCode 需要更新。如果系统允许 Agent 直接修改,会产生两个风险:

  1. AI 幻觉风险:Agent 可能产生错误的判断,用一段有问题的代码替换了正确的代码。由于修改是原地发生的,旧内容不可恢复。
  2. 静默漂移:知识的内容在没有任何人知道的情况下发生了变化。下次 Guard 根据修改后的规则检查代码时,开发者完全不知道规则已经变了。

Alembic 的安全设计是:Agent 永远不能直接修改已有知识,只能提出进化提案(Evolution Proposal)

进化提案是一种"附加"机制——它不修改原有知识的任何字段,而是创建一条独立的提案记录,关联到目标 Recipe。提案有六种类型:

类型语义风险等级
enhance增强现有知识(添加示例、扩展适用场景)
merge合并两条语义相似的知识
correction修正事实性错误(代码片段过时等)
supersede新知识完全取代旧知识
deprecate标记为过时(来自衰退检测)
contradiction检测到与其他知识的硬矛盾

风险等级决定了提案的执行路径。低风险提案(enhancemergecorrection)经过一个观察期后可以自动执行——如果在观察期内没有出现负面信号(如误报率上升、使用量下降)。高风险提案(contradiction永远不会自动执行,必须由开发者在 Dashboard 上明确确认。

typescript
// lib/service/evolution/ProposalExecutor.ts
const HIGH_RISK_TYPES = new Set<ProposalType>([
  'contradiction',
  'reorganize',
]);

观察期的长度也因类型而异:

提案类型观察窗口
correction24 小时
enhance48 小时
merge / supersede72 小时
deprecate / contradiction / reorganize7 天

这些时间窗口不是拍脑门的数字。enhance 类型的风险最低——它只是往已有知识上添加内容,24 小时足以观察有没有新增误报。merge 涉及两条知识的合并,需要更长时间观察合并后的搜索命中情况。deprecate 则需要 7 天,因为一条知识可能只在每周一次的发版流程中被使用——7 天覆盖一个完整的开发周期。

为什么不让 Agent 直接修改知识?根本原因是 SOUL 原则中的两条硬约束:永不删除(所有变更都是新增操作,旧版本保留在审计日志中)和无 AI 不伪装(AI 的判断必须标记为 AI 产出,不能假装是人工确认的)。进化提案机制天然满足这两条约束:旧内容不变、提案来源明确(source: 'ide-agent' | 'metabolism' | 'decay-scan')。

进化提案机制

架构与数据流

状态转换触发条件

六态状态机的每一次转换都有明确的触发条件和前置检查。RecipeLifecycleSupervisor 是状态转换的统一入口——所有状态变更都必须通过它,绕过它直接修改数据库中的 lifecycle 字段是被禁止的。

pending → staging

新创建的知识条目初始状态为 pending。当 ConfidenceRouter 判断其置信度满足阈值时,自动推进到 staging。置信度的阈值因 kind 而异:rule 类型要求较高的置信度(因为规则会影响 Guard 检查),fact 类型要求较低(事实性描述的风险小)。

staging → active

两条路径:

  • 路径 A(自动):暂存期(7 天)满且无负面反馈(无用户打回、无验证错误)。RecipeLifecycleSupervisor.checkTimeouts() 定期检查暂存时间。
  • 路径 B(手动):用户在 Dashboard 上审阅后主动批准。

active → evolving

当系统或 Agent 创建了一条关联到该 Recipe 的 Evolution Proposal,目标 Recipe 自动进入 evolving 状态。进入 evolving 不影响消费——Recipe 仍然以全权重参与搜索和 Guard,只是系统记录了一个 evolvingStartedAt 时间戳用于超时监控。

evolving → staging / active

提案被接受(内容更新)→ 进入 staging 重新观察。提案被拒绝 → 回到 active。如果 evolving 状态超过 7 天无结论,RecipeLifecycleSupervisor 自动回退到 active——这是一个安全网,防止提案被遗忘导致知识长期卡在中间态。

typescript
// lib/service/evolution/RecipeLifecycleSupervisor.ts
const TIMEOUT_MS = {
  evolving: 7 * 24 * 60 * 60 * 1000,   // 7 天
  decaying: 30 * 24 * 60 * 60 * 1000,  // 30 天
  staging:  7 * 24 * 60 * 60 * 1000,   // 7 天(安全兜底,正常由 StagingManager 处理)
  pending:  30 * 24 * 60 * 60 * 1000,  // 30 天
};

const TIMEOUT_TARGET = {
  evolving: 'active',     // 回退到 active(内容不变)
  decaying: 'deprecated', // 长期衰退 → 废弃
  pending:  'deprecated', // 30 天未审核 → 废弃
};

active → decaying

这是最关键的自动转换——它不依赖定时任务,而是由 DecayDetector 的信号驱动。当 DecayDetector 评估一条 active 状态的 Recipe 分数低于 60 分时,触发 active → decaying 转换。衰退评分的计算在下文详述。

decaying → active(自动恢复)

如果处于 decaying 状态的 Recipe 重新被搜索命中或被 Guard 使用(searchHitguardHit 信号),系统判断它仍然有价值,自动恢复到 active。这个自动恢复机制是信号驱动设计的典型体现——不需要人工干预,使用行为本身就是最好的信号。

decaying → deprecated

30 天的衰退观察期内没有恢复信号,RecipeLifecycleSupervisor.checkTimeouts() 自动将其推进到 deprecated。特殊情况:如果 DecayDetector 给出 dead 级别(0-19 分),跳过 30 天等待直接废弃。

每一次状态转换都会被记录为不可变的 TransitionEvent

typescript
interface TransitionEvent {
  recipeId: string;
  from: string;
  to: string;
  reason: string;
  triggeredBy: string;   // 'system' | 'user' | 'decay-scan' | 'proposal-executor'
  timestamp: number;
}

这些事件构成了一条知识的完整"传记"——你可以在 Dashboard 中回溯任何一条 Recipe 的生命历程:它何时被创建、何时进入观察、何时正式发布、是否经历过进化提案、是否衰退过又恢复。

SourceRef 可信链

上一章提到,KnowledgeEntry 的 reasoning.sources 字段保存了知识的来源文件路径——它是知识的"证据链"。但文件路径是脆弱的:文件会被重命名、移动、删除。如果证据链断裂了,知识的可信度就应该下降。

SourceRefReconciler 负责维护这个可信链的健康状态。它管理一张独立的 recipe_source_refs 表,每条记录有三种状态:

状态含义
active文件存在,路径有效
renamed文件被 git rename,新路径已检测到
stale文件不存在,无法自动修复

核心流程分三个阶段:

阶段 1:reconcile() — 存在性验证

遍历所有 Recipe 的 reasoning.sources,检查文件是否仍然存在于项目目录中。验证结果有 24 小时 TTL 缓存——同一天内不会重复检查同一个路径。如果发现 stale 引用,发射 quality 信号,信号权值与 stale 比例成正比。

阶段 2:repairRenames() — git rename 追踪

对于标记为 stale 的引用,尝试通过 git log --diff-filter=R 追踪文件的重命名历史。如果发现旧路径被 rename 到了新路径,将引用状态更新为 renamed 并记录 new_path。这个步骤使用 execFile() 的数组参数形式执行 git 命令,而非模板字符串拼接——防止路径中的特殊字符被用于命令注入。

阶段 3:applyRepairs() — 写回修复

renamed 状态的引用自动修复回 Recipe 的 .md 文件中。定位 reasoning.sources 部分,将旧路径替换为新路径,然后将引用状态更新为 active

这三个阶段不是在一次调用中串行执行的。reconcile() 可能在每次 Guard 运行后触发,repairRenames() 在每次项目扫描时运行,applyRepairs() 需要在用户确认后执行。它们通过信号机制松散耦合。

SourceRef 的健康度直接影响衰退评分。DecayDetector 在计算 authority 维度时会查询 stale ratio:

text
authority = baseAuthority × (1 - staleRatio × 0.3)

当所有 SourceRef 都失活时(staleRatio = 1.0),authority 维度被乘以 0.7 的惩罚因子。这个惩罚不会让一条高质量的知识立刻衰退,但会在边界情况下把它推入 decaying 状态——给用户一个机会去审视它是否还有价值。

核心实现

RecipeProductionGateway — 统一生产管线

所有 Recipe 创建——不论来自 Agent Tool、MCP 外部调用、IDE Agent 还是批量导入——都通过 RecipeProductionGateway 的统一管线。它保证无论入口在哪,前置校验的顺序和严格度完全一致。

管线分为 7 个步骤,每个步骤有独立的中止和回退逻辑:

yaml
Step 1: Schema Validation (UnifiedValidator)
    ↓ 不通过 → rejected[]
Step 2: Similarity Check (可选跳过)
    ↓ 相似度 ≥ 0.7 → duplicates[]
Step 3: Consolidation Scan (可选跳过)
    ↓ 建议 merge/reorganize → merged[] / blocked[]
Step 4: KnowledgeService.create()
    ↓ ConfidenceRouter → staging 或 pending
Step 5: Quality Scoring (best effort)
    ↓ 不阻塞创建流程
Step 6: Supersede Proposal (如果指定被替代的旧 Recipe)
Step 7: Audit 日志
typescript
// lib/service/knowledge/RecipeProductionGateway.ts
type GatewaySource = 'agent-tool' | 'mcp-external' | 'ide-agent' | 'batch-import';

interface CreateRecipeResult {
  created: CreatedRecipeInfo[];    // ✅ 成功创建
  rejected: RejectedRecipeInfo[];  // ❌ 校验不通过
  merged: MergedRecipeInfo[];      // ⚠️ ConsolidationAdvisor 建议合并,已建提案
  blocked: BlockedRecipeInfo[];    // 🚫 被融合建议阻止
  duplicates: SimilarRecipeInfo[]; // 📍 相似度过高
  supersedeProposal: { proposalId: string } | null;
}

Step 1 — Schema Validation

UnifiedValidator 检查必填字段(title、trigger、description 等)的合法性,同时在批量提交中追踪已提交的标题和指纹集合(existingTitles / existingFingerprints),防止批量内重复。

Step 2 — Similarity Check

对每个候选调用 findSimilarRecipes(),阈值 0.5 召回候选、0.7 判定重复。重复项记入 duplicates[] 但不阻塞(信息性警告)。batch-import 来源可通过 skipSimilarityCheck 跳过此步骤。

Step 3 — Consolidation Scan

ConsolidationAdvisor.analyzeBatch() 对通过相似度检查的候选做融合分析——如果发现某个候选与已有 Recipe 高度重叠,建议 merge、reorganize 或 supersede。建议被转换为 Evolution Proposal 写入 evolution_proposals 表,候选本身不创建。ConsolidationAdvisor 失败时静默降级——直接进入 Step 4。

Step 4 — Create

通过 KnowledgeService.create() 写入数据库,ConfidenceRouter 根据置信度决定进入 staging 还是 pending

Step 5 — Quality Scoring

创建后立即调用 updateQuality() 执行 5 维度质量评分。这是 best effort——评分失败不回滚创建。

Step 6 — Supersede Proposal

如果调用方指定了 options.supersedes(被替代的旧 Recipe ID),在新 Recipe 创建成功后自动创建 supersede 类型的进化提案,关联新旧 Recipe。

这个设计的核心价值是入口统一——Agent 通过 submit_knowledge 工具调用和用户通过 MCP asd_submit_knowledge 走完全相同的校验管线。没有"捷径"可以绕过 Schema Validation 或 Similarity Check 直接创建 Recipe。

RecipeLifecycleSupervisor

RecipeLifecycleSupervisor 是所有状态转换的守门人。它不只是检查 VALID_TRANSITIONS 表——在每次转换的进入和退出时执行副作用:

typescript
// lib/service/evolution/RecipeLifecycleSupervisor.ts(简化)
async transition(request: TransitionRequest): Promise<TransitionResult> {
  const { recipeId, from, to, reason, triggeredBy } = request;

  // 1. 守卫检查:合法性
  if (!isValidTransition(from, to)) {
    return { success: false, error: `Invalid transition: ${from} → ${to}` };
  }

  // 2. Exit Action — 离开旧状态
  this.#recordExitTimestamp(recipeId, from);

  // 3. Entry Action — 进入新状态
  this.#recordEntryTimestamp(recipeId, to);

  // 4. 持久化 lifecycle 字段
  await this.#repository.updateLifecycle(recipeId, to);

  // 5. 记录不可变事件
  this.#eventLog.push({ recipeId, from, to, reason, triggeredBy, timestamp: Date.now() });

  return { success: true };
}

Entry/Exit Action 记录的时间戳被后续模块消费:例如 stagingEnteredAt 用于计算暂存期是否满 7 天,evolvingStartedAt 用于检测进化提案是否超时。

checkTimeouts() 是 Supervisor 的另一个核心方法。它扫描所有处于中间态(evolvingdecayingpendingstaging)的 Recipe,检查是否超过预设时间:

typescript
async checkTimeouts(): Promise<TimeoutCheckResult> {
  const now = Date.now();
  const results = [];

  for (const [state, timeoutMs] of Object.entries(TIMEOUT_MS)) {
    const stuck = await this.#repository.findByLifecycleOlderThan(state, now - timeoutMs);
    for (const recipe of stuck) {
      const target = TIMEOUT_TARGET[state];
      await this.transition({
        recipeId: recipe.id,
        from: state,
        to: target,
        reason: `Timeout: stuck in ${state} for >${timeoutMs / DAY_MS}d`,
        triggeredBy: 'system',
      });
      results.push({ recipeId: recipe.id, from: state, to: target });
    }
  }

  return { transitioned: results };
}

这个方法不是 cron job 调用的——它在每次知识库操作(搜索、Guard 检查、Dashboard 访问)的伴随流程中被触发。这符合 SOUL 原则"信号驱动 > 时间驱动"的设计哲学:不依赖外部调度器,而是利用用户的使用行为作为"心跳"。

DecayDetector:四维衰退评分

DecayDetector 四维衰退评分

DecayDetector 是衰退信号的核心引擎。它不是简单地检查"最后使用时间是否超过 N 天"——而是用四个维度综合评估一条知识的健康度:

yaml
decayScore = freshness × 0.3 + usage × 0.3 + quality × 0.2 + authority × 0.2

freshness(新鲜度 · 0.3 权重)

基于最后一次被使用的时间距今。365 天无使用得 0 分,当天使用过得满分,中间线性插值(1 - daysSinceHit / 365)。这里的"使用"包括两种信号:guardHit(Guard 检查时命中该 Recipe 的规则)和 searchHit(搜索结果中返回了该 Recipe)。

usage(使用率 · 0.3 权重)

统计最近 90 天的命中次数(hitsLast90d),归一化为 0-1 分数:min(1, hitsLast90d / 50)——即 50 次以上命中得满分,0 次得 0 分。注意这里只看近期窗口而非全生命期累计:如果一条知识在最近 90 天完全没有被使用,usage 维度得分为零。这是一个刻意的设计选择——衰退检测关注的是"现在还有没有价值",而非"历史上曾经有过多少价值"。

quality(质量 · 0.2 权重)

来自 QualityScorer v2 的综合评分。v2 采用五维度加权模型:结构完整性(completeness, 0.25)、内容深度(contentDepth, 0.30)、交付就绪度(deliveryReady, 0.20)、可操作性(actionability, 0.15)、溯源可信度(provenance, 0.10)。低质量的知识更容易被判定为衰退——这是一个有意义的设计选择:如果一条知识本身质量就不高,又长期无人使用,它几乎可以确定是过时的。

authority(权威性 · 0.2 权重)

基于 SourceRef 健康度。当引用文件大量失活时,authority 下降,推动衰退评分恶化。这是 SourceRefReconciler 和 DecayDetector 的连接点。

评分结果映射为五个级别:

分数级别系统行为
80-100healthy无动作
60-79watchDashboard 显示黄色警告
40-59decaying触发 active → decaying 转换
20-39severe缩短 Grace Period 至 15 天
0-19dead跳过确认,直接 deprecated

除了综合评分,DecayDetector 还检测六种具体的衰退策略:

typescript
// 六种衰退策略(任一命中即产生衰退信号)
type DecayStrategy =
  | 'no_recent_usage'     // 90+ 天无使用
  | 'high_false_positive' // 误报率 >40%(至少 10 次触发)
  | 'symbol_drift'        // ReverseGuard 检测到 API 符号已删除
  | 'source_ref_stale'    // SourceRef 引用路径失活
  | 'superseded'          // 存在 deprecated_by 关系指向更新版本
  | 'contradiction';      // ContradictionDetector 发现硬矛盾

symbol_drift 策略值得特别说明。当 ReverseGuard 执行反向验证时,它会检查 Recipe 的 coreCode 中引用的 API 符号是否仍然存在于项目代码中。如果 coreCode 中调用了 NetworkManager.shared.request(),但项目中 NetworkManager 类已经被彻底删除,symbol_drift 会被触发。这比简单的"无人使用"更精准——它直接检测知识内容的语义有效性。

KnowledgeMetabolism:治理编排

KnowledgeMetabolism 是知识治理的编排层——它不做具体的检测工作,而是协调 DecayDetectorContradictionDetectorRedundancyAnalyzer 三个引擎的执行顺序,收集结果,生成进化提案。

一个完整的治理周期:

typescript
// lib/service/evolution/KnowledgeMetabolism.ts(简化)
async runFullCycle(): Promise<MetabolismResult> {
  // 1. 衰退扫描 — 哪些知识在变旧?
  const decayResults = await this.#decayDetector.scanAll();

  // 2. 矛盾检测 — 哪些知识互相冲突?
  const contradictions = await this.#contradictionDetector.detectAll();

  // 3. 冗余分析 — 哪些知识在说同一件事?
  const redundancies = await this.#redundancyAnalyzer.analyzeAll();

  // 4. 生成提案
  const proposals = [
    ...this.#createDecayProposals(decayResults),
    ...this.#createContradictionProposals(contradictions),
    ...this.#createMergeProposals(redundancies),
  ];

  // 5. 持久化到 evolution_proposals 表
  await this.#proposalRepository.insertBatch(proposals);

  // 6. 发射信号触发下游(如 Dashboard 通知)
  this.#signalBus.emit('quality', { type: 'metabolism-complete', proposals });

  return { decayResults, contradictions, redundancies, proposals };
}

runFullCycle() 不是定时执行的。它通过 SignalBus 订阅 decay | quality | anomaly 信号,30 秒防抖后执行。触发信号的来源包括:

  • Guard 检查发现高误报率 → 发射 quality 信号
  • SourceRefReconciler 发现大量 stale 引用 → 发射 quality 信号
  • 用户在 Dashboard 标记某条知识有问题 → 发射 anomaly 信号

30 秒防抖的设计是为了批量处理:如果一次项目扫描触发了 10 个 quality 信号,系统只会在最后一个信号后 30 秒执行一次 runFullCycle(),而不是执行 10 次。

ProposalExecutor:到期提案执行

提案在观察期内是"待评估"状态(observing)。ProposalExecutor 负责检查哪些提案的观察期已满,并根据观察期内收集到的信号决定是否执行。

核心判据是:提案创建后的这段时间里,被提案的 Recipe 的使用情况有没有变化?

typescript
// lib/service/evolution/ProposalExecutor.ts(简化判据)
async #evaluateProposal(proposal, currentMetrics, snapshot): Promise<Decision> {
  switch (proposal.type) {
    case 'merge':
    case 'enhance':
      // FP 率 <40% 且仍有使用 → 通过
      return currentMetrics.fpRate < 0.4 && currentMetrics.totalHits > 0
        ? 'execute' : 'reject';

    case 'supersede':
      // 新 Recipe 已 active 且使用量 ≥ 旧的 50% → 通过
      return newRecipe.lifecycle === 'active'
        && newRecipe.usage >= oldRecipe.usage * 0.5
        ? 'execute' : 'reject';

    case 'deprecate':
      // decay score 无回升 → 通过
      return currentMetrics.decayScore <= snapshot.decayScore
        ? 'execute' : 'reject';

    case 'correction':
      // 有使用信号 → 通过
      return currentMetrics.totalHits > 0 ? 'execute' : 'reject';
  }
}

执行动作因提案类型而异:

  • merge/enhance:将 Recipe 推入 evolving,应用内容补丁,然后进入 staging 重新观察
  • supersede:旧 Recipe 推入 decaying,在知识图中建立 deprecated_by 边指向新 Recipe
  • deprecate:根据衰退级别推入 decaying 或直接 deprecated
  • correction:推入 evolving,应用修正,进入 staging

如果观察期内 Recipe 的情况好转(比如被重新使用、误报率下降),提案会被自动拒绝。这就是观察期存在的意义——它给了系统一个"后悔"的窗口。

运行时行为

场景 1:新建候选的晋升之路

Agent 在项目冷启动时提取了一条关于 CookieProviding 的 Recipe,置信度 0.85。

  1. T+0:Recipe 创建,状态 pending
  2. T+0(秒级):ConfidenceRouter 评估置信度 0.85 高于阈值,自动推进到 staging
  3. T+7 天RecipeLifecycleSupervisor.checkTimeouts() 检测到暂存期满且无负面反馈 → staging → active
  4. T+7 天后:Recipe 以全权重参与搜索和 Guard 检查

场景 2:重构导致的自然衰退

团队决定弃用 NetworkManager,用原生 async/await 重写网络层。

  1. T+0NetworkManager.swift 被删除
  2. T+N(下次扫描)SourceRefReconciler.reconcile() 发现引用该文件的三条 Recipe 的 SourceRef 变为 stale
  3. T+N:发射 quality 信号(stale_ratio: 0.67
  4. T+N+30sKnowledgeMetabolism.runFullCycle() 被触发
  5. T+N+30sDecayDetector 评估三条 Recipe:authority 大幅下降 + 无近期使用 → decayScore 42 分(decaying 级别)
  6. T+N+30s:Metabolism 生成三条 deprecate 类型的提案,观察期 7 天
  7. T+N+30s:三条 Recipe 进入 decaying 状态
  8. T+N+7 天ProposalExecutor 检查——decay score 无回升,提案通过 → decaying → deprecated

场景 3:Agent 驱动的知识增强

Agent 在一次代码分析中发现某条 Recipe 的 coreCode 缺少了错误处理的示例。

  1. T+0:Agent 通过 MCP 工具创建一条 enhance 类型的进化提案
  2. T+0:目标 Recipe 进入 evolving 状态
  3. T+0:提案进入 observing 状态,观察窗口 24-48 小时
  4. T+36hProposalExecutor 检查——FP 率仍然为 0,且 Recipe 在观察期内有 3 次使用命中 → 通过
  5. T+36h:Recipe 内容被更新(新增错误处理示例),状态推入 staging
  6. T+36h+7 天:暂存期满,无负面反馈 → staging → active

场景 4:冗余知识的合并

RedundancyAnalyzer 在一次治理周期中检测到 Recipe A("使用 CookieProviding 管理 Cookie")和 Recipe B("Cookie 操作必须通过 CookieProviding")语义相似度 > 0.85。

  1. T+0KnowledgeMetabolism 生成一条 merge 提案,关联 Recipe A 和 B
  2. T+0:两条 Recipe 都进入 evolving 状态
  3. T+72hProposalExecutor 检查——两条 Recipe 都有使用记录,FP 率正常 → 通过
  4. T+72h:执行合并——保留 Recipe A 作为主体,将 B 的独特内容合入 A,B 推入 deprecated 并建立 merged_into 关系边
  5. T+72h:合并后的 Recipe A 进入 staging 重新观察

权衡与替代方案

为什么不用二态模型?

简单的 active / archived 二态模型面临三个无法回避的问题:

  1. 缺少缓冲区:新创建的知识直接进入 active,没有观察窗口让人或系统验证其质量。对于 AI 生成的知识,这是不可接受的风险。
  2. 无法区分变化类型:一条正在被修改的知识和一条正在衰退的知识,在二态模型下都是 active——但系统对它们应该有不同的处理策略。
  3. 归档不可逆:一旦标记为 archived,恢复成本很高,因为两个状态之间没有中间地带。六态模型中的 decaying 状态天然支持自动恢复。

为什么不让 Agent 直接修改?

最直接的方案确实是允许 Agent 在发现更好的模式时直接更新 Recipe 内容。但这引入了两个不对称风险:

  • 修改正确的概率 << 幻觉错误的成本:Agent 修改对了,知识库改善一点点;Agent 修改错了,可能导致后续所有基于此 Recipe 的代码检查和生成都出错。
  • 静默漂移的可追溯性:如果允许直接修改,要准确回答"这条知识为什么变成现在这样"需要完整的 diff 历史——而进化提案机制天然记录了每次变更的原因、来源和判据。

提案机制的代价是增加了中间步骤和延迟。一个 enhance 类型的改进需要等待 24-48 小时的观察期才能生效。在 Alembic 的设计判断中,知识库的准确性比更新的及时性更重要——一条过时但正确的知识,远好于一条新但错误的知识。

staging 期的价值

有人可能质疑:既然已经有了 pending(待审核),为什么还需要 staging?它们的区别是什么?

pending 是"尚未被系统信任"——搜索不可见、Guard 不使用。staging 是"系统初步信任,但给用户一个观察窗口"——搜索可见(降权)、Guard 参与(降权),用户可以在 Dashboard 上看到这些"试用版"的知识条目。

这个设计的核心价值是渐进式信任。对于一个 AI 驱动的系统,让用户参与但不要求用户参与——高置信度的知识自动走完 staging → active,低置信度的停留在 staging 等待人工审阅。这比"全自动"或"全手动"都更符合实际的工作流。

小结

知识生命周期是 Alembic 中最能体现"信号驱动"设计哲学的子系统。六态状态机不是复杂性的来源,而是复杂性的管理工具——每个状态对应一种明确的知识状态语义,每次转换都有可追溯的触发条件和审计日志。

进化提案机制将 AI 的能力(发现、建议、评估)和人类的判断(确认、否决)分离到不同的阶段——低风险的变更自动化,高风险的交给人。这不是对 AI 能力的不信任,而是对知识库准确性的工程保障。

下一章将探讨质量评分体系——它是 ConfidenceRouter 和 DecayDetector 的数据来源,也是知识从候选到正式的关键判据。

Released under the MIT License.