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};