Skip to main content

lellm_agent/runtime/
builder.rs

1//! AgentBuilder — Agent 链式构建器。
2//!
3//! 提供推荐的入口 API,一步构建 ToolUseLoop。
4//!
5//! # 示例
6//! ```ignore
7//! use lellm_agent::{AgentBuilder, ToolRegistration};
8//!
9//! let agent = AgentBuilder::new(model)
10//!     .system_prompt("你是一个有帮助的助手。".to_string())
11//!     .tool(search_tool)
12//!     .tool(weather_tool)
13//!     .max_iterations(20)
14//!     .build();
15//! ```
16
17use std::sync::Arc;
18
19use lellm_core::{ReasoningConfig, ToolChoice};
20use lellm_provider::ResolvedModel;
21
22use super::config::{ToolUseConfig, ToolUseDeps};
23use super::context::ContextBudget;
24use super::fallback::FallbackStrategy;
25use super::request_opts::RequestOptions;
26use super::retry::RetryPolicy;
27use super::runtime::ToolUseLoop;
28use super::tools::{CompositeCatalog, StaticCatalog, ToolCatalog, ToolExecutor, ToolRegistration};
29
30/// Agent 链式构建器 — 推荐的 Agent 创建方式。
31///
32/// 内部收集静态工具和动态目录,`build()` 时组装为 `ToolCatalog`,
33/// 再传给 `ToolUseLoop::new()`。所有 setter 返回 `self`(不借用),
34/// 支持流畅的链式调用。
35pub struct AgentBuilder {
36    model: ResolvedModel,
37    /// 收集通过 `.tool()` 注册的本地静态工具(最高优先级)
38    static_tools: Vec<ToolRegistration>,
39    /// 收集通过 `.catalog()` 注册的动态目录(按注册顺序,先绑定的优先级高于后绑定的)
40    catalogs: Vec<Arc<dyn ToolCatalog>>,
41    config: ToolUseConfig,
42    deps: ToolUseDeps,
43}
44
45impl AgentBuilder {
46    /// 创建构建器,绑定模型。
47    pub fn new(model: ResolvedModel) -> Self {
48        Self {
49            model,
50            static_tools: Vec::new(),
51            catalogs: Vec::new(),
52            config: ToolUseConfig::default(),
53            deps: ToolUseDeps::default(),
54        }
55    }
56
57    /// 注册工具。
58    pub fn tool(mut self, reg: ToolRegistration) -> Self {
59        self.static_tools.push(reg);
60        self
61    }
62
63    /// 批量注册工具。
64    pub fn tools(mut self, registrations: impl IntoIterator<Item = ToolRegistration>) -> Self {
65        self.static_tools.extend(registrations);
66        self
67    }
68
69    /// 绑定动态工具目录(MCP、插件系统等)。
70    ///
71    /// 可调用多次。按注册顺序,先绑定的优先级高于后绑定的。
72    /// 静态工具(`.tool()`)永远拥有最高优先级。
73    ///
74    /// # 示例
75    /// ```ignore
76    /// use std::sync::Arc;
77    /// use lellm_agent::{AgentBuilder, ToolCatalog};
78    /// use lellm_mcp::{McpCatalog, McpClient};
79    ///
80    /// let client = Arc::new(McpClient::with_transport(transport));
81    /// let catalog = McpCatalog::discover(client).await?;
82    /// let agent = AgentBuilder::new(model)
83    ///     .catalog(Arc::new(catalog))
84    ///     .build();
85    /// ```
86    pub fn catalog(mut self, catalog: Arc<dyn ToolCatalog>) -> Self {
87        self.catalogs.push(catalog);
88        self
89    }
90
91    /// 设置最大迭代轮次(默认 10)。
92    pub fn max_iterations(mut self, max: usize) -> Self {
93        self.config.max_iterations = max;
94        self
95    }
96
97    /// 设置每次 LLM 请求的最大输出 token 数(默认 4k)。
98    pub fn max_output_tokens(mut self, max: u32) -> Self {
99        self.config.max_output_tokens = max;
100        self
101    }
102
103    /// 设置整个 Agent Run 的最大输出 token 总数。
104    pub fn max_total_output_tokens(mut self, max: u32) -> Self {
105        self.config.max_total_output_tokens = Some(max);
106        self
107    }
108
109    /// 设置系统提示。
110    pub fn system_prompt(mut self, prompt: String) -> Self {
111        self.config.system_prompt = Some(prompt);
112        self
113    }
114
115    // ─── RequestOptions 快捷 setter ──────────────────────────
116
117    /// 设置完整的 RequestOptions(覆盖所有生成参数)。
118    pub fn request_options(mut self, opts: RequestOptions) -> Self {
119        self.config.request_options = opts;
120        self
121    }
122
123    /// 设置生成温度(0.0 ~ 2.0)。
124    pub fn temperature(mut self, t: f64) -> Self {
125        self.config.request_options.temperature = Some(t);
126        self
127    }
128
129    /// 设置 nucleus sampling 阈值(0.0 ~ 1.0)。
130    pub fn top_p(mut self, p: f64) -> Self {
131        self.config.request_options.top_p = Some(p);
132        self
133    }
134
135    /// 设置随机种子,保证可复现性。
136    pub fn seed(mut self, s: u64) -> Self {
137        self.config.request_options.seed = Some(s);
138        self
139    }
140
141    /// 设置工具选择策略(仅首轮生效)。
142    pub fn tool_choice(mut self, choice: ToolChoice) -> Self {
143        self.config.request_options.tool_choice = Some(choice);
144        self
145    }
146
147    /// 设置停止序列。
148    pub fn stop_sequences(mut self, seqs: Vec<String>) -> Self {
149        self.config.request_options.stop_sequences = Some(seqs);
150        self
151    }
152
153    /// 设置预填充文本(引导模型输出方向)。
154    pub fn prefill(mut self, text: String) -> Self {
155        self.config.request_options.prefill = Some(text);
156        self
157    }
158
159    /// 设置推理配置(控制模型是否进行深度推理)。
160    pub fn reasoning(mut self, r: ReasoningConfig) -> Self {
161        self.config.request_options.reasoning = Some(r);
162        self
163    }
164
165    /// 设置是否流式输出推理过程。
166    pub fn stream_thinking(mut self, enable: bool) -> Self {
167        self.config.stream_thinking = enable;
168        self
169    }
170
171    /// 设置单轮推理 Token 上限。
172    pub fn reasoning_budget(mut self, max: u32) -> Self {
173        self.config.request_options.max_reasoning_tokens = Some(max);
174        self
175    }
176
177    /// 设置整个 Agent Run 的最大推理 Token 总数。
178    pub fn max_total_reasoning_tokens(mut self, max: u32) -> Self {
179        self.config.max_total_reasoning_tokens = Some(max);
180        self
181    }
182
183    /// 设置 Fallback 策略。
184    pub fn fallback(mut self, fallback: Arc<dyn FallbackStrategy>) -> Self {
185        self.deps.fallback = fallback;
186        self
187    }
188
189    /// 设置工具重试策略。
190    pub fn retry_policy(mut self, policy: RetryPolicy) -> Self {
191        self.config.retry_policy = policy;
192        self
193    }
194
195    /// 设置上下文预算(Token 上限 + 压缩策略)。
196    /// 若要关闭限制,设置 `max_tokens = usize::MAX`。
197    pub fn context_budget(mut self, budget: ContextBudget) -> Self {
198        self.config.context_budget = budget;
199        self
200    }
201
202    /// 构建 ToolUseLoop。
203    ///
204    /// 将静态工具和动态目录坍缩为最终的 `ToolCatalog`,
205    /// 传给 `ToolUseLoop::new()`。
206    pub fn build(self) -> ToolUseLoop {
207        // 构造优先级队列:本地静态工具永远拥有最高优先级
208        let mut sources: Vec<Arc<dyn ToolCatalog>> = Vec::new();
209
210        if !self.static_tools.is_empty() {
211            sources.push(Arc::new(StaticCatalog::from_tools(self.static_tools)));
212        }
213
214        sources.extend(self.catalogs);
215
216        // 坍缩成最终的单根 Catalog
217        let final_catalog: Arc<dyn ToolCatalog> = match sources.len() {
218            0 => Arc::new(StaticCatalog::empty()),
219            1 => sources.remove(0),
220            _ => Arc::new(CompositeCatalog::new(sources)),
221        };
222
223        let executor =
224            ToolExecutor::with_retry_policy(final_catalog, self.config.retry_policy.clone());
225        ToolUseLoop::new(self.model, executor, self.config, self.deps)
226    }
227}