1. 项目概述从“技能零”到“技能满”的智能体进化之路最近在开源社区里一个名为“SkillZero”的项目引起了我的注意。这个由ZJU-REAL实验室开源的项目名字起得很有意思——“技能零”。乍一听你可能会觉得这是个面向初学者的入门工具但深入研究后才发现它瞄准的是一个更前沿、也更棘手的问题如何让一个大型语言模型LLM驱动的智能体在没有预先编程或大量演示数据的情况下自主地学会并掌握完成复杂任务所需的“技能”。这让我想起了自己早期做自动化脚本的经历。那时候每遇到一个新需求比如从网页上抓取特定格式的数据或者把一堆散乱的文件按规则整理好我都得手动写一套代码。虽然最终能解决问题但过程繁琐而且代码的复用性很差。后来有了RPA机器人流程自动化工具情况好了些可以通过录制操作来生成流程但一旦界面或流程稍有变化整个“机器人”就可能罢工。SkillZero试图解决的正是这个问题的下一代版本如何让一个AI智能体像人一样通过尝试、观察结果、总结经验最终自己摸索出一套完成任务的最佳方法并且这个方法还能被抽象、存储和复用。简单来说SkillZero是一个基于大型语言模型的技能发现与组合框架。它的核心目标不是执行某个固定任务而是让智能体在探索一个环境比如一个软件界面、一个API集合或者一个虚拟世界时能够自动识别出哪些动作序列是有效的、可重复的“技能”并将这些技能构建成一个不断增长的“技能库”。当下次遇到类似或更复杂的任务时智能体就可以像搭积木一样从技能库中调用和组合已有的技能而不是从头开始摸索。这个项目适合谁呢首先是对AI智能体和自动化感兴趣的研究者和开发者。如果你想了解如何让LLM超越单纯的对话或代码生成真正具备在复杂环境中“做事”的能力SkillZero提供了一个绝佳的研究范本。其次是那些面临大量重复性、但又有一定变化性的数字流程的团队比如数据工程师、测试工程师或运营人员。SkillZero所探索的“技能学习”范式可能是未来构建自适应、可进化业务流程自动化系统的关键技术基础。即使你只是对AI的前沿应用感到好奇这个项目也能让你直观地感受到当前最先进的AI模型在“自主探索与学习”方面走到了哪一步。2. 核心设计思路让智能体学会“归纳”与“复用”SkillZero的设计哲学非常清晰将“任务求解”分解为“技能发现”与“技能复用”两个核心循环。这听起来简单但实现起来需要精巧地设计智能体与环境交互的每一个环节。传统的智能体要么是硬编码的规则引擎不灵活要么是依赖大量标注数据训练的强化学习模型成本高、泛化差。SkillZero巧妙地利用了大语言模型的规划能力、代码生成能力和自然语言理解能力走出了一条新路。2.1 核心循环拆解探索、抽象、规划、执行整个系统的运行可以看作是两个紧密耦合的循环第一个循环技能发现与提炼循环。智能体被赋予一个目标例如“在GUI计算器应用中计算(1234)56”。一开始它的技能库是空的。它会像一个人一样尝试最基础的操作点击按钮、输入文本、读取屏幕信息。LLM作为它的“大脑”会根据当前目标“计算表达式”和观察到的环境状态计算器界面规划出一个初步的动作序列比如先点“1”再点“2”再点“”…。执行这些动作后环境会给出反馈显示结果。关键的一步来了智能体会反思这一系列动作和最终结果。如果任务成功了LLM会尝试对这一连串的低级动作进行“抽象”和“命名”。例如它可能将“点击数字1、点击数字2”抽象为“输入数字12”将“点击、点击3、点击4”抽象为“输入加法和数字34”。更进一步它可能将整个“(点击1,2,,3,4,,5,6,)”的成功序列抽象为一个名为“计算器_执行四则运算”的技能并记录下这个技能对应的代码或动作模板以及其适用的前提条件界面处于初始状态且为标准计算器布局。注意这里的“抽象”能力完全依赖于LLM。模型需要理解这些底层动作在语义上的共同目标。这就要求用于驱动智能体的LLM必须具备较强的推理和概括能力。实践中项目可能会使用如GPT-4、Claude-3或开源的DeepSeek等先进模型。第二个循环基于技能的层次化规划与执行循环。当技能库中积累了一些技能后智能体再面对新任务时其策略就发生了变化。它首先会检查技能库看看有没有现成的技能可以直接使用或者通过组合现有技能来解决新问题。例如新任务是“计算(98-76)/11”。智能体发现技能库里有“计算器_执行四则运算”但参数不同。这时LLM会进行“高层规划”它将任务分解为“使用‘计算器_执行四则运算’技能并传入参数序列[9,8,-,7,6,/,1,1,]”。这个高层计划会被“编译”成具体的底层动作序列去执行。如果现有技能无法直接解决智能体可能会尝试修改技能参数或者退回到基础探索模式去发现新的技能片段再将其加入库中。这种设计的优势显而易见效率提升避免了每次任务都从零开始的“蛮力探索”。技能一旦被学会就成为可复用的资产。可解释性增强技能库本身就是一个可读的、高级别的“操作手册”记录了智能体学会了什么以及如何做。支持复杂任务通过技能的层次化组合理论上可以解决非常复杂的任务因为复杂任务被分解为了已知技能的执行序列。2.2 关键技术组件与选型考量要实现上述循环SkillZero需要几个核心组件每个组件的选型都直接影响系统性能1. 环境交互器这是智能体的“手”和“眼睛”。它需要能够接收智能体发出的动作如click(button_id),type(text),read_screen()并将其转换为对真实环境如浏览器、桌面应用、API的实际操作同时将环境的反馈如屏幕截图、DOM树、API返回的JSON收集回来。选型上对于Web环境可能会选用Playwright或Selenium因为它们支持可靠的自动化操作和丰富的状态获取。对于桌面GUI可能使用pyautogui结合pytesseractOCR的方式。关键在于这个交互器需要提供一种结构化的、可供LLM理解的环境状态表示比如将网页简化为一个可操作的UI元素列表及其属性。2. 技能库管理器这是智能体的“记忆库”。它负责技能的存储、检索和更新。每个技能条目至少包含技能名称/描述自然语言描述如“在搜索框输入关键词并点击搜索按钮”。技能实现可以是一段可执行的代码Python函数也可以是一组参数化的动作模板。前提条件技能执行前环境必须满足的状态。后置条件/效果技能执行后预期会达成的状态。成功历史该技能过去被成功调用的记录可用于评估其可靠性。存储方式可以是简单的JSON文件、向量数据库便于通过语义搜索检索相似技能或更结构化的SQLite数据库。选型取决于对检索速度和语义匹配精度的要求。3. 大语言模型引擎这是智能体的“大脑”是整个系统的核心。它承担多项职责任务规划根据目标和当前状态生成动作序列或技能调用序列。技能抽象从成功的低级动作轨迹中归纳出高级技能。代码/参数生成将抽象技能或高层规划具体化为可执行的代码或动作参数。反思与评估判断任务是否成功分析失败原因。这里最大的考量是成本与能力的平衡。最强的闭源模型如GPT-4在推理和代码生成上表现优异但API调用成本高且不适合处理需要频繁交互的长期任务。开源模型如CodeLlama、DeepSeek-Coder可以本地部署成本可控但可能需要更精细的提示工程和上下文管理才能达到相近效果。SkillZero项目可能需要采用混合策略例如用强模型进行关键的“技能抽象”和“复杂规划”用轻量级模型处理常规的动作选择。3. 实操流程构建一个简易的技能学习智能体理解了核心思路后我们可以尝试构建一个极度简化的原型来体验SkillZero的核心流程。我们将模拟一个“Web表单填写”环境。3.1 环境搭建与基础定义首先我们定义环境和动作。为了简化我们不启动真实浏览器而是用一个Python字典模拟一个简单的用户注册页面状态。# 模拟环境状态 class MockWebEnv: def __init__(self): self.state { current_page: register, elements: [ {id: name, type: text_input, value: , description: 用户名输入框}, {id: email, type: text_input, value: , description: 邮箱输入框}, {id: submit_btn, type: button, description: 提交按钮}, ], message: # 用于显示操作结果消息 } def execute_action(self, action: dict): 执行动作更新环境状态 action_type action.get(type) element_id action.get(element_id) value action.get(value) if action_type type: for elem in self.state[elements]: if elem[id] element_id and elem[type] text_input: elem[value] value self.state[message] f已在 {element_id} 中输入: {value} return True elif action_type click: for elem in self.state[elements]: if elem[id] element_id and elem[type] button: # 模拟提交逻辑 name next((e[value] for e in self.state[elements] if e[id] name), ) email next((e[value] for e in self.state[elements] if e[id] email), ) if name and in email: self.state[message] f提交成功用户 {name} 已注册。 else: self.state[message] 提交失败请填写完整且有效的邮箱。 return True self.state[message] f动作执行失败: {action} return False def get_observation(self): 返回LLM可读的环境观察 obs f当前页面: {self.state[current_page]}\n obs 可操作元素:\n for elem in self.state[elements]: obs f - [{elem[id]}] ({elem[type]}): {elem[description]} if elem[type] text_input: obs f, 当前值: {elem[value]} obs \n obs f系统消息: {self.state[message]}\n return obs3.2 实现核心循环逻辑接下来我们实现一个简化的智能体循环。这里我们用openai库调用大模型实际使用时需替换为你的API密钥并假设我们已经有了一个空的技能库。import openai import json import time class SimpleSkillZeroAgent: def __init__(self, env, llm_client, skill_lib_fileskill_lib.json): self.env env self.llm llm_client self.skill_lib self._load_skill_lib(skill_lib_file) self.max_attempts 5 def _load_skill_lib(self, filepath): try: with open(filepath, r) as f: return json.load(f) except FileNotFoundError: return [] # 初始技能库为空 def _save_skill_lib(self): with open(skill_lib.json, w) as f: json.dump(self.skill_lib, f, indent2) def _call_llm(self, prompt, system_msg你是一个有帮助的AI助手。): # 这里是模拟调用实际应替换为真实的API调用 # 为简化演示我们返回一个固定响应 # 实际项目中这里会是 openai.ChatCompletion.create(...) 或类似调用 print(f[LLM Prompt]: {prompt[:200]}...) time.sleep(0.5) # 模拟延迟 # 根据不同的提示类型返回不同的模拟响应 if 下一步动作 in prompt: return {action: {type: type, element_id: name, value: 张三}} elif 抽象为技能 in prompt: return {skill_name: 填写用户名, implementation: type_text(\name\, username), precondition: 当前页面为register且存在id为name的输入框} elif 规划技能 in prompt and self.skill_lib: return {plan: [使用技能:填写用户名参数:李四, 使用技能:填写邮箱参数:lisiexample.com, 点击提交按钮]} else: return {action: {type: click, element_id: submit_btn}} def run_task(self, task_description): print(f\n 开始新任务: {task_description} ) attempts 0 while attempts self.max_attempts: attempts 1 print(f\n--- 尝试第 {attempts} 次 ---) # 1. 获取当前环境观察 obs self.env.get_observation() print(f[环境状态]:\n{obs}) # 2. 规划根据任务和技能库决定下一步是调用技能还是探索 # 这里简化处理如果技能库为空或任务不匹配则进入探索模式 use_skill_plan False if self.skill_lib: # 简单检查是否有相关技能实际应用需语义匹配 if 填写 in task_description and any(填写 in s.get(skill_name, ) for s in self.skill_lib): use_skill_plan True if use_skill_plan: plan_prompt f 任务: {task_description} 当前环境状态: {obs} 现有技能库: {json.dumps(self.skill_lib, ensure_asciiFalse)} 请规划一个使用现有技能来完成任务的步骤序列。以JSON格式输出包含一个plan字段值为步骤列表。 llm_response self._call_llm(plan_prompt) # 解析并执行规划此处简化跳过解析 print(f[高层规划]: 使用技能组合执行) # ... 执行规划中的每个技能步骤 else: # 探索模式让LLM直接生成下一个低级动作 action_prompt f 任务: {task_description} 当前环境状态: {obs} 请根据任务和当前状态决定下一个最合理的原子操作动作。 可用的动作类型: type在输入框中打字, click点击按钮。 请以严格的JSON格式输出只包含一个名为action的对象其内部有type, element_id, 必要时有value字段。 例如: {{action: {{type: type, element_id: name, value: Alice}}}} llm_response self._call_llm(action_prompt) # 3. 解析并执行动作这里简化了JSON解析 print(f[LLM响应]: {llm_response}) # 假设我们解析出了一个动作 action_to_take {type: type, element_id: name, value: 测试用户} # 4. 执行动作 success self.env.execute_action(action_to_take) print(f[执行动作]: {action_to_take}, 结果: {success}) print(f[环境反馈]: {self.env.state[message]}) # 5. 检查任务是否完成简化检查消息是否包含成功 if 成功 in self.env.state[message]: print(f\n*** 任务完成 ***) # 6. 技能抽象如果本次探索成功且动作序列有抽象价值则尝试提炼技能 if not use_skill_plan: # 如果是探索成功的 self._abstract_skill(task_description, [action_to_take]) # 简化只传最后一个动作 break if attempts self.max_attempts: print(f\n*** 任务失败达到最大尝试次数。 ***) def _abstract_skill(self, task_desc, action_sequence): 尝试从成功的动作序列中抽象出技能 print(\n 尝试抽象新技能...) abstraction_prompt f 智能体刚刚通过执行一系列原子操作成功完成了任务: {task_desc} 执行的操作序列最后一步是关键: {action_sequence} 请将这个成功的操作模式抽象为一个可复用的、有意义的技能。 以JSON格式输出包含字段: - skill_name: 技能名称简短描述性中文或英文 - implementation: 技能的实现方式描述或伪代码 - precondition: 执行此技能所需的环境前提条件 llm_response self._call_llm(abstraction_prompt) # 解析响应添加到技能库 try: # 这里应是解析JSON的逻辑 new_skill {skill_name: 模拟技能, implementation: type_text(name, $1), precondition: 页面有name输入框} self.skill_lib.append(new_skill) self._save_skill_lib() print(f[新技能已添加]: {new_skill}) except: print([技能抽象失败]) # 模拟运行 if __name__ __main__: env MockWebEnv() agent SimpleSkillZeroAgent(env, llm_clientNone) # 简化版未接入真实LLM # 第一个任务探索并学习 agent.run_task(注册一个用户用户名为张三) # 假设技能库已更新再次运行类似任务 print(\n *50) print(技能库已更新再次执行类似任务...) # 这里可以修改env的state重置环境然后运行新任务 # agent.run_task(注册一个用户用户名为李四)这个极度简化的原型演示了SkillZero的核心循环感知环境、规划/探索、执行、反馈、抽象技能。在实际的SkillZero项目中每个环节都复杂得多例如LLM的提示工程、技能的语义匹配与检索、长序列动作的可靠执行与回滚等。3.3 实操心得与参数调优在尝试复现或基于SkillZero思想进行开发时有几个关键点需要特别注意1. 环境观察的表示是关键给LLM的环境观察不能是原始的像素或复杂的DOM树必须经过精心设计的信息压缩和结构化。好的观察表示应该包含当前界面的语义描述这是什么页面、可交互对象的列表及其属性id, 类型, 当前值, 是否可点击等、上次操作的结果或系统消息。这相当于为LLM提供了清晰的“游戏画面UI”而不是一堆像素点。2. 提示工程决定智能体上限驱动智能体的LLM提示词Prompt需要精心设计。通常需要采用多角色提示或链式思考CoT提示。例如系统提示定义智能体的角色“你是一个自动化助手”、目标“通过探索学习技能”、输出格式约束。规划提示需要让模型先“思考”再“输出”。例如“请先分析当前任务与技能库的匹配度。如果匹配输出技能调用计划如果不匹配请逐步推理下一步最该执行的基础动作是什么。”抽象提示引导模型从具体动作中找出通用模式。例如“请忽略具体的输入值‘张三’关注操作的对象和类型。将‘在id为name的输入框输入文本’这一模式进行概括。”3. 技能粒度的权衡技能抽象得太粗如“完成用户注册”复用性强但实现复杂且可能不稳定注册流程可能会变。技能抽象得太细如“点击id为name的输入框”虽然稳定但复用价值低组合起来也繁琐。一个实用的策略是分层技能库底层是原子操作点击、输入中层是常见复合操作填写表单字段、提交表单高层是业务流用户注册、数据查询。智能体优先尝试匹配高层技能失败时再逐层降级。4. 失败处理与探索策略智能体在探索中必然会失败。关键在于如何从失败中学习。除了抽象成功技能还应建立失败案例库。当某个动作导致错误如元素未找到、无效操作应记录该动作及其上下文并在未来规划时避免在相同上下文中重复此动作。这相当于给智能体增加了“避坑”经验。4. 典型应用场景与扩展思考SkillZero所代表的“技能学习”范式其应用潜力远不止于演示中的简单表单填写。它可以被应用到许多需要与数字环境交互的复杂场景中。4.1 场景一软件测试自动化传统的自动化测试需要测试工程师编写大量的测试用例脚本。当软件UI或流程变更时维护成本很高。基于SkillZero的智能体可以这样工作初始探索给定一个软件版本如一个Web应用智能体的目标是“探索所有功能”。它会随机或按策略点击按钮、输入数据。技能发现在探索中它会自动将“登录”、“创建一条数据”、“搜索过滤”等成功操作序列抽象为技能存入库中。回归测试当新版本发布时智能体可以调用技能库中的技能自动执行一系列核心用户旅程如“登录-创建项目-添加成员-查看报表”并比较结果与基线版本的差异自动报告异常。自适应维护如果新版本中“登录”按钮的ID变了导致旧技能失败智能体可以自动进入探索模式重新学习“登录”技能并更新技能库实现测试套件的自我修复。4.2 场景二业务流程的发现与文档化在许多企业存在大量依赖员工手工操作、未被IT系统固化的业务流程Shadow IT。这些流程效率低、易出错、且知识难以传承。可以部署一个受控的桌面智能体记录员工完成某个业务如“月度财务报告编制”的所有操作切换软件、复制数据、整理Excel、发送邮件等。智能体在后台运行SkillZero算法将这一系列操作抽象为“从系统A导出数据”、“清洗Excel表格”、“邮件合并发送”等技能并自动生成该业务流程的标准化文档甚至可执行的脚本骨架。这相当于完成了业务的自动挖掘与初步自动化。4.3 场景三个性化助手的能力扩展现在的AI助手如Copilot大多基于静态的指令集或插件。想象一个未来版的个人助手它通过观察你日常的电脑操作来学习你的习惯和工作流。例如它看到你每次收到名为“数据日报”的邮件后都会下载附件用特定Python脚本处理然后将结果上传到某个内部网盘。经过几次观察它可以将这一系列操作学习为“处理数据日报”的技能。之后当你再收到此类邮件时助手可以直接询问“检测到‘数据日报’邮件需要我自动处理吗”获得确认后它自动调用该技能完成全部工作。这使得助手的能力可以随着用户的使用而不断增长和个性化。4.4 面临的挑战与解决思路当然将SkillZero从研究原型推向实际应用还有重重挑战1. 探索效率与安全性在复杂环境中盲目探索效率极低且危险可能误删数据。解决方案是混合探索策略结合基于模型的规划利用LLM的世界知识进行有根据的猜测、模仿学习提供少量人类演示作为种子技能和安全沙盒在隔离环境中训练。2. 技能的泛化与匹配学习到的技能在稍有变化的环境中可能失效。例如为“Chrome浏览器中的Gmail登录”学习的技能无法直接用于“Edge浏览器中的Outlook登录”。需要提升技能的抽象层次和匹配算法的语义理解能力。可以利用计算机视觉CV识别UI元素的语义角色“这是一个登录按钮”而非依赖其易变的ID或坐标。3. 长期依赖与复杂规划对于需要多步骤、长周期才能完成的任务智能体的规划能力面临考验。需要引入更强大的长期记忆和子目标分解机制。技能库本身可以作为一种记忆记录达到某种状态的方法。高层规划器需要能将“撰写年度报告”分解为“收集各部门数据”、“制作图表”、“汇总成文”、“格式审查”等子任务并递归地调用或学习相应技能。4. 评估与奖励稀疏在真实任务中“成功”的反馈往往是稀疏且延迟的比如流程最后才弹出“提交成功”。如何在中途评估动作的好坏可以引入基于模型的奖励预测让LLM对当前状态进行评估“距离完成任务更近了吗”或者设计课程学习从简单的、反馈明确的子任务开始训练逐步增加难度。5. 常见问题与实战调试记录在实际尝试实现或应用类似SkillZero的思路时我遇到并总结了一些典型问题及其解决思路这对于避开初期弯路很有帮助。5.1 LLM响应不稳定或格式错误问题描述要求LLM输出严格的JSON格式以解析动作或技能但模型时常输出多余的解释、格式错误或字段缺失的JSON。排查与解决强化格式指令在系统提示词和用户提示词中反复、明确地强调输出格式。使用“你必须输出且仅输出一个合法的JSON对象不要有任何其他文字”这样的强约束语句。甚至可以提供JSON Schema。后处理与重试在代码中不要假设LLM的输出是完美的。实现一个健壮的解析函数尝试提取JSON部分如用正则表达式匹配{.*}如果解析失败则将错误信息和原始输出重新发送给LLM要求它纠正。通常第二次请求能获得正确格式。降低温度参数将LLM API调用时的temperature参数设为0或接近0如0.1以减少输出的随机性使结果更确定、更符合指令。使用函数调用/工具调用如果使用的LLM API支持Function Calling或Tool Calling如OpenAI的gpt-4尽量使用该功能。这相当于为模型提供了结构化的输出模板其格式遵从性远好于自由文本生成。5.2 技能库爆炸与检索失效问题描述随着探索进行技能库中积累了成百上千个技能。当新任务到来时从海量技能中找到最相关的一个变得非常低效甚至可能检索出错误技能导致任务失败。排查与解决技能去重与合并定期对技能库进行“维护”。利用LLM对技能描述进行聚类和合并。例如将“点击登录按钮”和“按下登录键”识别为同一技能的不同表述并进行合并。分层检索不要用单一的语义检索。首先根据当前环境的“上下文标签”如应用名称、页面标题过滤出一批候选技能。然后在这批技能中再进行基于任务描述的语义相似度计算。技能效用评分为每个技能增加元数据如success_count成功次数、last_used上次使用时间、generalizability泛化性评分可由LLM评估。检索时综合语义相关性和效用评分进行排序优先选择又相关又可靠的技能。设置技能容量上限实现一个“遗忘”机制。当技能数量超过阈值时淘汰那些最久未使用且成功率低的技能。这模拟了人的记忆特点保持技能库的活力。5.3 在真实GUI环境中元素定位失败问题描述在模拟环境中运行良好的智能体迁移到真实浏览器或桌面应用时经常因为找不到UI元素ID变化、动态加载、被遮挡而失败。排查与解决多属性融合定位不要只依赖单一的id或xpath。构建一个包含元素多种特征的“定位器”如{“tag”: “button”, “text”: “登录”, “aria-label”: “Sign in”, “class”: [“btn”, “btn-primary”]}。执行时尝试所有特征只要有一个匹配成功即可。视觉辅助定位在关键步骤引入轻量级计算机视觉。当传统定位器失效时可以截取当前屏幕使用OCR识别文本或者用预训练的UI元素检测模型来找到类似“按钮”、“输入框”的组件再结合位置信息进行交互。库如pytesseract和opencv可以在此发挥作用。增加等待与重试机制在操作元素前加入显式等待如WebDriverWait等待元素出现、可点击、可见。操作失败后不是立即报错而是重试几次并可能附带简单的恢复操作如滚动一下屏幕。记录“脆弱”定位点将那些经常定位失败的元素及其上下文记录下来。当下次遇到类似上下文时可以主动尝试备用定位策略或提前触发某些操作如点击“展开更多”按钮使目标元素出现。5.4 任务陷入无限循环或无关动作问题描述智能体在某些状态下陷入死循环重复执行无意义的动作如反复刷新页面、在两个输入框间来回切换无法推进任务。排查与解决状态哈希与循环检测为环境状态计算一个简化的哈希值例如基于主要UI元素的文本和类型。在执行每个动作前检查当前状态哈希是否在近期如过去10步内出现过。如果出现则判定可能陷入循环触发恢复策略。引入随机探索因子即使在规划模式下也以一个小概率如5%执行一个随机、合法的探索性动作。这有助于跳出局部最优或死循环状态。让LLM进行自我反思当连续几步未能改变环境状态或达成子目标时将最近几步的动作和状态历史喂给LLM并提问“我似乎陷入了困境为什么这些动作没有效果我下一步应该尝试什么不同的策略”利用LLM的推理能力寻找突破口。设计子目标奖励对于复杂任务除了最终奖励人为设计一些中间子目标的奖励。例如在注册任务中“成功输入用户名”、“成功输入邮箱”都可以给予小的正向奖励。这可以引导智能体更快地朝着正确方向前进避免在无关动作上浪费时间。从我个人的实验经验来看SkillZero代表的是一种非常诱人的方向——让AI智能体从“被动执行指令”走向“主动学习做事”。虽然目前完全通用的技能学习智能体仍面临诸多挑战但在特定领域、特定环境如单个Web应用、一套固定的API内结合精心设计的观察表示、提示工程和故障处理机制已经可以构建出非常有用的、能够自我改进的自动化工具。它的价值不仅在于替代重复劳动更在于其可发现性——它能找出人类开发者可能未曾想到的、却行之有效的操作流程。
SkillZero:基于LLM的智能体技能发现与组合框架解析
发布时间:2026/5/16 4:41:48
1. 项目概述从“技能零”到“技能满”的智能体进化之路最近在开源社区里一个名为“SkillZero”的项目引起了我的注意。这个由ZJU-REAL实验室开源的项目名字起得很有意思——“技能零”。乍一听你可能会觉得这是个面向初学者的入门工具但深入研究后才发现它瞄准的是一个更前沿、也更棘手的问题如何让一个大型语言模型LLM驱动的智能体在没有预先编程或大量演示数据的情况下自主地学会并掌握完成复杂任务所需的“技能”。这让我想起了自己早期做自动化脚本的经历。那时候每遇到一个新需求比如从网页上抓取特定格式的数据或者把一堆散乱的文件按规则整理好我都得手动写一套代码。虽然最终能解决问题但过程繁琐而且代码的复用性很差。后来有了RPA机器人流程自动化工具情况好了些可以通过录制操作来生成流程但一旦界面或流程稍有变化整个“机器人”就可能罢工。SkillZero试图解决的正是这个问题的下一代版本如何让一个AI智能体像人一样通过尝试、观察结果、总结经验最终自己摸索出一套完成任务的最佳方法并且这个方法还能被抽象、存储和复用。简单来说SkillZero是一个基于大型语言模型的技能发现与组合框架。它的核心目标不是执行某个固定任务而是让智能体在探索一个环境比如一个软件界面、一个API集合或者一个虚拟世界时能够自动识别出哪些动作序列是有效的、可重复的“技能”并将这些技能构建成一个不断增长的“技能库”。当下次遇到类似或更复杂的任务时智能体就可以像搭积木一样从技能库中调用和组合已有的技能而不是从头开始摸索。这个项目适合谁呢首先是对AI智能体和自动化感兴趣的研究者和开发者。如果你想了解如何让LLM超越单纯的对话或代码生成真正具备在复杂环境中“做事”的能力SkillZero提供了一个绝佳的研究范本。其次是那些面临大量重复性、但又有一定变化性的数字流程的团队比如数据工程师、测试工程师或运营人员。SkillZero所探索的“技能学习”范式可能是未来构建自适应、可进化业务流程自动化系统的关键技术基础。即使你只是对AI的前沿应用感到好奇这个项目也能让你直观地感受到当前最先进的AI模型在“自主探索与学习”方面走到了哪一步。2. 核心设计思路让智能体学会“归纳”与“复用”SkillZero的设计哲学非常清晰将“任务求解”分解为“技能发现”与“技能复用”两个核心循环。这听起来简单但实现起来需要精巧地设计智能体与环境交互的每一个环节。传统的智能体要么是硬编码的规则引擎不灵活要么是依赖大量标注数据训练的强化学习模型成本高、泛化差。SkillZero巧妙地利用了大语言模型的规划能力、代码生成能力和自然语言理解能力走出了一条新路。2.1 核心循环拆解探索、抽象、规划、执行整个系统的运行可以看作是两个紧密耦合的循环第一个循环技能发现与提炼循环。智能体被赋予一个目标例如“在GUI计算器应用中计算(1234)56”。一开始它的技能库是空的。它会像一个人一样尝试最基础的操作点击按钮、输入文本、读取屏幕信息。LLM作为它的“大脑”会根据当前目标“计算表达式”和观察到的环境状态计算器界面规划出一个初步的动作序列比如先点“1”再点“2”再点“”…。执行这些动作后环境会给出反馈显示结果。关键的一步来了智能体会反思这一系列动作和最终结果。如果任务成功了LLM会尝试对这一连串的低级动作进行“抽象”和“命名”。例如它可能将“点击数字1、点击数字2”抽象为“输入数字12”将“点击、点击3、点击4”抽象为“输入加法和数字34”。更进一步它可能将整个“(点击1,2,,3,4,,5,6,)”的成功序列抽象为一个名为“计算器_执行四则运算”的技能并记录下这个技能对应的代码或动作模板以及其适用的前提条件界面处于初始状态且为标准计算器布局。注意这里的“抽象”能力完全依赖于LLM。模型需要理解这些底层动作在语义上的共同目标。这就要求用于驱动智能体的LLM必须具备较强的推理和概括能力。实践中项目可能会使用如GPT-4、Claude-3或开源的DeepSeek等先进模型。第二个循环基于技能的层次化规划与执行循环。当技能库中积累了一些技能后智能体再面对新任务时其策略就发生了变化。它首先会检查技能库看看有没有现成的技能可以直接使用或者通过组合现有技能来解决新问题。例如新任务是“计算(98-76)/11”。智能体发现技能库里有“计算器_执行四则运算”但参数不同。这时LLM会进行“高层规划”它将任务分解为“使用‘计算器_执行四则运算’技能并传入参数序列[9,8,-,7,6,/,1,1,]”。这个高层计划会被“编译”成具体的底层动作序列去执行。如果现有技能无法直接解决智能体可能会尝试修改技能参数或者退回到基础探索模式去发现新的技能片段再将其加入库中。这种设计的优势显而易见效率提升避免了每次任务都从零开始的“蛮力探索”。技能一旦被学会就成为可复用的资产。可解释性增强技能库本身就是一个可读的、高级别的“操作手册”记录了智能体学会了什么以及如何做。支持复杂任务通过技能的层次化组合理论上可以解决非常复杂的任务因为复杂任务被分解为了已知技能的执行序列。2.2 关键技术组件与选型考量要实现上述循环SkillZero需要几个核心组件每个组件的选型都直接影响系统性能1. 环境交互器这是智能体的“手”和“眼睛”。它需要能够接收智能体发出的动作如click(button_id),type(text),read_screen()并将其转换为对真实环境如浏览器、桌面应用、API的实际操作同时将环境的反馈如屏幕截图、DOM树、API返回的JSON收集回来。选型上对于Web环境可能会选用Playwright或Selenium因为它们支持可靠的自动化操作和丰富的状态获取。对于桌面GUI可能使用pyautogui结合pytesseractOCR的方式。关键在于这个交互器需要提供一种结构化的、可供LLM理解的环境状态表示比如将网页简化为一个可操作的UI元素列表及其属性。2. 技能库管理器这是智能体的“记忆库”。它负责技能的存储、检索和更新。每个技能条目至少包含技能名称/描述自然语言描述如“在搜索框输入关键词并点击搜索按钮”。技能实现可以是一段可执行的代码Python函数也可以是一组参数化的动作模板。前提条件技能执行前环境必须满足的状态。后置条件/效果技能执行后预期会达成的状态。成功历史该技能过去被成功调用的记录可用于评估其可靠性。存储方式可以是简单的JSON文件、向量数据库便于通过语义搜索检索相似技能或更结构化的SQLite数据库。选型取决于对检索速度和语义匹配精度的要求。3. 大语言模型引擎这是智能体的“大脑”是整个系统的核心。它承担多项职责任务规划根据目标和当前状态生成动作序列或技能调用序列。技能抽象从成功的低级动作轨迹中归纳出高级技能。代码/参数生成将抽象技能或高层规划具体化为可执行的代码或动作参数。反思与评估判断任务是否成功分析失败原因。这里最大的考量是成本与能力的平衡。最强的闭源模型如GPT-4在推理和代码生成上表现优异但API调用成本高且不适合处理需要频繁交互的长期任务。开源模型如CodeLlama、DeepSeek-Coder可以本地部署成本可控但可能需要更精细的提示工程和上下文管理才能达到相近效果。SkillZero项目可能需要采用混合策略例如用强模型进行关键的“技能抽象”和“复杂规划”用轻量级模型处理常规的动作选择。3. 实操流程构建一个简易的技能学习智能体理解了核心思路后我们可以尝试构建一个极度简化的原型来体验SkillZero的核心流程。我们将模拟一个“Web表单填写”环境。3.1 环境搭建与基础定义首先我们定义环境和动作。为了简化我们不启动真实浏览器而是用一个Python字典模拟一个简单的用户注册页面状态。# 模拟环境状态 class MockWebEnv: def __init__(self): self.state { current_page: register, elements: [ {id: name, type: text_input, value: , description: 用户名输入框}, {id: email, type: text_input, value: , description: 邮箱输入框}, {id: submit_btn, type: button, description: 提交按钮}, ], message: # 用于显示操作结果消息 } def execute_action(self, action: dict): 执行动作更新环境状态 action_type action.get(type) element_id action.get(element_id) value action.get(value) if action_type type: for elem in self.state[elements]: if elem[id] element_id and elem[type] text_input: elem[value] value self.state[message] f已在 {element_id} 中输入: {value} return True elif action_type click: for elem in self.state[elements]: if elem[id] element_id and elem[type] button: # 模拟提交逻辑 name next((e[value] for e in self.state[elements] if e[id] name), ) email next((e[value] for e in self.state[elements] if e[id] email), ) if name and in email: self.state[message] f提交成功用户 {name} 已注册。 else: self.state[message] 提交失败请填写完整且有效的邮箱。 return True self.state[message] f动作执行失败: {action} return False def get_observation(self): 返回LLM可读的环境观察 obs f当前页面: {self.state[current_page]}\n obs 可操作元素:\n for elem in self.state[elements]: obs f - [{elem[id]}] ({elem[type]}): {elem[description]} if elem[type] text_input: obs f, 当前值: {elem[value]} obs \n obs f系统消息: {self.state[message]}\n return obs3.2 实现核心循环逻辑接下来我们实现一个简化的智能体循环。这里我们用openai库调用大模型实际使用时需替换为你的API密钥并假设我们已经有了一个空的技能库。import openai import json import time class SimpleSkillZeroAgent: def __init__(self, env, llm_client, skill_lib_fileskill_lib.json): self.env env self.llm llm_client self.skill_lib self._load_skill_lib(skill_lib_file) self.max_attempts 5 def _load_skill_lib(self, filepath): try: with open(filepath, r) as f: return json.load(f) except FileNotFoundError: return [] # 初始技能库为空 def _save_skill_lib(self): with open(skill_lib.json, w) as f: json.dump(self.skill_lib, f, indent2) def _call_llm(self, prompt, system_msg你是一个有帮助的AI助手。): # 这里是模拟调用实际应替换为真实的API调用 # 为简化演示我们返回一个固定响应 # 实际项目中这里会是 openai.ChatCompletion.create(...) 或类似调用 print(f[LLM Prompt]: {prompt[:200]}...) time.sleep(0.5) # 模拟延迟 # 根据不同的提示类型返回不同的模拟响应 if 下一步动作 in prompt: return {action: {type: type, element_id: name, value: 张三}} elif 抽象为技能 in prompt: return {skill_name: 填写用户名, implementation: type_text(\name\, username), precondition: 当前页面为register且存在id为name的输入框} elif 规划技能 in prompt and self.skill_lib: return {plan: [使用技能:填写用户名参数:李四, 使用技能:填写邮箱参数:lisiexample.com, 点击提交按钮]} else: return {action: {type: click, element_id: submit_btn}} def run_task(self, task_description): print(f\n 开始新任务: {task_description} ) attempts 0 while attempts self.max_attempts: attempts 1 print(f\n--- 尝试第 {attempts} 次 ---) # 1. 获取当前环境观察 obs self.env.get_observation() print(f[环境状态]:\n{obs}) # 2. 规划根据任务和技能库决定下一步是调用技能还是探索 # 这里简化处理如果技能库为空或任务不匹配则进入探索模式 use_skill_plan False if self.skill_lib: # 简单检查是否有相关技能实际应用需语义匹配 if 填写 in task_description and any(填写 in s.get(skill_name, ) for s in self.skill_lib): use_skill_plan True if use_skill_plan: plan_prompt f 任务: {task_description} 当前环境状态: {obs} 现有技能库: {json.dumps(self.skill_lib, ensure_asciiFalse)} 请规划一个使用现有技能来完成任务的步骤序列。以JSON格式输出包含一个plan字段值为步骤列表。 llm_response self._call_llm(plan_prompt) # 解析并执行规划此处简化跳过解析 print(f[高层规划]: 使用技能组合执行) # ... 执行规划中的每个技能步骤 else: # 探索模式让LLM直接生成下一个低级动作 action_prompt f 任务: {task_description} 当前环境状态: {obs} 请根据任务和当前状态决定下一个最合理的原子操作动作。 可用的动作类型: type在输入框中打字, click点击按钮。 请以严格的JSON格式输出只包含一个名为action的对象其内部有type, element_id, 必要时有value字段。 例如: {{action: {{type: type, element_id: name, value: Alice}}}} llm_response self._call_llm(action_prompt) # 3. 解析并执行动作这里简化了JSON解析 print(f[LLM响应]: {llm_response}) # 假设我们解析出了一个动作 action_to_take {type: type, element_id: name, value: 测试用户} # 4. 执行动作 success self.env.execute_action(action_to_take) print(f[执行动作]: {action_to_take}, 结果: {success}) print(f[环境反馈]: {self.env.state[message]}) # 5. 检查任务是否完成简化检查消息是否包含成功 if 成功 in self.env.state[message]: print(f\n*** 任务完成 ***) # 6. 技能抽象如果本次探索成功且动作序列有抽象价值则尝试提炼技能 if not use_skill_plan: # 如果是探索成功的 self._abstract_skill(task_description, [action_to_take]) # 简化只传最后一个动作 break if attempts self.max_attempts: print(f\n*** 任务失败达到最大尝试次数。 ***) def _abstract_skill(self, task_desc, action_sequence): 尝试从成功的动作序列中抽象出技能 print(\n 尝试抽象新技能...) abstraction_prompt f 智能体刚刚通过执行一系列原子操作成功完成了任务: {task_desc} 执行的操作序列最后一步是关键: {action_sequence} 请将这个成功的操作模式抽象为一个可复用的、有意义的技能。 以JSON格式输出包含字段: - skill_name: 技能名称简短描述性中文或英文 - implementation: 技能的实现方式描述或伪代码 - precondition: 执行此技能所需的环境前提条件 llm_response self._call_llm(abstraction_prompt) # 解析响应添加到技能库 try: # 这里应是解析JSON的逻辑 new_skill {skill_name: 模拟技能, implementation: type_text(name, $1), precondition: 页面有name输入框} self.skill_lib.append(new_skill) self._save_skill_lib() print(f[新技能已添加]: {new_skill}) except: print([技能抽象失败]) # 模拟运行 if __name__ __main__: env MockWebEnv() agent SimpleSkillZeroAgent(env, llm_clientNone) # 简化版未接入真实LLM # 第一个任务探索并学习 agent.run_task(注册一个用户用户名为张三) # 假设技能库已更新再次运行类似任务 print(\n *50) print(技能库已更新再次执行类似任务...) # 这里可以修改env的state重置环境然后运行新任务 # agent.run_task(注册一个用户用户名为李四)这个极度简化的原型演示了SkillZero的核心循环感知环境、规划/探索、执行、反馈、抽象技能。在实际的SkillZero项目中每个环节都复杂得多例如LLM的提示工程、技能的语义匹配与检索、长序列动作的可靠执行与回滚等。3.3 实操心得与参数调优在尝试复现或基于SkillZero思想进行开发时有几个关键点需要特别注意1. 环境观察的表示是关键给LLM的环境观察不能是原始的像素或复杂的DOM树必须经过精心设计的信息压缩和结构化。好的观察表示应该包含当前界面的语义描述这是什么页面、可交互对象的列表及其属性id, 类型, 当前值, 是否可点击等、上次操作的结果或系统消息。这相当于为LLM提供了清晰的“游戏画面UI”而不是一堆像素点。2. 提示工程决定智能体上限驱动智能体的LLM提示词Prompt需要精心设计。通常需要采用多角色提示或链式思考CoT提示。例如系统提示定义智能体的角色“你是一个自动化助手”、目标“通过探索学习技能”、输出格式约束。规划提示需要让模型先“思考”再“输出”。例如“请先分析当前任务与技能库的匹配度。如果匹配输出技能调用计划如果不匹配请逐步推理下一步最该执行的基础动作是什么。”抽象提示引导模型从具体动作中找出通用模式。例如“请忽略具体的输入值‘张三’关注操作的对象和类型。将‘在id为name的输入框输入文本’这一模式进行概括。”3. 技能粒度的权衡技能抽象得太粗如“完成用户注册”复用性强但实现复杂且可能不稳定注册流程可能会变。技能抽象得太细如“点击id为name的输入框”虽然稳定但复用价值低组合起来也繁琐。一个实用的策略是分层技能库底层是原子操作点击、输入中层是常见复合操作填写表单字段、提交表单高层是业务流用户注册、数据查询。智能体优先尝试匹配高层技能失败时再逐层降级。4. 失败处理与探索策略智能体在探索中必然会失败。关键在于如何从失败中学习。除了抽象成功技能还应建立失败案例库。当某个动作导致错误如元素未找到、无效操作应记录该动作及其上下文并在未来规划时避免在相同上下文中重复此动作。这相当于给智能体增加了“避坑”经验。4. 典型应用场景与扩展思考SkillZero所代表的“技能学习”范式其应用潜力远不止于演示中的简单表单填写。它可以被应用到许多需要与数字环境交互的复杂场景中。4.1 场景一软件测试自动化传统的自动化测试需要测试工程师编写大量的测试用例脚本。当软件UI或流程变更时维护成本很高。基于SkillZero的智能体可以这样工作初始探索给定一个软件版本如一个Web应用智能体的目标是“探索所有功能”。它会随机或按策略点击按钮、输入数据。技能发现在探索中它会自动将“登录”、“创建一条数据”、“搜索过滤”等成功操作序列抽象为技能存入库中。回归测试当新版本发布时智能体可以调用技能库中的技能自动执行一系列核心用户旅程如“登录-创建项目-添加成员-查看报表”并比较结果与基线版本的差异自动报告异常。自适应维护如果新版本中“登录”按钮的ID变了导致旧技能失败智能体可以自动进入探索模式重新学习“登录”技能并更新技能库实现测试套件的自我修复。4.2 场景二业务流程的发现与文档化在许多企业存在大量依赖员工手工操作、未被IT系统固化的业务流程Shadow IT。这些流程效率低、易出错、且知识难以传承。可以部署一个受控的桌面智能体记录员工完成某个业务如“月度财务报告编制”的所有操作切换软件、复制数据、整理Excel、发送邮件等。智能体在后台运行SkillZero算法将这一系列操作抽象为“从系统A导出数据”、“清洗Excel表格”、“邮件合并发送”等技能并自动生成该业务流程的标准化文档甚至可执行的脚本骨架。这相当于完成了业务的自动挖掘与初步自动化。4.3 场景三个性化助手的能力扩展现在的AI助手如Copilot大多基于静态的指令集或插件。想象一个未来版的个人助手它通过观察你日常的电脑操作来学习你的习惯和工作流。例如它看到你每次收到名为“数据日报”的邮件后都会下载附件用特定Python脚本处理然后将结果上传到某个内部网盘。经过几次观察它可以将这一系列操作学习为“处理数据日报”的技能。之后当你再收到此类邮件时助手可以直接询问“检测到‘数据日报’邮件需要我自动处理吗”获得确认后它自动调用该技能完成全部工作。这使得助手的能力可以随着用户的使用而不断增长和个性化。4.4 面临的挑战与解决思路当然将SkillZero从研究原型推向实际应用还有重重挑战1. 探索效率与安全性在复杂环境中盲目探索效率极低且危险可能误删数据。解决方案是混合探索策略结合基于模型的规划利用LLM的世界知识进行有根据的猜测、模仿学习提供少量人类演示作为种子技能和安全沙盒在隔离环境中训练。2. 技能的泛化与匹配学习到的技能在稍有变化的环境中可能失效。例如为“Chrome浏览器中的Gmail登录”学习的技能无法直接用于“Edge浏览器中的Outlook登录”。需要提升技能的抽象层次和匹配算法的语义理解能力。可以利用计算机视觉CV识别UI元素的语义角色“这是一个登录按钮”而非依赖其易变的ID或坐标。3. 长期依赖与复杂规划对于需要多步骤、长周期才能完成的任务智能体的规划能力面临考验。需要引入更强大的长期记忆和子目标分解机制。技能库本身可以作为一种记忆记录达到某种状态的方法。高层规划器需要能将“撰写年度报告”分解为“收集各部门数据”、“制作图表”、“汇总成文”、“格式审查”等子任务并递归地调用或学习相应技能。4. 评估与奖励稀疏在真实任务中“成功”的反馈往往是稀疏且延迟的比如流程最后才弹出“提交成功”。如何在中途评估动作的好坏可以引入基于模型的奖励预测让LLM对当前状态进行评估“距离完成任务更近了吗”或者设计课程学习从简单的、反馈明确的子任务开始训练逐步增加难度。5. 常见问题与实战调试记录在实际尝试实现或应用类似SkillZero的思路时我遇到并总结了一些典型问题及其解决思路这对于避开初期弯路很有帮助。5.1 LLM响应不稳定或格式错误问题描述要求LLM输出严格的JSON格式以解析动作或技能但模型时常输出多余的解释、格式错误或字段缺失的JSON。排查与解决强化格式指令在系统提示词和用户提示词中反复、明确地强调输出格式。使用“你必须输出且仅输出一个合法的JSON对象不要有任何其他文字”这样的强约束语句。甚至可以提供JSON Schema。后处理与重试在代码中不要假设LLM的输出是完美的。实现一个健壮的解析函数尝试提取JSON部分如用正则表达式匹配{.*}如果解析失败则将错误信息和原始输出重新发送给LLM要求它纠正。通常第二次请求能获得正确格式。降低温度参数将LLM API调用时的temperature参数设为0或接近0如0.1以减少输出的随机性使结果更确定、更符合指令。使用函数调用/工具调用如果使用的LLM API支持Function Calling或Tool Calling如OpenAI的gpt-4尽量使用该功能。这相当于为模型提供了结构化的输出模板其格式遵从性远好于自由文本生成。5.2 技能库爆炸与检索失效问题描述随着探索进行技能库中积累了成百上千个技能。当新任务到来时从海量技能中找到最相关的一个变得非常低效甚至可能检索出错误技能导致任务失败。排查与解决技能去重与合并定期对技能库进行“维护”。利用LLM对技能描述进行聚类和合并。例如将“点击登录按钮”和“按下登录键”识别为同一技能的不同表述并进行合并。分层检索不要用单一的语义检索。首先根据当前环境的“上下文标签”如应用名称、页面标题过滤出一批候选技能。然后在这批技能中再进行基于任务描述的语义相似度计算。技能效用评分为每个技能增加元数据如success_count成功次数、last_used上次使用时间、generalizability泛化性评分可由LLM评估。检索时综合语义相关性和效用评分进行排序优先选择又相关又可靠的技能。设置技能容量上限实现一个“遗忘”机制。当技能数量超过阈值时淘汰那些最久未使用且成功率低的技能。这模拟了人的记忆特点保持技能库的活力。5.3 在真实GUI环境中元素定位失败问题描述在模拟环境中运行良好的智能体迁移到真实浏览器或桌面应用时经常因为找不到UI元素ID变化、动态加载、被遮挡而失败。排查与解决多属性融合定位不要只依赖单一的id或xpath。构建一个包含元素多种特征的“定位器”如{“tag”: “button”, “text”: “登录”, “aria-label”: “Sign in”, “class”: [“btn”, “btn-primary”]}。执行时尝试所有特征只要有一个匹配成功即可。视觉辅助定位在关键步骤引入轻量级计算机视觉。当传统定位器失效时可以截取当前屏幕使用OCR识别文本或者用预训练的UI元素检测模型来找到类似“按钮”、“输入框”的组件再结合位置信息进行交互。库如pytesseract和opencv可以在此发挥作用。增加等待与重试机制在操作元素前加入显式等待如WebDriverWait等待元素出现、可点击、可见。操作失败后不是立即报错而是重试几次并可能附带简单的恢复操作如滚动一下屏幕。记录“脆弱”定位点将那些经常定位失败的元素及其上下文记录下来。当下次遇到类似上下文时可以主动尝试备用定位策略或提前触发某些操作如点击“展开更多”按钮使目标元素出现。5.4 任务陷入无限循环或无关动作问题描述智能体在某些状态下陷入死循环重复执行无意义的动作如反复刷新页面、在两个输入框间来回切换无法推进任务。排查与解决状态哈希与循环检测为环境状态计算一个简化的哈希值例如基于主要UI元素的文本和类型。在执行每个动作前检查当前状态哈希是否在近期如过去10步内出现过。如果出现则判定可能陷入循环触发恢复策略。引入随机探索因子即使在规划模式下也以一个小概率如5%执行一个随机、合法的探索性动作。这有助于跳出局部最优或死循环状态。让LLM进行自我反思当连续几步未能改变环境状态或达成子目标时将最近几步的动作和状态历史喂给LLM并提问“我似乎陷入了困境为什么这些动作没有效果我下一步应该尝试什么不同的策略”利用LLM的推理能力寻找突破口。设计子目标奖励对于复杂任务除了最终奖励人为设计一些中间子目标的奖励。例如在注册任务中“成功输入用户名”、“成功输入邮箱”都可以给予小的正向奖励。这可以引导智能体更快地朝着正确方向前进避免在无关动作上浪费时间。从我个人的实验经验来看SkillZero代表的是一种非常诱人的方向——让AI智能体从“被动执行指令”走向“主动学习做事”。虽然目前完全通用的技能学习智能体仍面临诸多挑战但在特定领域、特定环境如单个Web应用、一套固定的API内结合精心设计的观察表示、提示工程和故障处理机制已经可以构建出非常有用的、能够自我改进的自动化工具。它的价值不仅在于替代重复劳动更在于其可发现性——它能找出人类开发者可能未曾想到的、却行之有效的操作流程。