1 介绍
loop 是 Agent 实现最重要的一个 part,其中分为 lead agent 的 loop 和 sub_agent 的 loop
2 代码-接收控制台输入的命令
python
def interactive_mode():
"""🎮 启动交互式命令行模式"""
# 打印Banner
print_banner()
# 打印使用提示
print_info("输入任务描述,或输入 [bold]quit[/] 退出")
print_info("使用 [bold]--plan[/] 前缀启用任务规划模式")
console.print()
# 循环接收任务
while True:
try:
user_input = get_user_input(">>")
# 退出命令
if user_input.lower() in ['quit', 'exit', 'q']:
console.print("\n[bold cyan]👋 感谢使用 EasyAgent[/]\n"); break
if not user_input.strip():
continue
# 检测是否启用任务规划
use_plan = user_input.startswith("--plan ")
task = user_input.replace("--plan ", "").strip()
if not task:
print_error("请输入有效的任务描述"); continue
console.print()
# 执行智能体
run_agent_plus(task, use_plan=use_plan)
console.print()
except KeyboardInterrupt:
console.print("\n[yellow]⚠️ 任务中断[/]"); continue
except Exception as e:
print_error(f"执行异常: {e}"); continue
- 第一步: 边界条件的判断,如果输入包含
quit等退出指令,则打印提示,并break循环 loop; - 第二步: 判断用户是否使用任务分解
--plan,如果使用的话,作为智能体执行run_agent_plus()的参数;
3 代码-Agent的入口
python
def run_agent_plus(task, use_plan=False, keep_chatting=False, use_team=False):
"""增强版智能体入口"""
# 加载历史记忆
memory = load_memory()
system_prompt = "您是一位能够与系统交互的得力助手。请言简意赅。"
# 拼接记忆到系统提示
if memory:
system_prompt += f"\n\n之前的上下文:\n{memory}"
messages = [{"role": "system", "content": system_prompt}]
# 使用 Agent 团队处理(如果启用)
if use_team and agent_team:
print_section("🤖 使用 Agent 团队处理", style=THEME["primary"])
task_id = agent_team.submit_task({"content": task, "description": task})
print_info(f"任务已提交到队列: {task_id}")
return f"Task {task_id} submitted to team"
# 生成任务步骤
steps = create_plan(task) if use_plan else [task]
print_section("🚀 开始执行任务", style=THEME["success"])
all_results, step_index = [], 0
# 遍历执行所有步骤
while step_index < len(steps):
step_index += 1
current_step = steps[step_index - 1]
# 多步骤时显示当前步骤面板
if len(steps) > 1:
console.print(Panel(f"[bold]{current_step}[/]", title=f"[{THEME['primary']}]📍 步骤 {step_index}/{len(steps)}[/]", border_style=THEME["border"], padding=(1, 2)))
# 执行单步任务
result, actions, messages = run_agent_step(current_step, messages)
all_results.append(result)
print_result(result, title=f"✨ 步骤 {step_index} 执行完成")
# 获取用户反馈
feedback, should_continue = get_step_advice(step_index, len(steps), current_step, result)
# 处理反馈指令
if feedback == "__skip_all__":
console.print("[yellow]⏭️ 跳过剩余步骤,任务提前结束[/]"); break
# 处理控制指令
if feedback == "__retry__":
print_info(f"🔄 重新执行步骤 {step_index}...")
step_index -= 1 # 回退索引,重试当前步骤
continue
elif feedback == "confirmed":
# 用户确认,无需额外操作,继续下一步
pass
elif feedback: # 非空 = 用户建议,直接透传给 AI
console.print(Panel("[dim]🔄 正在处理您的建议...[/]", border_style=THEME["primary"], padding=(0, 2)))
messages.append({"role": "user", "content": f"[步骤反馈] {current_step}\n用户建议: {feedback}"})
response = with_spinner("🤖 思考中...", client.chat.completions.create,
model=MODEL_NAME, messages=messages, tools=TOOLS)
ai_response = response.choices[0].message.content
# 展示 AI 响应
if ai_response:
print_result(ai_response, title=f"💬 响应")
messages.append({"role": "assistant", "content": ai_response})
if not should_continue:
break
# 合并所有结果并保存记忆
final_result = "\n".join(all_results)
save_memory(task, final_result)
console.print(Panel("[bold green]🎉 任务执行完成![/]", border_style=THEME["success"], padding=(1, 2)))
# 开启连续对话
if keep_chatting:
messages = continue_chatting(messages, task)
return final_result
第一部分:加载历史记忆
这里我们用的是 .md 存储用户以往的对话,对话内容包含 Query 和 Result (summary之后的内容,所以 Token 消耗并不大),具体操作就是简单的拼接,然后以 System 的方式封装到 messages 列表中:
python
memory = load_memory()
system_prompt = "您是一位能够与系统交互的得力助手。请言简意赅。"
# 拼接记忆到系统提示
if memory:
system_prompt += f"\n\n之前的上下文:\n{memory}"
messages = [{"role": "system", "content": system_prompt}]
第二部分:是否使用 Agent Team
如果使用 Agent Team,那么任务就提交到任务队列中,字段包含 task_id、description 等(顶层任务无依赖方);
python
# 使用 Agent 团队处理(如果启用)
if use_team and agent_team:
print_section("🤖 使用 Agent 团队处理", style=THEME["primary"])
task_id = agent_team.submit_task({"content": task, "description": task})
print_info(f"任务已提交到队列: {task_id}")
return f"Task {task_id} submitted to team"
第三部分:任务分解
本质上,就是通过提示词的方式,指定 response_format 让大模型生成 json 结构的分解步骤:
python
# 生成任务步骤
steps = create_plan(task) if use_plan else [task]
print_section("🚀 开始执行任务", style=THEME["success"])
- 如果设置任务分解,这里会是第一次问答;
第四部分:回答每个 step 任务
返回最终的结果,其中 result 是模型对一个 Step 最后一次回答的结果(完成一个 Step 至少需要回答两次);
而 actions 的内容是所有执行的工具的 name 和 args;
messages 列表中包含了 tools_result 和 model_response;
python
all_results, step_index = [], 0
# 遍历执行所有步骤
while step_index < len(steps):
step_index += 1
current_step = steps[step_index - 1]
# 多步骤时显示当前步骤面板
if len(steps) > 1:
console.print(Panel(f"[bold]{current_step}[/]", title=f"[{THEME['primary']}]📍 步骤 {step_index}/{len(steps)}[/]", border_style=THEME["border"], padding=(1, 2)))
# 执行单步任务
result, actions, messages = run_agent_step(current_step, messages)
all_results.append(result)
print_result(result, title=f"✨ 步骤 {step_index} 执行完成")
单步骤执行的具体逻辑 run_agent_step() :
-
- 先对任务进行请求,提取
tool_calling字段看需要调用的工具内容和参数;
- 先对任务进行请求,提取
-
- 注入工具,再进行问答,封装到
messages列表中;
- 注入工具,再进行问答,封装到
-
- 工具,可以通过懒加载先把元数据加载到
system_prompt中,然后在具体使用具体某个 tool 的时候再加载详细的描述;
- 工具,可以通过懒加载先把元数据加载到
python
# ===================== 单步执行 =====================
def run_agent_step(task, messages, max_iterations=5):
"""执行单个步骤"""
# 将当前任务加入对话上下文
messages.append({"role": "user", "content": task})
# 存储执行的动作
actions = []
# 最大迭代次数,防止死循环
for iteration in range(max_iterations):
if iteration > 0:
print_info(f"第 {iteration + 1} 次迭代...")
# 调用AI,带加载动画
response = with_spinner("AI 思考中...", client.chat.completions.create, model=MODEL_NAME, messages=messages, tools=TOOLS)
message = response.choices[0].message
# 将AI回复加入上下文
messages.append({
"role": message.role,
"content": message.content,
"tool_calls": message.tool_calls if hasattr(message, "tool_calls") else None
})
# 无工具调用,直接返回结果
if not message.tool_calls:
result = message.content if message.content else "[dim](任务已完成,无额外输出)[/]"
return result, actions, messages
# 遍历所有工具调用
for tool_call in message.tool_calls:
function_payload = getattr(tool_call, "function", None)
if function_payload is None:
continue
# 获取函数名和参数
function_name = str(getattr(function_payload, "name", ""))
raw_arguments = str(getattr(function_payload, "arguments", ""))
function_args = parse_tool_arguments(raw_arguments)
# 打印工具调用信息
print_tool_call(function_name, function_args)
# 查找并执行对应函数
function_impl = AVAILABLE_FUNCTIONS.get(function_name)
if function_impl is None:
function_response = f"Error: Unknown tool '{function_name}'"
elif "_argument_error" in function_args:
function_response = f"Error: {function_args['_argument_error']}"
else:
function_response = function_impl(**function_args)
actions.append({"tool": function_name, "args": function_args})
# 将工具执行结果加入上下文
messages.append({"role": "tool", "tool_call_id": tool_call.id, "content": function_response})
# 达到最大迭代次数,终止执行
print_error("达到最大迭代次数,终止执行")
return "Max iterations reached", actions, messages
第五部分:对每个 step 的结果提出建议
get_step_advice:从控制台读取user_input,作为messages列表的输入;- 第四次问答,模型将根据用户的建议,对
step重新回答一次;
python
# 获取用户反馈
feedback, should_continue = get_step_advice(step_index, len(steps), current_step, result)
# 处理反馈指令
if feedback == "__skip_all__":
console.print("[yellow]⏭️ 跳过剩余步骤,任务提前结束[/]"); break
# 处理控制指令
if feedback == "__retry__":
print_info(f"🔄 重新执行步骤 {step_index}...")
step_index -= 1 # 回退索引,重试当前步骤
continue
elif feedback == "confirmed":
# 用户确认,无需额外操作,继续下一步
pass
elif feedback: # 非空 = 用户建议,直接透传给 AI
console.print(Panel("[dim]🔄 正在处理您的建议...[/]", border_style=THEME["primary"], padding=(0, 2)))
messages.append({"role": "user", "content": f"[步骤反馈] {current_step}\n用户建议: {feedback}"})
response = with_spinner("🤖 思考中...", client.chat.completions.create,
model=MODEL_NAME, messages=messages, tools=TOOLS)
ai_response = response.choices[0].message.content
# 展示 AI 响应
if ai_response:
print_result(ai_response, title=f"💬 响应")
messages.append({"role": "assistant", "content": ai_response})
if not should_continue:
break
第六部分:存储记忆
将第三次问答的 response 存储到 .md 中;
python
# 合并所有结果并保存记忆
final_result = "\n".join(all_results)
save_memory(task, final_result)
console.print(Panel("[bold green]🎉 任务执行完成![/]", border_style=THEME["success"], padding=(1, 2)))
# 开启连续对话
if keep_chatting:
messages = continue_chatting(messages, task)
return final_result
总结
第 1 次问答: 任务分解,假设分为 n 个子任务(1次问答);
第 2 ~ n+1 次问答: 查看每个子任务需要调用的工具(n次问答);
第 n+2 ~ 2n+2 次问答: 每次调用完工具至少还需要一次问答生成答案总结(n次问答) ;
第 2n+3 ~ 3n+3 次问答: 每个子任务可以提出建议(n次问答);
一共 3n+1 次问答,如果你的任务很复杂,那么单 Agent 会堵死去。这也是为什么要用懒加载和任务规划的原因;