Skip to main content

lc_agents/plan_execute/
agent.rs

1//! PlanExecuteAgent - 规划-执行-重规划
2
3use std::sync::Arc;
4
5use crate::{AgentError, AgentExecutor, BaseAgent, FunctionCallingAgent};
6use lc_core::language_models::BaseChatModel;
7use lc_core::tools::BaseTool;
8use lc_providers::ProviderError;
9
10use super::plan::StepStatus;
11use super::planner::Planner;
12
13/// Plan-Execute Agent 错误类型
14#[derive(Debug, thiserror::Error)]
15pub enum PlanExecuteError {
16    /// 规划失败
17    #[error("Planning failed: {0}")]
18    PlanningError(String),
19    /// 步骤执行失败
20    #[error("Step execution failed: {0}")]
21    StepExecutionError(String),
22    /// 达到最大重规划次数
23    #[error("Max replans reached: step [{step}] failed: {reason}")]
24    MaxReplansReached { step: String, reason: String },
25    /// 计划未完成
26    #[error("Plan incomplete after all replans")]
27    PlanIncomplete,
28}
29
30impl From<AgentError> for PlanExecuteError {
31    fn from(e: AgentError) -> Self {
32        PlanExecuteError::StepExecutionError(e.to_string())
33    }
34}
35
36/// Plan-Execute Agent:先规划,逐步执行,失败时重规划
37///
38/// 支持任何实现了 `BaseChatModel` 的 LLM Provider。
39pub struct PlanExecuteAgent {
40    llm: Arc<dyn BaseChatModel<Error = ProviderError> + Send + Sync>,
41    tools: Vec<Arc<dyn BaseTool>>,
42    max_replans: usize,
43}
44
45impl PlanExecuteAgent {
46    /// 创建新的 Plan-Execute Agent
47    ///
48    /// # 参数
49    /// * `llm` - LLM 客户端(任何实现了 `BaseChatModel` 的类型)
50    /// * `tools` - 可用工具列表
51    ///
52    /// # 向后兼容
53    /// 旧代码 `PlanExecuteAgent::new(openai_chat, tools)` 仍然可用。
54    pub fn new<L>(llm: L, tools: Vec<Arc<dyn BaseTool>>) -> Self
55    where
56        L: BaseChatModel + Send + Sync + 'static,
57        L::Error: Into<ProviderError>,
58    {
59        Self {
60            llm: lc_providers::wrap_chat_model(llm),
61            tools,
62            max_replans: 2,
63        }
64    }
65
66    /// 从已包装的 `Arc<dyn BaseChatModel>` 创建 Agent
67    pub fn from_arc(
68        llm: Arc<dyn BaseChatModel<Error = ProviderError> + Send + Sync>,
69        tools: Vec<Arc<dyn BaseTool>>,
70    ) -> Self {
71        Self {
72            llm,
73            tools,
74            max_replans: 2,
75        }
76    }
77
78    pub fn with_max_replans(mut self, n: usize) -> Self {
79        self.max_replans = n;
80        self
81    }
82
83    /// 运行完整任务:规划 -> 执行每步 -> 失败重规划 -> 汇总
84    pub async fn run(&self, objective: &str) -> Result<String, PlanExecuteError> {
85        let planner = Planner::new(self.llm.clone());
86        let mut plan = planner
87            .plan(objective)
88            .await
89            .map_err(PlanExecuteError::PlanningError)?;
90
91        for replan_count in 0..=self.max_replans {
92            let pending_ids: Vec<usize> = plan
93                .steps
94                .iter()
95                .filter(|s| s.status == StepStatus::Pending)
96                .map(|s| s.id)
97                .collect();
98
99            let mut failed = false;
100            for step_id in pending_ids {
101                let step = plan.steps.iter_mut().find(|s| s.id == step_id);
102                let step_desc = match step {
103                    Some(s) => {
104                        s.status = StepStatus::Running;
105                        s.description.clone()
106                    }
107                    None => {
108                        // step_id does not correspond to any step; skip it
109                        continue;
110                    }
111                };
112
113                match self.execute_step(&step_desc).await {
114                    Ok(result) => plan.mark_completed(step_id, result),
115                    Err(e) => {
116                        let error_msg = e.to_string();
117                        plan.mark_failed(step_id, error_msg.clone());
118                        if replan_count < self.max_replans {
119                            plan = planner
120                                .replan(objective, &step_desc, &error_msg)
121                                .await
122                                .map_err(PlanExecuteError::PlanningError)?;
123                            failed = true;
124                            break;
125                        } else {
126                            return Err(PlanExecuteError::MaxReplansReached {
127                                step: step_desc,
128                                reason: error_msg,
129                            });
130                        }
131                    }
132                }
133            }
134
135            if !failed && plan.is_complete() {
136                let summary: Vec<String> = plan
137                    .steps
138                    .iter()
139                    .map(|s| {
140                        format!(
141                            "{}. {}: {}",
142                            s.id + 1,
143                            s.description,
144                            s.result.as_deref().unwrap_or("无结果")
145                        )
146                    })
147                    .collect();
148                return Ok(summary.join("\n"));
149            }
150        }
151        Err(PlanExecuteError::PlanIncomplete)
152    }
153
154    /// 执行单步:用 FunctionCallingAgent + tools
155    async fn execute_step(&self, step: &str) -> Result<String, PlanExecuteError> {
156        let agent = FunctionCallingAgent::from_arc(self.llm.clone(), self.tools.clone(), None);
157        let executor =
158            AgentExecutor::new(Arc::new(agent) as Arc<dyn BaseAgent>, self.tools.clone())
159                .with_max_iterations(5);
160        executor
161            .invoke(step.to_string())
162            .await
163            .map_err(|e| PlanExecuteError::StepExecutionError(e.to_string()))
164    }
165}