推理与规划

推理与规划是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系统。