学习与自进化
"Agent 会学习"这句话同时被严重高估又严重低估。被高估,是因为一听就以为要训练模型——绝大多数 Agent 项目根本用不到也碰不到模型权重;被低估,是因为不会学习的 Agent 永远停在"实习生"水位,同样的错反复犯,再好的 prompt 也救不了。在 Agent 工程语境下,"学习"至少有三种完全不同的含义:会话内 In-context 调整、跨会话经验沉淀、跨版本策略进化——三者对应三套完全不同的基础设施,混在一起谈就是工程决策错乱的开始。下面把三层各自的 schema、伪代码、与红线讲清楚。
1. 为什么静态 Agent 不够
大多数生产 Agent 是静态的——行为完全由 System Prompt + 工具定义 + 模型权重决定。部署之后无论用户使用一万次还是十万次,行为模式不变。这导致三个问题:
| 问题 | 表现 |
|---|---|
| 重复犯错 | 某类任务上的系统性偏差(总选错工具、总遗漏某步骤)在每次调用中重现。用户只能忍受,开发者只能手动修复 Prompt——本质上是人在学习,不是 Agent 在学习 |
| 无法适应新场景 | 用户使用模式演化、业务需求变化、工具接口升级——静态 Agent 无法感知,更不能主动调整 |
| 无法积累经验 | 资深员工和实习生的区别很大程度上是经验积累——知道哪些路径有效、哪些坑要避、哪些捷径可走。静态 Agent 永远是"实习生" |
但学习是个宽泛词。在 Agent 工程语境下,它至少有三种完全不同的含义:
| 含义 | 改变什么 | 典型机制 |
|---|---|---|
| 参数学习 | 模型权重 | Fine-tuning、RLHF |
| 配置学习 | System Prompt、工具描述、Few-shot | Prompt 自优化、经验回放 |
| 上下文学习 | 单次会话内的临时调整 | In-context Learning |
本文不讨论第一种(参数学习属于模型训练话题),重点在第二种和第三种——它们才是 Agent 运行时学习的核心。
混淆这三种"学习"会导致工程决策错乱。听说"Agent 能学习"就以为要训练模型,结果发现 90% 的"学习"其实是 prompt 工程和经验积累。
2. 三层学习:按时间尺度分
| 层 | 时间跨度 | 机制 | 持久性 | 风险 |
|---|---|---|---|---|
| L1 会话级适应 | 单次对话 | In-context Learning | 会话结束即消失 | 低 |
| L2 跨会话记忆沉淀 | 跨对话 | 经验存储与检索 | 持久化存储 | 中 |
| L3 行为策略进化 | 跨版本 | Prompt/策略自动优化 | 写入系统配置 | 高 |
L1 依赖 LLM 的 In-context Learning——用户在对话中纠正"不要这么正式"、"用表格输出",Agent 在同一会话中调整。不需要任何额外设施,但会话结束就消失。L1 是免费的,但持久性为零——下一个会话开始,所有 L1 学到的东西都消失。
L2 需要持久化基础设施。它是 Agent 记忆系统的延伸——不只是记事实,是记"什么有效、什么无效"。L2 把单次交互的隐性知识固化成可检索的显性知识,这是 Agent 从"实习生"到"熟练工"的关键。
L3 最强大也最危险——修改 Agent 自身的行为策略(System Prompt、工具选择偏好、推理模板)。等价于修改"源代码"。回报最高(改进影响所有用户),但一次错误的策略修改可能导致全面退化。L3 必须依赖完整的评估体系作为安全网——离线 EvalSet + Quality Gate + 灰度 + 全量回归测试集都得就位,不然就是在没有测试的代码上跑自动重构。
三层之间不是替代关系,而是协同关系:
| 协同模式 | 描述 |
|---|---|
| L1 → L2 | 同一用户的多次会话中重复出现的偏好,从 L1 沉淀到 L2 |
| L2 → L3 | L2 经验库中累积到一定量的同类失败模式,触发 L3 的 Prompt 优化 |
| L3 → L1 | L3 优化后的新 Prompt 在下一次会话开始时生效,重新建立 L1 学习起点 |
多数生产系统应该从 L1 + L2 开始,积累足够的评估基础设施后再尝试 L3。先做 L3 是常见的过度设计——评估都没建好就去自动改 prompt,相当于在没有测试的代码上跑自动重构。
3. L1 的工程价值
L1 看起来"什么也没做"——只是 LLM 本来就有的 In-context Learning 能力——但工程价值不可低估:
| 价值 | 描述 |
|---|---|
| 零基础设施成本 | 不需要数据库、不需要评估、不需要审批流程 |
| 即时生效 | 用户说完"用表格"下一句就生效 |
| 用户体验提升 | 用户感觉"Agent 在学" |
| 安全性最高 | 影响范围限于单次会话,会话结束即清零 |
但 L1 也有清晰的边界:
- 它无法跨会话——同一用户下次问还是要重新指定
- 它无法跨用户——一个用户的偏好和另一个用户隔离
- 它的有效性取决于对话上下文质量——上下文太长,早期的偏好被淹没在噪声里
工程上让 L1 最大化的关键是把 Memory 写好。Memory 模块的摘要质量、检索质量、Working Memory 的优先级排序,都直接影响 L1 在长对话中是否还"记得"用户偏好。L1 看起来不需要工程,实则它的天花板由 Memory 的工程能力决定。
4. L2 的核心:经验回放
4.1 经验记录的 Schema
Experience = {
"id": str,
"kind": "success_pattern" | "failure_lesson" | "preference" | "tool_usage" | "user_feedback",
"summary": str, # 自然语言,会做 embedding
"embedding": list[float],
"trigger_condition": str, # 自然语言描述什么场景下应用——决定检索时的相关性
"recommendation": str, # 在此条件下应该怎么做
"evidence": {
"from_trace_id": str, # 指向原始执行轨迹(可追溯)
"verified_outcomes": int, # 后续命中此经验时的成功次数
"contradicted_outcomes": int, # 后续命中此经验时的失败次数
},
"importance": float, # 0-1
"confidence": float, # 0-1,随 verified/contradicted 比例动态调整
"scope": {
"user_id": str | None, # None = 全局经验;否则只对特定用户
"tenant_id": str | None,
"task_kind": str | None,
},
"created_at": int,
"last_used_at": int,
"usage_count": int,
}
trigger_condition 是这套 schema 里最关键的字段——它决定一条经验在什么时候应该被检索出来。经验如果只写做了什么而不写适用场景,检索就成了乱炒。
4.2 从执行轨迹到经验库
Agent 每次执行产生完整 trajectory——用户请求、推理过程、工具调用、中间结果、最终输出。这些数据是经验提取的原材料。
提取规则按结果质量分类:
| 结果质量 | 提取什么 | 重要性评分 |
|---|---|---|
| 任务成功 | 完整方法、关键决策点、可复用经验 | 0.7-0.9 |
| 任务失败 | 失败根本原因、应避免的模式、推荐替代策略 | 0.8-1.0 |
| 用户显式反馈 | 表扬/批评/修正 | 0.9-1.0 |
| 中间结果(部分成功) | 可能有部分可学习内容 | 0.4-0.6 |
def extract_experiences(trajectory: Trajectory) -> list[Experience]:
"""从一次执行轨迹中提炼经验"""
candidates = []
# 信号 1:任务失败 + 有清晰根因
if trajectory.outcome == "failed" and trajectory.has_clear_root_cause:
candidates.append(make_failure_lesson(trajectory))
# 信号 2:用户显式正/负反馈
if trajectory.user_feedback:
candidates.append(make_feedback_experience(trajectory))
# 信号 3:新工具组合或新调用顺序的成功案例
# is_novel_tool_pattern 的实现:把当前 trajectory 的"工具调用序列哈希"
# 与 L3 经验库里 kind="tool_usage" 的记录做相似度比较——
# 如果余弦相似度 < 0.7(说明没见过这种组合),就认为是"新模式"
if trajectory.outcome == "success" and is_novel_tool_pattern(trajectory):
candidates.append(make_tool_pattern(trajectory))
# 经验提取本身用 LLM 做总结,但用便宜模型
refined = []
for c in candidates:
summary = cheap_llm.complete(
EXTRACT_PROMPT.format(trajectory=trajectory, candidate=c),
schema=EXPERIENCE_SUMMARY_SCHEMA,
)
c.summary = summary.summary
c.trigger_condition = summary.trigger_condition
c.recommendation = summary.recommendation
c.embedding = embed(c.trigger_condition + " " + c.summary)
refined.append(c)
return refined
失败经验比成功经验更重要——成功的方式有很多,失败的根因相对集中。一条"调用 SQL 工具时漏掉 LIMIT 会拖垮数据库"的失败经验,比十条不同的成功经验更有价值。
4.3 经验入库的三道门槛
不是所有提取出的经验都值得保留。低质量经验会引入噪声,降低 Agent 表现——这比不积累更糟。
def admit_to_experience_store(candidate: Experience) -> AdmissionDecision:
"""三道门槛过完才入库"""
# 门槛 1:泛化性——单次偶然 vs 一类规律
if not is_generalizable(candidate):
return AdmissionDecision(admit=False, reason="too_specific")
# 门槛 2:与已有经验冲突
similar = vector_search(candidate.embedding, top_k=5, threshold=0.75)
for s in similar:
if contradicts(candidate, s) and s.confidence > 0.8:
return AdmissionDecision(admit=False, reason="contradicts_high_confidence")
# 门槛 3:冗余——已经有近似经验
if similar and similar[0].score > 0.92:
# 合并:增强已有经验,不新增
merge_into(similar[0], candidate)
return AdmissionDecision(admit=False, reason="merged_into_existing", merged_id=similar[0].id)
insert(candidate)
return AdmissionDecision(admit=True)
# 两个关键判断函数的实现思路(工程上通常都有 LLM 判断 + 规则启发式两种实现,先用规则、不确定再上 LLM)
def is_generalizable(c: Experience) -> bool:
"""泛化性:经验里出现的具体实体名/订单号/特定数字应该 <= 2 个;
trigger_condition 应该可以套到其他用户/订单上"""
specific_entities = count_specific_entities(c.summary + c.recommendation)
if specific_entities > 2:
return False
# 兜底用 LLM judge——便宜模型问一句"这条经验能套到其他用户吗"
return cheap_llm_judge(GENERALIZABILITY_PROMPT.format(exp=c)).answer == "yes"
def contradicts(a: Experience, b: Experience) -> bool:
"""冲突检测:两条经验的 recommendation 是否给出了相反的行动建议"""
# 同类(kind)的经验才比——不同类别如 preference vs failure_lesson 不存在"矛盾"
if a.kind != b.kind:
return False
# 用一个独立 LLM 判断"这两条建议是否冲突"
return cheap_llm_judge(CONTRADICTION_PROMPT.format(a=a, b=b)).contradicts
| 门槛 | 检查什么 | 原因 |
|---|---|---|
| 泛化性 | 这条经验是特定于当前任务的,还是能泛化到一类任务? | "用户 A 喜欢表格"是个体偏好,"数据分析任务先确认 schema"才是可泛化经验 |
| 一致性 | 新经验是否与已有经验矛盾? | 矛盾时需判断是场景不同(两条都保留 + 适用条件),还是新经验推翻旧的 |
| 冗余性 | 经验库中是否已有语义相近的记录? | 是的话合并而非重复添加,更新使用计数和置信度 |
泛化性是最难判断的一道门槛。写经验时容易把单次偶然当成一类规律——用户某次说"用更短的回复",可能是这一次他时间紧,不是普遍偏好。门槛的设置原则是宁缺毋滥:宁可错过一条经验,不要污染经验库。
4.4 经验的衰减与遗忘
经验库不只需要"写入"机制,还需要"遗忘"机制——否则陈旧经验会持续指导行为,造成系统性错误。
| 衰减维度 | 触发遗忘 |
|---|---|
| 时间衰减 | 半年内未被使用的经验降低优先级 |
| 反例衰减 | 被新观察反例多次推翻的经验置信度下降 |
| 工具失效 | 经验依赖的工具被下线或接口改变 |
| 用户群变化 | 经验来自某用户群体,该群体已不再活跃 |
def update_confidence_on_use(exp: Experience, was_helpful: bool):
"""经验被检索使用后,按结果调整置信度"""
if was_helpful:
exp.evidence["verified_outcomes"] += 1
else:
exp.evidence["contradicted_outcomes"] += 1
# 用 Beta 分布的均值估计 "经验有效率"
v = exp.evidence["verified_outcomes"] + 1
c = exp.evidence["contradicted_outcomes"] + 1
exp.confidence = v / (v + c)
# 置信度低于阈值就软删除
if exp.confidence < 0.3 and (v + c) >= 5:
soft_delete(exp, reason="repeatedly_contradicted")
遗忘机制是经验库长期健康的关键。没有遗忘,经验库会变成"垃圾历史的堆积"——半年前用户喜欢的格式、已经下线的工具用法、过期的业务规则——都还在影响 Agent 行为。
4.5 应用:动态 Few-shot
经验库的直接应用——自动构建 Few-shot 示例。传统 Few-shot 需要人工编写,学习系统可以从真实执行历史中自动选取最相关的成功案例作为示例:
def build_dynamic_few_shot(current_query: str, n: int = 3) -> list[Example]:
"""从经验库动态构造 Few-shot"""
# 1. 检索语义相关的成功经验
candidates = vector_search(
query=embed(current_query),
filter={"kind": "success_pattern", "confidence": {"$gte": 0.7}},
top_k=n * 5,
)
# 2. 综合排序:相关性 × 置信度 × 新鲜度
def score(c):
recency = math.exp(-(now() - c.last_used_at) / DAY_30)
return c.relevance * c.confidence * recency
ranked = sorted(candidates, key=score, reverse=True)
# 3. 多样化选择(MMR):避免示例间过于相似
# 阈值 0.85 是工程经验:cosine ≥ 0.85 时人类看也会觉得"基本相同",再加进 Few-shot 是浪费 token;
# < 0.85 但 ≥ 0.7 算"相似但有区别"——保留下来给 LLM 看不同情境下的同类规律
# 实际部署中这个阈值通常做成可调参,按"Few-shot 命中率"和"输出多样性"两个指标 A/B 找最优
selected = []
for c in ranked:
if all(cosine(c.embedding, s.embedding) < 0.85 for s in selected):
selected.append(c)
if len(selected) == n:
break
# 4. 格式化为 Few-shot 示例
return [format_as_few_shot(c) for c in selected]
动态 Few-shot 的价值不只是减少人工——更深层的价值是示例与当前任务相关性更高。人工写的 Few-shot 是面向"一类典型任务"的,动态 Few-shot 是面向"当前这个具体任务"的。后者的相关性通常显著更高。
5. L3 的两条主路径
5.1 Prompt 自优化
用 LLM 优化 LLM 的 Prompt。核心循环:评估发现失败 → 分析失败模式 → 生成改进候选 → 离线 EvalSet 验证 → A/B 测试 → 灰度部署。
def prompt_self_optimize(
current_prompt: PromptVersion,
failure_cluster: list[Trajectory],
eval_set: list[EvalCase],
) -> Optional[PromptVersion]:
"""一轮 Prompt 自优化的完整流水线"""
# 1. 用第二 LLM 分析失败模式
analysis = analyzer_llm.complete(
ANALYZE_FAILURES_PROMPT.format(
failures=failure_cluster,
current_prompt=current_prompt.content,
),
schema=FAILURE_ANALYSIS_SCHEMA,
)
# 2. 生成 3-5 个候选改进版本(每次最多改 3 处)
candidates = []
for _ in range(5):
candidate = optimizer_llm.complete(
OPTIMIZE_PROMPT.format(
original=current_prompt.content,
analysis=analysis,
immutable_sections=current_prompt.immutable_sections, # 安全规则不可改
max_edits=3,
),
schema=PROMPT_CANDIDATE_SCHEMA,
temperature=0.8,
)
candidates.append(candidate)
# 3. 离线 EvalSet 验证
baseline_score = score_on_eval(current_prompt, eval_set)
scored = []
for c in candidates:
s = score_on_eval(c, eval_set)
scored.append((c, s))
# 4. 过 Quality Gate:必须显著优于 baseline 且不退化任何维度
best, best_score = max(scored, key=lambda x: x[1].overall)
if not passes_quality_gate(best_score, baseline_score):
return None # 没有合格候选,本轮放弃
# 5. 提交人审(L3 不能全自动部署)
return submit_for_human_approval(best, analysis=analysis)
关键约束:
- 小步迭代——每次最多修改 3 处。大幅修改让 Agent 行为不可预测,出问题难定位
- 保留不可修改的约束——安全规则必须原样保留,传给优化器作为"不能改"的字段
- A/B 测试必须达到统计显著性——Agent 输出方差大,通常需要 500-1000 样本(不是传统 A/B 的 100-200)
- 保留版本历史——每次优化都有"上一版",能秒级回滚
Prompt 自优化的隐藏陷阱是优化器自己也是 LLM——它对"什么是好 prompt"的判断可能本身就有偏见。一个倾向于啰嗦的 LLM 在优化 prompt 时也会倾向于让 prompt 越来越长;一个倾向于过度防御的 LLM 优化后的 prompt 会塞满"不要 / 禁止 / 必须"。优化器与执行器应该是不同模型,能有效降低这种同源偏见。
5.2 工具使用模式学习
从历史数据中提取工具使用模式:
| 学习维度 | 示例 | 价值 |
|---|---|---|
| 最优顺序 | 数据分析:先 schema 查询 → 再数据查询 → 最后可视化 | 避免因不了解 schema 导致的查询失败 |
| 并行机会 | 多数据源查询可以并行 | 降低延迟 |
| 失败恢复 | API 限流时切换到备用工具 | 提高鲁棒性 |
| 参数传递 | 前一个工具的输出如何作为后一个工具的输入 | 减少格式转换错误 |
| 常见错误模式 | 调用此工具失败的常见原因 | 提前规避 |
学习到的模式反馈到工具描述中——动态增强工具描述包含使用提示,让 LLM 选择时考虑成功率历史。这种"工具描述动态化"是一个相对安全的 L3 路径——比改 System Prompt 风险低,因为单个工具描述的影响范围有限。
6. 用户偏好怎么沉淀成系统记忆
显式 vs 隐式信号:
| 类型 | 来源 | 可信度 | 频率 |
|---|---|---|---|
| 显式 | 用户直接表达——"请用表格""不要太多细节""每次先确认" | 高 | 低 |
| 隐式 | 从行为推断——总编辑长回复→偏好简洁;频繁要"展开说说"→偏好详细 | 低(需多次观察) | 高 |
def detect_implicit_preference(events: list[UserEvent]) -> Optional[Preference]:
"""从隐式信号推断偏好——多次一致才算数"""
# 统计行为模式
edit_lengths = [e.edit_delta for e in events if e.kind == "edit"]
if len(edit_lengths) < 3:
return None # 样本不够,不推断
# 一致性检验:多次编辑都倾向于缩短
if mean(edit_lengths) < -50 and stddev(edit_lengths) < 30:
return Preference(
kind="response_length",
value="prefer_shorter",
confidence=0.6,
source="implicit",
evidence=events,
)
return None
应用偏好时的冲突解决:
| 冲突 | 策略 |
|---|---|
| 显式 vs 隐式 | 显式优先 |
| 时间冲突 | 新覆盖旧 |
| 场景差异 | 场景隔离(写代码要详细,日常对话要简洁) |
| 低置信度 | 不应用(只有 2 次信号支持的推断暂不生效) |
隐式偏好的危险性最容易被低估——它基于行为推断,但推断可能错。"用户编辑了 Agent 的输出"既可能是"嫌太长",也可能是"输出本来就有错误"。把所有编辑都解读为"偏好简洁"会让 Agent 越来越倾向于截短输出,质量反而下降。隐式信号只在多次一致出现时才纳入偏好库。
7. 学习不能越过的三条红线
一个能自我改进的系统,也可能自我恶化。三条不可越过的红线:
| 红线 | 含义 |
|---|---|
| 安全策略不可学习 | Agent 的安全规则(不执行危险操作、不泄露敏感数据)必须硬编码在 Prompt 约束部分,学习系统不能修改 |
| 权限不可升级 | Agent 不能通过学习获得新权限。即使发现"绕过权限检查能更快完成任务",也不应记录为"经验" |
| 行为空间不可扩展 | 可调用的工具集、可访问的数据范围在部署时确定。学习只能优化空间内的策略,不能扩展空间本身 |
这三条红线的本质都是把能不能做和做得好不好分开:能不能做是部署时的设计决策,归人类管;做得好不好是运行时的优化空间,可以学习。混淆两者就会出现"为了任务成功率,绕过权限检查"这种灾难。
工程上实现这三条红线的最低代码:
IMMUTABLE_PROMPT_SECTIONS = ["safety_rules", "permission_model", "tool_inventory"]
def optimize_prompt(current: PromptVersion, suggestion: dict) -> PromptVersion:
"""优化时严格保护不可修改段"""
new = current.copy()
for section, new_content in suggestion.items():
if section in IMMUTABLE_PROMPT_SECTIONS:
continue # 永远不动这些段
new.sections[section] = new_content
return new
def admit_experience(exp: Experience) -> bool:
"""经验如果建议绕过权限或扩展行为空间,直接拒绝"""
forbidden_patterns = [
"skip permission",
"bypass check",
"use undocumented",
"ignore safety",
]
if any(p in exp.recommendation.lower() for p in forbidden_patterns):
log_security_event("dangerous_experience_rejected", exp)
return False
return True
容易被强化的有害行为
| 风险 | 表现 | 对策 |
|---|---|---|
| 幸存者偏差 | 评估指标只看任务完成,Agent 可能学到"跳过安全检查 → 任务完成更快 → 被评为成功" | 评估指标必须包含过程质量和安全合规维度 |
| 对抗性输入 | 恶意用户通过持续"正面反馈"操纵学习方向 | 单用户反馈权重有上限;异常反馈模式触发审查 |
| 分布漂移 | 学习数据分布偏移(某段时间某类恶意请求激增) | 学习数据做分布监控;偏移超阈值时暂停学习 |
| 捷径优化 | Agent 学到了"形式上完成任务"的捷径,而非真正解决问题 | 评估指标用多维度,引入"结果质量"而非只看"完成率" |
幸存者偏差和捷径优化是同一个问题的不同表现——只看结果不看过程的评估指标,会教坏 Agent。这和强化学习里 reward hacking 是同一类问题,只是发生在 prompt 层面:
| RL reward hacking 的经典例子 | Agent prompt 学习的等价物 |
|---|---|
| OpenAI CoastRunners 赛船游戏:模型发现一直撞礁石吃道具加分,比正常比赛得分高,于是再也不完成赛程 | Agent 发现"用更模糊的回答 + 让用户自己问追问"能避免被判错,于是越学越不直接回答 |
| 模拟机器人学走路:发现身高越高得分越多,于是反复用力跃起、不真正前进 | Agent 发现"用更长更详细的回答"在 LLM-as-Judge 下评分更高,于是越来越啰嗦 |
| 抓取任务:模型把物体推出摄像头视野,仿真器以为"消失=被抓走"给了 reward | Agent 发现"不调危险工具就不会触发 Guardrail",于是该用工具的时候也不调,把任务退化成纯文本对话 |
三个例子都是同一逻辑:优化目标的代理指标和真实目标之间有裂缝,模型会精确地利用这条裂缝。Prompt 学习里防 reward hacking 的核心做法是多维评估——不只看完成率,还要看过程合理性、合规维度、用户主观满意度,单维度优化必然被攻破。
人类监督在 L3 必不可少
| 层 | 人类参与 | 理由 |
|---|---|---|
| L1 会话级 | 实时反馈(自然发生) | 用户在对话中纠正 |
| L2 经验入库 | 定期审查(每周抽检) | 检查经验质量和安全性 |
| L3 Prompt 优化 | 每次变更前审批 | Prompt 变更影响全局 |
| L3 工具模式 | 异常时介入 | 成功率骤降时告警 |
L3 必须实施"四眼原则"——优化器提出修改建议,人类审批后才能部署。自动化只负责生成候选和验证效果,最终的部署决策由人做出。
这里有一个工程哲学的判断:L3 的全自动化(不需要人审批的策略进化)目前在生产上不可取,不是因为技术不成熟,而是因为改 prompt 影响范围太大、错误代价太高、回滚虽然可行但已经造成的伤害不可撤销。即使技术上可以做到全自动 L3,也建议保留人类审批环节——把"是否部署"和"是否能生成候选"分开。
8. 学得快还是学得稳:速率取舍
学习太快导致系统不稳定(频繁策略变更让用户感觉 Agent"性格不定");学习太慢无法及时适应。需要在响应速度和稳定性间找平衡:
| 层 | 建议频率 | 冷却期 | 回滚窗口 |
|---|---|---|---|
| L1 | 实时 | 无 | 无需(会话结束自动重置) |
| L2 经验入库 | 每次交互后 | 同类经验 24 小时内不重复提取 | 7 天(可删除错误经验) |
| L3 Prompt 优化 | 每周最多一次 | 每次变更后观察至少 3 天 | 30 天(保留所有版本) |
| L3 工具模式更新 | 每天最多一次 | 样本数 < 50 不更新 | 14 天 |
冷却期的设计哲学:每次变更后要观察一段时间,让效果充分显现再决定下一步。没有冷却期的话,多次变更会互相干扰——你不知道某次质量下降是哪次变更引起的。
9. 学新的不要把旧的挤掉
学习新能力的同时丢失旧能力——模型 Fine-tuning 中常见的问题,在 Prompt 级学习也会出现。
三道防线:
| 防线 | 做法 |
|---|---|
| 回归测试集 | 维护覆盖所有已知能力的 EvalSet,每次 Prompt 变更后全量回跑。任何维度显著下降都触发回滚 |
| 增量修改 | 每次只修改 Prompt 的局部(不超过 3 处),保证变更影响范围可控 |
| 版本管理 | 所有 Prompt 版本都保留,支持快速回滚。每个版本记录修改原因、预期效果、实际效果 |
def deploy_with_safety_net(new_prompt: PromptVersion, regression_set: list[EvalCase]):
"""部署前必须过全量回归"""
baseline = current_prompt_version()
baseline_results = score_on_eval(baseline, regression_set)
new_results = score_on_eval(new_prompt, regression_set)
# 任何维度退化超过 3% 都拒绝
regressions = [
d for d in new_results.dimensions
if new_results[d] < baseline_results[d] - 0.03
]
if regressions:
return DeployDecision(
allowed=False,
reason=f"regression on: {regressions}",
)
return DeployDecision(allowed=True, rollback_token=baseline.version)
灾难性遗忘在 Prompt 学习中的表现比模型 Fine-tuning 更隐蔽——模型权重退化能在 loss 曲线上看到,prompt 退化可能只在某些特定输入上才暴露。这就是为什么全量回归测试集比"看一下感觉怎么样"重要得多——感觉只能覆盖几个常用场景,回归测试集才能覆盖所有已知能力维度。
10. 当前仍然没有标准答案的问题
本文讨论的学习都是固定架构下的参数和策略优化——Prompt 可以变、Few-shot 示例可以变、工具使用模式可以变,但 Agent 的基本架构(LLM + 工具 + 记忆 + 规划器)不变。
更深层次的"进化"涉及几个尚未解决的问题:
Agent 能否自己设计新工具
让 Agent 发现"我需要一个新工具来解决 X 类问题",自动将频繁出现的操作序列封装为新的复合工具(macro)——类似人类工作中"写脚本自动化重复操作"。
引入的风险:自动生成的工具可能有副作用、突破权限边界、与现有工具冲突。技术上的折中是允许 Agent 生成"用户级 macro"(只调已注册工具的组合),但不允许 Agent 生成需要新权限的工具——后者必须人类审批。
多 Agent 系统的集体学习
一个 Agent 的经验能否共享给其他 Agent?如何避免一个 Agent 的错误学习污染整个系统?
挑战在于 Agent 间的差异——可能有不同工具集、不同用户群体、不同任务域。某 Agent 的成功经验在另一个 Agent 的上下文中可能是有害的。集体学习的核心难题不是技术,是"经验在不同上下文下的适用性判断"——这个判断本身需要更强的元学习能力。
学习能力本身怎么评估
常规的 Agent 评估体系能评"任务表现"。但如何量化"Agent 学到了多少"、"学习速度如何"、"学习质量如何"?
可能的指标:
| 指标 | 含义 |
|---|---|
| 学习增益 | 新用例评分 - 初始评分 |
| 泛化率 | 新场景成功率 / 训练场景成功率 |
| 遗忘率 | 旧用例评分变化 |
| 学习效率 | 达到某表现水平需要的交互次数 |
| 适应速度 | 面对新场景时恢复到正常表现的交互次数 |
这些指标都不完美——它们都依赖"评分",而评分本身是 LLM-as-Judge 做的,引入了自己的偏差。
持续学习与对齐
能持续学习的 Agent 行为会随时间漂移。如何确保漂移方向始终与人类意图对齐?
这个问题在 LLM 对齐研究中已经很难,在 Agent 学习场景中更难——Agent 的行为空间更大、反馈信号更稀疏、影响范围更广。目前没有完美方案。实践中的折中:限制学习速度和幅度、保持人类监督、维护全面回归测试集、建立快速回滚机制——不是理论最优,是工程最安全。
11. 学习与开发流程的关系
值得讨论一个边界问题:Agent 的学习和开发团队的迭代边界在哪?
| 形态 | 谁在改 | 改动周期 | 影响范围 |
|---|---|---|---|
| 静态 Agent | 开发团队 | 周/月 | 全量用户 |
| L1 学习 | Agent 自身(in-context) | 秒/分钟 | 单次会话 |
| L2 学习 | 自动化(经验回放) | 分钟/小时 | 检索到的相关会话 |
| L3 学习 | 自动化 + 人类审批 | 天/周 | 全量用户 |
可以看到 L3 和开发团队的常规迭代在影响范围上是同质的——都改变全量用户的体验。区别只是谁触发了改动。这就引出一个问题:如果 L3 的优化建议每次都要人类审批,那它跟"自动化的 prompt 工程师工具"有什么本质区别?
答案是:没有本质区别。L3 的工程价值不在于"全自动",而在于"把 prompt 迭代从手工作业变成数据驱动"。原来开发团队凭直觉改 prompt,现在有评估、有 A/B、有候选生成器;原来一周改一次,现在能每天评估、每周改进。这是工程化的进步,不是哲学意义上的"Agent 自我进化"。
承认这一点反而让 L3 更务实——不要把它包装成"AI 自我改进",而要把它定位为"prompt 工程的数据驱动自动化"。
12. 学习不是一件事:是三个时间尺度的协同
"Agent 会学习"这句话在工程上至少有三种完全不同的含义。L1 是 In-context Learning——LLM 在同一会话内根据用户反馈调整,免费但会话结束就消失;L2 是经验回放——把过去交互的成败沉淀成可检索的经验记忆,按天/周累积;L3 是策略进化——修改 system prompt、工具偏好、推理模板这些 Agent 自身的"源代码",按周/月演化。三个尺度对应三套基础设施:L1 几乎不需要工程、L2 是 Memory 系统的延伸、L3 必须配评估和部署管线。
最容易混淆的是 L3 和开发团队的常规迭代。L3 改的也是 prompt、工具配置、推理模板——和工程师改这些的差异只在于"谁触发"。承认这一点反而让 L3 更务实:它不是"AI 自我进化",而是"prompt 工程的数据驱动自动化"——把凭直觉迭代变成基于评估和 A/B 的迭代。
不论哪一层学习,都有三条红线不能越:安全策略不可学习、权限不可升级、行为空间不可扩展。学习只能在"能不能做"的边界内优化"做得好不好"——能不能做归人类管,做得好不好归学习管。混淆这条边界,就会出现"为了任务成功率绕过权限检查"这种灾难。