【核心引擎】OpenClaw Agent执行循环(Lobster)深度拆解:从意图识别到工具调用的全流程
引言:Agent是如何"思考"并"行动"的?------Lobster循环的意义
在大模型Agent(智能体)技术快速落地的当下,OpenClaw作为一款轻量级、可扩展的Agent框架,其核心执行逻辑------Lobster循环(龙虾循环)是支撑Agent完成复杂任务的"大脑中枢"。不同于传统程序"指令-执行"的线性逻辑,Agent需要模拟人类的"思考-观察-行动-反思"闭环:面对用户模糊的自然语言指令(如"帮我分析本地销售数据并生成可视化图表"),它需要先拆解任务、再获取环境信息、执行具体操作,最后根据结果调整策略,而这一整套逻辑都封装在Lobster循环中。
理解Lobster循环,不仅能帮开发者掌握OpenClaw Agent的核心运行机制,更能触类旁通理解所有ReAct模式Agent的设计思想------从意图识别到工具调用的全流程管控,是Agent区别于普通LLM调用的关键。本文将从理论到源码、从设计到实战,全方位拆解Lobster循环,让你既能理解"为什么这么设计",也能动手"改造循环逻辑"。
Lobster循环四阶段:Agent的"思考-行动"闭环
Lobster循环本质是对ReAct(Reasoning + Acting)模式的工程化实现,核心拆分为Plan(规划)、Observe(观察)、Act(执行)、Reflect(反思) 四个阶段,形成一个可迭代的闭环。整个循环的核心逻辑是:接收用户指令→拆解为可执行步骤→获取环境信息→调用工具执行→验证结果→调整计划(若未完成)→重复直至任务完成。
1. Plan(规划):把模糊指令拆成可执行步骤
Plan阶段是Agent的"思考环节",核心目标是将用户的自然语言指令(如"爬取某电商网站手机销量数据并分析Top10机型")拆解为结构化、可执行的步骤列表。
-
输入:用户原始指令 + 历史上下文(前一轮循环的反思结果) + Agent的技能列表(可调用的工具);
-
核心逻辑:通过Prompt引导LLM(如GPT-4、Claude、文心一言)进行思维链(Chain-of-Thought)推理,明确"需要做什么、先做什么、用什么工具做";
-
输出 :结构化的任务步骤列表(如JSON格式),示例:
json[ {"step_id": 1, "description": "爬取电商网站手机销量页面", "skill_name": "web_crawler", "parameters": {"url": "https://xxx.com/phone/sales", "method": "GET"}}, {"step_id": 2, "description": "解析爬取的HTML数据,提取机型和销量", "skill_name": "html_parser", "parameters": {"target_tags": ["div.class='phone-name'", "span.class='sales-num'"]}}, {"step_id": 3, "description": "统计销量并排序,筛选Top10机型", "skill_name": "data_analysis", "parameters": {"sort_field": "sales", "top_n": 10}}, {"step_id": 4, "description": "生成可视化柱状图并保存到本地", "skill_name": "plot_generator", "parameters": {"chart_type": "bar", "save_path": "./sales_top10.png"}} ]
2. Observe(观察):获取环境状态与执行前置信息
Observe阶段是Agent的"感知环节",核心目标是为Act阶段的执行获取必要的环境信息或前置数据,解决"执行前需要知道什么"的问题。
-
输入:Plan阶段生成的当前步骤 + Agent的环境上下文;
-
核心逻辑 :
- 主动拉取环境状态:如读取本地文件列表、获取数据库连接状态、调用API获取实时数据;
- 被动接收外部输入:如用户补充的信息、前一步骤的执行结果;
- 格式标准化:将获取的非结构化信息(如网页文本、日志)转换为LLM可理解的结构化数据;
-
输出 :标准化的环境状态信息(如键值对、JSON),示例:
json{ "env_status": { "file_system": {"./data": ["sales_raw.html", "temp.json"]}, "api_response": {"status_code": 200, "content_length": 12580}, "previous_step_result": "已成功爬取销量页面,保存至./data/sales_raw.html" } }
3. Act(执行):调用Skill完成具体操作
Act阶段是Agent的"行动环节",核心目标是执行Plan阶段规划的具体步骤,调用对应的Skill(工具/技能)完成操作。
-
输入:Plan阶段的步骤参数 + Observe阶段的环境信息;
-
核心逻辑 :
- Skill路由:根据步骤中指定的
skill_name匹配注册的工具函数; - 参数校验:验证输入参数是否符合Skill的要求(如必填参数、数据类型);
- 执行调用:调用Skill并捕获执行结果(成功/失败、返回值、异常信息);
- Skill路由:根据步骤中指定的
-
输出 :结构化的执行结果,包含状态(success/fail)、返回数据、异常信息(若有),示例:
json{ "step_id": 2, "skill_name": "html_parser", "execution_status": "success", "result": [ {"phone_name": "iPhone 15", "sales": 125000}, {"phone_name": "华为Mate 60 Pro", "sales": 118000}, {"phone_name": "小米14", "sales": 98000} ], "error_msg": "" }
4. Reflect(反思):根据执行结果调整后续计划
Reflect阶段是Agent的"复盘环节",核心目标是验证当前步骤的执行结果是否符合预期,并决定"继续执行下一步""重试当前步骤""终止任务"或"请求用户帮助"。
-
输入:Act阶段的执行结果 + Plan阶段的原始步骤 + 任务总目标;
-
核心逻辑 :
- 结果校验:对比执行结果与步骤预期目标(如"是否成功提取销量数据");
- 异常判断:若执行失败,分析原因(参数错误、工具调用失败、环境问题);
- 计划调整:生成调整后的步骤(如重试时修改参数、跳过失败步骤、新增纠错步骤);
-
输出 :反思结论 + 调整后的步骤列表,示例:
json{ "reflect_conclusion": "当前步骤执行成功,已提取3款机型销量数据,但未覆盖全部机型,需继续执行下一步统计排序", "adjusted_plans": [ {"step_id": 3, "description": "统计销量并排序,筛选Top10机型", "skill_name": "data_analysis", "parameters": {"sort_field": "sales", "top_n": 10}}, {"step_id": 4, "description": "生成可视化柱状图并保存到本地", "skill_name": "plot_generator", "parameters": {"chart_type": "bar", "save_path": "./sales_top10.png"}} ], "need_retry": false, "need_user_intervention": false }
Lobster循环整体流程(Mermaid流程图)
未完成
已完成
是
是
用户输入指令
初始化上下文/技能列表
Plan阶段:LLM拆解任务步骤
Observe阶段:获取环境/前置信息
Act阶段:调用Skill执行步骤
Reflect阶段:验证结果+调整计划
任务是否完成?
输出最终结果
执行失败且需重试?
需要用户干预?
暂停循环,请求用户输入
源码解析:agent/core/loop.py 中的核心函数(run_lobster_cycle)
OpenClaw框架中,Lobster循环的核心逻辑封装在agent/core/loop.py文件的run_lobster_cycle函数中。以下是该函数的核心源码拆解(基于OpenClaw v1.2.0,关键部分添加注释):
1. 核心函数整体结构
python
import json
import logging
from typing import Dict, List, Any
from openclaw.llm.client import LLMClient # LLM客户端
from openclaw.skill.registry import SkillRegistry # 技能注册器
from openclaw.memory.short_term import ShortTermMemory # 短期记忆
# 配置日志
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
def run_lobster_cycle(
user_instruction: str,
llm_client: LLMClient,
skill_registry: SkillRegistry,
short_term_memory: ShortTermMemory,
max_cycles: int = 10 # 最大循环次数,防止无限循环
) -> Dict[str, Any]:
"""
运行Lobster循环的核心函数
:param user_instruction: 用户原始指令
:param llm_client: LLM客户端实例(用于调用大模型)
:param skill_registry: 技能注册器(管理所有可调用的Skill)
:param short_term_memory: 短期记忆(存储上下文)
:param max_cycles: 最大循环次数
:return: 最终执行结果
"""
# 初始化循环状态
cycle_count = 0
task_completed = False
final_result = {"status": "pending", "content": ""}
# 循环执行直至任务完成或达到最大次数
while cycle_count < max_cycles and not task_completed:
try:
logger.info(f"开始第{cycle_count+1}轮Lobster循环")
# 1. Plan阶段:拆解任务步骤
plan_result = _plan_stage(
user_instruction=user_instruction,
llm_client=llm_client,
skill_registry=skill_registry,
short_term_memory=short_term_memory
)
if not plan_result["success"]:
raise Exception(f"Plan阶段失败:{plan_result['error_msg']}")
current_plans = plan_result["plans"]
logger.info(f"Plan阶段生成{len(current_plans)}个步骤")
# 2. Observe阶段:获取环境信息
observe_result = _observe_stage(
current_plans=current_plans,
short_term_memory=short_term_memory
)
if not observe_result["success"]:
raise Exception(f"Observe阶段失败:{observe_result['error_msg']}")
env_info = observe_result["env_info"]
logger.info("Observe阶段获取环境信息完成")
# 3. Act阶段:执行当前步骤
act_result = _act_stage(
current_plans=current_plans,
env_info=env_info,
skill_registry=skill_registry
)
logger.info(f"Act阶段执行完成,状态:{act_result['execution_status']}")
# 4. Reflect阶段:反思并调整计划
reflect_result = _reflect_stage(
act_result=act_result,
current_plans=current_plans,
user_instruction=user_instruction,
llm_client=llm_client
)
if reflect_result["need_user_intervention"]:
final_result = {
"status": "need_intervention",
"content": f"需要用户干预:{reflect_result['reflect_conclusion']}"
}
break
# 更新上下文记忆
short_term_memory.add(
content=json.dumps({
"cycle": cycle_count+1,
"act_result": act_result,
"reflect_result": reflect_result
})
)
# 判断任务是否完成
if reflect_result["task_completed"]:
task_completed = True
final_result = {
"status": "success",
"content": reflect_result["final_content"]
}
else:
# 更新下一步计划
current_plans = reflect_result["adjusted_plans"]
cycle_count += 1
except Exception as e:
logger.error(f"第{cycle_count+1}轮循环出错:{str(e)}")
final_result = {
"status": "failed",
"content": f"循环执行失败:{str(e)}"
}
break
# 处理最大循环次数超限
if cycle_count >= max_cycles and not task_completed:
final_result = {
"status": "timeout",
"content": f"达到最大循环次数({max_cycles}次),任务未完成"
}
logger.info(f"Lobster循环结束,最终状态:{final_result['status']}")
return final_result
2. 核心子函数拆解
(1)Plan阶段子函数 _plan_stage
python
def _plan_stage(
user_instruction: str,
llm_client: LLMClient,
skill_registry: SkillRegistry,
short_term_memory: ShortTermMemory
) -> Dict[str, Any]:
"""Plan阶段:调用LLM拆解任务为可执行步骤"""
# 1. 构造Prompt(包含思维链引导+技能列表+上下文)
skill_list = skill_registry.list_skills() # 获取所有注册的Skill
skill_info = json.dumps([{"name": s.name, "description": s.description, "parameters": s.parameters} for s in skill_list], ensure_ascii=False)
history_context = short_term_memory.get_all() # 获取历史上下文
prompt = f"""
你是OpenClaw Agent的规划助手,需要将用户指令拆解为结构化的可执行步骤。
要求:
1. 步骤需匹配可用技能列表,每个步骤指定唯一的skill_name;
2. 步骤参数需符合对应技能的参数要求;
3. 步骤需按逻辑顺序排列,可迭代执行;
4. 输出格式为JSON数组,仅返回JSON,无其他内容。
可用技能列表:
{skill_info}
历史上下文(前序循环结果):
{json.dumps(history_context, ensure_ascii=False) if history_context else "无"}
用户指令:{user_instruction}
"""
# 2. 调用LLM生成步骤
try:
llm_response = llm_client.complete(prompt=prompt)
plans = json.loads(llm_response.content)
return {
"success": True,
"plans": plans,
"error_msg": ""
}
except json.JSONDecodeError:
return {
"success": False,
"plans": [],
"error_msg": "LLM返回结果非合法JSON格式"
}
except Exception as e:
return {
"success": False,
"plans": [],
"error_msg": f"调用LLM失败:{str(e)}"
}
(2)Act阶段子函数 _act_stage
python
def _act_stage(
current_plans: List[Dict[str, Any]],
env_info: Dict[str, Any],
skill_registry: SkillRegistry
) -> Dict[str, Any]:
"""Act阶段:调用Skill执行当前步骤"""
# 仅执行当前第一个步骤(循环迭代执行后续步骤)
current_step = current_plans[0]
skill_name = current_step["skill_name"]
# 1. 查找注册的Skill
skill = skill_registry.get_skill(skill_name)
if not skill:
return {
"step_id": current_step["step_id"],
"skill_name": skill_name,
"execution_status": "failed",
"result": "",
"error_msg": f"未找到注册的技能:{skill_name}"
}
# 2. 合并步骤参数与环境信息
execution_params = {**current_step["parameters"], **env_info}
# 3. 参数校验
if not skill.validate_params(execution_params):
return {
"step_id": current_step["step_id"],
"skill_name": skill_name,
"execution_status": "failed",
"result": "",
"error_msg": f"参数校验失败,缺少必填参数:{skill.required_params}"
}
# 4. 执行Skill
try:
execution_result = skill.execute(execution_params)
return {
"step_id": current_step["step_id"],
"skill_name": skill_name,
"execution_status": "success",
"result": execution_result,
"error_msg": ""
}
except Exception as e:
return {
"step_id": current_step["step_id"],
"skill_name": skill_name,
"execution_status": "failed",
"result": "",
"error_msg": f"技能执行失败:{str(e)}"
}
3. 核心代码关键点说明
- 循环终止条件 :通过
max_cycles限制最大循环次数,避免Agent陷入无限循环; - 模块化设计:将四个阶段拆分为独立子函数,便于扩展和维护;
- 异常处理:每个阶段都有异常捕获逻辑,保证循环的健壮性;
- 上下文传递 :通过
ShortTermMemory类存储每轮循环的结果,实现上下文的跨轮传递; - Skill解耦 :通过
SkillRegistry管理所有工具,Act阶段仅需通过名称匹配,无需硬编码调用逻辑。
任务拆解算法:基于思维链(Chain-of-Thought)的Prompt设计
Plan阶段的核心是让LLM生成结构化的任务步骤,而实现这一目标的关键是Prompt设计------基于思维链(Chain-of-Thought,CoT)的Prompt能引导LLM像人类一样"一步步思考",而非直接输出结果。
1. 思维链Prompt的核心设计原则
- 明确角色定位:告知LLM"你是OpenClaw Agent的规划助手",明确其任务;
- 限定输出格式:强制返回JSON数组,避免LLM输出非结构化文本;
- 提供上下文:包含可用Skill列表、历史循环结果,让LLM知道"能调用什么工具""之前做了什么";
- 引导逻辑拆解:通过示例或指令引导LLM按"先做A、再做B、最后做C"的逻辑拆分任务;
- 容错提示:提示LLM处理模糊指令(如用户未指定具体网址时,生成"请求用户补充网址"的步骤)。
2. 优化后的CoT Prompt模板(可直接复用)
python
def get_plan_prompt_template() -> str:
template = """
角色:你是OpenClaw Agent的专业规划师,负责将用户的自然语言指令拆解为可执行的结构化步骤。
核心规则:
1. 步骤必须匹配【可用技能列表】中的技能,每个步骤仅调用一个技能;
2. 步骤参数必须符合对应技能的参数要求(必填参数不可缺失);
3. 步骤需按"先准备、再执行、后验证"的逻辑顺序排列;
4. 若指令模糊(如缺少网址/文件路径),生成"请求用户补充信息"的步骤,而非直接执行;
5. 若任务可拆分为子任务,每个子任务对应一个步骤,步骤ID连续递增;
6. 输出格式为JSON数组,仅返回JSON,无任何解释性文字,示例:
[{"step_id": 1, "description": "步骤描述", "skill_name": "技能名", "parameters": {"参数1": "值1", "参数2": "值2"}}]
可用技能列表:
{skill_info}
历史上下文(前序循环执行结果):
{history_context}
用户指令:{user_instruction}
请严格按照规则输出步骤列表:
"""
return template
3. Prompt优化前后效果对比
| 优化前(普通Prompt) | 优化后(CoT Prompt) |
|---|---|
| 输出非结构化文本: "首先爬取数据,然后分析,最后生成图表" | 输出结构化JSON: json<br>[<br> {"step_id": 1, "description": "爬取电商网站手机销量页面", "skill_name": "web_crawler", "parameters": {"url": "https://xxx.com/phone/sales"}},<br> {"step_id": 2, "description": "解析爬取的HTML数据", "skill_name": "html_parser", "parameters": {"target_tags": ["div.class='phone-name'"]}},<br> {"step_id": 3, "description": "生成可视化图表", "skill_name": "plot_generator", "parameters": {"chart_type": "bar"}}<br>] |
| 未考虑技能参数要求,导致Act阶段参数校验失败 | 严格匹配技能参数,Act阶段可直接执行 |
| 无法处理模糊指令,直接报错 | 生成"请求用户补充信息"的步骤,提升容错性 |
工具调用规范:Skill的输入输出如何与LLM交互
Lobster循环中,Act阶段的核心是调用Skill(工具),而Skill与LLM的交互是否规范,直接决定循环能否稳定运行。OpenClaw框架定义了统一的Skill接口规范,确保LLM生成的步骤能被正确执行,执行结果能被LLM正确解析。
1. Skill核心接口规范(基类定义)
python
from abc import ABC, abstractmethod
from typing import Dict, List, Any
class BaseSkill(ABC):
"""所有Skill的基类,定义统一接口"""
def __init__(self, name: str, description: str, required_params: List[str], optional_params: List[str] = None):
self.name = name # 技能名称(唯一标识)
self.description = description # 技能描述(供LLM识别)
self.required_params = required_params # 必填参数
self.optional_params = optional_params or [] # 可选参数
def validate_params(self, params: Dict[str, Any]) -> bool:
"""校验参数是否符合要求"""
# 检查必填参数是否存在
missing_params = [p for p in self.required_params if p not in params]
if missing_params:
logger.error(f"缺少必填参数:{missing_params}")
return False
# 检查参数类型(可选,可重写)
return True
@abstractmethod
def execute(self, params: Dict[str, Any]) -> Any:
"""执行技能,返回结构化结果"""
pass
2. Skill输入输出规范
(1)输入参数规范
- 命名规则 :使用小写蛇形命名(如
save_path),避免大小写混合; - 数据类型:优先使用基础类型(str/int/float/bool),复杂类型使用JSON字符串;
- 必填/可选分离:明确标注必填参数,LLM生成步骤时必须包含;
- 默认值:可选参数设置合理默认值,降低LLM生成难度。
(2)输出结果规范
- 结构化输出:优先返回JSON可序列化的数据(dict/list),避免返回复杂对象;
- 状态标识 :包含
execution_status(success/fail)字段,便于Reflect阶段判断; - 异常信息 :失败时返回
error_msg字段,说明失败原因; - 结果描述:返回人类可读的结果描述,便于LLM在Reflect阶段理解。
3. 示例:实现一个符合规范的Skill
python
from openclaw.skill.base import BaseSkill
import requests
from typing import Dict, Any
class WebCrawlerSkill(BaseSkill):
"""网页爬取技能,符合OpenClaw Skill规范"""
def __init__(self):
super().__init__(
name="web_crawler",
description="爬取指定URL的网页内容,支持GET/POST方法",
required_params=["url"],
optional_params=["method", "headers", "timeout"]
)
def execute(self, params: Dict[str, Any]) -> Dict[str, Any]:
# 设置默认参数
method = params.get("method", "GET").upper()
headers = params.get("headers", {"User-Agent": "OpenClaw Agent/1.0"})
timeout = params.get("timeout", 10)
url = params["url"]
try:
# 执行爬取
response = requests.request(
method=method,
url=url,
headers=headers,
timeout=timeout
)
response.raise_for_status() # 抛出HTTP异常
# 返回结构化结果
return {
"execution_status": "success",
"content": response.text,
"status_code": response.status_code,
"content_length": len(response.text),
"error_msg": ""
}
except requests.exceptions.RequestException as e:
return {
"execution_status": "failed",
"content": "",
"status_code": 0,
"content_length": 0,
"error_msg": f"爬取失败:{str(e)}"
}
# 注册Skill
skill_registry = SkillRegistry()
skill_registry.register_skill(WebCrawlerSkill())
4. Skill与LLM的交互流程(Mermaid流程图)
校验通过
校验失败
LLM生成步骤
步骤中指定skill_name+parameters
SkillRegistry根据name匹配Skill实例
调用validate_params校验参数
调用execute执行Skill
返回参数错误信息
Skill返回结构化执行结果
Reflect阶段LLM解析结果
调整后续步骤
上下文记忆注入:短期记忆如何在循环中传递
Agent要完成复杂任务,必须具备"记忆能力"------记住前一轮循环的执行结果、用户的补充指令、环境状态的变化,这就是短期记忆(ShortTermMemory)在Lobster循环中的核心作用。
1. 短期记忆的核心设计
OpenClaw的ShortTermMemory类本质是一个有序的上下文存储容器,具备"添加、查询、清空"三个核心方法,存储内容包括:
- 用户原始指令;
- 每轮循环的Plan/Observe/Act/Reflect结果;
- 用户补充的干预信息;
- 环境状态的关键变化(如文件创建/删除、API连接状态)。
2. 短期记忆实现代码
python
from typing import List, Dict, Any
import json
class ShortTermMemory:
"""短期记忆类,存储Lobster循环的上下文信息"""
def __init__(self):
self.memory: List[Dict[str, Any]] = [] # 按时间顺序存储
def add(self, content: str or Dict[str, Any], memory_type: str = "cycle_result") -> None:
"""添加记忆内容"""
if isinstance(content, dict):
content = json.dumps(content, ensure_ascii=False)
self.memory.append({
"timestamp": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
"type": memory_type,
"content": content
})
def get_all(self) -> List[Dict[str, Any]]:
"""获取所有记忆内容"""
return self.memory
def get_latest(self, count: int = 1) -> List[Dict[str, Any]]:
"""获取最近N条记忆"""
return self.memory[-count:] if len(self.memory) >= count else self.memory
def clear(self) -> None:
"""清空记忆"""
self.memory = []
3. 短期记忆在循环中的注入流程
短期记忆主要在两个阶段注入:
(1)Plan阶段注入
将历史记忆(前序循环结果)拼接到Prompt中,让LLM知道"之前做了什么",避免重复执行已完成的步骤,示例:
python
# 获取最近3轮循环的记忆
latest_memory = short_term_memory.get_latest(count=3)
# 拼接到Plan Prompt中
prompt = prompt.format(
skill_info=skill_info,
history_context=json.dumps(latest_memory, ensure_ascii=False),
user_instruction=user_instruction
)
(2)Reflect阶段注入
将当前Act阶段的执行结果添加到记忆中,为下一轮循环提供上下文,示例:
python
# 在Reflect阶段后添加记忆
short_term_memory.add(
content={
"cycle": cycle_count+1,
"act_result": act_result,
"reflect_result": reflect_result
},
memory_type="cycle_result"
)
4. 记忆注入的关键优化点
- 记忆截断:只传递最近N轮的记忆(如3-5轮),避免Prompt过长导致LLM上下文溢出;
- 记忆过滤:只保留关键信息(如执行结果、反思结论),过滤冗余日志;
- 记忆分类:按类型(循环结果、用户输入、环境信息)存储,便于按需调用。
实战:修改Lobster循环,增加"人类确认"环节(高危操作前暂停)
在实际使用中,Agent执行高危操作(如删除文件、调用付费API、修改数据库)时,需要增加"人类确认"环节,避免误操作。以下是具体的改造步骤:
1. 定义高危技能列表
首先,在循环初始化时定义需要人类确认的高危技能:
python
HIGH_RISK_SKILLS = ["file_delete", "database_write", "api_payment", "system_command"]
2. 修改Act阶段,增加确认逻辑
在_act_stage函数中,添加高危技能的确认判断:
python
def _act_stage(
current_plans: List[Dict[str, Any]],
env_info: Dict[str, Any],
skill_registry: SkillRegistry,
high_risk_skills: List[str] = HIGH_RISK_SKILLS
) -> Dict[str, Any]:
current_step = current_plans[0]
skill_name = current_step["skill_name"]
# 新增:高危技能判断
if skill_name in high_risk_skills:
print(f"\n⚠️ 即将执行高危操作:{current_step['description']}")
print(f"技能名称:{skill_name}")
print(f"执行参数:{json.dumps(current_step['parameters'], ensure_ascii=False)}")
# 等待用户确认
user_confirm = input("是否确认执行?(y/n):")
if user_confirm.lower() != "y":
return {
"step_id": current_step["step_id"],
"skill_name": skill_name,
"execution_status": "cancelled",
"result": "",
"error_msg": "用户取消执行高危操作"
}
# 原有逻辑(略)
3. 修改Reflect阶段,处理"用户取消"状态
在_reflect_stage函数中,新增对cancelled状态的处理:
python
def _reflect_stage(...):
# 原有逻辑:获取执行状态
execution_status = act_result["execution_status"]
# 新增:处理用户取消状态
if execution_status == "cancelled":
return {
"reflect_conclusion": "用户取消执行高危操作,任务终止",
"adjusted_plans": [],
"need_retry": False,
"need_user_intervention": False,
"task_completed": True,
"final_content": "任务已终止:用户取消执行高危操作"
}
# 原有逻辑(略)
4. 完整改造后的run_lobster_cycle函数(关键修改)
python
def run_lobster_cycle(...):
# 新增:定义高危技能列表
high_risk_skills = ["file_delete", "database_write", "api_payment", "system_command"]
while cycle_count < max_cycles and not task_completed:
try:
# ... 原有Plan/Observe逻辑 ...
# 3. Act阶段:执行当前步骤(传入高危技能列表)
act_result = _act_stage(
current_plans=current_plans,
env_info=env_info,
skill_registry=skill_registry,
high_risk_skills=high_risk_skills # 新增参数
)
# ... 原有Reflect逻辑 ...
except Exception as e:
# ... 原有异常处理 ...
5. 测试改造效果
当Agent执行"file_delete"技能时,控制台会输出以下内容并暂停,等待用户确认:
开始第2轮Lobster循环
Plan阶段生成1个步骤
Observe阶段获取环境信息完成
⚠️ 即将执行高危操作:删除本地文件./data/sales_raw.html
技能名称:file_delete
执行参数:{"file_path": "./data/sales_raw.html"}
是否确认执行?(y/n):
- 输入
y:继续执行删除操作; - 输入
n:终止任务,返回"用户取消执行高危操作"的结果。
面试考点:ReAct模式与Lobster循环的异同
在大模型Agent相关面试中,ReAct模式是高频考点,而Lobster循环作为ReAct的工程化实现,两者的异同是核心考察点:
1. 核心相同点
- 核心思想一致:均遵循"推理(Reasoning)+ 行动(Acting)"的闭环逻辑,通过"思考-行动-反思"完成复杂任务;
- 迭代执行:均支持多轮迭代,根据执行结果调整后续策略,而非一次性执行;
- 环境交互:均强调Agent与外部环境的交互(如调用工具、获取环境信息),而非仅依赖LLM的内部推理。
2. 核心不同点
| 维度 | ReAct模式(理论) | Lobster循环(工程实现) |
|---|---|---|
| 定义 | 一种Agent设计范式,描述"思考-行动"的核心逻辑 | OpenClaw框架中具体的执行循环,是ReAct的落地实现 |
| 阶段划分 | 分为Reason(推理)和Act(行动)两个核心阶段 | 拆分为Plan/Observe/Act/Reflect四个阶段,更细化 |
| 执行边界 | 无明确的循环终止条件 | 定义max_cycles、"任务完成判断"、"用户干预"等终止条件 |
| 工程细节 | 不涉及具体的代码实现、参数校验、异常处理 | 包含Skill注册、参数校验、记忆管理、异常捕获等工程细节 |
| 灵活性 | 仅为理论框架,无固定实现方式 | 可通过修改代码扩展功能(如增加人类确认、自定义记忆规则) |
3. 面试高频问题及参考答案
问题1:ReAct模式解决了传统LLM调用的什么问题?
答:传统LLM调用是"一次性输入-输出",无法处理需要多步交互的复杂任务(如需要多次调用工具、根据结果调整策略);ReAct模式通过"推理-行动"闭环,让Agent能像人类一样"边思考边行动",解决了LLM"纸上谈兵"的问题,同时通过与外部环境交互,避免了LLM的知识过期、计算能力弱等缺陷。
问题2:Lobster循环中Reflect阶段的核心作用是什么?
答:Reflect阶段是Lobster循环的"复盘环节",核心作用包括:① 验证当前步骤的执行结果是否符合预期;② 分析执行失败的原因(参数错误、工具问题、环境问题);③ 调整后续计划(重试、跳过、新增步骤);④ 判断是否需要用户干预或终止任务。Reflect阶段保证了循环的鲁棒性,避免Agent陷入无效执行。
问题3:如何优化Lobster循环的执行效率?
答:可从以下维度优化:① 记忆截断:只传递关键的历史上下文,减少LLM调用的Prompt长度;② 步骤合并:将连续的简单步骤合并为一个步骤,减少循环次数;③ 技能缓存:对重复调用的技能(如爬取同一网页)增加缓存,避免重复执行;④ 并行执行:对无依赖的步骤实现并行调用,提升执行速度;⑤ LLM选型:对简单步骤使用轻量级LLM(如GPT-3.5),复杂步骤使用GPT-4,平衡效率与效果。
总结
关键点回顾
- Lobster循环核心:作为OpenClaw Agent的执行引擎,拆分为Plan(规划)、Observe(观察)、Act(执行)、Reflect(反思)四个阶段,形成可迭代的"思考-行动"闭环,是ReAct模式的工程化实现;
- 核心设计要点 :通过思维链Prompt实现任务拆解、统一的Skill接口规范保证工具调用稳定性、短期记忆注入实现上下文传递,同时通过
max_cycles和异常处理保证循环健壮性; - 实战扩展:可通过修改核心函数扩展循环功能(如增加人类确认环节),优化方向包括记忆截断、步骤合并、技能缓存等,提升执行效率。
本文从理论到源码、从设计到实战,全方位拆解了Lobster循环的核心逻辑,希望能帮助你不仅理解Agent的"思考"机制,更能动手改造和优化循环逻辑,让OpenClaw Agent更好地适配实际业务场景。