use serde::{Deserialize, Serialize}; // ─── 角色 ─── #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] #[serde(rename_all = "lowercase")] pub enum Role { System, User, Assistant, Tool, } // ─── 消息 ─── #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Message { pub role: Role, #[serde(default)] pub content: String, #[serde(skip_serializing_if = "Option::is_none")] pub tool_call_id: Option, #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, #[serde(skip_serializing_if = "Option::is_none")] pub tool_calls: Option>, } impl Message { pub fn system(content: impl Into) -> Self { Self { role: Role::System, content: content.into(), tool_call_id: None, name: None, tool_calls: None } } pub fn user(content: impl Into) -> Self { Self { role: Role::User, content: content.into(), tool_call_id: None, name: None, tool_calls: None } } pub fn assistant(content: impl Into) -> Self { Self { role: Role::Assistant, content: content.into(), tool_call_id: None, name: None, tool_calls: None } } pub fn assistant_with_tool_calls(tool_calls: Vec) -> Self { Self { role: Role::Assistant, content: String::new(), tool_call_id: None, name: None, tool_calls: Some(tool_calls) } } pub fn tool_result(tool_call_id: &str, name: &str, result: &str) -> Self { Self { role: Role::Tool, content: result.to_string(), tool_call_id: Some(tool_call_id.to_string()), name: Some(name.to_string()), tool_calls: None } } } // ─── 工具调用 ─── #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ToolCall { pub id: String, #[serde(rename = "type")] pub call_type: String, // "function" pub function: ToolFunctionCall, } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ToolFunctionCall { pub name: String, pub arguments: String, // JSON string } // ─── 流式响应块 ─── #[derive(Debug, Clone)] pub enum StreamChunk { /// 文本片段 delta Text(String), /// 思考/推理内容(DeepSeek thinking) Reasoning(String), /// 完成(携带完整文本,以及可选的工具调用) Done { text: String, reasoning: Option, tool_calls: Option>, usage: Option, }, /// 错误 Error(String), } // ─── Token 用量 ─── #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Usage { pub prompt_tokens: u32, pub completion_tokens: u32, pub total_tokens: u32, #[serde(default)] pub prompt_cache_hit_tokens: u32, #[serde(default)] pub prompt_cache_miss_tokens: u32, } // ─── 对话配置 ─── #[derive(Debug, Clone)] pub struct ConversationConfig { pub system_prompt: String, pub model: String, pub temperature: f32, pub max_tokens: u32, pub thinking: bool, /// LLM function calling 的工具定义(JSON 数组) pub tools: Option>, } impl Default for ConversationConfig { fn default() -> Self { Self { system_prompt: "You are a concise and helpful assistant replying in Chinese. \ Keep replies practical and natural." .to_string(), model: "deepseek-v4-flash".to_string(), temperature: 0.7, max_tokens: 4096, thinking: true, tools: None, } } }