Skip to main content

mofa_plugins/tools/
response_optimizer.rs

1use super::*;
2use serde_json::json;
3use std::sync::{Arc, Mutex};
4
5/// 教育反馈统计信息
6#[derive(Debug, Default)]
7struct FeedbackStats {
8    /// 连续"不懂"的次数
9    consecutive_confused: u32,
10    /// 当前教学模式
11    current_mode: String,
12    /// 总反馈次数
13    total_feedback: u32,
14}
15
16/// 响应优化插件 - 根据学生反馈调整教学策略
17pub struct ResponseOptimizerTool {
18    definition: ToolDefinition,
19    feedback_stats: Arc<Mutex<FeedbackStats>>,
20}
21
22impl Default for ResponseOptimizerTool {
23    fn default() -> Self {
24        Self::new()
25    }
26}
27
28impl ResponseOptimizerTool {
29    pub fn new() -> Self {
30        Self {
31            definition: ToolDefinition {
32                name: "response_optimizer".to_string(),
33                description: "Educational response optimization: tracks student feedback and adjusts teaching strategies based on rules.".to_string(),
34                parameters: json!({
35                    "type": "object",
36                    "properties": {
37                        "action": {
38                            "type": "string",
39                            "enum": ["record_feedback", "check_status", "reset_stats"],
40                            "description": "Action to perform"
41                        },
42                        "feedback_type": {
43                            "type": "string",
44                            "enum": ["understand", "confused", "too_fast", "too_slow", "other"],
45                            "description": "Type of student feedback"
46                        },
47                        "feedback_content": {
48                            "type": "string",
49                            "description": "Detailed feedback content"
50                        }
51                    },
52                    "required": ["action"]
53                }),
54                requires_confirmation: false,
55            },
56            feedback_stats: Arc::new(Mutex::new(FeedbackStats::default())),
57        }
58    }
59
60    /// 更新反馈统计并检查是否需要切换教学模式
61    fn update_feedback_stats(&self, feedback_type: &str) -> String {
62        let mut stats = self.feedback_stats.lock().unwrap();
63        // 确保初始模式为normal
64        if stats.current_mode.is_empty() {
65            stats.current_mode = "normal".to_string();
66        }
67
68        let old_mode = stats.current_mode.clone();
69
70        match feedback_type {
71            "confused" => {
72                stats.consecutive_confused += 1;
73            }
74            _ => {
75                // 非"不懂"反馈重置连续计数
76                stats.consecutive_confused = 0;
77            }
78        }
79
80        stats.total_feedback += 1;
81
82        // 检查规则:连续三次"不懂"切换到更基础的模式
83        if stats.consecutive_confused >= 3 && stats.current_mode != "basic" {
84            stats.current_mode = "basic".to_string();
85            return format!(
86                "Mode switched from {} to basic because of {} consecutive 'confused' feedbacks",
87                old_mode, stats.consecutive_confused
88            );
89        }
90        // 如果学生表示理解且当前模式是基础模式,切换回正常模式
91        else if feedback_type == "understand" && stats.current_mode == "basic" {
92            stats.current_mode = "normal".to_string();
93            return "Mode switched from basic to normal because student reported understanding"
94                .to_string();
95        }
96
97        "No mode change".to_string()
98    }
99}
100
101#[async_trait::async_trait]
102impl ToolExecutor for ResponseOptimizerTool {
103    fn definition(&self) -> &ToolDefinition {
104        &self.definition
105    }
106
107    async fn execute(&self, arguments: serde_json::Value) -> PluginResult<serde_json::Value> {
108        let action = arguments["action"]
109            .as_str()
110            .ok_or_else(|| anyhow::anyhow!("Action is required"))?;
111
112        match action {
113            "record_feedback" => {
114                let feedback_type = arguments["feedback_type"].as_str().ok_or_else(|| {
115                    anyhow::anyhow!("feedback_type is required for record_feedback")
116                })?;
117
118                let feedback_content = arguments["feedback_content"].as_str().unwrap_or("");
119
120                // 更新反馈统计并检查模式切换
121                let mode_change = self.update_feedback_stats(feedback_type);
122
123                let stats = self.feedback_stats.lock().unwrap();
124
125                Ok(json!({
126                    "status": "success",
127                    "feedback_type": feedback_type,
128                    "feedback_content": feedback_content,
129                    "mode_change": mode_change,
130                    "current_mode": stats.current_mode,
131                    "consecutive_confused": stats.consecutive_confused,
132                    "total_feedback": stats.total_feedback
133                }))
134            }
135            "check_status" => {
136                let mut stats = self.feedback_stats.lock().unwrap();
137                // 确保初始模式为normal
138                if stats.current_mode.is_empty() {
139                    stats.current_mode = "normal".to_string();
140                }
141
142                Ok(json!({
143                    "status": "success",
144                    "current_mode": stats.current_mode,
145                    "consecutive_confused": stats.consecutive_confused,
146                    "total_feedback": stats.total_feedback
147                }))
148            }
149            "reset_stats" => {
150                let mut stats = self.feedback_stats.lock().unwrap();
151
152                *stats = FeedbackStats::default();
153
154                Ok(json!({
155                    "status": "success",
156                    "message": "Feedback stats reset successfully"
157                }))
158            }
159            _ => Err(anyhow::anyhow!("Unknown action: {}", action)),
160        }
161    }
162}
163
164#[cfg(test)]
165mod tests {
166    use super::*;
167
168    #[tokio::test]
169    async fn test_response_optimizer_mode_switch() {
170        let optimizer = ResponseOptimizerTool::new();
171
172        // 初始状态检查
173        let status = optimizer
174            .execute(json!({
175                "action": "check_status"
176            }))
177            .await
178            .unwrap();
179        assert_eq!(status["current_mode"], "normal");
180        assert_eq!(status["consecutive_confused"], 0);
181
182        // 第一次反馈"不懂"
183        let result = optimizer
184            .execute(json!({
185                "action": "record_feedback",
186                "feedback_type": "confused",
187                "feedback_content": "不明白"
188            }))
189            .await
190            .unwrap();
191        assert_eq!(result["consecutive_confused"], 1);
192        assert_eq!(result["current_mode"], "normal");
193
194        // 第二次反馈"不懂"
195        let result = optimizer
196            .execute(json!({
197                "action": "record_feedback",
198                "feedback_type": "confused",
199                "feedback_content": "还是不明白"
200            }))
201            .await
202            .unwrap();
203        assert_eq!(result["consecutive_confused"], 2);
204        assert_eq!(result["current_mode"], "normal");
205
206        // 第三次反馈"不懂" - 应该切换到基础模式
207        let result = optimizer
208            .execute(json!({
209                "action": "record_feedback",
210                "feedback_type": "confused",
211                "feedback_content": "完全不明白"
212            }))
213            .await
214            .unwrap();
215        assert_eq!(result["consecutive_confused"], 3);
216        assert_eq!(result["current_mode"], "basic");
217        assert!(
218            result["mode_change"]
219                .as_str()
220                .unwrap()
221                .contains("Mode switched")
222        );
223
224        // 反馈"理解" - 应该切换回正常模式
225        let result = optimizer
226            .execute(json!({
227                "action": "record_feedback",
228                "feedback_type": "understand",
229                "feedback_content": "现在明白了"
230            }))
231            .await
232            .unwrap();
233        assert_eq!(result["consecutive_confused"], 0);
234        assert_eq!(result["current_mode"], "normal");
235
236        println!("✓ 所有测试用例通过!");
237    }
238}