可迭代知识库的工程设计

作者:知识工程专题调研
日期:2026-06-09
系列:AI 知识库系统调研 · 第 08 篇


前言

静态知识库是一个谎言。它在创建的那一刻就开始过时,而大多数团队在创建后就将其束之高阁。传统 wiki 的平均”半衰期”约为 18 个月——也就是说,18 个月后,约有一半的内容已经不再准确。

可迭代知识库(Iterable Knowledge Base)的核心理念是:知识不是文档,而是有生命周期的实体。它需要被创建、验证、使用、衰减、更新,最终归档或废弃。本文从工程视角系统阐述如何构建一个能够自我演化的知识库。


1. 知识腐烂问题

1.1 什么是知识腐烂

知识腐烂(Knowledge Rot)是指知识条目随时间推移逐渐失去准确性、相关性或可用性,但这一失效过程没有被及时发现和处理的现象。

与代码腐烂不同,知识腐烂没有编译器报错,没有单元测试失败,也没有 CI 告警。它是静默的、渐进的,往往在造成实际损失之后才被发现——比如,工程师按照过时的文档操作导致生产事故,或者 AI 助手给出了基于旧方案的错误建议。

1.2 腐烂的四种类型

类型一:工具版本升级导致方案失效

这是最常见也最危险的腐烂类型。示例:

# 2023年写入的知识条目
title: "Gradle 构建加速方案"
content: "在 gradle.properties 中设置 org.gradle.parallel=true 并配合 --build-cache 参数..."
created_at: "2023-03-15"
tool_version: "Gradle 7.x"

当项目升级到 Gradle 8.x 后,部分配置语法已更改,但知识库里的条目仍然是旧语法,且没有任何警告。

类型二:场景变化导致经验不再适用

环境假设发生了变化。例如,“在单机部署场景下,使用本地缓存即可”这条经验,在系统从单机扩展到分布式集群后完全失效,但没有人更新这条知识。

类型三:新的更好方案出现

旧方案仍然有效,但已经不是最优解。例如,使用手动管理内存的 C 代码,在 Rust 方案成熟后显得过时,但知识库里仍然只有旧方案,没有指向更好替代方案的关联。

类型四:错误的知识被错误摄取

这是质量腐烂——知识在创建时就是错的,或者基于错误的前提推断出来的,但由于缺乏验证机制而被存储和使用。

1.3 量化知识健康度的指标

指标名称计算方式健康阈值
平均知识龄sum(now - created_at) / total_count< 180 天
活跃率active_count / total_count> 70%
验证覆盖率verified_count / total_count> 80%
置信度均值mean(confidence_score)> 0.75
30天未访问率stale_count / total_count< 20%
矛盾条目率contradicted_count / total_count< 5%
def compute_knowledge_health_score(kb_stats: dict) -> float:
    """
    综合健康度评分,0~1,越高越好。
    """
    weights = {
        "active_ratio": 0.25,
        "avg_confidence": 0.25,
        "verification_coverage": 0.20,
        "freshness_score": 0.15,
        "access_rate": 0.15,
    }
    score = sum(kb_stats[k] * w for k, w in weights.items())
    return round(score, 3)

2. 知识的生命周期状态机

2.1 状态定义

[摄取] → draft → [人工/AI验证] → active → [定期审查] → needs_review
                                    ↓                         ↓
                                deprecated ←──────────────────┘
                                    ↓
                                archived
状态含义对外可见性
draft刚摄取,未经验证仅内部可见,AI 回答时标注”未验证”
active已验证,当前有效完全可见,正常参与检索
needs_review需要人工审查可见但降低检索权重
deprecated已过时,有替代方案可见但明确标注过时,指向替代
archived历史归档,不再使用仅历史查询时可见

2.2 状态转换条件

from enum import Enum
from datetime import datetime, timedelta
from typing import Optional
 
class KnowledgeStatus(Enum):
    DRAFT = "draft"
    ACTIVE = "active"
    NEEDS_REVIEW = "needs_review"
    DEPRECATED = "deprecated"
    ARCHIVED = "archived"
 
class KnowledgeEntry:
    def __init__(self, entry_id: str, content: str, source: str):
        self.entry_id = entry_id
        self.content = content
        self.source = source
        self.status = KnowledgeStatus.DRAFT
        self.confidence = 0.5
        self.created_at = datetime.now()
        self.last_verified: Optional[datetime] = None
        self.last_accessed: Optional[datetime] = None
        self.review_due: Optional[datetime] = None
        self.deprecated_by: Optional[str] = None  # 替代条目的 ID
        self.contradictions: list[str] = []
 
    def transition_to(self, new_status: KnowledgeStatus, reason: str = "") -> bool:
        """执行状态转换,返回是否成功。"""
        valid_transitions = {
            KnowledgeStatus.DRAFT: [KnowledgeStatus.ACTIVE, KnowledgeStatus.ARCHIVED],
            KnowledgeStatus.ACTIVE: [KnowledgeStatus.NEEDS_REVIEW, KnowledgeStatus.DEPRECATED],
            KnowledgeStatus.NEEDS_REVIEW: [KnowledgeStatus.ACTIVE, KnowledgeStatus.DEPRECATED, KnowledgeStatus.ARCHIVED],
            KnowledgeStatus.DEPRECATED: [KnowledgeStatus.ARCHIVED],
            KnowledgeStatus.ARCHIVED: [],  # 终态
        }
        if new_status not in valid_transitions.get(self.status, []):
            return False
        
        old_status = self.status
        self.status = new_status
        
        # 状态转换时的副作用
        if new_status == KnowledgeStatus.ACTIVE:
            self.last_verified = datetime.now()
            # 默认 90 天后需要复审
            self.review_due = datetime.now() + timedelta(days=90)
        elif new_status == KnowledgeStatus.NEEDS_REVIEW:
            self.confidence *= 0.9  # 进入审查时轻微降低置信度
        
        print(f"[KnowledgeEntry] {self.entry_id}: {old_status.value}{new_status.value}. reason={reason}")
        return True
 
    def should_trigger_review(self) -> bool:
        """判断是否应该触发审查。"""
        now = datetime.now()
        # 条件1:超过审查日期
        if self.review_due and now > self.review_due:
            return True
        # 条件2:置信度低于阈值
        if self.confidence < 0.6:
            return True
        # 条件3:超过 60 天未访问
        if self.last_accessed and (now - self.last_accessed).days > 60:
            return True
        return False

2.3 状态机的持久化

每次状态变更都应记录到审计日志:

import json
from pathlib import Path
 
class StatusAuditLog:
    def __init__(self, log_path: str):
        self.log_path = Path(log_path)
        self.log_path.parent.mkdir(parents=True, exist_ok=True)
 
    def record(self, entry_id: str, from_status: str, to_status: str,
               reason: str, operator: str = "system"):
        event = {
            "timestamp": datetime.now().isoformat(),
            "entry_id": entry_id,
            "from_status": from_status,
            "to_status": to_status,
            "reason": reason,
            "operator": operator,
        }
        with open(self.log_path, "a", encoding="utf-8") as f:
            f.write(json.dumps(event, ensure_ascii=False) + "\n")

3. 置信度系统设计

3.1 初始置信度:基于来源质量

不同来源的知识初始置信度不同。这是知识摄取时的”先验”:

SOURCE_CONFIDENCE_MAP = {
    # 高置信度来源
    "verified_fix": 0.90,        # 经过验证的修复方案(有 PR/Commit 佐证)
    "official_doc": 0.85,        # 官方文档
    "peer_reviewed": 0.85,       # 经过同行评审的内容
    "production_verified": 0.88, # 生产环境验证过的方案
    
    # 中等置信度来源
    "ai_generated_reviewed": 0.70, # AI 生成 + 人工确认
    "blog_post": 0.65,             # 技术博客
    "stack_overflow": 0.65,        # Stack Overflow(高赞答案)
    "ai_generated": 0.55,          # AI 生成未经人工确认
    
    # 低置信度来源
    "speculation": 0.40,           # 推测/未验证
    "anonymous": 0.35,             # 匿名来源
    "outdated_doc": 0.30,          # 已知过时的文档
}
 
def initial_confidence(source_type: str, vote_count: int = 0) -> float:
    """
    计算初始置信度,vote_count 是来源内的投票/点赞数。
    """
    base = SOURCE_CONFIDENCE_MAP.get(source_type, 0.5)
    # 高赞内容小幅提升置信度(上限 0.95)
    boost = min(0.05, vote_count * 0.001)
    return min(0.95, base + boost)

3.2 置信度衰减:时间函数

不同类型的知识有不同的”保质期”。API 文档变化快,架构设计原则变化慢:

import math
 
# 不同知识类型的半衰期(天)
HALF_LIFE_DAYS = {
    "api_usage": 180,        # API 用法,半年一轮
    "tool_config": 270,      # 工具配置,9个月
    "debug_trick": 365,      # 调试技巧,1年
    "architecture": 730,     # 架构设计,2年
    "concept": 1095,         # 概念性知识,3年
    "best_practice": 365,    # 最佳实践,1年
}
 
def decayed_confidence(
    original_confidence: float,
    last_verified: datetime,
    knowledge_type: str,
    now: Optional[datetime] = None,
) -> float:
    """
    使用指数衰减模型计算当前置信度。
    公式: C(t) = C0 * exp(-λ * t)
    其中 λ = ln(2) / half_life
    """
    if now is None:
        now = datetime.now()
    
    days_elapsed = (now - last_verified).days
    half_life = HALF_LIFE_DAYS.get(knowledge_type, 365)
    decay_rate = math.log(2) / half_life
    
    decayed = original_confidence * math.exp(-decay_rate * days_elapsed)
    # 最低衰减至 0.1,避免完全清零
    return max(0.1, round(decayed, 4))

3.3 置信度提升:新证据验证

当有新证据支持一条知识时,使用贝叶斯更新:

def bayesian_confidence_update(
    prior: float,
    evidence_type: str,
    evidence_strength: float = 1.0,
) -> float:
    """
    贝叶斯置信度更新。
    prior: 当前置信度(先验概率)
    evidence_type: "confirm"(正向证据)或 "refute"(反向证据)
    evidence_strength: 证据强度,0~1
    """
    if evidence_type == "confirm":
        # 正向证据:P(H|E) = P(E|H) * P(H) / P(E)
        # 简化:置信度向 1.0 靠近
        likelihood_ratio = 1.0 + evidence_strength * 0.5
        posterior = prior * likelihood_ratio / (prior * likelihood_ratio + (1 - prior))
    elif evidence_type == "refute":
        # 反向证据:置信度向 0 靠近
        likelihood_ratio = evidence_strength
        posterior = prior * (1 - likelihood_ratio) / (
            prior * (1 - likelihood_ratio) + (1 - prior) * likelihood_ratio
        )
    else:
        return prior
    
    return round(max(0.05, min(0.99, posterior)), 4)
 
# 使用示例
confidence = 0.7
# 用户确认方案有效
confidence = bayesian_confidence_update(confidence, "confirm", strength=0.8)  # → ~0.82
# 发现反例
confidence = bayesian_confidence_update(confidence, "refute", strength=0.6)   # → ~0.58

4. 知识更新策略

4.1 发现新证据时的处理逻辑

from dataclasses import dataclass, field
from typing import Literal
 
EvidenceType = Literal["confirm", "refute", "supersede"]
 
@dataclass
class Evidence:
    source: str
    evidence_type: EvidenceType
    strength: float  # 0~1
    description: str
    new_entry_id: str = ""  # 当 type=supersede 时,指向新条目
 
class KnowledgeUpdater:
    def __init__(self, kb):
        self.kb = kb  # 知识库存储层
 
    def apply_evidence(self, entry_id: str, evidence: Evidence):
        entry = self.kb.get(entry_id)
        if entry is None:
            return
 
        if evidence.evidence_type == "confirm":
            # 同向证据:提升置信度,更新验证时间
            entry.confidence = bayesian_confidence_update(
                entry.confidence, "confirm", evidence.strength
            )
            entry.last_verified = datetime.now()
            # 重置审查周期
            entry.review_due = datetime.now() + timedelta(days=90)
 
        elif evidence.evidence_type == "refute":
            # 反向证据:降低置信度 + 标记矛盾
            entry.confidence = bayesian_confidence_update(
                entry.confidence, "refute", evidence.strength
            )
            entry.contradictions.append(evidence.description)
            if entry.confidence < 0.4:
                entry.transition_to(KnowledgeStatus.NEEDS_REVIEW, 
                                    reason=f"反向证据导致置信度降至 {entry.confidence}")
 
        elif evidence.evidence_type == "supersede":
            # 更好方案:deprecated 旧条目,建立关联
            entry.deprecated_by = evidence.new_entry_id
            entry.transition_to(KnowledgeStatus.DEPRECATED,
                                reason=f"被更优方案 {evidence.new_entry_id} 取代")
            # 确保新条目存在并标记关联
            new_entry = self.kb.get(evidence.new_entry_id)
            if new_entry:
                new_entry.supersedes = entry_id
 
        self.kb.save(entry)

4.2 版本升级时的知识处理

对于与特定工具版本绑定的知识,应当在条目元数据中明确标注版本约束:

# 知识条目的元数据结构示例(YAML 格式)
id: "KB-2024-0312-gradle-parallel"
title: "Gradle 并行构建配置"
content: |
  在 gradle.properties 中添加:
  org.gradle.parallel=true
  org.gradle.caching=true
  ...
knowledge_type: "tool_config"
confidence: 0.88
status: "active"
version_constraints:
  gradle: ">=7.0,<8.0"   # 版本约束
  java: ">=11"
created_at: "2024-03-12"
last_verified: "2024-09-01"
review_due: "2025-03-01"
tags: [gradle, build, performance]
def check_version_compatibility(entry: KnowledgeEntry, env_versions: dict) -> bool:
    """
    检查知识条目是否与当前环境版本兼容。
    env_versions: {"gradle": "8.2", "java": "17"}
    """
    from packaging.version import Version
    
    constraints = entry.version_constraints or {}
    for tool, constraint in constraints.items():
        current = env_versions.get(tool)
        if current is None:
            continue  # 未知版本,跳过检查
        
        # 解析约束(简化版,生产中建议用 packaging 库)
        if not _satisfies_constraint(current, constraint):
            return False
    return True

4.3 多版本知识共存方案

KB-gradle-parallel-v7  (status: deprecated, gradle: >=7.0 <8.0)
    └── deprecated_by → KB-gradle-parallel-v8
KB-gradle-parallel-v8  (status: active, gradle: >=8.0)

查询时,知识库应根据用户环境自动路由到正确版本:

def retrieve_with_version_routing(query: str, env_versions: dict, kb) -> list:
    candidates = kb.semantic_search(query, top_k=20)
    compatible = [
        entry for entry in candidates
        if check_version_compatibility(entry, env_versions)
        and entry.status == KnowledgeStatus.ACTIVE
    ]
    return compatible

5. 定期知识审查机制

5.1 自动识别需要审查的条目

from dataclasses import dataclass
 
@dataclass
class ReviewCandidate:
    entry_id: str
    reason: str
    priority: int  # 1=高优先级,3=低优先级
 
def identify_review_candidates(kb, now: Optional[datetime] = None) -> list[ReviewCandidate]:
    if now is None:
        now = datetime.now()
    
    candidates = []
    for entry in kb.iter_active():
        # 优先级 1:即将过期或已过期
        if entry.review_due and now >= entry.review_due:
            candidates.append(ReviewCandidate(
                entry.entry_id,
                reason=f"审查日期已到({entry.review_due.date()})",
                priority=1,
            ))
        # 优先级 1:置信度骤降(存在未处理的矛盾)
        elif len(entry.contradictions) > 0 and entry.confidence < 0.6:
            candidates.append(ReviewCandidate(
                entry.entry_id,
                reason=f"存在 {len(entry.contradictions)} 个矛盾记录,置信度 {entry.confidence}",
                priority=1,
            ))
        # 优先级 2:长期未验证(>180天)
        elif entry.last_verified and (now - entry.last_verified).days > 180:
            candidates.append(ReviewCandidate(
                entry.entry_id,
                reason=f"已 {(now - entry.last_verified).days} 天未验证",
                priority=2,
            ))
        # 优先级 3:长期未访问(>60天)
        elif entry.last_accessed and (now - entry.last_accessed).days > 60:
            candidates.append(ReviewCandidate(
                entry.entry_id,
                reason="超过60天未被查询访问",
                priority=3,
            ))
    
    return sorted(candidates, key=lambda c: c.priority)

5.2 每周知识审查报告生成

def generate_weekly_review_report(kb, output_path: str):
    candidates = identify_review_candidates(kb)
    stats = kb.compute_health_stats()
    
    report_lines = [
        f"# 知识库每周审查报告",
        f"",
        f"**生成时间**: {datetime.now().strftime('%Y-%m-%d %H:%M')}",
        f"",
        f"## 健康度概览",
        f"",
        f"| 指标 | 当前值 | 目标值 | 状态 |",
        f"|-----|-------|-------|-----|",
        f"| 活跃条目数 | {stats['active_count']} | - | - |",
        f"| 活跃率 | {stats['active_ratio']:.1%} | >70% | {'✅' if stats['active_ratio'] > 0.7 else '⚠️'} |",
        f"| 平均置信度 | {stats['avg_confidence']:.2f} | >0.75 | {'✅' if stats['avg_confidence'] > 0.75 else '⚠️'} |",
        f"| 验证覆盖率 | {stats['verification_coverage']:.1%} | >80% | {'✅' if stats['verification_coverage'] > 0.8 else '⚠️'} |",
        f"",
        f"## 需要审查的条目(共 {len(candidates)} 条)",
        f"",
    ]
    
    for priority in [1, 2, 3]:
        priority_items = [c for c in candidates if c.priority == priority]
        if not priority_items:
            continue
        label = {1: "高优先级", 2: "中优先级", 3: "低优先级"}[priority]
        report_lines.append(f"### {label}{len(priority_items)} 条)")
        report_lines.append("")
        for item in priority_items:
            entry = kb.get(item.entry_id)
            report_lines.append(f"- **{item.entry_id}**: {entry.title if entry else '未知'}")
            report_lines.append(f"  - 原因:{item.reason}")
        report_lines.append("")
    
    with open(output_path, "w", encoding="utf-8") as f:
        f.write("\n".join(report_lines))
    
    print(f"[ReviewReport] 报告已生成:{output_path},共 {len(candidates)} 条待审查")

5.3 AI 辅助审查流程

AI 辅助审查的核心是:让 AI 用最新的互联网知识来验证知识库中的旧条目

async def ai_assisted_review(entry: KnowledgeEntry, llm_client) -> dict:
    """
    使用 LLM 对知识条目进行辅助审查。
    返回审查结果字典。
    """
    prompt = f"""
你是一名知识验证专家。请审查以下知识条目,判断它是否仍然准确、有效。
 
**知识条目**:
- 标题: {entry.title}
- 内容: {entry.content}
- 知识类型: {entry.knowledge_type}
- 创建时间: {entry.created_at.strftime('%Y-%m-%d')}
- 最后验证: {entry.last_verified.strftime('%Y-%m-%d') if entry.last_verified else '从未'}
- 版本约束: {entry.version_constraints}
 
**请回答**:
1. 该知识是否仍然准确?(是/否/不确定)
2. 如果不准确,哪部分需要更新?
3. 是否有更好的替代方案?
4. 建议的置信度(0.0~1.0)?
5. 是否应该标记为需要人工审查?
 
以 JSON 格式返回结果。
"""
    response = await llm_client.complete(prompt)
    return parse_review_response(response)

6. 知识图谱的动态演化

6.1 新知识的自动关联发现

当一条新知识被摄取时,系统应自动发现它与已有知识的关联关系:

from typing import NamedTuple
 
class KnowledgeRelation(NamedTuple):
    source_id: str
    target_id: str
    relation_type: str  # "related_to", "contradicts", "supersedes", "requires", "part_of"
    confidence: float
 
async def discover_relations(new_entry: KnowledgeEntry, kb, embedder, llm_client) -> list[KnowledgeRelation]:
    """
    为新摄取的知识条目发现关联关系。
    """
    # Step 1: 向量近邻搜索,找候选关联
    new_embedding = embedder.encode(new_entry.content)
    candidates = kb.vector_search(new_embedding, top_k=10, min_score=0.75)
    
    relations = []
    for candidate in candidates:
        # Step 2: 让 LLM 判断关联类型
        relation_type = await classify_relation(new_entry, candidate, llm_client)
        if relation_type:
            relations.append(KnowledgeRelation(
                source_id=new_entry.entry_id,
                target_id=candidate.entry_id,
                relation_type=relation_type,
                confidence=candidate.similarity_score,
            ))
    
    return relations

6.2 知识图谱的存储结构

# 使用有向图存储知识关联
import networkx as nx
 
class KnowledgeGraph:
    def __init__(self):
        self.graph = nx.DiGraph()
 
    def add_entry(self, entry: KnowledgeEntry):
        self.graph.add_node(
            entry.entry_id,
            title=entry.title,
            status=entry.status.value,
            confidence=entry.confidence,
            knowledge_type=entry.knowledge_type,
        )
 
    def add_relation(self, relation: KnowledgeRelation):
        self.graph.add_edge(
            relation.source_id,
            relation.target_id,
            relation_type=relation.relation_type,
            confidence=relation.confidence,
        )
 
    def get_related(self, entry_id: str, relation_type: str = None) -> list:
        """获取相关知识,支持按关系类型过滤。"""
        neighbors = list(self.graph.neighbors(entry_id))
        if relation_type:
            neighbors = [
                n for n in neighbors
                if self.graph[entry_id][n].get("relation_type") == relation_type
            ]
        return neighbors
 
    def find_orphan_nodes(self) -> list[str]:
        """找出孤立节点(无任何关联)。"""
        return [node for node in self.graph.nodes() 
                if self.graph.degree(node) == 0]
 
    def detect_contradiction_clusters(self) -> list[list[str]]:
        """
        找出互相矛盾的知识簇,供人工审查。
        """
        contradiction_edges = [
            (u, v) for u, v, data in self.graph.edges(data=True)
            if data.get("relation_type") == "contradicts"
        ]
        # 构建矛盾子图,找连通分量
        contradiction_subgraph = nx.Graph(contradiction_edges)
        return [list(c) for c in nx.connected_components(contradiction_subgraph)]

6.3 孤立知识节点的处理

孤立节点是知识图谱中最危险的存在——它们既无法通过关联被发现,也无法通过上下文被验证:

def handle_orphan_nodes(kg: KnowledgeGraph, kb, embedder):
    """
    处理孤立知识节点的策略:
    1. 尝试自动发现关联
    2. 如果无法关联,降低置信度并标记为需要审查
    """
    orphans = kg.find_orphan_nodes()
    print(f"[KnowledgeGraph] 发现 {len(orphans)} 个孤立节点")
    
    for entry_id in orphans:
        entry = kb.get(entry_id)
        if entry is None:
            continue
        
        # 尝试用更低的相似度阈值重新搜索
        embedding = embedder.encode(entry.content)
        candidates = kb.vector_search(embedding, top_k=5, min_score=0.6)
        
        if candidates:
            # 找到潜在关联,人工确认
            entry.pending_relations = [c.entry_id for c in candidates]
            entry.transition_to(KnowledgeStatus.NEEDS_REVIEW, 
                               reason="孤立节点,建议确认与候选条目的关联")
        else:
            # 真正孤立,降低置信度
            entry.confidence *= 0.85
            if entry.confidence < 0.5:
                entry.transition_to(KnowledgeStatus.NEEDS_REVIEW,
                                   reason="孤立节点且置信度过低")

7. Git 版本控制最佳实践

7.1 Commit 规范

知识库使用 Git 管理时,commit message 应遵循专门的规范,与代码变更区分:

knowledge: <type>(<scope>) <subject>

Types:
  add      - 新增知识条目
  update   - 更新现有条目内容
  verify   - 验证条目(更新验证时间和置信度)
  deprecate - 标记条目为过时
  archive  - 归档条目
  relation - 新增/修改知识关联

示例:
  knowledge: add(gradle) 新增 Gradle 8.x 并行构建配置方案
  knowledge: deprecate(gradle) KB-2023-gradle-parallel 被 v8 方案取代
  knowledge: verify(android-debug) 经生产验证,置信度提升至 0.92
  knowledge: update(perfetto) 补充 Android 14 的新 track event API 用法
  knowledge: relation(flutter) 建立 hot-reload 与 JIT 编译器的关联

7.2 PR 审查工作流

重要知识变更(如 deprecated 已被大量引用的条目)必须经过 PR 审查:

# .github/workflows/knowledge-review.yml
name: Knowledge Review Gate
 
on:
  pull_request:
    paths:
      - 'knowledge/**/*.yaml'
      - 'knowledge/**/*.json'
 
jobs:
  review-gate:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Detect High-Impact Changes
        id: detect
        run: |
          python scripts/detect_kb_impact.py \
            --diff-files "$(git diff --name-only origin/main...HEAD)" \
            --output impact_report.json
      
      - name: Require Review for Deprecations
        run: |
          python scripts/enforce_review_policy.py \
            --impact impact_report.json \
            --min-reviewers 2
# scripts/detect_kb_impact.py
def detect_high_impact_changes(changed_files: list[str], kb) -> dict:
    """
    检测高影响变更:
    - 被高频引用的条目(引用次数 > 10)
    - 置信度 > 0.85 的条目
    - 关键标签的条目("core", "production-verified")
    """
    high_impact = []
    for file_path in changed_files:
        entry_id = extract_entry_id_from_path(file_path)
        entry = kb.get(entry_id)
        if entry and (
            entry.reference_count > 10
            or entry.confidence > 0.85
            or "core" in entry.tags
        ):
            high_impact.append({
                "entry_id": entry_id,
                "reference_count": entry.reference_count,
                "confidence": entry.confidence,
                "reason": "high_impact_entry",
            })
    return {"high_impact_changes": high_impact}

7.3 知识 Changelog 自动生成

def generate_knowledge_changelog(since_tag: str, repo_path: str) -> str:
    """
    从 Git 历史自动生成知识变更日志。
    """
    import subprocess
    result = subprocess.run(
        ["git", "log", f"{since_tag}..HEAD", "--oneline", "--grep=knowledge:"],
        capture_output=True, text=True, cwd=repo_path,
    )
    commits = result.stdout.strip().split("\n")
    
    changelog = {
        "add": [], "update": [], "verify": [],
        "deprecate": [], "archive": [], "relation": [],
    }
    
    for commit in commits:
        if not commit.strip():
            continue
        for change_type in changelog.keys():
            if f"knowledge: {change_type}" in commit:
                changelog[change_type].append(commit)
                break
    
    lines = [f"# Knowledge Changelog (since {since_tag})\n"]
    type_labels = {
        "add": "新增",      "update": "更新",    "verify": "已验证",
        "deprecate": "废弃", "archive": "已归档", "relation": "关联变更",
    }
    for t, items in changelog.items():
        if items:
            lines.append(f"\n## {type_labels[t]}{len(items)} 条)\n")
            lines.extend(f"- {item}" for item in items)
    
    return "\n".join(lines)

8. 知识质量度量体系

8.1 四维质量指标

@dataclass
class KnowledgeQualityMetrics:
    # 覆盖度:知识库覆盖的问题类型广度
    coverage_ratio: float       # 已覆盖问题类型 / 总问题类型
    coverage_gap_topics: list   # 未覆盖的热门查询主题
 
    # 准确度:AI 基于知识库的回答准确率
    accuracy_rate: float        # 人工抽样评估的准确率
    sample_size: int
    last_evaluated: datetime
 
    # 新鲜度:活跃知识的平均年龄
    avg_age_days: float         # 平均条目年龄(天)
    median_confidence: float    # 置信度中位数
 
    # 利用率:查询频率分布
    top_accessed_entries: list  # 最频繁访问的条目
    zero_access_ratio: float    # 从未被访问过的条目占比
 
def compute_quality_metrics(kb, query_logs) -> KnowledgeQualityMetrics:
    now = datetime.now()
    active_entries = list(kb.iter_active())
    
    avg_age = sum((now - e.created_at).days for e in active_entries) / len(active_entries)
    median_conf = sorted([e.confidence for e in active_entries])[len(active_entries) // 2]
    
    access_counts = {e.entry_id: 0 for e in active_entries}
    for log in query_logs:
        for retrieved_id in log.retrieved_entry_ids:
            if retrieved_id in access_counts:
                access_counts[retrieved_id] += 1
    
    zero_access = sum(1 for c in access_counts.values() if c == 0)
    top_accessed = sorted(access_counts.items(), key=lambda x: x[1], reverse=True)[:10]
    
    return KnowledgeQualityMetrics(
        coverage_ratio=0.0,  # 需要业务层计算
        coverage_gap_topics=[],
        accuracy_rate=0.0,   # 需要人工评估数据
        sample_size=0,
        last_evaluated=now,
        avg_age_days=avg_age,
        median_confidence=median_conf,
        top_accessed_entries=top_accessed,
        zero_access_ratio=zero_access / len(active_entries),
    )

8.2 Dashboard 设计方案

Dashboard 的核心是一张实时刷新的健康仪表盘,推荐以下信息层级:

┌─────────────────────────────────────────────────────────────┐
│  知识库健康仪表盘                          2026-06-09 10:00  │
├──────────┬──────────┬──────────┬───────────────────────────┤
│ 总条目   │ 活跃率   │ 平均置信 │ 待审查                    │
│  1,247   │  76.3%   │  0.801   │  ⚠️ 23 条                 │
├──────────┴──────────┴──────────┴───────────────────────────┤
│  状态分布                    │  置信度分布                  │
│  active    ████████  953     │  0.9+  ████████  612        │
│  draft     ███       184     │  0.7~  █████     420        │
│  review    ██        110     │  0.5~  ███       157        │
│  deprecated█         58      │  <0.5  █         58         │
├──────────────────────────────┴─────────────────────────────┤
│  Top 5 热门查询条目                                          │
│  1. Android Logcat 过滤技巧        (访问 847 次, conf=0.92) │
│  2. ADB 无线调试连接方法           (访问 623 次, conf=0.88) │
│  ...                                                         │
└─────────────────────────────────────────────────────────────┘

9. 从 AI 对话中学习的闭环

9.1 闭环设计架构

用户提问
    ↓
AI 检索知识库 → 生成回答 → 用户使用
    ↑                           ↓
知识库更新 ←── 反馈收集器 ←── 用户反馈

9.2 反馈类型与处理策略

反馈信号含义处理动作
用户说”解决了”回答有效提升引用条目置信度
用户说”不对”回答错误降低置信度,标记矛盾
用户提供了更好的答案有新知识触发知识摄取流程
用户无响应/放弃回答可能无效轻微降低置信度(弱信号)
用户多次重新提问回答不够清晰或有误标记为需要人工审查

9.3 反馈闭环的代码框架

from enum import Enum
from dataclasses import dataclass, field
 
class FeedbackSignal(Enum):
    CONFIRMED_CORRECT = "confirmed_correct"    # 用户确认正确
    REPORTED_INCORRECT = "reported_incorrect"  # 用户报告错误
    BETTER_ANSWER_PROVIDED = "better_answer"   # 用户提供更好答案
    ABANDONED = "abandoned"                    # 用户放弃(弱信号)
    REPEATED_QUESTION = "repeated_question"    # 重复追问(弱信号)
 
@dataclass
class ConversationFeedback:
    conversation_id: str
    query: str
    retrieved_entries: list[str]  # 被引用的知识条目 ID 列表
    signal: FeedbackSignal
    user_provided_answer: str = ""  # 当 signal=BETTER_ANSWER_PROVIDED 时
    timestamp: datetime = field(default_factory=datetime.now)
 
class FeedbackProcessor:
    def __init__(self, kb, updater: KnowledgeUpdater, ingestion_pipeline):
        self.kb = kb
        self.updater = updater
        self.ingestion = ingestion_pipeline
        
        # 信号强度配置
        self.signal_strengths = {
            FeedbackSignal.CONFIRMED_CORRECT: 0.8,
            FeedbackSignal.REPORTED_INCORRECT: 0.7,
            FeedbackSignal.BETTER_ANSWER_PROVIDED: 0.6,
            FeedbackSignal.ABANDONED: 0.2,
            FeedbackSignal.REPEATED_QUESTION: 0.3,
        }
 
    async def process(self, feedback: ConversationFeedback):
        strength = self.signal_strengths[feedback.signal]
        
        if feedback.signal == FeedbackSignal.CONFIRMED_CORRECT:
            for entry_id in feedback.retrieved_entries:
                evidence = Evidence(
                    source=f"conversation:{feedback.conversation_id}",
                    evidence_type="confirm",
                    strength=strength,
                    description=f"用户在对话 {feedback.conversation_id} 中确认答案正确",
                )
                self.updater.apply_evidence(entry_id, evidence)
        
        elif feedback.signal == FeedbackSignal.REPORTED_INCORRECT:
            for entry_id in feedback.retrieved_entries:
                evidence = Evidence(
                    source=f"conversation:{feedback.conversation_id}",
                    evidence_type="refute",
                    strength=strength,
                    description=f"用户在对话 {feedback.conversation_id} 中报告答案错误",
                )
                self.updater.apply_evidence(entry_id, evidence)
        
        elif feedback.signal == FeedbackSignal.BETTER_ANSWER_PROVIDED:
            # 创建新知识条目
            new_entry = await self.ingestion.ingest_from_conversation(
                content=feedback.user_provided_answer,
                query=feedback.query,
                source_type="user_correction",
                conversation_id=feedback.conversation_id,
            )
            # 将旧条目标记为被取代
            for entry_id in feedback.retrieved_entries:
                evidence = Evidence(
                    source=f"conversation:{feedback.conversation_id}",
                    evidence_type="supersede",
                    strength=strength,
                    description="用户提供了更准确的答案",
                    new_entry_id=new_entry.entry_id,
                )
                self.updater.apply_evidence(entry_id, evidence)
        
        elif feedback.signal in (FeedbackSignal.ABANDONED, FeedbackSignal.REPEATED_QUESTION):
            # 弱信号:只轻微降低置信度,不触发矛盾标记
            for entry_id in feedback.retrieved_entries:
                entry = self.kb.get(entry_id)
                if entry:
                    entry.confidence = max(0.3, entry.confidence - 0.02 * strength)
                    self.kb.save(entry)
 
    async def batch_process_conversation_history(self, history: list[ConversationFeedback]):
        """
        批量处理历史反馈,用于初始化时的知识质量校准。
        """
        for feedback in sorted(history, key=lambda f: f.timestamp):
            await self.process(feedback)

9.4 防止反馈污染

恶意或错误的反馈可能导致知识库质量下降,需要保护机制:

class FeedbackGuard:
    """
    防止反馈污染知识库的安全层。
    """
    def __init__(self, max_negative_per_day: int = 5):
        self.max_negative = max_negative_per_day
        self.negative_counts: dict[str, int] = {}  # user_id → daily count
 
    def is_safe_to_apply(self, feedback: ConversationFeedback, user_id: str) -> bool:
        # 规则1:单个条目单日负反馈不超过阈值
        key = f"{user_id}:{feedback.conversation_id}"
        count = self.negative_counts.get(key, 0)
        if feedback.signal == FeedbackSignal.REPORTED_INCORRECT and count >= self.max_negative:
            return False
        # 规则2:高置信度(>0.9)条目需要多个独立反馈才能降级
        for entry_id in feedback.retrieved_entries:
            entry = self.kb.get(entry_id)
            if entry and entry.confidence > 0.9:
                if self._get_refute_count(entry_id) < 3:
                    return False  # 要求至少3个独立反馈
        return True

10. 实践检查清单

以下是一份可直接使用的知识库健康检查清单,建议每月执行一次:

# 知识库健康检查清单
 
检查日期: ___________   执行人: ___________
 
## A. 基础健康度 ✅/⚠️/❌
 
- [ ] **活跃率 > 70%**:运行 `kb stats --active-ratio`,确认活跃条目占比
- [ ] **平均置信度 > 0.75**:运行 `kb stats --avg-confidence`
- [ ] **待审查条目 < 50 条**:运行 `kb review --list --priority 1`
- [ ] **矛盾条目已处理**:运行 `kb graph --contradictions`,确认无未处理矛盾
- [ ] **孤立节点 < 5%**:运行 `kb graph --orphans`
 
## B. 新鲜度检查 ✅/⚠️/❌
 
- [ ] **工具类知识(tool_config/api_usage)last_verified < 180 天**
- [ ] **调试技巧类知识(debug_trick)last_verified < 365 天**
- [ ] **无超过两年未验证的 active 条目**
- [ ] **上周新增知识是否经过验证审核**`kb audit --since last-week`
 
## C. 关联质量 ✅/⚠️/❌
 
- [ ] **高访问条目(>100次/月)有 ≥ 1 个相关条目关联**
- [ ] **deprecated 条目均有 deprecated_by 指向替代条目**
- [ ] **新增条目(本周)已运行关联发现**`kb relation --discover --since last-week`
 
## D. 反馈闭环 ✅/⚠️/❌
 
- [ ] **本周 AI 对话反馈已处理**`kb feedback --process --since last-week`
- [ ] **有负反馈(用户报错)的条目已被复查**
- [ ] **有用户提供新答案的查询已触发知识摄取**
- [ ] **反馈处理日志无异常**:检查 `logs/feedback_processor.log`
 
## E. 版本兼容性 ✅/⚠️/❌
 
- [ ] **主要工具版本(Gradle/Android SDK/Flutter 等)已更新**
- [ ] **版本约束超出当前环境的条目已标记**`kb version-check --env current`
- [ ] **有工具升级公告时,相关知识条目已触发审查**
 
## F. 度量指标 ✅/⚠️/❌
 
- [ ] **每周知识审查报告已生成并发送**
- [ ] **本月准确率抽样评估已完成(至少 30 条)**
- [ ] **知识覆盖度 Gap 分析已更新**:查看最近 30 天无匹配结果的查询
- [ ] **零访问条目已审查**`kb stats --zero-access --since 90days`
 
## G. Git 版本控制 ✅/⚠️/❌
 
- [ ] **所有 deprecate/archive 变更均已提交 PR 并经人工审查**
- [ ] **本月 Knowledge Changelog 已生成**`kb changelog --since last-month`
- [ ] **无直接推送到 main 分支的重要知识变更**
 
---
 
**总结评分**:  
- ✅ 全部通过:知识库健康,继续保持  
- ⚠️ 有警告项:制定改进计划,下次检查前解决  
- ❌ 有失败项:立即处理,记录 issue 跟踪

总结

可迭代知识库的本质是将知识管理工程化。核心原则可以归纳为五点:

  1. 知识是有生命周期的实体,不是静态文档。每条知识都需要状态机来管理其从摄取到归档的完整生命周期。

  2. 置信度是知识的核心属性。基于来源质量设定初始置信度,通过时间衰减和证据更新动态调整,让知识库能够自动反映知识的可靠程度。

  3. 反馈闭环是知识库进化的引擎。AI 使用知识回答问题,用户的确认或纠正反馈回知识库,形成自我改进的闭环。这个闭环是知识库保持活力的关键机制。

  4. 图谱化关联让知识不孤立。单条知识的价值有限,通过自动发现关联、建立知识图谱,才能实现”1+1>2”的知识涌现效应。

  5. 可度量才能可改进。设计完善的质量度量体系和定期执行检查清单,让知识库的健康状态始终可见,问题才能在造成损失之前被发现和解决。

建议工程团队从一个小规模的垂直领域知识库开始实践,先建立基础的生命周期状态机和置信度系统,再逐步引入 AI 辅助审查和反馈闭环,最终形成完整的可迭代知识管理体系。