Skip to main content

rucora_core/agent/
mod.rs

1//! Agent(智能体)核心抽象模块
2//!
3//! # 概述
4//!
5//! 本模块定义了 Agent 的抽象接口。Agent 是能够思考、决策和行动的自主实体。
6//!
7//! # 核心概念
8//!
9//! ## 决策与执行分离
10//!
11//! - **Agent trait**: 负责思考、决策、规划(大脑)
12//! - **AgentExecutor trait**: 负责执行、调用、编排(身体)
13//!
14//! Agent 通过 `think()` 方法返回决策,`AgentExecutor` 或其他执行器负责执行。
15
16pub mod types;
17
18/// 运行时适配器抽象
19pub mod runtime_adapter;
20
21use async_trait::async_trait;
22use futures_util::stream::BoxStream;
23use serde_json::Value;
24
25use crate::channel::types::ChannelEvent;
26
27/// Agent 决策结果。
28///
29/// Agent 通过 `think()` 方法返回决策,Runtime 或其他执行器负责执行。
30#[derive(Debug, Clone)]
31pub enum AgentDecision {
32    /// 调用 LLM 进行对话。
33    Chat {
34        /// 对话请求。
35        request: Box<crate::provider::types::ChatRequest>,
36    },
37    /// 调用工具。
38    ToolCall {
39        /// 工具名称。
40        name: String,
41        /// 工具输入参数。
42        input: Value,
43    },
44    /// 直接返回结果。
45    Return(Value),
46    /// 需要更多思考(继续循环)。
47    ThinkAgain,
48    /// 停止执行。
49    Stop,
50}
51
52/// Agent 上下文。
53///
54/// 包含 Agent 思考所需的所有信息。
55#[derive(Debug, Clone)]
56pub struct AgentContext {
57    /// 用户原始输入。
58    pub input: AgentInput,
59    /// 对话历史。
60    pub messages: Vec<crate::provider::types::ChatMessage>,
61    /// 工具调用结果。
62    pub tool_results: Vec<ToolResult>,
63    /// 当前步骤数。
64    pub step: usize,
65    /// 最大步骤数。
66    pub max_steps: usize,
67}
68
69impl AgentContext {
70    /// 创建新的上下文。
71    pub fn new(input: AgentInput, max_steps: usize) -> Self {
72        Self {
73            input,
74            messages: Vec::new(),
75            tool_results: Vec::new(),
76            step: 0,
77            max_steps,
78        }
79    }
80
81    /// 添加消息到历史。
82    pub fn add_message(&mut self, message: crate::provider::types::ChatMessage) {
83        self.messages.push(message);
84    }
85
86    /// 添加工具调用结果。
87    pub fn add_tool_result(&mut self, tool_name: String, result: Value) {
88        self.tool_results.push(ToolResult { tool_name, result });
89    }
90
91    /// 创建默认的对话请求。
92    ///
93    /// 所有 LLM 参数(temperature 等)默认为 None,使用模型默认值。
94    /// 可通过 `default_chat_request_with()` 传入自定义参数。
95    pub fn default_chat_request(&self) -> crate::provider::types::ChatRequest {
96        crate::provider::types::ChatRequest {
97            messages: self.messages.clone(),
98            model: None,
99            tools: None,
100            temperature: None,
101            max_tokens: None,
102            response_format: None,
103            metadata: None,
104            top_p: None,
105            top_k: None,
106            frequency_penalty: None,
107            presence_penalty: None,
108            stop: None,
109            extra: None,
110        }
111    }
112
113    /// 创建带 LLM 参数的对话请求。
114    pub fn default_chat_request_with(
115        &self,
116        params: &crate::provider::types::LlmParams,
117    ) -> crate::provider::types::ChatRequest {
118        let mut request = self.default_chat_request();
119        params.apply_to(&mut request);
120        request
121    }
122}
123
124/// 工具调用结果。
125#[derive(Debug, Clone)]
126pub struct ToolResult {
127    /// 工具名称。
128    pub tool_name: String,
129    /// 工具返回结果。
130    pub result: Value,
131}
132
133/// Agent 输入。
134///
135/// 用于向 Agent 传递用户请求。
136///
137/// # 使用示例
138///
139/// ```rust
140/// use rucora_core::agent::AgentInput;
141///
142/// // 简单文本输入
143/// let input = AgentInput::new("你好");
144///
145/// // 使用 builder 模式
146/// let input = AgentInput::builder("帮我查询天气")
147///     .with_context("user_location", "北京")
148///     .build();
149/// ```
150#[derive(Debug, Clone)]
151pub struct AgentInput {
152    /// 文本输入。
153    pub text: String,
154    /// 额外上下文数据。
155    pub context: serde_json::Value,
156}
157
158impl AgentInput {
159    /// 从文本创建输入。
160    pub fn new(text: impl Into<String>) -> Self {
161        let text = text.into();
162        assert!(!text.is_empty(), "AgentInput text must not be empty");
163        Self {
164            text,
165            context: serde_json::Value::Object(serde_json::Map::new()),
166        }
167    }
168
169    /// 从文本和上下文创建输入。
170    pub fn with_context(text: impl Into<String>, context: serde_json::Value) -> Self {
171        let text = text.into();
172        assert!(!text.is_empty(), "AgentInput text must not be empty");
173        Self {
174            text,
175            context,
176        }
177    }
178
179    /// 创建 builder。
180    pub fn builder(text: impl Into<String>) -> AgentInputBuilder {
181        AgentInputBuilder::new(text)
182    }
183
184    /// 获取文本内容。
185    pub fn text(&self) -> &str {
186        &self.text
187    }
188
189    /// 获取上下文数据。
190    pub fn context(&self) -> &serde_json::Value {
191        &self.context
192    }
193}
194
195/// AgentInput 构建器。
196pub struct AgentInputBuilder {
197    text: String,
198    context: serde_json::Value,
199}
200
201impl AgentInputBuilder {
202    /// 创建新的构建器。
203    pub fn new(text: impl Into<String>) -> Self {
204        let text = text.into();
205        assert!(!text.is_empty(), "AgentInput text must not be empty");
206        Self {
207            text,
208            context: serde_json::Value::Object(serde_json::Map::new()),
209        }
210    }
211
212    /// 添加上下文键值对。
213    pub fn with_context(
214        mut self,
215        key: impl Into<String>,
216        value: impl Into<serde_json::Value>,
217    ) -> Self {
218        if let serde_json::Value::Object(ref mut map) = self.context {
219            map.insert(key.into(), value.into());
220        }
221        self
222    }
223
224    /// 设置完整上下文。
225    pub fn context(mut self, context: serde_json::Value) -> Self {
226        self.context = context;
227        self
228    }
229
230    /// 构建输入。
231    pub fn build(self) -> AgentInput {
232        AgentInput {
233            text: self.text,
234            context: self.context,
235        }
236    }
237}
238
239impl From<String> for AgentInput {
240    fn from(text: String) -> Self {
241        Self::new(text)
242    }
243}
244
245impl From<&str> for AgentInput {
246    fn from(text: &str) -> Self {
247        Self::new(text)
248    }
249}
250
251/// Agent 输出。
252///
253/// 包含 Agent 执行的结果和相关信息。
254///
255/// # 字段说明
256///
257/// - `value`: 主要输出内容(通常是 JSON 格式)
258/// - `messages`: 对话历史
259/// - `tool_calls`: 工具调用记录
260///
261/// # 使用示例
262    ///
263    /// ```rust
264    /// use rucora_core::agent::AgentOutput;
265    /// use serde_json::json;
266    ///
267    /// // 创建输出
268    /// let output = AgentOutput::new(json!({"content": "Hello"}));
269    ///
270    /// // 提取文本内容
271    /// if let Some(content) = output.value.get("content").and_then(|v| v.as_str()) {
272    ///     assert_eq!(content, "Hello");
273    /// }
274    ///
275    /// // 访问对话历史
276    /// assert_eq!(output.messages.len(), 0);
277    ///
278    /// // 访问工具调用
279    /// assert_eq!(output.tool_calls.len(), 0);
280    /// ```
281#[derive(Debug, Clone)]
282pub struct AgentOutput {
283    /// 主要输出内容(通常是 JSON 格式,包含 `content` 字段)。
284    pub value: Value,
285    /// 对话历史。
286    pub messages: Vec<crate::provider::types::ChatMessage>,
287    /// 工具调用记录。
288    pub tool_calls: Vec<ToolCallRecord>,
289    /// Token 使用统计(累计所有 LLM 调用的 usage)。
290    pub usage: Option<crate::provider::types::Usage>,
291}
292
293impl AgentOutput {
294    /// 创建新的输出。
295    pub fn new(value: Value) -> Self {
296        Self {
297            value,
298            messages: Vec::new(),
299            tool_calls: Vec::new(),
300            usage: None,
301        }
302    }
303
304    /// 创建带历史的输出。
305    pub fn with_history(
306        value: Value,
307        messages: Vec<crate::provider::types::ChatMessage>,
308        tool_calls: Vec<ToolCallRecord>,
309    ) -> Self {
310        Self {
311            value,
312            messages,
313            tool_calls,
314            usage: None,
315        }
316    }
317
318    /// 创建带 usage 的输出。
319    pub fn with_usage(
320        value: Value,
321        messages: Vec<crate::provider::types::ChatMessage>,
322        tool_calls: Vec<ToolCallRecord>,
323        usage: Option<crate::provider::types::Usage>,
324    ) -> Self {
325        Self {
326            value,
327            messages,
328            tool_calls,
329            usage,
330        }
331    }
332
333    /// 获取文本内容(如果存在)。
334    pub fn text(&self) -> Option<&str> {
335        self.value.get("content").and_then(|v| v.as_str())
336    }
337
338    /// 获取文本内容,如果不存在则返回空字符串。
339    pub fn text_unwrap(&self) -> &str {
340        self.text().unwrap_or("")
341    }
342
343    /// 获取文本内容,如果不存在则返回默认值。
344    pub fn text_or<'a>(&'a self, default: &'a str) -> &'a str {
345        self.text().unwrap_or(default)
346    }
347
348    /// 消费自身,获取文本内容的所有权。
349    pub fn into_text(self) -> String {
350        self.text().map(String::from).unwrap_or_default()
351    }
352
353    /// 获取对话历史长度。
354    pub fn message_count(&self) -> usize {
355        self.messages.len()
356    }
357
358    /// 获取工具调用次数。
359    pub fn tool_call_count(&self) -> usize {
360        self.tool_calls.len()
361    }
362
363    /// 获取 Token 使用统计。
364    pub fn usage(&self) -> Option<&crate::provider::types::Usage> {
365        self.usage.as_ref()
366    }
367
368    /// 获取总 Token 数。
369    pub fn total_tokens(&self) -> u32 {
370        self.usage.as_ref().map_or(0, |u| u.total_tokens)
371    }
372
373    /// 获取提示词 Token 数。
374    pub fn prompt_tokens(&self) -> u32 {
375        self.usage.as_ref().map_or(0, |u| u.prompt_tokens)
376    }
377
378    /// 获取输出 Token 数。
379    pub fn completion_tokens(&self) -> u32 {
380        self.usage.as_ref().map_or(0, |u| u.completion_tokens)
381    }
382
383    /// 格式化 Token 使用信息。
384    pub fn usage_summary(&self) -> String {
385        match &self.usage {
386            Some(u) => format!(
387                "Tokens: {} total ({} prompt + {} completion)",
388                u.total_tokens, u.prompt_tokens, u.completion_tokens
389            ),
390            None => "Tokens: N/A".to_string(),
391        }
392    }
393}
394
395impl std::fmt::Display for AgentOutput {
396    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
397        match self.text() {
398            Some(text) => write!(f, "{text}"),
399            None => Ok(()),
400        }
401    }
402}
403
404/// 工具调用记录。
405#[derive(Debug, Clone)]
406pub struct ToolCallRecord {
407    /// 工具名称。
408    pub name: String,
409    /// 输入参数。
410    pub input: Value,
411    /// 返回结果。
412    pub result: Value,
413}
414
415/// Agent trait - 智能体的抽象接口。
416///
417/// Agent 负责思考、决策和规划。它可以:
418/// - 独立运行(处理简单任务)
419/// - 使用内置执行能力(处理复杂任务)
420/// - 调用 Tool/MCP/Skill/A2A 等外部能力
421///
422/// # 设计原则
423///
424/// Agent trait 只定义决策接口(`think`),执行能力(`run`/`run_stream`)由具体实现提供。
425///
426/// ## 决策与执行分离
427///
428/// - **决策层** (`think`): 每个 Agent 类型有不同的思考策略
429/// - **执行层** (`run`/`run_stream`): 所有 Agent 共享相同的执行能力
430///
431/// ## 使用方式
432///
433/// ```rust,no_run
434/// use rucora_core::agent::{Agent, AgentContext, AgentDecision, AgentInput, AgentOutput};
435/// use async_trait::async_trait;
436///
437/// struct MyAgent;
438///
439/// #[async_trait]
440/// impl Agent for MyAgent {
441///     async fn think(&self, context: &AgentContext) -> AgentDecision {
442///         // 自定义决策逻辑
443///         AgentDecision::Return(serde_json::json!({"content": "Hello"}))
444///     }
445///
446///     fn name(&self) -> &str { "my_agent" }
447/// }
448/// ```
449///
450/// # 内置执行能力
451///
452/// 如果 Agent 需要工具调用、流式输出等能力,可以组合 `DefaultExecution`:
453///
454/// ```rust,ignore
455/// use rucora::agent::execution::DefaultExecution;
456/// use rucora_core::agent::Agent;
457///
458/// struct MyAgent {
459///     execution: DefaultExecution,
460///     // ... 其他字段
461/// }
462///
463/// impl Agent for MyAgent {
464///     // ... 实现 think 方法
465///     
466///     // DefaultExecution 提供默认的 run/run_stream 实现
467/// }
468/// ```
469#[async_trait]
470pub trait Agent: Send + Sync {
471    /// 思考:分析当前情况,决定下一步行动。
472    ///
473    /// 这是 Agent 的核心方法,返回决策结果。
474    async fn think(&self, context: &AgentContext) -> AgentDecision;
475
476    /// 获取 Agent 名称。
477    fn name(&self) -> &str;
478
479    /// 获取 Agent 描述(可选)。
480    ///
481    /// 返回 Agent 的简短描述,用于调试和日志。
482    fn description(&self) -> Option<&str> {
483        None
484    }
485
486    /// 运行 Agent(非流式)。
487    ///
488    /// 默认实现适用于简单场景(直接返回结果)。
489    /// 需要工具调用等复杂能力的 Agent 应该使用 `run_with()` 方法配合 `AgentExecutor`。
490    ///
491    /// # 默认行为
492    ///
493    /// 默认实现会循环调用 `think()` 直到返回 `Return` 或 `Stop`。
494    /// 如果返回 `Chat` 或 `ToolCall`,会返回错误(需要 Runtime 支持)。
495    ///
496    /// # 配置
497    ///
498    /// 默认最大步骤数为 20。如果需要自定义,请使用 `run_with()` 方法。
499    ///
500    /// # 示例
501    ///
502    /// ```rust,no_run
503    /// use rucora_core::agent::{Agent, AgentInput};
504    ///
505    /// # async fn example(agent: &dyn Agent) -> Result<(), Box<dyn std::error::Error>> {
506    /// let output = agent.run(AgentInput::new("你好")).await?;
507    /// # Ok(())
508    /// # }
509    /// ```
510    async fn run(&self, input: AgentInput) -> Result<AgentOutput, AgentError> {
511        // 默认最大步骤数:20
512        const DEFAULT_MAX_STEPS: usize = 20;
513
514        let mut context = AgentContext::new(input.clone(), DEFAULT_MAX_STEPS);
515
516        loop {
517            let decision = self.think(&context).await;
518
519            match decision {
520                AgentDecision::Return(value) => {
521                    return Ok(AgentOutput::with_history(
522                        value,
523                        context.messages,
524                        Vec::new(),
525                    ));
526                }
527                AgentDecision::Stop => {
528                    return Ok(AgentOutput::with_history(
529                        Value::Null,
530                        context.messages,
531                        Vec::new(),
532                    ));
533                }
534                AgentDecision::ThinkAgain => {
535                    context.step += 1;
536                    if context.step >= context.max_steps {
537                        return Err(AgentError::MaxStepsExceeded {
538                            max_steps: context.max_steps,
539                        });
540                    }
541                }
542                AgentDecision::Chat { request: _ } => {
543                    // Chat 决策需要 LLM 调用,默认实现无法处理
544                    return Err(AgentError::RequiresRuntime);
545                }
546                AgentDecision::ToolCall { .. } => {
547                    // ToolCall 决策需要工具执行,默认实现无法处理
548                    return Err(AgentError::RequiresRuntime);
549                }
550            }
551        }
552    }
553
554    /// 运行 Agent(流式)。
555    ///
556    /// 默认实现返回错误(需要具体实现提供流式能力)。
557    ///
558    /// # 示例
559    ///
560    /// ```rust,no_run
561    /// use rucora_core::agent::{Agent, AgentInput};
562    /// use futures_util::StreamExt;
563    ///
564    /// # async fn example(agent: &dyn Agent) -> Result<(), Box<dyn std::error::Error>> {
565    /// let mut stream = agent.run_stream(AgentInput::new("你好"));
566    /// while let Some(event) = stream.next().await {
567    ///     match event? {
568    ///         rucora_core::channel::types::ChannelEvent::TokenDelta(delta) => {
569    ///             print!("{}", delta.delta);
570    ///         }
571    ///         _ => {}
572    ///     }
573    /// }
574    /// # Ok(())
575    /// # }
576    /// ```
577    fn run_stream(
578        &self,
579        _input: AgentInput,
580    ) -> BoxStream<'static, Result<ChannelEvent, AgentError>> {
581        use futures_util::stream;
582        Box::pin(stream::once(async {
583            Err(AgentError::Message("此 Agent 不支持流式输出".to_string()))
584        }))
585    }
586
587    /// 运行 Agent(使用执行器)。
588    ///
589    /// 此方法允许使用外部执行器来运行 Agent。
590    /// 这是实现 dyn 兼容的关键方法。
591    ///
592    /// # 参数
593    ///
594    /// - `executor`: 执行器,负责实际的运行逻辑
595    /// - `input`: 用户输入
596    ///
597    /// # 示例
598    ///
599    /// ```rust,no_run
600    /// use rucora_core::agent::{Agent, AgentInput, AgentExecutor};
601    ///
602    /// # async fn example(agent: &impl Agent, executor: &dyn AgentExecutor) -> Result<(), Box<dyn std::error::Error>> {
603    /// let output = agent.run_with(executor, AgentInput::new("你好")).await?;
604    /// # Ok(())
605    /// # }
606    /// ```
607    async fn run_with(
608        &self,
609        executor: &dyn AgentExecutor,
610        input: AgentInput,
611    ) -> Result<AgentOutput, AgentError>
612    where
613        Self: Sized,
614    {
615        executor.run(self, input).await
616    }
617}
618
619/// Agent 执行器 trait
620///
621/// 用于执行 Agent 的运行逻辑,支持工具调用、流式输出等。
622/// 这是实现 dyn 兼容的关键。
623#[async_trait]
624pub trait AgentExecutor: Send + Sync {
625    /// 运行 Agent
626    async fn run(&self, agent: &dyn Agent, input: AgentInput) -> Result<AgentOutput, AgentError>;
627
628    /// 流式运行 Agent
629    ///
630    /// 注意:由于生命周期限制,此方法不支持 Agent 决策。
631    /// 它只执行简单的工具调用循环。
632    fn run_stream(&self, input: AgentInput)
633    -> BoxStream<'static, Result<ChannelEvent, AgentError>>;
634}
635
636// 重新导出统一的 AgentError 定义
637pub use crate::error::AgentError;
638
639/// 重新导出运行时适配器相关类型
640pub use runtime_adapter::{
641    LogLevel, NativeRuntimeAdapter, RestrictedRuntimeAdapter, RuntimeAdapter, RuntimeCapabilities,
642    RuntimeError, RuntimePlatform, ShellResult,
643};