推理与规划
推理与规划是AI智能体最核心的能力,决定了Agent能否有效地解决复杂问题。推理是Agent理解问题、分析信息、得出结论的过程;规划则是将目标分解为可执行步骤的策略制定过程。两者相辅相成,共同构成了Agent的"思维"能力。
一、思维链(Chain-of-Thought)
思维链(Chain-of-Thought,CoT)是一种让大语言模型逐步推理的技术。通过在提示中引导模型展示中间推理步骤,而非直接给出答案,CoT显著提升了模型在复杂任务上的表现。
CoT的核心思想是:将复杂推理分解为一系列简单的中间步骤,每一步都基于前一步的结果。这种方式模拟了人类的逐步思考过程,使得模型能够处理需要多步推理的问题。
# 思维链推理示例
class ChainOfThought:
"""思维链推理引擎"""
def __init__(self, llm):
self.llm = llm
def reason(self, question, context=""):
"""使用思维链进行逐步推理"""
prompt = f"""请逐步思考以下问题,展示你的推理过程。
背景信息:{context}
问题:{question}
请按以下步骤回答:
1. 首先,分析问题的关键要素
2. 然后,逐步推理每个部分
3. 最后,综合得出结论
思考过程:"""
response = self.llm.generate(prompt)
return self.parse_reasoning_chain(response)
def parse_reasoning_chain(self, response):
"""解析思维链结构"""
steps = []
current_step = {"thought": "", "conclusion": ""}
for line in response.split("\n"):
if line.startswith("步骤") or line.startswith("第"):
if current_step["thought"]:
steps.append(current_step)
current_step = {"thought": line, "conclusion": ""}
else:
current_step["thought"] += line + "\n"
steps.append(current_step)
return ReasoningChain(steps=steps, final_answer=steps[-1]["conclusion"])
# 使用示例
# 问题:一个商店打8折后再打9折,原价200元,最终价格是多少?
# 思维链:
# 步骤1:原价200元,打8折 -> 200 * 0.8 = 160元
# 步骤2:160元再打9折 -> 160 * 0.9 = 144元
# 结论:最终价格是144元
二、思维树(Tree-of-Thought)
思维树(Tree-of-Thought,ToT)是CoT的进阶版本。与线性的思维链不同,ToT允许Agent在推理过程中探索多条路径,评估每条路径的前景,并选择最优路径继续深入。这种机制类似于人类在解决问题时"发散思考再收敛"的过程。
ToT的关键优势在于:
- 探索性:不局限于单一路径,可以同时考虑多种解决方案。
- 自我评估:在每个节点评估当前路径的质量,及时放弃不可行的方向。
- 回溯能力:当发现当前路径行不通时,可以回退到之前的节点尝试其他分支。
- 全局优化:通过搜索算法(如BFS、DFS、束搜索)找到全局最优解。
class TreeOfThought:
"""思维树推理引擎"""
def __init__(self, llm, max_branches=3, max_depth=5):
self.llm = llm
self.max_branches = max_branches
self.max_depth = max_depth
def solve(self, problem):
"""使用思维树求解"""
root = ThoughtNode(
thought="初始问题分析",
parent=None,
score=self.evaluate_promising(problem, "初始分析")
)
# 束搜索(Beam Search)
current_beam = [root]
for depth in range(self.max_depth):
next_beam = []
for node in current_beam:
# 生成多个可能的下一步思考
branches = self.generate_branches(node, self.max_branches)
for branch in branches:
score = self.evaluate_promising(problem, branch)
child = ThoughtNode(
thought=branch,
parent=node,
score=score
)
next_beam.append(child)
# 检查是否已找到解决方案
if self.is_solution(problem, child):
return self.extract_solution(child)
# 保留得分最高的节点
next_beam.sort(key=lambda x: x.score, reverse=True)
current_beam = next_beam[:self.max_branches]
# 返回得分最高的路径
best = max(current_beam, key=lambda x: x.score)
return self.extract_solution(best)
def generate_branches(self, node, n):
"""在当前节点生成n个思考分支"""
prompt = f"""当前思考路径:{node.get_path()}
请提出{n}个可能的下一步思考方向,每个方向用一行描述。"""
response = self.llm.generate(prompt)
return response.strip().split("\n")[:n]
def evaluate_promising(self, problem, thought_path):
"""评估一条思考路径的前景(0-1分)"""
prompt = f"""问题:{problem}
当前思考路径:{thought_path}
请评估这条思路解决原问题的可能性,给出0到1之间的分数。
只回答数字。"""
score = float(self.llm.generate(prompt).strip())
return min(max(score, 0), 1)
CoT vs ToT:如何选择
思维链适合线性推理任务,如数学计算、逻辑推导等步骤明确的问题。思维树适合需要探索多种可能性的任务,如创意写作、策略规划、复杂决策等。ToT的计算成本更高(需要多次LLM调用),但在复杂问题上能产出更高质量的解决方案。
三、规划算法
规划(Planning)是Agent将高层目标分解为具体可执行步骤的能力。有效的规划需要考虑任务依赖关系、资源约束、时间限制等因素。以下是几种常用的规划方法:
1. 任务分解(Task Decomposition)
将复杂任务递归地分解为更小的子任务,直到每个子任务足够简单可以直接执行。这是最直观的规划方法。
2. 层次规划(Hierarchical Planning)
在不同抽象层次上进行规划。高层计划定义战略目标,低层计划实现具体操作。
3. 基于约束的规划(Constraint-based Planning)
在满足各种约束条件(时间、资源、依赖关系)的前提下寻找可行方案。
class TaskPlanner:
"""Agent任务规划器"""
def __init__(self, llm):
self.llm = llm
def decompose(self, task, max_depth=3):
"""递归任务分解"""
plan = self._decompose_recursive(task, depth=0, max_depth=max_depth)
return self.optimize_dependencies(plan)
def _decompose_recursive(self, task, depth, max_depth):
"""递归分解子任务"""
if depth >= max_depth or self.is_atomic(task):
return TaskNode(task=task, subtasks=[], is_leaf=True)
prompt = f"""将以下任务分解为2-5个可独立执行的子任务:
任务:{task}
要求:
- 每个子任务应该是具体、可执行的
- 标明子任务之间的依赖关系
- 如果任务已经足够简单,直接返回该任务本身
输出格式:
子任务1: [描述] (依赖: 无/子任务X)
子任务2: [描述] (依赖: 无/子任务X)
..."""
response = self.llm.generate(prompt)
subtasks = self.parse_subtasks(response)
node = TaskNode(task=task, subtasks=[], is_leaf=False)
for subtask in subtasks:
child = self._decompose_recursive(
subtask["description"],
depth + 1,
max_depth
)
child.dependencies = subtask.get("dependencies", [])
node.subtasks.append(child)
return node
def optimize_dependencies(self, plan):
"""优化任务依赖关系,识别可并行的任务"""
# 构建依赖图
graph = self.build_dependency_graph(plan)
# 拓扑排序
ordered = self.topological_sort(graph)
# 识别可并行的任务组
parallel_groups = self.find_parallel_groups(ordered)
return ExecutionPlan(
ordered_steps=ordered,
parallel_groups=parallel_groups
)
def find_parallel_groups(self, ordered_tasks):
"""找出可以并行执行的任务组"""
groups = []
current_group = []
for task in ordered_tasks:
if not task.has_unmet_dependencies(current_group):
current_group.append(task)
else:
if current_group:
groups.append(current_group)
current_group = [task]
if current_group:
groups.append(current_group)
return groups
四、ReAct 框架
ReAct(Reasoning + Acting)是将推理和行动紧密结合的Agent框架。在ReAct中,Agent交替进行推理(Thought)、行动(Action)和观察(Observation),形成一个持续的思考-行动-反馈循环。
ReAct的核心优势在于:
- 推理指导行动:每一步行动都基于明确的推理,而非盲目尝试。
- 行动丰富推理:行动的结果(观察)为后续推理提供了新的信息。
- 可解释性:推理过程被显式记录,便于调试和理解Agent的决策逻辑。
- 错误恢复:当行动结果不符合预期时,Agent可以通过推理调整策略。
class ReActAgent:
"""ReAct框架实现"""
def __init__(self, llm, tools, max_steps=10):
self.llm = llm
self.tools = {t.name: t for t in tools}
self.max_steps = max_steps
def run(self, task):
"""执行ReAct循环"""
history = [f"任务: {task}"]
for step in range(self.max_steps):
# Thought: 推理当前应该做什么
thought = self.llm.generate(self._build_prompt(history))
# 解析推理结果
action = self._parse_action(thought)
if action == "finish":
return self._parse_final_answer(thought)
# Action: 执行选定的行动
if action.tool_name in self.tools:
observation = self.tools[action.tool_name].run(
**action.arguments
)
else:
observation = f"错误: 未知工具 {action.tool_name}"
# Observation: 记录观察结果
history.append(f"思考: {thought}")
history.append(f"行动: {action.tool_name}({action.arguments})")
history.append(f"观察: {observation}")
return "达到最大步数限制,未能完成任务"
def _build_prompt(self, history):
"""构建ReAct提示"""
tool_descriptions = "\n".join(
f"- {t.name}: {t.description}"
for t in self.tools.values()
)
return f"""请根据任务和历史记录,决定下一步行动。
可用工具:
{tool_descriptions}
历史记录:
{chr(10).join(history)}
请按照以下格式回答:
思考: [你的推理过程]
行动: [工具名称]
参数: [工具参数]
或者如果已有足够信息:
思考: [总结推理]
回答: [最终答案]"""
ReAct 的实践要点
ReAct是目前最流行的Agent执行框架之一。在实践中,需要注意:1)工具描述要清晰准确,帮助Agent正确选择工具;2)设置合理的最大步数,防止无限循环;3)记录完整的推理历史,便于调试和优化;4)对于简单任务,可以跳过推理直接行动以节省成本。在OpenClaw中,ReAct是默认的执行模式。
五、推理与规划的工程优化
在实际部署中,推理与规划模块需要针对性能和成本进行优化:
- 缓存推理结果:对常见推理模式进行缓存,避免重复计算。
- 分层推理:简单问题用轻量模型快速回答,复杂问题才使用大模型深度推理。
- 计划复用:将成功的计划模板化,类似任务可以复用已有计划。
- 提前终止:当推理过程中发现明确答案时,立即终止而非继续探索。
- 并行探索:在ToT等搜索框架中,并行评估多个分支以加速推理。
推理与规划能力是区分"智能"Agent和简单脚本的关键。通过合理选择推理策略(CoT、ToT、ReAct)和规划算法,我们可以构建出能够处理各种复杂任务的强大Agent系统。