第15节:实战项目 - 构建自定义AI代理

3 阅读6分钟

1. 概述

本节是一个综合性实战项目,旨在引导你构建一个基于 Claude Code 架构的自定义 AI 代理。通过本项目,你将应用前面所学的所有核心概念,包括 Agent 循环、工具系统、权限管理、上下文处理等,创建一个功能完整的 AI 代理系统。

2. 项目目标

构建一个名为 DevAssistant 的自定义 AI 代理,具备以下功能:

  • 代码分析和生成
  • 项目结构管理
  • 依赖项分析
  • 测试自动化
  • 部署辅助
  • 文档生成

3. 技术栈选择

技术版本用途
Node.jsv18+运行环境
TypeScriptv5+开发语言
Anthropic APIv1AI 模型接口
Commanderv11+命令行界面
Chalkv5+终端美化
Axiosv1+HTTP 客户端
Inquirerv9+交互式命令行

4. 项目结构设计

dev-assistant/
├── src/
│   ├── agent/                # 代理核心
│   │   ├── Agent.ts          # 主代理类
│   │   ├── loop.ts           # 代理循环
│   │   └── context.ts        # 上下文管理
│   ├── tools/                # 工具系统
│   │   ├── CodeAnalyzeTool.ts
│   │   ├── FileReadTool.ts
│   │   ├── FileWriteTool.ts
│   │   ├── TestRunTool.ts
│   │   └── DeployTool.ts
│   ├── permissions/          # 权限系统
│   │   ├── checker.ts
│   │   └── rules.ts
│   ├── utils/                # 工具函数
│   │   ├── api.ts
│   │   ├── fs.ts
│   │   └── logger.ts
│   ├── config/               # 配置管理
│   │   └── index.ts
│   └── cli/                  # 命令行界面
│       ├── commands/         # 命令定义
│       └── index.ts
├── package.json
├── tsconfig.json
└── .env.example

5. 核心组件实现

5.1 代理核心

Agent 类

// src/agent/Agent.ts
import { Anthropic } from '@anthropic-ai/sdk';
import { Tool } from '../tools/Tool';
import { ContextManager } from './context';
import { PermissionChecker } from '../permissions/checker';

export class Agent {
  private anthropic: Anthropic;
  private tools: Tool[];
  private contextManager: ContextManager;
  private permissionChecker: PermissionChecker;
  
  constructor(apiKey: string) {
    this.anthropic = new Anthropic({ apiKey });
    this.tools = [];
    this.contextManager = new ContextManager();
    this.permissionChecker = new PermissionChecker();
  }
  
  registerTool(tool: Tool) {
    this.tools.push(tool);
  }
  
  async run(query: string) {
    // 构建工具列表
    const toolList = this.tools.map(tool => tool.getSchema());
    
    // 构建消息
    const messages = this.contextManager.getMessages();
    messages.push({ role: 'user', content: query });
    
    // 调用 Anthropic API
    const response = await this.anthropic.messages.create({
      model: 'claude-3-opus-20240229',
      max_tokens: 1024,
      messages,
      tools: toolList.length > 0 ? toolList : undefined
    });
    
    // 处理响应
    return this.processResponse(response);
  }
  
  private async processResponse(response: any) {
    // 处理工具调用
    if (response.content && response.content[0]?.type === 'tool_use') {
      const toolUse = response.content[0];
      const tool = this.tools.find(t => t.getName() === toolUse.name);
      
      if (!tool) {
        return 'Tool not found';
      }
      
      // 检查权限
      if (!this.permissionChecker.check(tool.getName(), toolUse.input)) {
        return 'Permission denied';
      }
      
      // 执行工具
      const result = await tool.execute(toolUse.input);
      
      // 将工具执行结果添加到上下文
      this.contextManager.addMessage({
        role: 'assistant',
        content: response.content
      });
      
      this.contextManager.addMessage({
        role: 'tool',
        content: {
          tool_call_id: toolUse.id,
          output: result
        }
      });
      
      // 继续执行
      return this.run('');
    }
    
    // 处理文本响应
    if (response.content && response.content[0]?.type === 'text') {
      const text = response.content[0].text;
      this.contextManager.addMessage({
        role: 'assistant',
        content: response.content
      });
      return text;
    }
    
    return 'No response';
  }
}

上下文管理器

// src/agent/context.ts
export class ContextManager {
  private messages: any[] = [];
  private maxMessages = 50;
  
  addMessage(message: any) {
    this.messages.push(message);
    // 限制消息数量
    if (this.messages.length > this.maxMessages) {
      this.messages = this.messages.slice(-this.maxMessages);
    }
  }
  
  getMessages() {
    return [...this.messages];
  }
  
  clear() {
    this.messages = [];
  }
}

5.2 工具系统

工具基类

// src/tools/Tool.ts
export abstract class Tool {
  abstract getName(): string;
  abstract getSchema(): any;
  abstract execute(input: any): Promise<any>;
}

代码分析工具

// src/tools/CodeAnalyzeTool.ts
import { Tool } from './Tool';
import * as fs from 'fs/promises';

export class CodeAnalyzeTool extends Tool {
  getName(): string {
    return 'code_analyze';
  }
  
  getSchema(): any {
    return {
      name: this.getName(),
      description: '分析代码文件,提供结构和功能分析',
      input_schema: {
        type: 'object',
        properties: {
          file_path: {
            type: 'string',
            description: '要分析的文件路径'
          }
        },
        required: ['file_path']
      }
    };
  }
  
  async execute(input: any): Promise<any> {
    try {
      const { file_path } = input;
      const content = await fs.readFile(file_path, 'utf8');
      
      // 简单的代码分析
      const lines = content.split('\n');
      const functions = content.match(/function\s+\w+\s*\(/g) || [];
      const classes = content.match(/class\s+\w+/g) || [];
      
      return {
        file_path,
        lines_count: lines.length,
        functions_count: functions.length,
        classes_count: classes.length,
        sample: lines.slice(0, 20).join('\n') + '...'
      };
    } catch (error) {
      return { error: (error as Error).message };
    }
  }
}

5.3 权限系统

// src/permissions/checker.ts
export class PermissionChecker {
  check(toolName: string, input: any): boolean {
    // 简单的权限检查逻辑
    const dangerousTools = ['file_write', 'deploy'];
    
    if (dangerousTools.includes(toolName)) {
      // 这里可以实现更复杂的权限检查
      // 例如:检查文件路径是否在允许的目录内
      return true; // 简化处理,实际应用中应该更严格
    }
    
    return true;
  }
}

5.4 命令行界面

// src/cli/index.ts
import { Command } from 'commander';
import { Agent } from '../agent/Agent';
import { CodeAnalyzeTool } from '../tools/CodeAnalyzeTool';
import { FileReadTool } from '../tools/FileReadTool';
import { FileWriteTool } from '../tools/FileWriteTool';
import { TestRunTool } from '../tools/TestRunTool';
import { DeployTool } from '../tools/DeployTool';
import * as dotenv from 'dotenv';

// 加载环境变量
dotenv.config();

const program = new Command();

program
  .name('dev-assistant')
  .description('AI-powered development assistant')
  .version('1.0.0');

program
  .command('run')
  .description('Run the assistant with a query')
  .argument('<query>', 'The query to run')
  .action(async (query) => {
    const apiKey = process.env.ANTHROPIC_API_KEY;
    if (!apiKey) {
      console.error('ANTHROPIC_API_KEY is not set');
      process.exit(1);
    }
    
    const agent = new Agent(apiKey);
    
    // 注册工具
    agent.registerTool(new CodeAnalyzeTool());
    agent.registerTool(new FileReadTool());
    agent.registerTool(new FileWriteTool());
    agent.registerTool(new TestRunTool());
    agent.registerTool(new DeployTool());
    
    try {
      const result = await agent.run(query);
      console.log(result);
    } catch (error) {
      console.error('Error:', (error as Error).message);
    }
  });

program.parse();

6. 项目配置

package.json

{
  "name": "dev-assistant",
  "version": "1.0.0",
  "description": "AI-powered development assistant",
  "main": "dist/cli/index.js",
  "bin": {
    "dev-assistant": "dist/cli/index.js"
  },
  "scripts": {
    "build": "tsc",
    "dev": "ts-node src/cli/index.ts",
    "start": "node dist/cli/index.js"
  },
  "dependencies": {
    "@anthropic-ai/sdk": "^0.20.0",
    "commander": "^11.0.0",
    "chalk": "^5.0.0",
    "axios": "^1.0.0",
    "inquirer": "^9.0.0",
    "dotenv": "^16.0.0"
  },
  "devDependencies": {
    "typescript": "^5.0.0",
    "ts-node": "^10.0.0",
    "@types/node": "^18.0.0"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "target": "ES2018",
    "module": "commonjs",
    "lib": ["ES2018"],
    "outDir": "./dist",
    "rootDir": "./src",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true
  },
  "include": ["src/**/*"],
  "exclude": ["node_modules"]
}

.env.example

ANTHROPIC_API_KEY=your_api_key_here

7. 实现步骤

步骤 1: 初始化项目

# 创建项目目录
mkdir dev-assistant
cd dev-assistant

# 初始化 npm
npm init -y

# 安装依赖
npm install @anthropic-ai/sdk commander chalk axios inquirer dotenv
npm install --save-dev typescript ts-node @types/node

# 初始化 TypeScript
npx tsc --init

步骤 2: 创建核心文件

按照项目结构创建所有必要的文件,实现核心功能。

步骤 3: 构建和测试

# 构建项目
npm run build

# 运行测试
npm run dev run "分析当前目录下的 package.json 文件"

步骤 4: 扩展功能

根据需要扩展工具系统,添加更多功能:

  • 代码生成工具
  • 依赖分析工具
  • 文档生成工具
  • 性能分析工具

8. 测试和调试

测试策略

  1. 单元测试:测试各个工具的功能
  2. 集成测试:测试代理与工具的协作
  3. 端到端测试:测试完整的代理工作流

调试技巧

  • 使用环境变量 DEBUG=true 启用详细日志
  • 在工具执行前后添加日志记录
  • 使用 TypeScript 调试器进行断点调试

9. 部署和分发

本地部署

# 构建项目
npm run build

# 链接到全局
npm link

# 使用命令
 dev-assistant run "帮助我分析项目结构"

容器化部署

FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .
RUN npm run build

ENTRYPOINT ["node", "dist/cli/index.js"]

10. 项目扩展

高级功能

  1. 多代理协作:实现多个代理之间的协作
  2. 自主模式:参考 KAIROS 模式实现自主代理
  3. 多模态支持:添加语音输入和图像处理
  4. 插件系统:实现可扩展的插件架构

性能优化

  1. 缓存机制:缓存工具执行结果
  2. 批处理:批量处理多个请求
  3. 并行执行:并行执行多个工具
  4. 上下文压缩:优化上下文窗口使用

11. 最佳实践

  1. 安全第一:严格的权限检查
  2. 错误处理:完善的错误处理机制
  3. 日志记录:详细的日志记录
  4. 用户反馈:清晰的用户反馈
  5. 可扩展性:模块化设计

12. 总结

通过本实战项目,你已经构建了一个功能完整的自定义 AI 代理系统,应用了 Claude Code 的核心架构和设计理念。这个项目展示了如何:

  • 实现 Agent 循环和消息处理
  • 构建可扩展的工具系统
  • 实现权限检查和安全机制
  • 管理上下文和对话历史
  • 创建命令行界面和用户交互

你可以基于这个基础项目,根据具体需求进行扩展和定制,构建更加强大和智能的 AI 代理系统。

项目成果

  • 一个功能完整的 DevAssistant 代理
  • 可扩展的工具系统
  • 模块化的代码架构
  • 完整的命令行界面

这个项目不仅是对前面所学知识的综合应用,也是一个可以在实际开发中使用的实用工具。