echo_agent 0.1.4

Production-grade AI Agent framework for Rust — ReAct engine, multi-agent, memory, streaming, MCP, IM channels, workflows
Documentation
# ReAct Agent —— 核心执行引擎

## 是什么

ReAct(**Re**asoning + **Act**ing)是目前最主流的 Agent 执行范式。每一轮迭代分为三步:

```
Thought(推理)→ Action(调用工具)→ Observation(观测结果)
```

循环执行,直到 LLM 认为任务已完成并调用 `final_answer` 工具输出结果。

echo-agent 的核心实现是 `ReactAgent`,它将 ReAct 范式与工具管理、记忆、压缩、人工介入、SubAgent 编排等能力全部集成在一个结构体中。

---

## 解决什么问题

纯粹的 LLM 调用是一次性的:给定输入,返回输出。这无法处理需要多步骤推理、外部工具访问、动态决策的复杂任务。

ReAct 范式解决了:
- **推理与行动分离**:LLM 先"思考",再"行动",再"观测",可处理任意复杂度任务
- **工具调用**:让 LLM 能够执行代码、查询数据库、调用 API
- **迭代纠错**:工具返回错误时,LLM 可以调整策略重试
- **Chain-of-Thought**:自然产生可追溯的推理链,便于调试

---

## 执行流程

```
execute(task)
    ├─ 1. 加载会话历史(Checkpointer)
    ├─ 2. 注入长期记忆(Store)
    └─ Loop(max_iterations 次):
          ├─ context.prepare()    ← 自动压缩(若超 token_limit)
          ├─ llm.chat()           ← 调用 LLM
          ├─ 解析响应:
          │     ├─ content 非空  → Token 事件(流式 / CoT 推理文本)
          │     └─ tool_calls   → 工具调用列表
          ├─ 并行执行所有工具调用:
          │     ├─ 人工审批检查(若该工具已标记)
          │     ├─ ToolManager.execute_tool()
          │     └─ 触发 on_tool_start / on_tool_end 回调
          ├─ 调用 final_answer → 返回结果,退出循环
          └─ 将 assistant + tool_results 消息追加到上下文

    └─ 保存会话历史(Checkpointer)
```

---

## Agent 角色

`AgentRole` 控制 Agent 的执行模式:

| 角色 | 说明 |
|------|------|
| `Worker`(默认) | 直接执行任务,使用工具 |
| `Orchestrator` | 编排者,优先通过 `agent_tool` 将任务分发给 SubAgent |
| `Planner` | 先用 `plan` 工具拆解任务,再逐步创建并执行子任务 |

---

## 关键配置

```rust
AgentConfig::new("qwen3-max", "my_agent", "你是一个助手")
    .enable_tool(true)          // 启用工具调用(默认 true)
    .enable_task(true)          // 启用 DAG 任务规划(Planner 模式)
    .enable_subagent(true)      // 启用 SubAgent 编排(Orchestrator 模式)
    .enable_memory(true)        // 启用长期记忆(Store + remember/recall/forget 工具)
    .enable_human_in_loop(true) // 启用人工介入
    .enable_cot(true)           // 启用 Chain-of-Thought 引导语(默认 true)
    .session_id("thread-001")   // 线程 ID:用于 Checkpointer 恢复/续接
    .conversation_id("conv-001")// 可选:用于 transcript/history 投影
    .token_limit(8192)          // 上下文 token 上限(超限自动压缩)
    .max_iterations(30)         // 最大迭代次数(防止死循环)
    .verbose(true)              // 打印详细执行日志
```

---

## 生命周期回调

实现 `AgentCallback` trait,可以监听 Agent 执行的每个阶段(用于埋点、日志、UI 实时更新等):

```rust
use echo_agent::agent::{AgentCallback, AgentEvent};
use async_trait::async_trait;
use serde_json::Value;

struct MyCallback;

#[async_trait]
impl AgentCallback for MyCallback {
    async fn on_think_start(&self, agent: &str, messages: &[echo_agent::llm::types::Message]) {
        println!("[{}] 开始推理,上下文 {} 条消息", agent, messages.len());
    }

    async fn on_tool_start(&self, agent: &str, tool: &str, args: &Value) {
        println!("[{}] 调用工具: {} {:?}", agent, tool, args);
    }

    async fn on_tool_end(&self, agent: &str, tool: &str, result: &str) {
        println!("[{}] 工具结果: {} -> {}", agent, tool, &result[..result.len().min(80)]);
    }

    async fn on_final_answer(&self, agent: &str, answer: &str) {
        println!("[{}] 最终答案: {}", agent, answer);
    }
}
```

---

## 最简 Demo

```rust
use echo_agent::prelude::*;

#[tokio::main]
async fn main() -> Result<()> {
    let config = AgentConfig::new("qwen3-max", "assistant", "你是一个有帮助的助手");
    let mut agent = ReactAgent::new(config);

    let answer = agent.execute("1 + 1 等于几?").await?;
    println!("{}", answer);
    Ok(())
}
```

---

## 完整 Demo(带工具 + 回调)

```rust
use echo_agent::prelude::*;
use echo_agent::tools::others::math::{AddTool, MultiplyTool};
use std::sync::Arc;

struct LogCallback;

#[async_trait::async_trait]
impl AgentCallback for LogCallback {
    async fn on_tool_start(&self, agent: &str, tool: &str, args: &serde_json::Value) {
        println!("  [{}] 调用工具 {} args={}", agent, tool, args);
    }
    async fn on_final_answer(&self, _agent: &str, answer: &str) {
        println!("最终答案: {}", answer);
    }
}

#[tokio::main]
async fn main() -> Result<()> {
    let config = AgentConfig::new(
        "qwen3-max",
        "math_agent",
        "你是一个数学助手,使用工具进行计算。",
    )
    .enable_tool(true)
    .max_iterations(10);

    let mut agent = ReactAgent::new(config);
    agent.add_tools(vec![Box::new(AddTool), Box::new(MultiplyTool)]);
    agent.add_callback(Arc::new(LogCallback));

    let answer = agent
        .execute("计算 (3 + 4) * 5 等于多少?")
        .await?;
    println!("{}", answer);
    Ok(())
}
```

对应示例:`examples/demo01_tools.rs`、`examples/demo11_callbacks.rs`

---

## 关键设计细节

**为什么不用 `think` 工具而用 CoT 文本?**

旧方案是专门提供一个 `think` 工具让 LLM "思考"。新方案是在系统提示词末尾追加 `COT_INSTRUCTION`,让 LLM 在每次工具调用前在 `content` 字段输出推理文本。好处是:
1. 推理内容天然进入消息历史(context)
2. 直接产生流式 Token 事件,UI 可实时展示思考过程
3. 减少一次无意义的工具调用

**并行工具调用**

当 LLM 在一次响应中返回多个工具调用时,ReactAgent 使用 `join_all()` 并行执行所有工具,受 `ToolExecutionConfig::max_concurrency` 约束。