Agent 架构设计:从 Chatbot 到自主代理 🤖
"Agent 是能自主规划、执行和反思的 AI 系统。"
1. Agent vs Chatbot
1.1 核心区别
| 特性 | Chatbot | Agent |
|---|---|---|
| 交互模式 | 一问一答 | 自主多步执行 |
| 工具使用 | 可选 | 必须 |
| 规划能力 | 无 | 有 |
| 状态管理 | 简单 | 复杂 |
| 自我纠错 | 无 | 有 |
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. 关键要点
- ReAct 是基础: 推理-行动-观察的循环是 Agent 的核心
- 规划提升成功率: 复杂任务需要先规划再执行
- 反思实现自我改进: 让 Agent 检查和改进自己的输出
- 多 Agent 分工协作: 不同专长的 Agent 协同工作
- 状态管理很重要: 支持检查点和恢复
- 安全不可忽视: 限制、确认、审计