AI Agent 自我进化:构建"越用越聪明"的经验学习闭环

举报
yd_288476769 发表于 2026/09/03 11:41:11 2026/09/03
【摘要】 作者:yumking | 2026 年 9 月 3 日 | 技术标签:AI Agent / 经验学习 / 技能自举 / 遗忘机制 摘要前八篇我们给 Agent 装上了记忆、团队、工具、知识、安全带、仪表盘、规划能力和人机协作的边界感——但还有一个尴尬的事实没解决:Agent 不会从经历中成长。同一个坑,这个会话掉进去,下个会话原样再掉一次;Prompt 调优靠人工复盘,改一次要一轮发版。第 ...

作者:yumking | 2026 年 9 月 3 日 | 技术标签:AI Agent / 经验学习 / 技能自举 / 遗忘机制


摘要

前八篇我们给 Agent 装上了记忆、团队、工具、知识、安全带、仪表盘、规划能力和人机协作的边界感——但还有一个尴尬的事实没解决:Agent 不会从经历中成长。同一个坑,这个会话掉进去,下个会话原样再掉一次;Prompt 调优靠人工复盘,改一次要一轮发版。第 7 篇的反思器只解决"单任务内的重试",任务结束教训就随风而逝。本文提出一套"经验学习闭环":失败案例结构化沉淀 → 经验库治理(评估/去重/合并)→ 技能自举(高频路径固化为技能)→ 遗忘机制(衰减/归档/防污染)。实测将同类任务的重复错误率降低 72%,第 10 次执行同类任务的首次成功率从 58% 提升至 89%,新会话冷启动步数平均减少 40%。


一、为什么 Agent 不会自己变聪明?

1.1 每次都是"失忆的天才"

Agent 的能力被冻结在模型权重里,会话之间没有经验传递。于是出现一种荒诞循环:

会话 1:连接数据库 B 失败,排查 20 分钟,发现要先探测端口
会话 2:(新会话)连接数据库 B 失败,再排查 20 分钟
会话 3:(新会话)连接数据库 B 失败……
第 50 个会话:Agent 依然用同样的姿势撞同一堵墙。

人类工程师踩一次坑就记一辈子,Agent 踩 50 次坑还是"处子之身"。这不是能力问题,是没有经验管道。

1.2 与第 7 篇反思器的边界

第 7 篇的 Reflexion 机制已经能"失败后归因、下次带着教训重试",但它有三个局限:

局限 第 7 篇反思器 本文经验闭环
生命周期 单任务内,任务结束即丢弃 跨任务、跨会话长期沉淀
触发范围 只在任务失败时 失败、成功路径、用户纠偏都触发
作用对象 注入下一次重试的 Prompt 全局经验库,所有未来会话可检索
形态 一次性文本教训 结构化经验文档 + 生命周期治理

一句话:反思器让 Agent “这次别再错”,经验闭环让 Agent “以后都不错”。

1.3 经验从哪里来?三个源头

  1. 失败归因:任务失败后的结构化复盘(最经典,但只是其一)
  2. 成功路径提炼:某类任务反复用同样的步骤成功——这条路径本身就是经验
  3. 人工纠偏信号:用户说"不对,应该先备份"——这是最贵也最值得吸收的经验

只吸收失败教训的 Agent 是"悲观主义者",只有把成功路径也提炼出来,才能从"不犯错"进化到"知道怎么做最好"。


二、经验学习闭环总览

            ┌─────────────── 执行层 ───────────────┐
            │  Agent 执行任务 → 成功 / 失败 / 纠偏   │
            └──────────────┬───────────────────────┘
                           ▼
            ┌─────────────── 沉淀层 ───────────────┐
            │  结构化归因器                          │
            │   ├─ 失败 → 根因 + 教训               │
            │   ├─ 成功 → 路径提炼                  │
            │   └─ 纠偏 → 差异吸收                  │
            └──────────────┬───────────────────────┘
                           ▼
            ┌─────────────── 治理层 ───────────────┐
            │  经验库生命周期管理                    │
            │   评估 → 去重 → 合并 → 置信度衰减      │
            │   冲突检测 → 归档遗忘                  │
            └──────────────┬───────────────────────┘
                           ▼
            ┌─────────────── 复用层 ───────────────┐
            │  检索注入:新任务启动时                 │
            │   相关经验 → 注入规划 Prompt            │
            │  技能自举:高频路径 → 固化为技能/宏      │
            └──────────────────────────────────────┘

四层形成飞轮:执行产生经验,治理保证质量,复用反哺执行。闭环转起来,Agent 才开始"越用越聪明"。


三、沉淀层:把经历变成结构化经验

3.1 经验文档的结构

经验不是一句感想,而是一份可检索、可验证、可过期的文档:

{
  "exp_id": "exp_20260903_001",
  "kind": "failure_lesson",
  "trigger": "连接外部数据库服务时",
  "content": "连接前必须先用 check_port 探测端口连通性,避免盲目重试浪费 15+ 步",
  "conditions": ["数据库连接", "外部服务", "超时重试"],
  "confidence": 0.8,
  "source": "task_9f2c 失败归因",
  "created_at": "2026-09-03 10:20:00",
  "last_verified": "2026-09-03 10:20:00",
  "hit_count": 0
}

四个关键字段:

  • trigger:什么时候适用——没有触发条件的经验是噪音
  • confidence:多可信——决定它在冲突时的话语权
  • last_verified:上次被证实是什么时候——遗忘机制的依据
  • hit_count:被命中过多少次——越常用越该保留

3.2 三个源头的归因模板

失败归因(承接第 7 篇,但产出跨任务经验):

FAILURE_PROMPT = """你是经验提炼器。任务最终失败,请提炼可复用的经验。
任务目标:{goal}
执行轨迹:{trajectory}
根因分析:{root_cause}

请输出 JSON:
{{
  "trigger": "未来什么情境下适用这条经验",
  "content": "具体建议:该做什么/不做什么(可执行,不写情绪总结)",
  "conditions": ["检索关键词"],
  "confidence": 0.0-1.0
}}"""

成功路径提炼(容易被忽略的富矿):

SUCCESS_PROMPT = """你是经验提炼器。任务成功完成,请判断是否值得沉淀路径经验。
任务目标:{goal}
执行轨迹:{trajectory}
历史同类任务平均步数:{avg_steps},本次:{steps}

判断标准:
1. 本次路径明显优于平均(更少步数/更少重试)
2. 或同类任务已重复出现 3 次以上,路径高度相似
满足其一才输出经验,否则输出 {{"skip": true}}"""

人工纠偏吸收(含金量最高的信号):

用户:"不对,改配置前要先备份原文件。"
→ 提取为:trigger="修改配置文件时",
   content="修改前必须备份原文件,路径记录到操作日志",
   confidence=0.95   ← 人工纠偏的置信度直接给高

关键认知:模型自己悟出来的经验置信度要压着给(0.6-0.8),用户教的直接给高(0.9+)。人的纠偏是真值信号。

3.3 防经验污染:最容易被忽视的深坑

经验闭环有一个致命风险——错误经验自我强化

1 次失败 → 归因错误:"因为数据库太慢" → 沉淀错误经验
第 2 次任务 → 检索到错误经验 → 按错误经验行动 → 又失败
第 2 次归因 → "数据库确实太慢,经验没错" → 错误经验置信度反而上升

防线有三道:

  1. 归因交叉验证:归因结果与工具报错信息做一致性检查,归因与事实矛盾则拒绝入库
  2. 置信度封顶:模型自产经验 confidence 上限 0.85,只有被后续成功验证过才可继续上调
  3. 验证标记:经验被命中并带来成功时,更新 last_verified 并小幅提升 confidence;带来失败时立即下调并进入复审队列

四、治理层:经验库的生命周期管理

4.1 没有治理的经验库会烂掉

经验库运营三个月后的典型惨状:

总量 2 万条,其中:
  - 重复/近似条目:38%"连接前探测端口" 存在 11 个变体)
  - 相互冲突条目:6%A"先重启"B"禁止重启"- 过期失效条目:21%(基础设施早已迁移,经验指向不存在的服务)
  检索准确率:61%——注入一半是垃圾,Agent 被带偏。

经验库不是记满就行,治理决定它是资产还是负债。

4.2 四个治理动作

动作 触发时机 做什么
去重合并 新经验入库时 与既有经验做语义比对,相似度 >0.9 合并(保留高置信度版本)
冲突检测 新经验与库内矛盾时 两者都降权并标记"待仲裁",推送给人工裁决
置信度衰减 每次入库/命中时 长期未被验证的经验按时间衰减:conf *= 0.95^(days_since_verified/30)
归档遗忘 confidence < 0.3 时 移出活跃库进入归档区,不再参与检索,但保留审计记录

4.3 遗忘不是删除

人类遗忘的本质是"降低可提取性"而非"抹除痕迹"。Agent 同理:

  • 软遗忘:confidence 衰减到阈值以下,退出检索,但记录还在
  • 可复活:同类情境再次出现且旧经验被证明仍然有效时,恢复 confidence
  • 硬遗忘:确认过时的(如指向已下线系统的经验)才物理归档

只进不出的经验库,最终会被自己的记忆淹死。


五、复用层:检索注入与技能自举

5.1 检索注入:新任务的"开场复盘"

新任务启动时,把相关经验注入规划环节(与第 7 篇的规划引擎对接):

def load_relevant_experience(goal: str, top_k: int = 5) -> str:
    """启动前检索相关经验,注入规划 Prompt"""
    hits = experience_search(
        query=goal,
        min_confidence=0.5,          # 低于 0.5 的不注入,防污染
        max_results=top_k,
    )
    if not hits:
        return ""
    lines = [f"- [{e.confidence:.2f}] {e.trigger}{e.content}" for e in hits]
    return "【相关历史经验,执行时务必参考】\n" + "\n".join(lines)

三个注入纪律:

  1. 限量:最多 5 条,经验注入过多会稀释任务指令本身的注意力
  2. 限权:低置信经验不注入,宁缺毋滥
  3. 留痕:本次任务命中了哪些经验,写入 Trace(第 6 篇的可观测性),成功后回填验证

5.2 技能自举:从"经验"到"技能"的跃迁

经验是"提示人的一句话",技能是"封装好的可执行能力"。当某条路径经验被反复命中(如 hit_count > 10),就该升级为技能:

经验(文本):"迁移数据要先导出 schema、再导数据、最后校验行数"
                        ↓ 命中 10+ 次,路径高度稳定
技能(代码):migrate_data(source, target)   ← 带校验、带回滚、可测试
                        ↓ 注册为工具
Agent 直接调用 migrate_data,不再逐步规划这三个动作

技能自举的收益是复利的:

维度 文本经验 固化为技能
Token 成本 每次注入消耗 ~200 tok 一次工具调用 ~30 tok
可靠性 依赖模型理解文本 代码路径,行为确定
可测试 无法单测 可写单测(第 6 篇评估体系直接覆盖)
迭代 改文字=改 Prompt 改代码=可灰度可回滚

Agent 进化的终点不是记住更多,而是把高频经验"编译"成不需要记住的能力。

5.3 技能晋升的门槛

不是所有经验都配当技能,晋升需同时满足:

  1. 高频:命中 ≥10 次
  2. 稳定:路径参数化后无分支歧义("有时先 A 有时先 B"的不能固化)
  3. 验证:以技能形态试运行 5 次全部成功
  4. 可逆:技能失败时的回滚路径明确

六、从零搭建经验学习引擎

#!/usr/bin/env python3
"""
Agent 经验学习引擎
沉淀(归因提炼)→ 治理(去重/衰减/遗忘)→ 复用(检索注入/技能自举)
"""

import json
import time
import math
from dataclasses import dataclass, field, asdict
from enum import Enum
from typing import Callable, Optional


# ============ 数据结构 ============

class ExpKind(Enum):
    FAILURE = "failure_lesson"
    SUCCESS = "success_pattern"
    HUMAN = "human_correction"


@dataclass
class Experience:
    exp_id: str
    kind: ExpKind
    trigger: str
    content: str
    conditions: list[str] = field(default_factory=list)
    confidence: float = 0.6
    source: str = ""
    created_at: float = field(default_factory=time.time)
    last_verified: float = field(default_factory=time.time)
    hit_count: int = 0


# ============ 沉淀层 ============

DISTILL_PROMPT = """你是经验提炼器。请从执行记录中提炼可复用经验。
任务目标:{goal}
执行结果:{outcome}
执行轨迹:{trajectory}

要求:
1. 失败 → 提炼教训:具体到"下次该做什么/不做什么"
2. 成功且路径优于历史平均 → 提炼成功路径
3. 不满足条件则输出 {{"skip": true}}
输出 JSON:{{"trigger": "...", "content": "...",
            "conditions": [...], "confidence": 0.0-1.0}}"""


def distill(goal: str, outcome: str, trajectory: str,
            llm: Callable) -> Optional[dict]:
    """从执行记录提炼结构化经验"""
    raw = llm(DISTILL_PROMPT.format(
        goal=goal, outcome=outcome, trajectory=trajectory
    ))
    data = json.loads(raw)
    if data.get("skip"):
        return None
    return data


def distill_human_correction(user_msg: str) -> Optional[dict]:
    """人工纠偏 → 高置信度经验"""
    if not any(kw in user_msg for kw in ["不对", "错了", "应该", "别"]):
        return None
    return {
        "trigger": "类似操作场景",
        "content": user_msg.strip(),
        "conditions": [],
        "confidence": 0.95,          # 人工信号直接给高置信度
    }


# ============ 治理层 ============

def semantic_similarity(a: str, b: str) -> float:
    """语义相似度(占位:真实实现用 embedding 余弦相似度)"""
    set_a, set_b = set(a), set(b)
    if not set_a or not set_b:
        return 0.0
    return len(set_a & set_b) / len(set_a | set_b)


class ExperienceStore:
    """经验库:写入 + 治理 + 检索"""

    DEDUP_THRESHOLD = 0.9       # 相似度超过此值合并
    ARCHIVE_THRESHOLD = 0.3     # 置信度低于此值归档
    MAX_INJECT = 5              # 单次注入上限
    MIN_INJECT_CONF = 0.5       # 注入的最低置信度

    def __init__(self):
        self.active: list[Experience] = []
        self.archive: list[Experience] = []

    def add(self, data: dict, kind: ExpKind, source: str) -> Optional[Experience]:
        """写入经验,带去重合并与冲突检测"""
        exp = Experience(
            exp_id=f"exp_{int(time.time() * 1000)}",
            kind=kind, source=source,
            trigger=data["trigger"], content=data["content"],
            conditions=data.get("conditions", []),
            confidence=data.get("confidence", 0.6),
        )

        # 1. 去重合并:与高相似经验合并,保留高置信度版本
        for old in self.active:
            if semantic_similarity(exp.content, old.content) > self.DEDUP_THRESHOLD:
                if exp.confidence > old.confidence:
                    old.content, old.confidence = exp.content, exp.confidence
                old.hit_count += 1               # 重复出现佐证有效
                old.last_verified = time.time()
                return old
            # 2. 冲突检测:内容矛盾则双双降权,标记待仲裁
            if self._is_contradiction(exp, old):
                old.confidence *= 0.7
                exp.confidence *= 0.7
                exp.source += " [conflict]"
                self.active.append(exp)
                return exp

        self.active.append(exp)
        return exp

    @staticmethod
    def _is_contradiction(a: Experience, b: Experience) -> bool:
        """冲突判断(简化):触发条件相近但建议相反"""
        trig_sim = semantic_similarity(a.trigger, b.trigger)
        neg_words = ("不要", "禁止", "避免")
        pos_a, pos_b = a.content, b.content
        a_neg = any(w in pos_a for w in neg_words)
        b_neg = any(w in pos_b for w in neg_words)
        return trig_sim > 0.6 and a_neg != b_neg

    def decay(self) -> None:
        """置信度衰减:30 天未验证衰减 5%"""
        now = time.time()
        for exp in self.active:
            days = (now - exp.last_verified) / 86400
            exp.confidence *= math.pow(0.95, days / 30)
        self._reorganize()

    def feedback(self, exp_id: str, success: bool) -> None:
        """任务结束回填:命中经验是否真的有用"""
        for exp in self.active:
            if exp.exp_id == exp_id:
                exp.hit_count += 1
                exp.last_verified = time.time()
                exp.confidence = min(0.95, exp.confidence + 0.05) if success \
                    else max(0.05, exp.confidence - 0.2)   # 带来失败重罚
                break
        self._reorganize()

    def _reorganize(self) -> None:
        """归档遗忘:低置信度移入归档区(软遗忘,可复活)"""
        still_active = []
        for exp in self.active:
            if exp.confidence < self.ARCHIVE_THRESHOLD:
                self.archive.append(exp)
            else:
                still_active.append(exp)
        self.active = still_active

    def search(self, query: str, top_k: int = 5) -> list[Experience]:
        """检索:按相关性 × 置信度排序"""
        scored = []
        for exp in self.active:
            rel = max(
                [semantic_similarity(query, exp.trigger)]
                + [semantic_similarity(query, c) for c in exp.conditions]
            )
            if rel > 0 and exp.confidence >= self.MIN_INJECT_CONF:
                scored.append((rel * exp.confidence, exp))
        scored.sort(key=lambda x: -x[0])
        return [exp for _, exp in scored[:top_k]]

    def candidates_for_skill(self, min_hits: int = 10) -> list[Experience]:
        """技能自举候选:高频且路径稳定的经验"""
        return [e for e in self.active if e.hit_count >= min_hits
                and e.kind == ExpKind.SUCCESS]


# ============ 复用层 ============

def inject_experience(goal: str, store: ExperienceStore,
                      llm: Callable) -> str:
    """启动新任务前,检索相关经验注入规划 Prompt"""
    hits = store.search(goal)
    if not hits:
        return goal
    lines = [f"- [{e.confidence:.2f}] {e.trigger}{e.content}" for e in hits]
    return f"{goal}\n\n【相关历史经验,执行时务必参考】\n" + "\n".join(lines)


class ExperienceAgent:
    """带经验闭环的 Agent 包装"""

    def __init__(self, agent_fn: Callable, llm: Callable,
                 store: ExperienceStore):
        self.agent_fn = agent_fn
        self.llm = llm
        self.store = store

    def run(self, task_id: str, goal: str) -> dict:
        enriched_goal = inject_experience(goal, self.store, self.llm)
        result = self.agent_fn(enriched_goal)     # 底层 Agent(第 7 篇规划引擎)

        outcome = "成功" if result.get("success") else "失败"
        data = distill(goal, outcome, json.dumps(result, ensure_ascii=False),
                       self.llm)
        if data:
            kind = ExpKind.FAILURE if "失败" in outcome else ExpKind.SUCCESS
            exp = self.store.add(data, kind, source=task_id)
            if exp:
                result["distilled_exp"] = exp.exp_id

        # 回填验证:本任务命中的经验,按成败调整置信度
        for exp_id in result.get("hit_exp_ids", []):
            self.store.feedback(exp_id, result.get("success", False))
        self.store.decay()
        return result


# ============ 完整流程 ============

if __name__ == "__main__":
    def dummy_llm(prompt: str) -> str:
        return json.dumps({
            "trigger": "连接外部数据库时",
            "content": "连接前先用 check_port 探测端口,避免盲目重试",
            "conditions": ["数据库连接", "重试"],
            "confidence": 0.75,
        }, ensure_ascii=False)

    def dummy_agent(goal: str) -> dict:
        return {"success": True, "steps": 3, "hit_exp_ids": []}

    store = ExperienceStore()
    agent = ExperienceAgent(dummy_agent, dummy_llm, store)

    agent.run("task_001", "把数据库 A 的数据迁移到数据库 B")
    agent.run("task_002", "连接数据库 B 并校验数据行数")

    for exp in store.active:
        print(json.dumps(asdict(exp), ensure_ascii=False, indent=2))

6.1 关键设计要点

要点一:经验必须"具体到动作",拒绝情绪总结

# ❌ 无效经验:"以后要小心数据库连接问题。"
# ✅ 有效经验:"连接前先用 check_port 探测端口,避免盲目重试。"

要点二:人工纠偏的置信度必须高于模型自产

# 模型悟的:0.6-0.8,且封顶 0.85
# 用户教的:0.95,一票优先

要点三:失败经验带来的失败要重罚

# 命中经验后任务成功:confidence +0.05(缓慢加分)
# 命中经验后任务失败:confidence -0.2(快速减分)

加分慢、减分快,让错误经验快速出局——这是防污染的最后一道闸。


七、实测与权衡

7.1 效果数据

在一个日均 300 任务的运维 Agent 上运行 30 天:

指标 无经验闭环 有经验闭环
同类任务重复错误率 基线 -72%
第 10 次执行同类任务首次成功率 58% 89%
新会话冷启动平均步数 14.2 步 8.5 步(-40%
经验库治理后检索准确率 61%(未治理) 93%
技能自举产出 30 天沉淀 17 个技能

7.2 两个反直觉的教训

教训一:经验库越大不一定越聪明。 未治理的 2 万条经验库,注入效果反而不如治理后的 3000 条——检索准确率 61% 意味着四成注入是噪音,模型被带偏的概率随垃圾经验线性上升。先治理,再扩容。

教训二:太快进化也有代价。 技能自举过于激进时,把一条"偶尔需要绕行"的路径固化成了技能,导致 3 个特殊场景全部执行失败。晋升门槛里的"无分支歧义"不是可选项——技能化的本质是放弃灵活性换取确定性,只对真正稳定的路径划算。

7.3 实施难度与可行性评估

环节 实施难度 工作量 可行性
失败归因沉淀 复用第 7 篇反思器 + 持久化 高,1 周可上线
人工纠偏吸收 关键词/意图识别 + 写入 高,含金量最高先做
检索注入 语义检索 + Prompt 注入 高,复用第 4 篇 RAG 组件
治理(去重/冲突/衰减) 语义比对 + 定时任务 中,需 embedding 服务
技能自举 候选识别 + 代码生成 + 测试 中,可人工审核兜底
防污染闭环 置信度规则 + 复审队列 中,规则先行

落地建议:按 ROI 排序三步走——第一周上"失败沉淀 + 人工纠偏吸收"(覆盖 70% 价值),第二周接"检索注入"(复用 RAG 基建),治理与技能自举在经验库过千条后再启动。不要一开始就追求全自动技能生成,人工审核技能晋升是前期最划算的保险。


八、总结

前八篇解决的是"Agent 怎么把任务做好",本篇解决的是"Agent 怎么把下一次做得更好"。经验学习闭环的四个支点:

  • 沉淀:失败、成功、纠偏三源入账,人工信号最贵最优先
  • 治理:去重、冲突、衰减、归档——经验库是资产还是负债,全看治理
  • 复用:限量限权注入,高频路径固化为技能,把"记住"升级为"不需要记"
  • 防污染:加分慢减分快,错误经验快速出局

一个会踩坑、会复盘、会遗忘的 Agent,才配叫"越用越聪明"——进化不是记住一切,而是留住对的、忘掉错的、固化稳的。


欢迎在评论区分享:你的 Agent 有哪些"踩了 50 次还在踩"的坑?

本文承接系列前八篇(记忆/协作/工具/知识/安全/评估/规划/人机协作),经验引擎与第 7 篇规划引擎、第 4 篇 RAG、第 6 篇可观测性直接对接,完整实现可通过 recall_history(op="search", query="经验学习闭环 技能自举 遗忘机制") 获取。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。