返回博客列表
最佳实践2026-09-0126 分钟阅读

向 DSH 学什么:WeClaw 经验回写闭环的五个迭代方向

向 DSH 学什么:从防御模式、事件溯源与插件架构中提炼 WeClaw 经验回写闭环的五个迭代方向

向 DSH 学什么:WeClaw 经验回写闭环的五个迭代方向

系列文章第 9 篇 - 从 DeepSeek Harness 的防御模式、事件溯源和插件架构中提炼 WeClaw 可落地的优化思考


前言

[上一篇文章](./WeClaw_98_当自进化遇上极致工程化:WeClaw与DeepSeek Harness架构深度对比.md)中,我们对比了 WeClaw 的"自进化 Agent"路线和 DeepSeek Harness(DSH)的"极致可组合"路线。结论是:两者代表了 Agent 技术栈的两条互补路径。

本文聚焦实操层面:WeClaw 可以从 DSH 借鉴什么?这些借鉴如何落地为经验回写闭环的具体迭代?

我们提炼出五个方向,按实施难度从低到高排列,每个方向都配有代码级的设计草案和预期收益分析。


一、异常容器化:给 EventBus 装上"保险丝"

1.1 问题

DSH 的防御模式文档(defensive-patterns.md)第 5 条规则:

Contain callback exceptions in the dispatcher. A user-supplied listener that throws must not reject the promise it runs inside or starve the listeners after it.

WeClaw 的经验回写引擎通过 EventBus 订阅事件,采用 fire-and-forget 模式。当前的异常处理是粗粒度的 try/except:

# 当前实现(experience_writeback.py)
async def _handle_event(self, event):
    try:
        # ... 所有逻辑
    except Exception as e:
        logger.debug(f"Experience writeback event handling error: {e}")

风险:如果某个经验条目触发了未预期的异常(如畸形 JSON、嵌入向量维度不匹配),整个事件处理链可能中断,导致后续事件丢失。

1.2 DSH 的做法

DSH 在 Cordis 事件分发层实现了严格的异常容器化:

// DSH Cordis 事件分发(概念简化)
for (const listener of listeners) {
    try {
        await listener(event)
    } catch (err) {
        // 单个监听器异常被容器化,不影响后续监听器
        this.ctx.logger.warn(`listener failed: ${err.message}`)
    }
}

1.3 优化方案

为 WeClaw 的经验回写引擎引入分段容器化,将事件处理拆分为独立的阶段,每个阶段独立捕获异常:

# 优化后:分段容器化
async def _handle_event(self, event):
    """分段处理,每段独立异常容器化。"""

    # 阶段 1: 事件解析(不应因解析失败影响后续事件)
    try:
        candidate = self._extract_candidate(event)
        if not candidate:
            return
    except Exception as e:
        logger.debug(f"[Stage 1] Candidate extraction failed: {e}")
        return  # 本事件放弃,不影响后续

    # 阶段 2: 评分门控(纯计算,异常概率低但需要防御)
    try:
        score = self._score_candidate(candidate)
    except Exception as e:
        logger.debug(f"[Stage 2] Scoring failed for candidate: {e}")
        return

    # 阶段 3: 存储写入(数据库异常需要隔离)
    try:
        experience_id = self._store_candidate(candidate, score)
    except Exception as e:
        logger.warning(f"[Stage 3] Store failed: {e}")
        return

    # 阶段 4: 变异生成(模板异常需要隔离)
    if score >= self._mutate_threshold:
        try:
            self._generate_and_store_variants(candidate, experience_id)
        except Exception as e:
            logger.debug(f"[Stage 4] Mutation failed: {e}")
            # 变异失败不影响已入库的原始经验

1.4 预期收益

指标当前优化后
单事件异常影响范围整个处理链中断仅本事件放弃
异常定位粒度粗粒度(只知道"某处出错")精确到阶段
数据完整性变异失败可能回滚原始入库各阶段独立,互不影响

实施难度:低。纯重构,不改变外部行为。


二、事件类型强化:给经验生命周期一个"类型身份证"

2.1 问题

当前 WeClaw 的经验相关事件通过 EventBus 的通用 EventType 传递,没有专用的事件类型体系。经验生命周期的关键转换(采集 → 评分 → 入库 → 变异 → 回滚)散落在方法调用日志中,缺乏结构化的审计追踪。

DSH 的做法截然不同——它有 40+ 种强类型事件,每种事件都有:

  • 唯一的类型标识('goal/change'、'compaction/start')
  • 类型安全的载荷声明
  • Surface vs Log-only 的明确分类
  • 单调序列号保证顺序

2.2 优化方案

为经验回写闭环定义专用的事件类型枚举:

# src/core/experience_events.py(新增)

from enum import Enum
from dataclasses import dataclass
from typing import Optional

class ExperienceEventType(Enum):
    """经验生命周期事件类型。"""

    # 采集阶段
    CANDIDATE_CAPTURED = "experience/candidate_captured"
    CANDIDATE_REJECTED = "experience/candidate_rejected"

    # 评分阶段
    SCORED = "experience/scored"

    # 门控决策
    GATED_DISCARD = "experience/gated_discard"
    GATED_STORE = "experience/gated_store"
    GATED_MUTATE = "experience/gated_mutate"

    # 变异阶段
    VARIANT_GENERATED = "experience/variant_generated"
    VARIANT_STORED = "experience/variant_stored"

    # 观测阶段
    HIT_COUNT_SAMPLED = "experience/hit_count_sampled"

    # 回滚阶段
    ROLLBACK_TRIGGERED = "experience/rollback_triggered"
    ROLLBACK_COMPLETED = "experience/rollback_completed"

    # 系统事件
    ENGINE_ENABLED = "experience/engine_enabled"
    ENGINE_DISABLED = "experience/engine_disabled"
    DAILY_LIMIT_REACHED = "experience/daily_limit_reached"


@dataclass(frozen=True)
class ExperienceEvent:
    """经验生命周期事件(不可变)。"""
    type: ExperienceEventType
    seq: int                       # 单调递增序列号
    timestamp: float               # Unix 时间戳
    experience_id: Optional[int]   # 关联的经验条目 ID
    data: dict                     # 类型特定的载荷
    log_only: bool = True          # 默认 log-only,不进入模型上下文

2.3 事件流转图

sequenceDiagram
    participant EB as EventBus
    participant WE as WritebackEngine
    participant Store as ExperienceStore
    participant Log as writeback_log

    EB->>WE: TOOL_RESULT (success after failures)
    WE->>Log: experience/candidate_captured {tool, failures_count}
    WE->>WE: score = _score_candidate()
    WE->>Log: experience/scored {score=0.87, components={...}}

    alt score < 0.5
        WE->>Log: experience/gated_discard {reason="low_score"}
    else 0.5 <= score < 0.8
        WE->>Store: store(candidate)
        WE->>Log: experience/gated_store {id=142}
    else score >= 0.8
        WE->>Store: store(candidate)
        WE->>Log: experience/gated_store {id=142}
        WE->>WE: _generate_variants()
        WE->>Store: store(variant_1)
        WE->>Log: experience/variant_generated {parent=142, strategy="add_example"}
        WE->>Store: store(variant_2)
        WE->>Log: experience/variant_generated {parent=142, strategy="add_constraint"}
    end

    Note over WE,Log: 后台观测任务(定期执行)
    WE->>Store: query hit_counts(window)
    WE->>Log: experience/hit_count_sampled {parent=142, child_hits=3, parent_hits=8}

    alt child.hit_rate < parent.hit_rate * 0.5
        WE->>Store: rollback(variant_id)
        WE->>Log: experience/rollback_triggered {variant=143, reason="hit_rate_degradation"}
        WE->>Log: experience/rollback_completed {variant=143, status="deactivated"}
    end

2.4 预期收益

收益说明
审计完整性每个生命周期转换都有独立事件记录,可重建完整历史
调试效率异常定位从"方法调用栈"变为"事件流分析"
可观测性可以构建经验生命周期的仪表盘(如每日门控决策分布)
论文支撑W1 论文消融实验的数据采集基础

实施难度:低-中。新增事件类型定义 + 在现有代码中插入 emit 调用。


三、乐观并发控制:给经验库加上"版本号"

3.1 问题

当前 ExperienceStore 使用 threading.RLock 保护写操作,读操作依赖 SQLite 的默认隔离级别。在经验回写引擎与检索查询并发执行时,存在以下场景:

时间线:
  t1: 回写引擎读取经验 #42 的 hit_count = 10
  t2: 检索查询命中经验 #42,hit_count += 1 → 11
  t3: 回写引擎基于 hit_count=10 做回滚判定
  t4: 回滚决策基于过期数据,可能误判

DSH 在多个模块中使用了乐观并发控制(Optimistic Concurrency Control, OCC)来解决类似问题。

3.2 DSH 的做法

DSH 的 MessageFeedbackService 和 GoalService 都使用版本号 CAS(Compare-And-Set):

// DSH GoalService 的乐观并发(概念简化)
edit(agent, ref: GoalRef, request) {
    // ref 包含期望的当前 revision
    current = this.expectCurrent(cache, ref)
    // 如果 revision 不匹配 → 抛 "stale ref" 错误
    // 只有 revision 匹配时才执行更新
    newGoal = { ...current, revision: current.revision + 1 }
}

3.3 优化方案

为经验条目引入版本号,回滚决策使用 CAS 语义:

# experience_store.py 新增字段
@dataclass
class Experience:
    # ... 现有字段 ...
    revision: int = 1  # 乐观并发版本号

# 回滚决策的 CAS 语义
def rollback_if_stale(self, experience_id: int, expected_revision: int) -> bool:
    """仅在版本号匹配时执行回滚。

    Returns:
        True  if rollback succeeded (version matched)
        False if version mismatched (concurrent modification detected)
    """
    cursor = self._conn.execute(
        """UPDATE experiences
           SET status = 'inactive', revision = revision + 1
           WHERE id = ? AND revision = ? AND status = 'active'""",
        (experience_id, expected_revision),
    )
    self._conn.commit()
    return cursor.rowcount > 0

3.4 回滚决策的完整流程

# experience_writeback.py
def _check_and_rollback(self, parent_id: int):
    """命中率观测窗回滚(带 OCC 保护)。"""

    # 1. 读取当前快照(含 revision)
    parent = self._store.get_with_revision(parent_id)
    variants = self._store.get_variants(parent_id)

    # 2. 计算命中率
    window_hits = sum(v.hit_count for v in variants)
    window_total = sum(v.total_queries for v in variants)

    if window_total < 5:
        return  # 样本不足

    child_hit_rate = window_hits / window_total
    parent_hit_rate = parent.hit_count / max(parent.total_queries, 1)

    # 3. 回滚判定
    if child_hit_rate < parent_hit_rate * 0.5:
        for variant in variants:
            # 4. CAS 回滚:仅在版本号匹配时执行
            success = self._store.rollback_if_stale(
                variant.id, variant.revision
            )
            if success:
                self._log_event(ExperienceEventType.ROLLBACK_COMPLETED, {
                    "variant_id": variant.id,
                    "parent_revision": parent.revision,
                    "child_hit_rate": child_hit_rate,
                    "parent_hit_rate": parent_hit_rate,
                })
            else:
                # 版本号不匹配 → 并发修改已发生,跳过本次回滚
                logger.info(
                    f"Rollback skipped for variant {variant.id}: "
                    f"revision mismatch (expected {variant.revision})"
                )

3.5 预期收益

场景当前优化后
并发读写RLock 保护写,读可能过期OCC 版本号检测过期
回滚误判基于快照可能误判CAS 保证只有最新数据能触发回滚
竞态调试难以重现版本号不匹配时有明确日志

实施难度:中。需要在 experiences 表增加 revision 列并做 schema 迁移。


四、抽象服务层:为经验引擎预留"可插拔后端"

4.1 问题

当前 ExperienceWritebackEngine 是一个具体实现类,直接依赖 ExperienceStore 和 MutationEngine。如果未来需要:

  • 替换评分算法(如从归一化加权改为 LLM 评估)
  • 替换变异策略(如引入 LLM 驱动的语义变异)
  • 替换存储后端(如从 SQLite 迁移到 PostgreSQL)

需要修改 ExperienceWritebackEngine 的核心代码,违反开闭原则。

DSH 的做法是定义抽象服务层(Service Definition),具体实现作为独立的后端插件:

// DSH CompactionEngine 的抽象层(简化)
abstract class CompactionEngine extends Service {
    abstract compactIfNeeded(agent, trigger, signal): Promise<CompactionResult | null>
    abstract compactNow(agent, signal): Promise<CompactionResult | null>
    abstract compactRegion(start, end, agent, signal): Promise<CompactionResult>
}

// 具体实现
class CompactionBasic extends CompactionEngine {
    // 具体的压力策略和摘要算法
}

4.2 优化方案

将经验回写引擎拆分为三层:

┌─────────────────────────────────────────────┐
│ WritebackOrchestrator(编排层)              │
│ - EventBus 订阅                              │
│ - 频率保护(每日上限)                       │
│ - 生命周期管理                               │
└─────────────┬───────────────────────────────┘
              │ 依赖抽象接口
    ┌─────────┼─────────┬──────────────┐
    ▼         ▼         ▼              ▼
┌────────┐ ┌────────┐ ┌──────────┐ ┌────────┐
│ Scorer │ │ Gater  │ │ Mutator  │ │Observer│
│(评分器)│ │(门控器)│ │(变异器)  │ │(观测器)│
│        │ │        │ │          │ │        │
│ 接口   │ │ 接口   │ │ 接口     │ │ 接口   │
│ ────── │ │ ────── │ │ ──────── │ │ ────── │
│ 默认   │ │ 三档   │ │ 4 算子   │ │hit_cnt │
│ 实现   │ │ 实现   │ │ 实现     │ │ 实现   │
│        │ │        │ │          │ │        │
│ LLM    │ │ 二元   │ │ LLM      │ │ 任务批 │
│ 实现   │ │ 实现   │ │ 实现     │ │ 成功率 │
│(未来)  │ │(未来)  │ │(未来)    │ │(未来)  │
└────────┘ └────────┘ └──────────┘ └────────┘
# src/core/writeback/interfaces.py(新增)

from abc import ABC, abstractmethod
from dataclasses import dataclass

@dataclass
class ScoreResult:
    score: float               # [0, 1]
    components: dict[str, float]  # 各分量明细
    method: str                # "weighted_v1" | "llm_judge" | ...

class ExperienceScorer(ABC):
    """经验评分器接口。"""

    @abstractmethod
    def score(self, candidate: dict) -> ScoreResult:
        """评估候选经验的质量分数。"""
        ...


class ExperienceGater(ABC):
    """门控决策器接口。"""

    @abstractmethod
    def decide(self, score_result: ScoreResult) -> str:
        """返回门控决策:'discard' | 'store' | 'mutate'。"""
        ...


class ExperienceMutator(ABC):
    """变异策略器接口。"""

    @abstractmethod
    def generate_variants(
        self, parent: Any, max_variants: int = 2, **context
    ) -> list[dict]:
        """为高质量经验生成变体。"""
        ...


class ExperienceObserver(ABC):
    """效果观测器接口。"""

    @abstractmethod
    def should_rollback(self, parent_id: int, variants: list) -> bool:
        """基于观测数据判断是否需要回滚。"""
        ...

4.3 当前默认实现(向后兼容)

# src/core/writeback/defaults.py(新增)

class WeightedScorer(ExperienceScorer):
    """默认的归一化加权评分器(现有逻辑提取)。"""

    WEIGHTS = {
        "fail_recovery": 0.3,
        "field_completeness": 0.3,
        "keyword_hit": 0.2,
        "novelty_bonus": 0.2,
    }

    def score(self, candidate: dict) -> ScoreResult:
        # 现有评分逻辑原样迁移
        ...


class ThreeTierGater(ExperienceGater):
    """默认的三档门控器。"""

    def decide(self, score_result: ScoreResult) -> str:
        s = score_result.score
        if s < 0.5:
            return "discard"
        elif s < 0.8:
            return "store"
        else:
            return "mutate"


class TemplateMutator(ExperienceMutator):
    """默认的模板变异器(现有 4 算子原样迁移)。"""

    STRATEGIES = ["add_example", "add_constraint", "restructure", "add_edge_case"]
    ...

4.4 预期收益

场景当前优化后
替换评分算法修改 experience_writeback.py实现新的 ExperienceScorer
W1 消融实验需要大量代码分支运行时替换 Scorer/Gater 实例
LLM 评估对照硬编码条件分支注入 LLMScorer 实例
社区扩展不支持第三方可实现自定义后端

实施难度:中-高。需要将现有 655 行的 ExperienceWritebackEngine 拆分为 4 个接口 + 4 个默认实现 + 1 个编排器。


五、目标状态机:给经验库一个"使命"

5.1 问题

当前 WeClaw 的经验库是一个无目标的被动存储——它不知道"为什么积累经验"、"当前阶段的经验重点是什么"、"哪些经验已经完成了使命"。

DSH 的 GoalService 提供了形式化的目标管理:

// DSH GoalService 状态机
interface GoalSnapshot {
    id: GoalId
    revision: number
    objective: string           // 目标描述
    phase: GoalPhase            // active | paused | blocked | complete
    maxGoalRounds: number       // 轮次预算
}

5.2 优化方案:经验库的"使命周期"

为经验库引入使命(Mission)概念——一个有时限和成功标准的阶段性目标:

# src/core/experience_mission.py(新增概念设计)

@dataclass
class ExperienceMission:
    """经验库的阶段使命。"""
    id: str
    objective: str              # "提升文件操作类工具的故障恢复率"
    phase: str                  # active | paused | complete | archived
    target_tool_category: str   # "file_operations"
    success_threshold: float    # 0.8 (目标命中率)
    current_hit_rate: float     # 当前命中率
    round_count: int            # 已执行轮次
    max_rounds: int             # 最大轮次
    created_at: str
    completed_at: Optional[str]

    def is_satisfied(self) -> bool:
        """使命是否达成?"""
        return (
            self.current_hit_rate >= self.success_threshold
            and self.round_count >= 3  # 至少 3 个观测周期
        )
stateDiagram-v2
    [*] --> active : 创建使命
    active --> active : 执行回写轮次
    active --> paused : 人工暂停
    paused --> active : 恢复
    active --> complete : 命中率达标 + 周期足够
    active --> archived : 超过最大轮次
    complete --> [*]
    archived --> [*]

5.3 使命驱动的经验采集

有了使命后,评分门控可以引入使命相关性加分:

class MissionAwareScorer(ExperienceScorer):
    """使命感知的评分器。"""

    def score(self, candidate: dict) -> ScoreResult:
        base_score = self._base_scorer.score(candidate)

        # 使命相关性加分
        mission = self._get_active_mission()
        if mission and self._is_relevant(candidate, mission):
            bonus = 0.1  # 使命相关经验 +10% 加分
            adjusted = min(1.0, base_score.score + bonus)
            return ScoreResult(
                score=adjusted,
                components={**base_score.components, "mission_bonus": bonus},
                method="weighted_v1_mission_aware",
            )
        return base_score

5.4 预期收益

维度无使命(当前)有使命(优化后)
经验采集策略全量(所有工具失败都采集)可聚焦(优先采集使命相关工具)
质量评估通用评分使命相关性加分
成功标准无(经验库永远增长)有(命中率达标即使命完成)
库漂移治理被动(回滚检测退化)主动(使命完成后可归档整批经验)

实施难度:高。需要设计使命生命周期、与现有评分系统集成、构建使命管理 UI。


六、五个方向的实施优先级

优先级方向实施难度收益前置条件
P0异常容器化低高(稳定性)无
P1事件类型强化低-中高(可观测性 + 论文数据)无
P2乐观并发控制中中(回滚精度)schema 迁移
P3抽象服务层中-高高(可扩展性 + 消融实验)P1 完成
P4目标状态机高高(使命驱动)P3 完成
gantt
    title WeClaw 经验回写闭环迭代路线图
    dateFormat  YYYY-MM
    axisFormat  %Y-%m

    section P0 异常容器化
    代码重构         :p0, 2026-09, 1M
    测试验证         :p0t, after p0, 1M

    section P1 事件类型
    事件类型定义     :p1, 2026-09, 1M
    插入 emit 调用   :p1e, after p1, 1M
    仪表盘原型       :p1d, after p1e, 1M

    section P2 OCC
    Schema 迁移      :p2, 2026-10, 1M
    CAS 回滚逻辑     :p2c, after p2, 1M

    section P3 抽象层
    接口设计         :p3, 2026-11, 1M
    默认实现迁移     :p3m, after p3, 2M

    section P4 使命
    概念设计         :p4, 2026-12, 1M
    核心实现         :p4i, after p4, 2M

七、总结:从"能用"到"好用"的五个台阶

本文提出的五个优化方向,本质上是把 DSH 在工程化维度的最佳实践,适配到 WeClaw 的自进化场景中:

台阶借鉴来源WeClaw 落地
异常容器化DSH 防御模式 #5EventBus 分段 try/except
事件类型强化DSH Session Event Log经验生命周期专用事件
乐观并发控制DSH GoalService CAS经验版本号 + 回滚 CAS
抽象服务层DSH CompactionEngine 抽象类Scorer/Gater/Mutator/Observer 接口
目标状态机DSH GoalService 状态机经验库使命周期管理

核心观点:

  1. 自进化不等于粗糙。WeClaw 的经验回写闭环在概念层面领先全球(三档门控 + 遗传变异 + 命中率回滚的组合无完整先例),但在工程实现上仍有显著提升空间。DSH 的防御模式、类型安全、可插拔架构是值得学习的工程标杆。

  2. 事件溯源是论文数据采集的基础设施。P1(事件类型强化)的实施将直接为 W1 论文提供消融实验的数据采集管道——每一次门控决策、每一次变异、每一次回滚都有结构化事件记录。

  3. 抽象服务层是消融实验的前提。W1 论文需要对比"无门控 vs 二元门控 vs 三档门控"、"LLM 评分 vs 客观评分"等消融条件。P3(抽象服务层)使得这些对照可以通过运行时替换组件实例来实现,而不需要代码分支。

  4. 使命驱动是经验库治理的下一个前沿。当经验库从"被动积累"进化到"主动聚焦",我们不仅解决了漂移问题,还让 Agent 具备了"有目标地学习"的能力——这可能是 WeClaw 经验系统的下一个论文主题。


系列文章导航:

篇序标题核心内容
01–05WinClaw 工具优化实战专栏从工具滥用灾难到渐进式暴露
06双通道密钥管理开发者便利与用户安全的平衡
07双通道实时通信PWA 多实例绑定路由
08当自进化遇上极致工程化WeClaw vs DSH 架构对比
09本文DSH 借鉴思考与迭代方向

参考资料:

上一篇文章:[当自进化遇上极致工程化:WeClaw 与 DeepSeek Harness 架构深度对比](./WeClaw_98_当自进化遇上极致工程化:WeClaw与DeepSeek Harness架构深度对比.md)