Skip to content

Agent 架构设计:从 Chatbot 到自主代理 🤖

"Agent 是能自主规划、执行和反思的 AI 系统。"

1. Agent vs Chatbot

1.1 核心区别

特性ChatbotAgent
交互模式一问一答自主多步执行
工具使用可选必须
规划能力
状态管理简单复杂
自我纠错

1.2 Agent 的核心循环

┌─────────────────────────────────────────────────────────────────┐
│                     Agent Core Loop                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│    ┌──────────┐     ┌──────────┐     ┌──────────┐              │
│    │ Perceive │────▶│   Plan   │────▶│   Act    │              │
│    │  感知     │     │   规划   │     │   行动   │              │
│    └──────────┘     └──────────┘     └──────────┘              │
│         ▲                                   │                    │
│         │           ┌──────────┐            │                    │
│         └───────────│ Reflect  │◀───────────┘                    │
│                     │   反思   │                                 │
│                     └──────────┘                                 │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

2. ReAct 模式

2.1 什么是 ReAct

ReAct (Reasoning + Acting) 是最经典的 Agent 模式,让模型交替进行推理和行动。

用户: 帮我重构 UserList 组件,提取 hooks

思考: 我需要先看看 UserList 组件的当前实现
行动: read_file("src/components/UserList.tsx")
观察: [文件内容: 包含 useState, useEffect, 数据获取逻辑...]

思考: 我看到组件内部有数据获取逻辑,可以提取为 useUserList hook
行动: write_file("src/hooks/useUserList.ts", "...")
观察: 文件创建成功

思考: 现在需要修改原组件使用新 hook
行动: edit_file("src/components/UserList.tsx", ...)
观察: 编辑成功

思考: 我应该运行测试确保重构没有破坏功能
行动: run_terminal_cmd("npm test UserList")
观察: 所有测试通过

回答: 重构完成!我创建了 useUserList hook 并更新了 UserList 组件...

2.2 ReAct Prompt 模板

markdown
# System Prompt

你是一个能够使用工具完成任务的 AI 助手。

## 工作流程
对于每个任务,你需要交替进行"思考"和"行动":

1. **思考 (Thought)**: 分析当前情况,决定下一步
2. **行动 (Action)**: 调用工具执行操作
3. **观察 (Observation)**: 查看工具返回结果
4. 重复以上步骤直到任务完成

## 规则
- 每次只执行一个行动
- 行动前必须先思考
- 如果行动失败,思考原因并尝试其他方法
- 任务完成后,给出总结

## 可用工具
[工具列表]

2.3 ReAct 实现

javascript
class ReActAgent {
  constructor(llm, tools, maxIterations = 10) {
    this.llm = llm;
    this.tools = tools;
    this.maxIterations = maxIterations;
  }
  
  async run(task) {
    const messages = [
      { role: "system", content: this.buildSystemPrompt() },
      { role: "user", content: task }
    ];
    
    for (let i = 0; i < this.maxIterations; i++) {
      const response = await this.llm.chat({
        messages,
        tools: this.tools,
        stop: ["Observation:"]  // 让模型在需要观察时停止
      });
      
      messages.push({ role: "assistant", content: response.content });
      
      // 检查是否完成
      if (response.stop_reason === "end_turn" && !this.hasToolCall(response)) {
        return this.extractFinalAnswer(response);
      }
      
      // 执行工具调用
      if (this.hasToolCall(response)) {
        const results = await this.executeTools(response);
        messages.push({ role: "user", content: results });
      }
    }
    
    throw new Error("达到最大迭代次数");
  }
  
  buildSystemPrompt() {
    return `你是一个 ReAct Agent。
    
对于每个任务,遵循以下格式:

Thought: 我需要思考...
Action: 调用工具
[等待观察结果]

Thought: 根据观察,我认为...
Action: 下一个工具调用

...直到任务完成,给出最终答案。`;
  }
}

3. 规划模式 (Planning)

3.1 Plan-and-Execute

先制定完整计划,再逐步执行:

markdown
用户: 创建一个包含用户 CRUD 的 REST API

# 阶段 1: 规划
计划:
1. 创建 User model (Prisma schema)
2. 创建 UserService
3. 创建 UserController
4. 添加路由
5. 编写测试

# 阶段 2: 执行
[按计划逐步执行每个步骤]
javascript
class PlanAndExecuteAgent {
  async run(task) {
    // 阶段 1: 生成计划
    const plan = await this.generatePlan(task);
    console.log("计划:", plan);
    
    // 阶段 2: 执行每个步骤
    const results = [];
    for (const step of plan.steps) {
      console.log(`执行步骤 ${step.id}: ${step.description}`);
      
      const result = await this.executeStep(step, results);
      results.push({ step: step.id, result });
      
      // 可选: 根据结果调整后续计划
      if (result.needsReplan) {
        const newPlan = await this.replan(task, results);
        plan.steps = newPlan.steps;
      }
    }
    
    return this.summarize(task, results);
  }
  
  async generatePlan(task) {
    const response = await this.llm.chat({
      messages: [
        { role: "system", content: PLANNER_PROMPT },
        { role: "user", content: task }
      ],
      tools: [{ name: "create_plan", ... }],
      tool_choice: { type: "tool", name: "create_plan" }
    });
    
    return JSON.parse(response.tool_calls[0].input);
  }
}

3.2 Hierarchical Planning (分层规划)

高层目标: 重构认证系统

    ├── 子目标 1: 迁移到 JWT
    │       ├── 任务 1.1: 安装依赖
    │       ├── 任务 1.2: 创建 JWT utils
    │       └── 任务 1.3: 修改 auth middleware

    ├── 子目标 2: 添加 refresh token
    │       ├── 任务 2.1: 设计 token schema
    │       └── 任务 2.2: 实现 refresh 逻辑

    └── 子目标 3: 更新前端
            ├── 任务 3.1: 修改 login 流程
            └── 任务 3.2: 添加 token 刷新
javascript
class HierarchicalAgent {
  async run(goal) {
    // 分解为子目标
    const subgoals = await this.decompose(goal);
    
    for (const subgoal of subgoals) {
      // 每个子目标进一步分解为任务
      const tasks = await this.decompose(subgoal);
      
      for (const task of tasks) {
        // 使用 ReAct 执行具体任务
        await this.reactAgent.run(task);
      }
    }
  }
}

4. 反思模式 (Reflection)

4.1 Self-Critique

让 Agent 检查自己的输出并改进:

javascript
class ReflectiveAgent {
  async run(task) {
    // 首次尝试
    let result = await this.attempt(task);
    
    // 自我反思循环
    for (let i = 0; i < 3; i++) {
      const critique = await this.critique(task, result);
      
      if (critique.score >= 0.9) {
        return result;  // 足够好
      }
      
      // 根据反馈改进
      result = await this.improve(task, result, critique);
    }
    
    return result;
  }
  
  async critique(task, result) {
    const response = await this.llm.chat({
      messages: [{
        role: "user",
        content: `任务: ${task}
        
结果: ${result}

请评估这个结果:
1. 是否完成了任务目标?(0-1分)
2. 代码质量如何?
3. 有什么可以改进的地方?

以 JSON 格式输出: { score, issues: [], suggestions: [] }`
      }]
    });
    
    return JSON.parse(response.content);
  }
}

4.2 Reflexion 模式

在多次尝试中学习:

尝试 1:
  执行任务 → 失败
  反思: "我忘记处理边界情况"
  
尝试 2:
  带着反思重新执行 → 部分成功
  反思: "边界情况处理了,但性能不好"
  
尝试 3:
  带着所有反思执行 → 成功
javascript
class ReflexionAgent {
  async run(task, maxAttempts = 3) {
    const reflections = [];
    
    for (let attempt = 1; attempt <= maxAttempts; attempt++) {
      // 执行任务,携带之前的反思
      const result = await this.attempt(task, reflections);
      
      // 验证结果
      const validation = await this.validate(task, result);
      
      if (validation.success) {
        return result;
      }
      
      // 生成反思
      const reflection = await this.reflect(task, result, validation);
      reflections.push(reflection);
      
      console.log(`尝试 ${attempt} 失败。反思: ${reflection}`);
    }
    
    throw new Error("达到最大尝试次数");
  }
  
  async attempt(task, reflections) {
    const prompt = reflections.length > 0
      ? `任务: ${task}\n\n之前的教训:\n${reflections.map((r, i) => `${i+1}. ${r}`).join('\n')}\n\n请避免之前的错误,重新完成任务。`
      : task;
    
    return await this.reactAgent.run(prompt);
  }
}

5. 多 Agent 系统

5.1 分工协作模式

┌─────────────────────────────────────────────────────────────────┐
│                    Multi-Agent System                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌──────────────┐     ┌──────────────┐     ┌──────────────┐    │
│  │   Planner    │────▶│   Executor   │────▶│   Reviewer   │    │
│  │   规划者      │     │   执行者      │     │   审核者      │    │
│  │              │     │              │     │              │    │
│  │ 分解任务      │     │ 调用工具执行  │     │ 检查质量      │    │
│  │ 制定策略      │     │ 处理错误      │     │ 提出改进      │    │
│  └──────────────┘     └──────────────┘     └──────────────┘    │
│         ▲                                         │             │
│         └─────────────────────────────────────────┘             │
│                      反馈循环                                    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
javascript
class MultiAgentSystem {
  constructor() {
    this.planner = new PlannerAgent();
    this.executor = new ExecutorAgent();
    this.reviewer = new ReviewerAgent();
  }
  
  async run(task) {
    // Planner 制定计划
    const plan = await this.planner.createPlan(task);
    
    // Executor 执行计划
    const results = [];
    for (const step of plan.steps) {
      const result = await this.executor.execute(step);
      
      // Reviewer 检查每步结果
      const review = await this.reviewer.review(step, result);
      
      if (!review.approved) {
        // 返回 Planner 重新规划
        const revisedStep = await this.planner.revise(step, review.feedback);
        const revisedResult = await this.executor.execute(revisedStep);
        results.push(revisedResult);
      } else {
        results.push(result);
      }
    }
    
    return results;
  }
}

5.2 专家委员会模式

javascript
class ExpertCommittee {
  constructor() {
    this.experts = [
      new Expert("security", "安全专家,关注 XSS、CSRF、注入等"),
      new Expert("performance", "性能专家,关注渲染、内存、网络"),
      new Expert("accessibility", "可访问性专家,关注 ARIA、键盘导航"),
      new Expert("ux", "UX 专家,关注用户体验和交互设计")
    ];
  }
  
  async review(code) {
    // 所有专家并行审查
    const reviews = await Promise.all(
      this.experts.map(expert => expert.review(code))
    );
    
    // 综合意见
    const synthesis = await this.synthesize(reviews);
    
    return synthesis;
  }
  
  async synthesize(reviews) {
    const allIssues = reviews.flatMap(r => r.issues);
    
    // 按严重程度排序,去重
    return {
      critical: allIssues.filter(i => i.severity === 'critical'),
      major: allIssues.filter(i => i.severity === 'major'),
      minor: allIssues.filter(i => i.severity === 'minor')
    };
  }
}

5.3 辩论模式

javascript
class DebateSystem {
  async solve(problem) {
    const agents = [
      new DebateAgent("方案A支持者"),
      new DebateAgent("方案B支持者"),
    ];
    const judge = new JudgeAgent();
    
    let context = problem;
    
    // 多轮辩论
    for (let round = 0; round < 3; round++) {
      const arguments = await Promise.all(
        agents.map(agent => agent.argue(context))
      );
      
      context += `\n\n--- 第 ${round + 1} 轮 ---\n`;
      context += arguments.map((arg, i) => `Agent ${i+1}: ${arg}`).join('\n\n');
    }
    
    // 裁判总结
    const verdict = await judge.decide(context);
    
    return verdict;
  }
}

6. 状态管理

6.1 Agent 状态结构

typescript
interface AgentState {
  // 任务相关
  task: string;
  plan: Plan | null;
  currentStep: number;
  
  // 执行历史
  history: HistoryEntry[];
  
  // 工具调用记录
  toolCalls: ToolCallRecord[];
  
  // 上下文
  context: {
    files: Map<string, FileContent>;
    variables: Map<string, any>;
  };
  
  // 元信息
  status: 'planning' | 'executing' | 'reflecting' | 'completed' | 'failed';
  startTime: Date;
  totalTokens: number;
}

interface HistoryEntry {
  type: 'thought' | 'action' | 'observation' | 'reflection';
  content: string;
  timestamp: Date;
}

6.2 检查点与恢复

javascript
class StatefulAgent {
  constructor() {
    this.state = this.initState();
  }
  
  async run(task) {
    this.state.task = task;
    
    try {
      while (this.state.status !== 'completed') {
        // 保存检查点
        await this.saveCheckpoint();
        
        // 执行一步
        await this.step();
      }
    } catch (error) {
      // 从最近检查点恢复
      await this.loadCheckpoint();
      // 尝试不同策略
      await this.retry();
    }
  }
  
  async saveCheckpoint() {
    const checkpoint = {
      state: JSON.parse(JSON.stringify(this.state)),
      timestamp: new Date()
    };
    await fs.writeFile(
      `checkpoints/${this.state.task.slice(0, 20)}.json`,
      JSON.stringify(checkpoint)
    );
  }
  
  async loadCheckpoint() {
    // 恢复最近的有效状态
  }
}

7. 安全与限制

7.1 行动限制

javascript
class SafeAgent {
  constructor() {
    this.limits = {
      maxToolCalls: 50,           // 最大工具调用次数
      maxTokens: 100000,          // 最大 token 消耗
      maxTime: 5 * 60 * 1000,     // 最大执行时间 5 分钟
      maxFileEdits: 20,           // 最大文件编辑数
      forbiddenPaths: ['/etc', '/usr', process.env.HOME]
    };
    
    this.counters = {
      toolCalls: 0,
      tokens: 0,
      fileEdits: 0
    };
  }
  
  async executeToolCall(name, input) {
    // 检查限制
    this.counters.toolCalls++;
    if (this.counters.toolCalls > this.limits.maxToolCalls) {
      throw new Error("达到工具调用次数上限");
    }
    
    // 路径检查
    if (input.path && this.isForbiddenPath(input.path)) {
      throw new Error(`禁止访问路径: ${input.path}`);
    }
    
    // 执行
    return await this.tools[name](input);
  }
}

7.2 人在环中 (Human-in-the-Loop)

javascript
class HumanInLoopAgent {
  constructor(confirmFn) {
    this.confirmFn = confirmFn;  // 用户确认函数
    this.autoApproveActions = [
      'read_file',
      'list_directory',
      'search_code'
    ];
  }
  
  async executeAction(action) {
    if (this.requiresApproval(action)) {
      const description = this.describeAction(action);
      const approved = await this.confirmFn(description);
      
      if (!approved) {
        return { 
          success: false, 
          reason: "用户拒绝执行此操作" 
        };
      }
    }
    
    return await this.execute(action);
  }
  
  requiresApproval(action) {
    return !this.autoApproveActions.includes(action.name);
  }
}

8. 调试与可观测性

8.1 Trace 日志

javascript
class TracingAgent {
  constructor() {
    this.trace = [];
  }
  
  async run(task) {
    this.startTrace(task);
    
    try {
      const result = await this.execute(task);
      this.endTrace('success', result);
      return result;
    } catch (error) {
      this.endTrace('error', error);
      throw error;
    }
  }
  
  log(type, data) {
    this.trace.push({
      timestamp: Date.now(),
      type,
      data,
      tokensSoFar: this.totalTokens
    });
  }
  
  exportTrace() {
    return {
      task: this.currentTask,
      duration: this.endTime - this.startTime,
      totalTokens: this.totalTokens,
      toolCalls: this.trace.filter(t => t.type === 'tool_call').length,
      events: this.trace
    };
  }
}

8.2 可视化

javascript
// 生成 Mermaid 流程图
function visualizeAgentFlow(trace) {
  let mermaid = 'graph TD\n';
  
  trace.events.forEach((event, i) => {
    const id = `node${i}`;
    switch (event.type) {
      case 'thought':
        mermaid += `  ${id}[/"💭 ${event.data.slice(0, 30)}..."/]\n`;
        break;
      case 'tool_call':
        mermaid += `  ${id}[["🔧 ${event.data.name}"]]\n`;
        break;
      case 'observation':
        mermaid += `  ${id}(("👁️ Observe"))\n`;
        break;
    }
    
    if (i > 0) {
      mermaid += `  node${i-1} --> ${id}\n`;
    }
  });
  
  return mermaid;
}

9. 实战: 构建代码重构 Agent

javascript
class CodeRefactorAgent {
  constructor() {
    this.tools = [
      readFileTool,
      writeFileTool,
      searchCodeTool,
      runTestsTool,
      gitDiffTool
    ];
  }
  
  getSystemPrompt() {
    return `你是一个专业的代码重构 Agent。

## 工作流程
1. 理解重构目标
2. 分析现有代码结构
3. 制定重构计划
4. 逐步执行重构
5. 运行测试验证
6. 总结变更

## 规则
- 每次只修改一个文件
- 修改后立即运行相关测试
- 如果测试失败,回滚并尝试其他方案
- 保持 git 提交的原子性

## 思考格式
每步前先说明:
- 当前目标是什么
- 为什么选择这个方案
- 可能的风险

## 可用工具
- read_file: 读取文件
- write_file: 写入文件
- search_code: 搜索代码
- run_tests: 运行测试
- git_diff: 查看差异`;
  }
  
  async refactor(task) {
    const agent = new ReActAgent(this.llm, this.tools);
    return await agent.run(task);
  }
}

// 使用
const agent = new CodeRefactorAgent();
await agent.refactor(`
  重构 src/components/UserList.tsx:
  1. 将数据获取逻辑提取到 useUserList hook
  2. 将列表渲染逻辑提取到 UserListItem 组件
  3. 添加 loading 和 error 状态处理
`);

10. 关键要点

  1. ReAct 是基础: 推理-行动-观察的循环是 Agent 的核心
  2. 规划提升成功率: 复杂任务需要先规划再执行
  3. 反思实现自我改进: 让 Agent 检查和改进自己的输出
  4. 多 Agent 分工协作: 不同专长的 Agent 协同工作
  5. 状态管理很重要: 支持检查点和恢复
  6. 安全不可忽视: 限制、确认、审计

延伸阅读

前端面试知识库