Skip to main content

lellm_core/
request.rs

1//! 请求类型。
2
3use serde::{Deserialize, Serialize};
4
5/// 统一的聊天请求。
6#[derive(Debug, Clone, Default, Serialize, Deserialize)]
7pub struct ChatRequest {
8    pub model: String,
9    pub messages: Vec<crate::Message>,
10    pub tools: Option<Vec<ToolDefinition>>,
11    pub temperature: Option<f64>,
12    pub max_tokens: Option<u32>,
13    pub top_p: Option<f64>,
14    pub seed: Option<u64>,
15    pub tool_choice: Option<ToolChoice>,
16    pub stop_sequences: Option<Vec<String>>,
17    pub prefill: Option<String>,
18    /// 推理配置 — 控制模型是否进行深度推理。
19    ///
20    /// `None` = 不干预 Provider 默认行为
21    /// `Some(Disabled)` = 显式关闭推理
22    /// `Some(Low/Medium/High)` = 开启对应级别的推理
23    #[serde(skip_serializing_if = "Option::is_none")]
24    pub reasoning: Option<ReasoningConfig>,
25    /// 单次 LLM 调用的推理 Token 上限(可选,默认无限制)。
26    ///
27    /// 与 `max_tokens` 分离:reasoning 是模型内部推理,不计入输出预算。
28    /// 透传给 Provider Adapter,由 Adapter 映射为协议特定字段。
29    ///
30    /// **两种语义:**
31    /// - 流式: Hard limit — 达到限额当场切断 stream,省钱
32    /// - 非流式: Soft limit — response 已完整返回,事后检测并标记
33    ///
34    /// Adapter 映射示例:
35    /// - DeepSeek: `max_thinking_tokens`
36    /// - OpenAI: 无直接对应,由 `reasoning` 级别间接控制
37    /// - 其他: 放入 `extra` 或忽略
38    #[serde(skip_serializing_if = "Option::is_none")]
39    pub max_reasoning_tokens: Option<u32>,
40    /// Provider 特有参数(如 OpenAI 的 presence_penalty),由 Adapter 自行处理。
41    #[serde(skip_serializing_if = "Option::is_none")]
42    pub extra: Option<serde_json::Map<String, serde_json::Value>>,
43}
44
45// Default is derived - all fields have valid default values
46
47impl ChatRequest {
48    /// 便捷构造:单条用户消息
49    pub fn user_prompt(prompt: String) -> Self {
50        Self {
51            messages: vec![crate::Message::User {
52                content: crate::text_block(prompt),
53            }],
54            ..Default::default()
55        }
56    }
57
58    pub fn with_temperature(mut self, temp: f64) -> Self {
59        self.temperature = Some(temp);
60        self
61    }
62
63    pub fn with_max_tokens(mut self, max: u32) -> Self {
64        self.max_tokens = Some(max);
65        self
66    }
67
68    pub fn with_top_p(mut self, top_p: f64) -> Self {
69        self.top_p = Some(top_p);
70        self
71    }
72
73    pub fn with_seed(mut self, seed: u64) -> Self {
74        self.seed = Some(seed);
75        self
76    }
77
78    pub fn with_model(mut self, model: String) -> Self {
79        self.model = model;
80        self
81    }
82
83    pub fn with_tools(mut self, tools: Vec<ToolDefinition>) -> Self {
84        self.tools = Some(tools);
85        self
86    }
87
88    /// 便捷构造:单条系统消息
89    pub fn with_system_prompt(mut self, prompt: String) -> Self {
90        self.messages.insert(
91            0,
92            crate::Message::System {
93                content: crate::text_block(prompt),
94            },
95        );
96        self
97    }
98
99    /// 设置推理配置
100    pub fn with_reasoning(mut self, reasoning: ReasoningConfig) -> Self {
101        self.reasoning = Some(reasoning);
102        self
103    }
104
105    /// 设置单次调用的推理 Token 上限
106    pub fn with_max_reasoning_tokens(mut self, max: u32) -> Self {
107        self.max_reasoning_tokens = Some(max);
108        self
109    }
110
111    /// 设置 Provider 特有参数
112    pub fn with_extra(mut self, extra: serde_json::Map<String, serde_json::Value>) -> Self {
113        self.extra = Some(extra);
114        self
115    }
116}
117
118/// 工具选择策略
119#[derive(Debug, Clone, Serialize, Deserialize)]
120pub enum ToolChoice {
121    Tool { name: String },
122    Any,
123}
124
125/// 工具定义(输入侧)。
126#[derive(Debug, Clone, Serialize, Deserialize)]
127pub struct ToolDefinition {
128    pub name: String,
129    pub description: String,
130    pub parameters: serde_json::Value,
131}
132
133/// 推理配置 — 声明式控制模型的深度推理行为。
134///
135/// 四值语义(Option + Enum):
136/// - `None`(未设置)= 不干预,Provider 自行决定默认行为
137/// - `Some(Disabled)` = 显式关闭推理(尽最大努力)
138/// - `Some(Low)` = 低推理预算(快速、轻量)
139/// - `Some(Medium)` = 中等推理预算
140/// - `Some(High)` = 高推理预算(深度思考)
141///
142/// Adapter 映射示例:
143/// - OpenAI / NVIDIA / vLLM: `Disabled` → 不插字段;`Low` → "low";`Medium` → "medium";`High` → "high"
144/// - DeepSeek: `Disabled` → `enable_thinking=false`;其余 → `reasoning_effort=<level>`
145/// - llama.cpp: `Disabled` → `thinking=false`;其余 → `reasoning_effort=<level>`
146/// - Anthropic: `Disabled` → 静默忽略(不支持推理配置);其余 → `UnsupportedFeature`
147/// - 不支持推理的 Provider: `Disabled` → 静默忽略;其余 → `UnsupportedFeature`
148#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)]
149pub enum ReasoningConfig {
150    /// 显式关闭推理
151    Disabled,
152    /// 低推理预算
153    Low,
154    /// 中等推理预算
155    Medium,
156    /// 高推理预算
157    High,
158}
159
160impl ReasoningConfig {
161    /// 判断是否为 Disabled
162    pub fn is_disabled(self) -> bool {
163        matches!(self, Self::Disabled)
164    }
165}