Skip to main content

lellm_agent/runtime/
request_opts.rs

1//! RequestOptions — Agent 每轮 LLM 调用的生成参数。
2//!
3//! 独立字段定义,不与 `ChatRequest` 耦合。
4//! `apply()` 方法将非默认值覆盖到基础 `ChatRequest` 上。
5//!
6//! # 设计原则
7//!
8//! - **独立字段**:不包裹 `ChatRequest`,避免不必要的耦合
9//! - **选择性覆盖**:`apply()` 只覆盖非默认值,保留基础请求的核心字段
10//! - **Agent 保留字段**:`model`、`messages`、`tools` 由 Agent 层注入,`apply()` 跳过
11
12use lellm_core::ChatRequest;
13
14/// Agent 每轮 LLM 调用的生成参数覆盖。
15///
16/// 用户只需设置需要覆盖的字段。
17/// 未设置的字段保持默认值(None),`apply()` 时会被跳过。
18///
19/// # Agent 保留字段
20///
21/// 以下字段由 Agent 层自动注入,`apply()` 不会覆盖:
22/// - `model` — 来自 `ResolvedModel`
23/// - `messages` — 来自对话历史
24/// - `tools` — 来自 `ToolExecutor`
25///
26/// # 示例
27///
28/// ```ignore
29/// let opts = RequestOptions::new()
30///     .temperature(0.1)
31///     .reasoning(ReasoningConfig::High);
32///
33/// let agent = AgentBuilder::new(model)
34///     .request_options(opts)
35///     .build();
36/// ```
37#[derive(Debug, Clone, Default)]
38pub struct RequestOptions {
39    pub temperature: Option<f64>,
40    pub top_p: Option<f64>,
41    pub seed: Option<u64>,
42    pub tool_choice: Option<lellm_core::ToolChoice>,
43    pub stop_sequences: Option<Vec<String>>,
44    pub prefill: Option<String>,
45    pub reasoning: Option<lellm_core::ReasoningConfig>,
46    pub max_reasoning_tokens: Option<u32>,
47    pub extra: Option<serde_json::Map<String, serde_json::Value>>,
48}
49
50impl RequestOptions {
51    /// 创建空的 RequestOptions(所有字段为默认值)。
52    pub fn new() -> Self {
53        Self::default()
54    }
55
56    /// 将非默认值覆盖到基础 ChatRequest 上。
57    ///
58    /// **跳过字段:** `model`、`messages`、`tools`(由 Agent 层注入)
59    /// **跳过规则:** `None`、空 String、空 Vec、false 等默认值不覆盖
60    pub fn apply(&self, req: &mut ChatRequest) {
61        if self.temperature.is_some() {
62            req.temperature = self.temperature;
63        }
64        if self.top_p.is_some() {
65            req.top_p = self.top_p;
66        }
67        if self.seed.is_some() {
68            req.seed = self.seed;
69        }
70        if self.tool_choice.is_some() {
71            req.tool_choice = self.tool_choice.clone();
72        }
73        if self.stop_sequences.is_some() {
74            req.stop_sequences = self.stop_sequences.clone();
75        }
76        if self.prefill.is_some() {
77            req.prefill = self.prefill.clone();
78        }
79        if self.reasoning.is_some() {
80            req.reasoning = self.reasoning;
81        }
82        if self.max_reasoning_tokens.is_some() {
83            req.max_reasoning_tokens = self.max_reasoning_tokens;
84        }
85        if self.extra.is_some() {
86            req.extra = self.extra.clone();
87        }
88    }
89}
90
91// ─── 链式 setter ──────────────────────────────────────────────────
92
93impl RequestOptions {
94    pub fn temperature(mut self, t: f64) -> Self {
95        self.temperature = Some(t);
96        self
97    }
98
99    pub fn top_p(mut self, p: f64) -> Self {
100        self.top_p = Some(p);
101        self
102    }
103
104    pub fn seed(mut self, s: u64) -> Self {
105        self.seed = Some(s);
106        self
107    }
108
109    pub fn tool_choice(mut self, choice: lellm_core::ToolChoice) -> Self {
110        self.tool_choice = Some(choice);
111        self
112    }
113
114    pub fn stop_sequences(mut self, seqs: Vec<String>) -> Self {
115        self.stop_sequences = Some(seqs);
116        self
117    }
118
119    pub fn prefill(mut self, text: String) -> Self {
120        self.prefill = Some(text);
121        self
122    }
123
124    pub fn reasoning(mut self, r: lellm_core::ReasoningConfig) -> Self {
125        self.reasoning = Some(r);
126        self
127    }
128
129    pub fn max_reasoning_tokens(mut self, max: u32) -> Self {
130        self.max_reasoning_tokens = Some(max);
131        self
132    }
133
134    pub fn extra(mut self, extra: serde_json::Map<String, serde_json::Value>) -> Self {
135        self.extra = Some(extra);
136        self
137    }
138}