AI Agent 自我进化:构建"越用越聪明"的经验学习闭环
作者: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 经验从哪里来?三个源头
- 失败归因:任务失败后的结构化复盘(最经典,但只是其一)
- 成功路径提炼:某类任务反复用同样的步骤成功——这条路径本身就是经验
- 人工纠偏信号:用户说"不对,应该先备份"——这是最贵也最值得吸收的经验
只吸收失败教训的 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 次归因 → "数据库确实太慢,经验没错" → 错误经验置信度反而上升
防线有三道:
- 归因交叉验证:归因结果与工具报错信息做一致性检查,归因与事实矛盾则拒绝入库
- 置信度封顶:模型自产经验 confidence 上限 0.85,只有被后续成功验证过才可继续上调
- 验证标记:经验被命中并带来成功时,更新
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)
三个注入纪律:
- 限量:最多 5 条,经验注入过多会稀释任务指令本身的注意力
- 限权:低置信经验不注入,宁缺毋滥
- 留痕:本次任务命中了哪些经验,写入 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 技能晋升的门槛
不是所有经验都配当技能,晋升需同时满足:
- 高频:命中 ≥10 次
- 稳定:路径参数化后无分支歧义("有时先 A 有时先 B"的不能固化)
- 验证:以技能形态试运行 5 次全部成功
- 可逆:技能失败时的回滚路径明确
六、从零搭建经验学习引擎
#!/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="经验学习闭环 技能自举 遗忘机制")获取。
- 点赞
- 收藏
- 关注作者
评论(0)