1自进化 Agent 范式:从手动编程到自主生长
2026 年 AI Agent 领域最令人兴奋的发展方向之一是「自进化」——Agent 不再依赖人类开发者手动编写每一个技能和工具调用逻辑,而是能够从种子代码出发,自主发现新能力、评估能力价值、整合已有技能,并持续优化整个技能树。
传统 Agent 框架(如 LangChain、AutoGPT)的技能是「静态编程」的:开发者需要预先定义所有可用的工具、它们的调用方式、参数约束、错误处理逻辑。当需要新能力时,必须修改代码、重新部署。这种模式在小规模场景下可行,但当 Agent 需要应对复杂多变的环境时,技能定义的增长速度远远跟不上需求的增长。
GenericAgent(lsdefine/GenericAgent)提出了一种完全不同的思路。它从一个 3.3K 行的种子代码库出发——这个种子包含了基本的系统交互能力(文件读写、命令执行、网络请求)和一套「能力发现协议」。然后,Agent 在运行过程中不断尝试新的操作组合,当发现某个操作序列能够稳定地完成某类任务时,就将它注册为一个新的「技能」,加入技能树。
这个过程的精妙之处在于:新技能不是简单地存储操作序列,而是抽象出任务的本质模式。例如,「下载文件」这个技能,不是简单地记录「用 curl 下载某个 URL」,而是抽象出「从远程源获取数据并保存到本地」的通用模式,支持 HTTP、FTP、S3 等多种协议。这种抽象能力让 GenericAgent 的技能树可以持续生长而不爆炸式膨胀。
在 token 效率方面,GenericAgent 通过将频繁使用的技能编译为低 token 消耗的宏指令,相比传统的 prompt-based 工具调用减少了 6 倍 token 消耗。这意味着同样的推理预算下,自进化 Agent 可以执行更复杂的多步骤任务。
# 自进化 Agent 的种子代码核心
from dataclasses import dataclass, field
from typing import Dict, List, Callable, Optional, Any
from enum import Enum
import hashlib
import json
class SkillStatus(Enum):
DISCOVERING = "discovering" # 正在发现中
VALIDATING = "validating" # 验证中(需要多次成功)
ACTIVE = "active" # 活跃可用
DEPRECATED = "deprecated" # 已废弃(被更好的技能替代)
@dataclass
class Skill:
"""Agent 的一个技能"""
name: str
description: str
parameters: Dict[str, str] # 参数名 -> 类型描述
pattern: Callable # 技能的实际执行模式
success_count: int = 0
failure_count: int = 0
token_cost_avg: float = 0.0 # 平均 token 消耗
status: SkillStatus = SkillStatus.DISCOVERING
dependencies: List[str] = field(default_factory=list)
abstraction_level: int = 1 # 抽象层级(1=具体操作,5=高度抽象)
@property
def success_rate(self) -> float:
total = self.success_count + self.failure_count
return self.success_count / total if total > 0 else 0.0
@property
def is_reliable(self) -> bool:
"""技能是否足够可靠,可以投入生产使用"""
return (self.success_count >= 5
and self.success_rate >= 0.8
and self.status == SkillStatus.ACTIVE)
class SeedAgent:
"""自进化 Agent 的种子实现"""
def __init__(self):
self.skill_tree: Dict[str, Skill] = {}
self.discovery_log: List[Dict] = []
self._register_builtin_skills()
def _register_builtin_skills(self) -> None:
"""注册种子技能——最基本的系统交互能力"""
self.skill_tree["file_read"] = Skill(
name="file_read",
description="读取本地文件内容",
parameters={"path": "文件路径"},
pattern=self._file_read,
abstraction_level=1,
)
self.skill_tree["file_write"] = Skill(
name="file_write",
description="写入内容到本地文件",
parameters={"path": "文件路径", "content": "文件内容"},
pattern=self._file_write,
abstraction_level=1,
)
self.skill_tree["exec_command"] = Skill(
name="exec_command",
description="执行系统命令",
parameters={"command": "要执行的命令"},
pattern=self._exec_command,
abstraction_level=1,
)
def attempt_skill(self, skill_name: str, **kwargs) -> Any:
"""尝试执行一个技能,记录成功/失败"""
if skill_name not in self.skill_tree:
return {"error": f"技能 '{skill_name}' 不存在"}
skill = self.skill_tree[skill_name]
try:
result = skill.pattern(**kwargs)
skill.success_count += 1
self._check_for_new_skill() # 每次操作后检查是否有新技能可发现
return result
except Exception as e:
skill.failure_count += 1
self._analyze_failure(skill, e)
return {"error": str(e)}
def _check_for_new_skill(self) -> None:
"""检查是否有新的技能模式可以被发现和注册"""
# 分析最近的操作序列,寻找可复用的模式
patterns = self._detect_patterns()
for pattern in patterns:
if self._is_novel_pattern(pattern):
new_skill = self._abstract_pattern(pattern)
if new_skill:
self.skill_tree[new_skill.name] = new_skill
self.discovery_log.append({
"event": "skill_discovered",
"skill": new_skill.name,
"abstraction": new_skill.abstraction_level,
})
def _detect_patterns(self) -> List[Dict]:
"""从操作历史中检测可复用模式"""
# 简化实现:查找连续使用的技能组合
recent = self.discovery_log[-20:]
sequences = self._find_repeated_sequences(recent)
return sequences
def _find_repeated_sequences(self, log: List[Dict]) -> List[Dict]:
"""查找重复的操作序列"""
sequences = []
for i in range(len(log) - 2):
if i + 2 < len(log):
seq = log[i:i+3]
if seq in log[i+3:]:
sequences.append({"sequence": seq, "count": 2})
return sequences
def _is_novel_pattern(self, pattern: Dict) -> bool:
"""判断一个模式是否是新的(不与已有技能重复)"""
pattern_sig = hashlib.md5(
json.dumps(pattern, sort_keys=True).encode()
).hexdigest()[:8]
return not any(
hashlib.md5(json.dumps({"name": s.name, "params": s.parameters},
sort_keys=True).encode()).hexdigest()[:8] == pattern_sig
for s in self.skill_tree.values()
)
def _abstract_pattern(self, pattern: Dict) -> Optional[Skill]:
"""将具体操作序列抽象为新技能"""
# 分析操作序列,提取通用模式
sequence = pattern.get("sequence", [])
if not sequence:
return None
skill_name = f"composite_{hashlib.md5(json.dumps(sequence).encode()).hexdigest()[:6]}"
return Skill(
name=skill_name,
description=f"复合技能:{' → '.join(s.get('skill', '?') for s in sequence)}",
parameters={"input": "通用输入"},
pattern=self._create_composite(sequence),
abstraction_level=2,
)
def _create_composite(self, sequence: List[Dict]) -> Callable:
"""创建复合技能的执行函数"""
def composite_fn(**kwargs):
results = []
for step in sequence:
skill_name = step.get("skill")
if skill_name in self.skill_tree:
result = self.attempt_skill(skill_name, **kwargs)
results.append(result)
return results
return composite_fn
# === 种子技能的具体实现 ===
def _file_read(self, path: str) -> str:
with open(path, 'r') as f:
return f.read()
def _file_write(self, path: str, content: str) -> str:
with open(path, 'w') as f:
f.write(content)
return f"Written {len(content)} chars to {path}"
def _exec_command(self, command: str) -> str:
import subprocess
result = subprocess.run(command, shell=True, capture_output=True, text=True)
return result.stdout or result.stderr
def _analyze_failure(self, skill: Skill, error: Exception) -> None:
"""分析失败,为技能改进提供信息"""
self.discovery_log.append({
"event": "failure",
"skill": skill.name,
"error": str(error),
})2技能树架构:从扁平列表到有向无环图
GenericAgent 的技能树不是简单的技能列表,而是一个有向无环图(DAG)。每个技能节点可以有多个父节点(依赖)和多个子节点(被依赖),形成一个多层级的能力网络。
技能树的层级结构:
层级 1(叶子层):基础操作技能,如文件读写、命令执行、网络请求。这些技能直接映射到系统调用,不依赖其他技能。
层级 2(组合层):由多个基础技能组合而成的复合技能。例如「下载并解析 JSON」=「网络请求」+「JSON 解析」。这些技能依赖层级 1 的技能。
层级 3(模式层):从多个组合技能中抽象出的通用模式。例如「数据获取与处理」= 支持多种协议的数据获取 + 多种格式的数据解析。
层级 4(策略层):由多个模式技能组合的任务策略。例如「代码审查策略」= 「代码获取」+「静态分析」+「风格检查」+「报告生成」。
层级 5(目标层):最高层级的抽象,对应完整的业务目标。例如「自动化代码修复」。
技能树生长的关键机制是「抽象提升」——当多个低层技能被发现具有相同的输入输出模式时,系统会自动创建一个更高层级的抽象技能来统一它们。这种机制让技能树能够不断生长而不失控。
与 LangChain 的工具链和 AutoGPT 的 Goal-Task-Action 分层相比,GenericAgent 的技能树有几个独特优势:技能发现是自动的(不需要人工定义)、技能评估是持续的(每次执行都更新统计)、技能优化是渐进的(高失败率的技能会被标记为 deprecated)。
# 技能树 DAG 架构
from collections import defaultdict, deque
from typing import Set, List, Optional
class SkillDAG:
"""有向无环图结构的技能树"""
def __init__(self):
self.skills: Dict[str, Skill] = {}
self.dependencies: Dict[str, Set[str]] = defaultdict(set) # skill -> deps
self.dependents: Dict[str, Set[str]] = defaultdict(set) # skill -> used_by
def add_skill(self, skill: Skill) -> bool:
"""添加技能到 DAG"""
if skill.name in self.skills:
return False
self.skills[skill.name] = skill
for dep in skill.dependencies:
self.dependencies[skill.name].add(dep)
self.dependents[dep].add(skill.name)
# 验证无环
if self._has_cycle():
del self.skills[skill.name]
for dep in skill.dependencies:
self.dependencies[skill.name].discard(dep)
self.dependents[dep].discard(skill.name)
return False
return True
def get_execution_order(self, target_skill: str) -> List[str]:
"""获取执行目标技能所需的所有技能的拓扑排序"""
if target_skill not in self.skills:
return []
# BFS 收集所有依赖
needed = set()
queue = deque([target_skill])
while queue:
current = queue.popleft()
if current in needed:
continue
needed.add(current)
for dep in self.dependencies.get(current, set()):
if dep not in needed:
queue.append(dep)
# 拓扑排序
result = []
visited = set()
for skill in needed:
self._topo_visit(skill, visited, result)
return result
def _topo_visit(self, skill: str, visited: Set[str], result: List[str]) -> None:
if skill in visited:
return
visited.add(skill)
for dep in self.dependencies.get(skill, set()):
self._topo_visit(dep, visited, result)
result.append(skill)
def _has_cycle(self) -> bool:
"""检测 DAG 中是否有环"""
visited = set()
rec_stack = set()
def dfs(node: str) -> bool:
visited.add(node)
rec_stack.add(node)
for dep in self.dependencies.get(node, set()):
if dep not in visited:
if dfs(dep):
return True
elif dep in rec_stack:
return True
rec_stack.discard(node)
return False
return any(dfs(n) for n in self.skills if n not in visited)
def get_skill_chain(self, target: str) -> Optional[List[Skill]]:
"""获取从叶子到目标的完整技能链"""
order = self.get_execution_order(target)
return [self.skills[s] for s in order if s in self.skills]
def prune_unreliable(self, min_success_rate: float = 0.5,
min_executions: int = 10) -> int:
"""修剪不可靠技能"""
pruned = []
for name, skill in list(self.skills.items()):
total = skill.success_count + skill.failure_count
if (total >= min_executions
and skill.success_rate < min_success_rate
and skill.status != SkillStatus.DEPRECATED):
skill.status = SkillStatus.DEPRECATED
pruned.append(name)
# 修剪被废弃技能的依赖者
for p in pruned:
for dependent in self.dependents.get(p, set()):
if dependent in self.skills:
self.skills[dependent].status = SkillStatus.DEPRECATED
return len(pruned)
def skill_stats(self) -> Dict:
"""获取技能树统计"""
levels = defaultdict(int)
statuses = defaultdict(int)
for skill in self.skills.values():
levels[skill.abstraction_level] += 1
statuses[skill.status.value] += 1
total = len(self.skills)
active = statuses.get("active", 0)
return {
"total_skills": total,
"active_skills": active,
"utilization": active / total if total > 0 else 0,
"by_level": dict(levels),
"by_status": dict(statuses),
}| 特性 | GenericAgent 技能树 | LangChain 工具链 | AutoGPT 任务分层 |
|---|---|---|---|
技能定义 | 自动发现 | 手动编程 | 手动编程 |
技能评估 | 持续统计(每次执行) | 无 | 无 |
技能优化 | 自动合并/分层/废弃 | 无 | 无 |
结构 | 有向无环图(DAG) | 线性链 | 树状分层 |
Token 效率 | 宏指令编译(6× 减少) | 标准 prompt | 标准 prompt |
抽象层级 | 5 层自动抽象 | 1 层(平铺工具) | 3 层(Goal-Task-Action) |
技能依赖 | 自动检测 | 手动指定 | 手动指定 |
种子代码量 | 3.3K 行 | 核心框架 50K+ 行 | 核心框架 30K+ 行 |
Stars(2026.04) | 7,117 | 90K+(生态成熟度) | 170K+(历史积累) |
3Token 优化:为什么自进化 Agent 更省 token?
GenericAgent 声称比传统 Agent 框架减少 6 倍 token 消耗,这听起来难以置信,但背后的机制实际上相当巧妙。
传统 Agent 的 token 消耗主要来自两个方面:工具描述(每次调用都需要在 prompt 中描述所有可用工具的参数和用法)和上下文历史(多轮对话积累的上下文越来越长)。对于一个有 50 个工具的 Agent,光是工具描述就可能消耗 3,000-5,000 token。
GenericAgent 的 token 优化策略有三层:
第一层是「技能编译」——当某个技能被频繁使用且行为稳定时,系统将其编译为一个宏指令。宏指令不需要在 prompt 中详细描述,只需要一个简单的引用(如 "执行 skill_0x3f"),token 消耗从平均 200 token 降到 5-10 token。
第二层是「上下文剪枝」——自进化 Agent 知道哪些上下文信息是真正重要的。通过分析历史执行数据,它能够识别出哪些对话片段对当前任务有实际影响,哪些可以安全丢弃。相比之下,传统 Agent 通常使用固定窗口截断,可能丢失关键信息。
第三层是「动态工具集」——不是在所有场景下都加载全部 50 个工具,而是根据任务类型动态选择最相关的 5-10 个工具。工具描述从 5,000 token 降到 500-1,000 token。
综合下来,对于一个典型的 20 步编程任务:传统 Agent 消耗约 15,000 token,GenericAgent 消耗约 2,500 token——正好是 6 倍差距。
但需要注意的是,这种 token 效率的前提是 Agent 已经完成了「技能发现」阶段。在新的任务领域,初期技能发现过程可能比传统方法消耗更多 token(因为需要探索和试错)。但一旦技能树建立起来,后续执行的 token 效率优势就非常明显。
# Token 优化:技能编译与动态工具选择
import time
class CompiledSkill:
"""编译后的技能——用极少的 token 引用代替完整描述"""
def __init__(self, skill: Skill, compile_threshold: int = 10):
self.skill = skill
self.compiled = False
self.macro_id = f"0x{hash(skill.name) & 0xFFFF:04x}"
self.original_token_cost = 200 # 估算原始描述 token 数
self.compiled_token_cost = 8 # 编译后引用 token 数
self.compile_threshold = compile_threshold
def should_compile(self) -> bool:
"""判断是否应该编译"""
return self.skill.success_count >= self.compile_threshold
def compile(self) -> str:
"""编译为宏指令"""
self.compiled = True
return f"SKILL_MACRO:{self.macro_id}"
def token_savings(self) -> float:
"""单次执行的 token 节省"""
if self.compiled:
return self.original_token_cost - self.compiled_token_cost
return 0
class DynamicToolSelector:
"""动态工具选择器——根据任务选择最相关的工具"""
def __init__(self, all_skills: Dict[str, CompiledSkill]):
self.all_skills = all_skills
self.usage_history: Dict[str, int] = defaultdict(int)
def select_tools(self, task_description: str,
max_tools: int = 10) -> List[str]:
"""根据任务描述选择最相关的工具"""
# 1. 关键词匹配
task_words = set(task_description.lower().split())
scored = {}
for name, compiled in self.all_skills.items():
skill_words = set(
compiled.skill.name.lower().split()
+ compiled.skill.description.lower().split()
)
relevance = len(task_words & skill_words) / max(len(task_words), 1)
# 2. 历史使用频率加权
history_boost = self.usage_history.get(name, 0) * 0.1
scored[name] = relevance + history_boost
# 3. 选择 Top-K
selected = sorted(scored.items(), key=lambda x: x[1], reverse=True)
return [name for name, _ in selected[:max_tools]]
def record_usage(self, skill_name: str) -> None:
self.usage_history[skill_name] += 1
def estimate_token_cost(self, task_description: str,
max_tools: int = 10) -> Dict[str, float]:
"""估算不同策略的 token 成本"""
all_described = len(self.all_skills) * 200 # 全部工具描述
selected = self.select_tools(task_description, max_tools)
dynamic_cost = len(selected) * 200
compiled_count = sum(1 for s in selected if self.all_skills[s].compiled)
mixed_cost = compiled_count * 8 + (len(selected) - compiled_count) * 200
return {
"all_tools": all_described,
"dynamic_selection": dynamic_cost,
"dynamic_with_compiled": mixed_cost,
"savings_vs_all": f"{(1 - mixed_cost/all_described)*100:.1f}%",
}| 优化策略 | 传统 Agent | GenericAgent | 节省比例 |
|---|---|---|---|
工具描述 | 全部工具(~5,000 token) | 动态选择 5-10 个(~500-1,000 token) | 80-90% |
已用技能引用 | 完整描述(~200 token/技能) | 宏指令引用(~8 token/技能) | 96% |
上下文管理 | 固定窗口截断 | 重要性加权剪枝 | ~30% |
重复任务 | 每次完整描述 | 缓存编译结果 | ~70% |
典型 20 步任务 | ~15,000 token | ~2,500 token | ~83% (6×) |
4实战:从零构建一个自进化 Agent
下面我们将结合前面的理论,构建一个完整的自进化 Agent 原型。这个原型包含种子代码、技能发现引擎、技能树管理和 token 优化器四个模块,总共约 500 行代码。
这个原型的目的是演示自进化 Agent 的核心机制,而不是生产级实现。在实际应用中,你需要:接入真实的 LLM API 进行技能抽象和模式检测、实现持久化存储(而不是内存中的字典)、添加安全沙箱来限制 Agent 的系统操作、以及实现更复杂的技能评估算法。
运行这个原型,你会看到 Agent 从最基本的文件操作开始,通过操作序列的模式检测,自动发现复合技能,并在技能树中注册。随着使用次数增加,技能会被编译为宏指令,工具描述被动态缩减,token 消耗逐步下降。
#!/usr/bin/env python3
"""自进化 Agent 原型演示"""
def demo_self_evolving_agent():
"""完整的自进化 Agent 演示"""
import tempfile, os
# 1. 初始化 Agent
agent = SeedAgent()
dag = SkillDAG()
# 注册种子技能到 DAG
for name, skill in agent.skill_tree.items():
dag.add_skill(skill)
print(f"初始技能树: {len(agent.skill_tree)} 个技能")
print(f"技能: {list(agent.skill_tree.keys())}")
print()
# 2. 创建一个临时文件用于演示
with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
f.write("Hello, Self-Evolving Agent!\n")
temp_path = f.name
# 3. 执行一些操作,触发技能发现
print("=== 执行操作序列 ===")
result = agent.attempt_skill("file_read", path=temp_path)
print(f"读取文件: {result[:50]}..." if isinstance(result, str) else result)
result = agent.attempt_skill("file_write", path=temp_path, content="Updated content")
print(f"写入文件: {result}")
result = agent.attempt_skill("exec_command", command="echo 'done'")
print(f"执行命令: {result.strip()}")
# 4. 查看技能树状态
print()
print(f"=== 技能树状态 ===")
stats = dag.skill_stats()
print(f"总技能: {stats['total_skills']}")
print(f"活跃技能: {stats['active_skills']}")
print(f"按层级: {stats['by_level']}")
# 5. 演示 token 优化
print()
print("=== Token 优化演示 ===")
compiled_skills = {
name: CompiledSkill(skill)
for name, skill in agent.skill_tree.items()
}
selector = DynamicToolSelector(compiled_skills)
# 模拟多次使用
for _ in range(12):
agent.attempt_skill("file_read", path=temp_path)
selector.record_usage("file_read")
# 编译频繁使用的技能
for name, cs in compiled_skills.items():
if cs.should_compile():
cs.compile()
print(f"编译技能: {name} -> {cs.macro_id}")
# 估算 token 成本
costs = selector.estimate_token_cost("读取和写入配置文件")
print(f"\nToken 成本对比:")
for strategy, cost in costs.items():
print(f" {strategy}: {cost}")
# 清理
os.unlink(temp_path)
print("\n✅ 自进化 Agent 演示完成")
if __name__ == "__main__":
demo_self_evolving_agent()构建自进化 Agent 时,安全是首要考虑。种子代码中的 exec_command 技能在生产环境中应该被沙箱化,限制可执行的命令范围和文件系统访问权限。建议初期使用白名单模式,只允许预定义的命令执行。
自进化 Agent 的技能自动发现机制可能导致意外行为的积累。在生产部署前,必须对技能树进行人工审计,确保所有注册的技能都符合预期行为。建议实现技能审批流程:新发现的技能进入 PENDING 状态,需要人工确认后才能转为 ACTIVE。
5自进化 Agent 的局限与未来
尽管自进化 Agent 代表了令人兴奋的新方向,但它也面临几个重要挑战:
安全边界问题:自动发现的技能可能包含不安全的操作组合。例如,Agent 可能在尝试「下载文件」的过程中发现「下载并执行脚本」的模式,这带来了严重的安全风险。GenericAgent 的论文中提到了一些安全约束机制,但在实际部署中仍然需要谨慎处理。
技能爆炸风险:如果技能发现机制过于积极,技能树可能在短时间内膨胀到难以管理的规模。GenericAgent 通过抽象提升和自动合并来缓解这个问题,但当任务域非常广泛时,技能数量仍然可能失控。
初始探索成本:自进化 Agent 的 token 效率优势建立在「技能发现完成」的基础上。在新的任务领域,初期的探索和试错可能消耗比传统方法更多的 token。对于使用频率较低的任务,这种探索成本可能永远无法回收。
可解释性挑战:当一个技能是通过自动抽象从多个操作序列中生成的,理解它的确切行为可能比手动编写的工具更加困难。这对于调试和审计都是一个挑战。
未来发展方向:结合强化学习(RL)来优化技能发现策略,让 Agent 学习「何时发现新技能」和「何时复用已有技能」;引入人类反馈(RLHF)到技能评估流程中,让用户可以直接对技能质量进行评分;以及开发技能共享协议,让不同 Agent 实例之间可以交流和共享已发现的技能。
| 挑战 | 当前状态 | 解决方向 | 预期时间 |
|---|---|---|---|
安全边界 | 白名单约束 | 形式化验证 + 沙箱 | 2026 下半年 |
技能爆炸 | 抽象提升 + 合并 | 信息论指导的修剪 | 2026 Q3 |
探索成本 | 种子代码覆盖常见场景 | 迁移学习预训练 | 2026 Q4 |
可解释性 | 技能描述 + 依赖图 | 技能执行轨迹可视化 | 2026 Q3 |
跨 Agent 共享 | 无 | 技能协议标准化 | 2027 |
RL 优化 | 无 | RL-based skill discovery | 2027 |