Agent任务规划+工具调用原理
任务规划、工具调用与结果反思的实现要点
原题:请设计并实现一个基于大语言模型的简单Agent系统,要求具备任务规划、工具调用和结果反思的能力
Prompt工程 · 腾讯真题
30 秒回答
- ReAct思维链设计(Thought-Action-Observation循环)
- 工具注册与动态调用机制
- 反思模块的实现(检查工具结果、自我修正)
- 状态管理与上下文维护
回答与解析
答案要点
- ReAct思维链设计(Thought-Action-Observation循环)
- 工具注册与动态调用机制
- 反思模块的实现(检查工具结果、自我修正)
- 状态管理与上下文维护
- 错误处理与重试策略
核心架构:ReAct 循环
Agent = LLM + 工具 + 记忆 + 控制循环,采用 Thought → Action → Observation → ... → Finish 的推理模式。
关键模块实现
1. 工具注册与调用
class ToolRegistry:
def __init__(self):
self.tools = {}
def register(self, name, func, description, params):
self.tools[name] = {
"func": func, "desc": description,
"params": params # JSON Schema
}
def get_tool_prompt(self):
# 生成工具描述给LLM
return "\n".join([
f"{name}: {t['desc']}, 参数: {t['params']}"
for name, t in self.tools.items()
])
def execute(self, name, args):
return self.tools[name]["func"](**args)
2. ReAct 核心循环
class ReActAgent:
def __init__(self, llm, tools: ToolRegistry, max_steps=10):
self.llm = llm
self.tools = tools
self.max_steps = max_steps
self.memory = [] # 历史记录
def run(self, task: str) -> str:
self.memory.append(f"任务: {task}")
for step in range(self.max_steps):
# 构造Prompt:任务 + 工具说明 + 历史 + 输出格式要求
prompt = self._build_prompt()
# LLM输出结构化思考
response = self.llm.generate(prompt, stop=["Observation:"])
thought, action, action_input = self._parse(response)
self.memory.append(f"Thought: {thought}")
# 反思检查:是否需要调用工具
if action == "Finish":
return action_input # 最终答案
# 执行工具
try:
obs = self.tools.execute(action, json.loads(action_input))
self.memory.append(f"Action: {action}[{action_input}]")
self.memory.append(f"Observation: {obs}")
except Exception as e:
# 错误反馈给LLM自我修正
self.memory.append(f"Observation: 错误: {str(e)}")
return "达到最大步数,未完成"
3. 反思模块(关键)
def reflect(self, step_result: dict) -> bool:
"""检查是否需要回溯或修正"""
reflection_prompt = f"""
上一步结果: {step_result}
请判断: 1) 结果是否满足预期 2) 是否需要调整策略
输出: Continue / Retry / Backtrack / Finish
"""
decision = self.llm.generate(reflection_prompt)
return self._handle_decision(decision)
设计要点
| 模块 | 核心机制 |
|---|---|
| 规划 | LLM自主分解任务,每步生成Thought |
| 工具调用 | 结构化输出(JSON/特定格式)+ 动态路由 |
| 反思 | 结果验证 + 错误反馈 + 策略调整 |
| 记忆 | 滑动窗口上下文,关键信息摘要 |
生产优化:工具结果缓存、并行工具调用、超时熔断、人机协同确认。
口语版讲法(约4分钟)
- 一句话定位:Agent本质是LLM+工具+记忆+控制循环
- ReAct循环:Thought-Action-Observation不断迭代
- 工具注册与动态调用:结构化描述让LLM自主选工具
- 反思模块:检查结果、错误反馈、自我修正
- 落地风险:工具结果不可靠、循环失控、记忆溢出
这道题问的是Agent系统,说白了就是怎么让大模型不光能聊天,还能自主完成任务。核心框架就是ReAct循环,Thought、Action、Observation三步反复迭代,直到给出最终答案。
具体说一下,我设计一个Agent,先得有工具注册中心。比如客服场景,用户要退款,Agent得查订单、算金额、调用退款接口。每个工具我都注册进去,名字、功能描述、参数格式,用JSON Schema描述清楚。这样LLM看到提示就知道有哪些工具可用,怎么用。
然后核心循环来了。每次我先让LLM输出一个Thought,就是它打算怎么做,再输出Action和Action Input,就是调哪个工具、传什么参数。比如它想查订单号,就输出Action: query order, Input: {"order id": "123"}。我解析这个结构化输出,去执行工具,拿到Observation,也就是结果。如果结果正常,就把Thought、Action、Observation都追加到记忆里,继续下一轮。如果LLM输出Finish,那就返回最终答案。
这里有个坑,就是工具调用可能出错。比如订单号不存在,接口超时,或者LLM自己写错了参数。所以我做了错误处理,把异常信息也当成Observation塞回去,让LLM自己反思修正。比如它发现查不到订单,可能会换个订单号,或者问用户要更多信息。
再一个关键点是反思模块。每步执行完,我不是无脑往下走,而是让LLM判断结果是否合理。比如它调了库存查询,发现库存不足,那它得反思:是换个仓库,还是通知用户缺货?这个反思可以驱动它回溯、重试或者调整策略。说白了就是让模型自己检查自己的作业。
但真正落地,我特别关注几个风险。 一是工具返回的结果可能不可靠,比如第三方接口返回了脏数据,Agent会信以为真,导致后续全错。所以我会加一个验证步骤,对关键结果做格式校验和业务规则检查。二是循环可能失控,LLM在错误路径上越绕越深,所以我设了最大步数,超时就熔断,返回中间结果或者报错。三是记忆太长会超Token,我会用滑动窗口,只保留最近几轮,或者对历史做摘要压缩。
另外有个延伸点,就是当Agent需要同时调多个工具时,比如查订单的同时还要查用户信用分,我倾向于让LLM先规划一个子任务列表,再并行执行,而不是串行一步步走。这样能大幅提升效率,但对LLM的规划能力要求更高,也更容易出错。
所以我会把Agent看成LLM能力的外延,核心不是模型多强,而是控制循环和工具链的鲁棒性。我更倾向先搭一个简单但可靠的ReAct框架,再逐步加反思、并行、缓存这些优化,而不是一开始就上复杂架构。
关键一句:当Agent需要同时调多个工具时,先规划子任务列表再并行执行,能提升效率但增加复杂度。
面试官还可能这样问
- 问法 1 · 场景切入
假设你在做一个智能客服Agent,用户说‘帮我查一下上个月的订单’,Agent需要先调用订单查询工具,查到之后发现用户还想‘统计一下退款占比’,这时候它得自己规划下一步调用统计工具。你如果来实现这个能力,核心的循环机制怎么设计?
- 问法 2 · 层层追问
Agent怎么知道什么时候该调用工具?……调用完工具拿到结果后,如果发现结果不对或者不够,它怎么自我修正?……这个循环你怎么抽象成代码?
- 问法 3 · 直球架构
设计一个基于LLM的Agent系统,核心是ReAct循环,要求包含任务规划、工具调用和结果反思。你从整体架构开始,讲一下状态管理、工具注册、反思模块的具体实现,以及异常重试怎么处理?