前言:字节跳动也来做AI编程了

2025年初,字节跳动低调上线了一款名为 Trae 的AI编程工具,并在2026年推出了其升级版本 Trae SOLO。与同期火热的 Cursor、Windsurf 不同,Trae SOLO 打出了"免费 + 全栈 + 端到端"的旗号,试图在 AI 编程工具市场分一杯羹。

作为长期使用 Cursor 和 GitHub Copilot 的开发者,我抱着试试看的心态深度体验了 Trae SOLO 三个月。本文将把我踩过的坑、总结的经验、以及对竞品的客观对比,和盘托出。

本文适合谁:

  • 已经用过 AI 编程工具,想了解 Trae SOLO 有什么不同的开发者
  • 正在从传统 IDE 迁移到 AI Native 开发环境的团队
  • 对字节系产品持开放态度,希望找到趁手生产力的工程师

前置说明: 本文所有演示基于 Windows 11 + Trae SOLO v1.8.x,macOS/Linux 用户操作逻辑基本一致,UI 细节可能有细微差别。


一、Trae SOLO 核心能力全景图

1.1 产品定位与架构

Trae SOLO 不是一个简单的代码补全插件,而是一款内置 AI 引擎的完整 IDE。它的底层基于字节自研的大模型,针对代码场景做了专项微调,支持中英文双语交互。

核心架构可以用下图概括:

┌──────────────────────────────────────────────────┐
│                  Trae SOLO 界面层                 │
│  ┌──────────┐  ┌──────────┐  ┌──────────────┐   │
│  │  编辑区   │  │  终端区   │  │  AI 对话面板   │   │
│  └──────────┘  └──────────┘  └──────────────┘   │
├──────────────────────────────────────────────────┤
│                   AI 能力层                       │
│  ┌────────────┐  ┌────────────┐  ┌──────────┐  │
│  │  代码补全   │  │  智能对话   │  │ Agent   │  │
│  │ (Inline)   │  │ (Chat)    │  │ (Solo)  │  │
│  └────────────┘  └────────────┘  └──────────┘  │
├──────────────────────────────────────────────────┤
│                   模型层                          │
│  ┌──────────────────────────────────────────┐   │
│  │  字节自研代码模型 │ 第三方模型可选 │ 本地模型 │   │
│  └──────────────────────────────────────────┘   │
└──────────────────────────────────────────────────┘

1.2 三大核心模式

Trae SOLO 的核心交互模式分为三层:

模式 触发方式 典型场景 自主性
Code 模式 Ctrl+I / Cmd+I 代码补全、单函数重构 低(你主导)
MTC 模式 侧边栏切换 技术调研、方案设计、代码审查 中(协作式)
Solo Agent 模式 /solo 命令 端到端任务执行、自主开发 高(AI主导)

接下来,我们逐一深入。


二、Code 模式:比 Copilot 更懂中文开发者

2.1 基础补全体验

Code 模式本质上是一个增强版的代码补全引擎。在 settings.json 中可以找到相关配置项:

{
  "trae.code.enable": true,
  "trae.code.inlineCompletions": true,
  "trae.code.tabCompletion": true,
  "trae.code.phantomMode": false,
  "trae.code.languageSpecific": {
    "python": {
      "docstringStyle": "google",  // google | numpy | sphinx
      "typeInference": true
    },
    "typescript": {
      "strictMode": true,
      "importSorting": "eslint"
    }
  }
}

实测对比:在同一个 TypeScript React 组件上,Trae SOLO 的补全延迟约为 200-400ms,略快于 Copilot 的 300-500ms(受网络影响)。对于中文注释的语义理解,Trae SOLO 表现明显更好:

// 中文注释场景测试
// 用户输入:
/**
 * 根据用户ID获取其最近N条订单
 * @param userId 用户ID
 * @param limit  返回条数,默认10
 */
async function getUserOrders

// Trae SOLO 补全结果(直接生成):
async function getUserOrders(
  userId: string,
  limit: number = 10
): Promise<Order[]> {
  const cacheKey = `orders:${userId}:${limit}`;
  const cached = await redis.get(cacheKey);
  if (cached) return JSON.parse(cached);
  
  const orders = await db.orders.findMany({
    where: { userId },
    orderBy: { createdAt: 'desc' },
    take: limit,
  });
  
  await redis.setex(cacheKey, 300, JSON.stringify(orders));
  return orders;
}

这个补全质量已经达到了"可用生产代码"的水准,不像某些工具会生成一些半残的模板。

2.2 Inline 改写(最实用的功能)

Code 模式下最强大的功能是** Inline 改写**:选中一段代码,按 Ctrl+Shift+R,AI 会对选区进行智能重构。

场景示例:把一个 Promise 风格的函数批量改写为 async/await:

// 原始代码(需要改写)
function fetchUserData(userId, callback) {
  fetch(`/api/users/${userId}`)
    .then(response => response.json())
    .then(data => {
      callback(null, data);
    })
    .catch(error => {
      callback(error, null);
    });
}

// 选中后触发 Inline 改写,AI 自动识别为"异步模式转换"任务
// Trae SOLO 改写结果:
async function fetchUserData(userId) {
  try {
    const response = await fetch(`/api/users/${userId}`);
    if (!response.ok) {
      throw new Error(`HTTP error! status: ${response.status}`);
    }
    return await response.json();
  } catch (error) {
    console.error('Failed to fetch user data:', error);
    throw error;
  }
}

2.3 多文件上下文感知

Code 模式的上下文窗口默认为 32K token,支持手动扩展到 128K。这意味着你可以:

  1. 打开一个包含 10+ 文件的项目
  2. 询问"这个模块的接口与哪个服务对接"
  3. Trae SOLO 能准确回答,因为它的上下文感知覆盖了项目中所有打开的文件
# 查看当前上下文文件列表
# 在 AI 对话面板输入:@context 可列出当前加载的所有上下文文件

三、MTC 模式:不写代码也能用的AI助手

MTC(Multi-Turn Collaborative)模式是 Trae SOLO 最被低估的功能。很多开发者装完就只用 Code 模式,完全忽略了 MTC。

3.1 什么是 MTC 模式

MTC 模式本质是一个技术问答 + 文档生成的协作式对话工具。它不直接操作你的代码,而是通过多轮对话帮你理解、规划、审查代码。

打开方式: 点击左侧边栏的机器人图标 → 切换模式选择器到 “MTC”

3.2 典型使用场景

场景一:技术方案设计

你:我要做一个图片处理服务,支持裁剪、缩放、格式转换,每天处理量约50万张,
    峰值QPS 200,请帮我设计整体架构。

MTC 回复:
├── 核心模块划分
│   ├── 上传接收层(API Gateway + 预校验)
│   ├── 任务队列(Redis Queue / RabbitMQ)
│   ├── 处理器集群(Worker Pool)
│   └── 结果存储(OSS + CDN)
├── 关键技术选型
│   ├── 图片处理库:libvips(Go/Node binding)
│   ├── 任务队列:BullMQ(Redis-backed)
│   └── 缓存策略:LRU + CDN边缘缓存
└── 关键瓶颈分析(200 QPS 场景下)
    └── ...

场景二:代码审查

# 把这段 Python 代码丢给 MTC 审查
def authenticate_user(username, password):
    import hashlib
    hashed = hashlib.md5(password.encode()).hexdigest()
    result = db.execute(
        f"SELECT * FROM users WHERE username='{username}' AND password='{hashed}'"
    )
    return result.fetchone()

MTC 审查意见:

🔴 严重问题(必须修复)
1. SQL 注入漏洞:字符串拼接构造 SQL,username 未做任何过滤
2. 弱哈希算法:MD5 已不建议用于密码存储,应使用 bcrypt 或 argon2

🟡 优化建议
3. 缺少认证失败次数限制(防暴力破解)
4. 日志中不应记录明文密码尝试

✅ 修复示例(参考)

它会直接给出修复后的安全版本代码。

场景三:学习新技术

你:给我解释一下 Rust 的所有权系统,重点对比它和 Go 的垃圾回收机制
    在游戏服务器开发中应该如何选择?

MTC 回复:(给出详细对比表格 + 场景分析)

3.3 MTC vs Code 模式的选择

决策维度 Code 模式 MTC 模式
是否正在写代码 ✅ 是 → Code ❌ 否 → MTC
需要修改文件吗 是 → Code 否 → MTC
是学习/调研类问题吗 ❌ → MTC
需要生成完整新模块吗 Code + Solo MTC 规划 → Code 实施

四、Solo Agent 模式:让AI自主完成整个任务

这是 Trae SOLO 区别于其他 AI 编程工具的核心大招。Solo Agent 模式不是帮你补全代码,而是帮你自主规划 + 执行 + 验证一个完整任务。

4.1 激活方式

在 AI 对话面板中输入 /solo 或点击右上角的 “Solo” 按钮即可进入 Agent 模式。

# 快捷命令
/solo           # 启动 Solo Agent
/solo stop      # 停止当前任务
/solo status    # 查看执行进度
/solo rollback  # 回退最近一次修改

4.2 工作流程解析

Solo Agent 的执行流程如下:

┌─────────────────────────────────────────────────────┐
│  1. 任务理解:AI 分析需求,生成执行计划               │
│  2. 步骤拆分:将任务分解为可执行的子步骤              │
│  3. 工具调用:调用文件操作、终端、搜索等工具执行      │
│  4. 自我验证:执行后检查结果是否符合预期             │
│  5. 迭代修复:如果验证失败,自主尝试修复              │
│  6. 结果交付:汇总修改,报告完成状态                  │
└─────────────────────────────────────────────────────┘

4.3 实战:让 Solo Agent 独立完成一个功能模块

需求: 在现有 Node.js Express 项目中添加一个「文章点赞」功能,包括 API、数据库表、Redis 缓存。

Step 1 - 启动 Solo Agent 并下达任务

在 Trae SOLO 对话框中输入:

/solo 在当前项目中实现「文章点赞」功能:
1. 在 MySQL 中创建 likes 表
2. 实现 POST /api/articles/:id/like 点赞接口
3. 使用 Redis 做点赞计数缓存,防止重复点赞
4. 实现 GET /api/articles/:id/likes 获取点赞数
5. 写好单元测试

Step 2 - AI 自主规划

Solo Agent 分析项目结构后,生成执行计划:

📋 执行计划:
[1/6] 分析现有项目结构(数据库配置、路由组织方式)
[2/6] 创建数据库迁移文件 src/migrations/20260117_create_likes_table.sql
[3/6] 创建 Redis 工具模块 src/utils/likeCache.ts
[4/6] 创建点赞路由处理器 src/routes/like.ts
[5/6] 注册路由并在 app.ts 中挂载
[6/6] 编写测试 src/tests/like.test.ts
是否继续? (y/n)

Step 3 - 确认并执行

输入 y,AI 开始逐个步骤执行。Solo Agent 会:

  1. 创建迁移文件(包含事务支持)
  2. 写 Redis 缓存逻辑(带分布式锁防并发)
  3. 实现路由处理器(带参数校验和限流)
  4. 挂载路由
  5. 编写 Jest 测试(覆盖率 > 80%)

生成的关键代码示例:

src/utils/likeCache.ts:

import Redis from 'ioredis';
import { db } from '../config/database';

const redis = new Redis(process.env.REDIS_URL);
const LOCK_TTL = 5; // 分布式锁5秒超时

/**
 * 点赞操作(原子性保证)
 */
export async function likeArticle(
  userId: string,
  articleId: string
): Promise<{ success: boolean; likeCount: number }> {
  const cacheKey = `like:${articleId}`;
  const lockKey = `lock:like:${articleId}`;

  // 尝试获取分布式锁,防止并发重复点赞
  const lockAcquired = await redis.set(
    lockKey, userId, 'EX', LOCK_TTL, 'NX'
  );

  if (!lockAcquired) {
    throw new Error('请求过于频繁,请稍后重试');
  }

  try {
    // 检查是否已点赞(双重检查)
    const liked = await db.query(
      'SELECT 1 FROM likes WHERE user_id = ? AND article_id = ?',
      [userId, articleId]
    );

    if (liked.rows.length > 0) {
      return { success: false, likeCount: await getLikeCount(articleId) };
    }

    // 写入数据库
    await db.query(
      'INSERT INTO likes (user_id, article_id) VALUES (?, ?)',
      [userId, articleId]
    );

    // 更新缓存
    await redis.incr(cacheKey);

    return { success: true, likeCount: await getLikeCount(articleId) };
  } finally {
    await redis.del(lockKey);
  }
}

/**
 * 获取点赞数(优先读缓存)
 */
export async function getLikeCount(articleId: string): Promise<number> {
  const cacheKey = `like:${articleId}`;
  const cached = await redis.get(cacheKey);

  if (cached !== null) {
    return parseInt(cached, 10);
  }

  const result = await db.query(
    'SELECT COUNT(*) as count FROM likes WHERE article_id = ?',
    [articleId]
  );

  const count = result.rows[0].count;
  await redis.set(cacheKey, count, 'EX', 300); // 缓存5分钟

  return count;
}

4.4 Solo Agent 的能力边界

Solo Agent 非常强大,但不是万能的。以下是我的实测经验:

Solo Agent 表现优秀的场景:

  • 功能模块开发(CRUD 类)
  • 代码重构和迁移
  • 测试用例编写
  • 配置变更和环境搭建
  • 文档生成

Solo Agent 需要密切监督的场景:

  • 涉及数据库结构大幅变更(建议人工review SQL)
  • 需要理解复杂业务规则
  • 多服务分布式协调
  • 安全敏感的权限控制逻辑

使用建议: 给 Solo Agent 的任务描述越具体,结果越符合预期。对于模糊需求,建议先用 MTC 模式讨论清楚,再切换到 Solo 执行。


五、与 Cursor、Copilot 的横向对比

这一节我尽量客观,但完全中立是不可能的——我只代表我自己三个月的使用体验。

5.1 功能矩阵对比

能力维度 Trae SOLO Cursor GitHub Copilot
价格 免费(当前) $20/月(Pro) $10/月
代码补全 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
中文语义理解 ⭐⭐⭐⭐⭐ ⭐⭐⭐ ⭐⭐⭐
Agent 自主开发 ⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
多模型支持 字节自研 + 可扩展 Claude/GPT GPT
IDE 基础 定制化 Electron VS Code Fork VS Code 插件
团队协作 基础 高级 基础
调试辅助 ⭐⭐⭐ ⭐⭐⭐⭐ ⭐⭐⭐
生态插件 ⭐⭐⭐ ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐

5.2 场景化推荐

选 Trae SOLO 如果:

  • ✅ 预算有限,追求免费工具的最高性价比
  • ✅ 中文项目为主,中文注释和需求文档多
  • ✅ 需要完整的端到端开发(从需求到部署)
  • ✅ 想体验 Agent 驱动的开发流程

选 Cursor 如果:

  • ✅ 追求最极致的代码补全体验
  • ✅ 需要接入 Claude/GPT-4o 等顶级模型
  • ✅ 团队已经重度依赖 VS Code 生态
  • ✅ 愿意为更成熟的工具付费

选 Copilot 如果:

  • ✅ 已经是 VS Code 重度用户,不想切换 IDE
  • ✅ 主要使用 GitHub 产品线(深度集成)
  • ✅ 代码补全需求为主,不需要复杂 Agent 能力

5.3 Trae SOLO 目前的主要短板

说真话:

  1. 插件生态薄弱:相比 VS Code,Trae SOLO 的插件市场还很小,很多常用插件找不到替代品。
  2. 调试体验一般:断点调试、变量监视等功能不如 IntelliJ IDEA/VS Code 完善。
  3. 大项目性能:打开超过 50 个文件的巨型项目时,内存占用较高(实测约 1.5GB)。
  4. 模型能力上限:字节自研模型在某些复杂推理任务上不如 Claude-3.5-Sonnet。
  5. 文档稀缺:目前社区资源少,遇到问题主要靠官方文档和自我摸索。

六、真实项目实战:从需求到部署

这一节用一个完整案例,串联前面介绍的所有功能。目标是:用 Trae SOLO 从零开发一个轻量级任务看板后端 API

6.1 项目背景

  • 技术栈:Node.js + Express + TypeScript + PostgreSQL + Redis
  • 需求:团队内部使用的任务看板后端(Kanban Board API)
  • 团队规模:2人小团队,要求快速交付

6.2 Step 1 - 项目初始化(MTC 模式规划)

使用 MTC 模式做技术方案讨论:

你:我要做一个任务看板后端,支持多项目、看板列、自定义字段、
    需要鉴权,有哪些关键技术决策点?

MTC 回复:涵盖数据模型设计、鉴权方案选择(JWT vs Session)、
         字段扩展方案(JSONB vs EAV)、实时通知(WebSocket vs SSE)

6.3 Step 2 - 脚手架搭建(Solo Agent 模式)

/solo 搭建一个 Node.js + TypeScript + Express 的项目脚手架:
1. 使用 npm init + TypeScript 配置(tsconfig.json)
2. 配置 ESLint + Prettier
3. 安装依赖:express, typescript, @types/express, 
   pg, redis, jsonwebtoken, zod(参数校验)
4. 创建标准目录结构:src/{routes,controllers,services,
   models,middlewares,utils,config,types}
5. 创建 .env.example 和 src/config/index.ts 配置管理
6. 编写 README.md(包含启动说明)

Agent 执行后的目录结构:

project-root/
├── src/
│   ├── config/
│   │   ├── database.ts      # PostgreSQL 连接池
│   │   ├── redis.ts        # Redis 客户端
│   │   └── index.ts        # 环境变量加载
│   ├── controllers/        # 控制器层
│   ├── services/           # 业务逻辑层
│   ├── models/             # 数据模型
│   ├── routes/             # 路由定义
│   ├── middlewares/        # 中间件(Auth, ErrorHandler)
│   ├── utils/              # 工具函数
│   └── types/              # TypeScript 类型定义
├── tests/                  # 单元测试
├── package.json
├── tsconfig.json
└── .env.example

6.4 Step 3 - 核心功能开发(Code 模式)

6.4.1 数据库模型

使用 Code 模式的 Inline 改写功能,参考 MTC 给出的设计优化建议:

// src/models/Board.ts
import { z } from 'zod';

// Zod schema 作为类型 + 校验双重用途
export const BoardSchema = z.object({
  id: z.string().uuid(),
  projectId: z.string().uuid(),
  name: z.string().min(1).max(100),
  description: z.string().max(500).optional(),
  position: z.number().int().nonnegative(),
  createdAt: z.date(),
  updatedAt: z.date(),
});

export const TaskSchema = z.object({
  id: z.string().uuid(),
  boardId: z.string().uuid(),
  title: z.string().min(1).max(200),
  description: z.string().max(5000).optional(),
  status: z.enum(['TODO', 'IN_PROGRESS', 'REVIEW', 'DONE']),
  priority: z.enum(['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']).default('MEDIUM'),
  assigneeId: z.string().uuid().optional(),
  dueDate: z.date().optional(),
  customFields: z.record(z.any()).default({}), // JSONB 扩展字段
  position: z.number().int().nonnegative(),
  createdAt: z.date(),
  updatedAt: z.date(),
});

export type Board = z.infer<typeof BoardSchema>;
export type Task = z.infer<typeof TaskSchema>;
6.4.2 看板服务层
// src/services/boardService.ts
import { db } from '../config/database';
import { redis } from '../config/redis';
import { Board, BoardSchema } from '../models/Board';
import { Task } from '../models/Board';

const CACHE_TTL = 300; // 5分钟缓存

export class BoardService {
  /**
   * 创建看板
   */
  async createBoard(data: Omit<Board, 'id' | 'createdAt' | 'updatedAt'>): Promise<Board> {
    const id = crypto.randomUUID();
    const now = new Date();

    const board = await db.query(
      `INSERT INTO boards (id, project_id, name, description, position, created_at, updated_at)
       VALUES ($1, $2, $3, $4, $5, $6, $7)
       RETURNING *`,
      [id, data.projectId, data.name, data.description, data.position, now, now]
    );

    return BoardSchema.parse(board.rows[0]);
  }

  /**
   * 获取看板详情(含任务列表,Redis 缓存)
   */
  async getBoardWithTasks(boardId: string): Promise<{ board: Board; tasks: Task[] }> {
    const cacheKey = `board:${boardId}`;

    // 尝试从缓存读取
    const cached = await redis.get(cacheKey);
    if (cached) {
      return JSON.parse(cached);
    }

    const boardResult = await db.query(
      'SELECT * FROM boards WHERE id = $1',
      [boardId]
    );

    if (boardResult.rows.length === 0) {
      throw new Error('Board not found');
    }

    const tasksResult = await db.query(
      `SELECT * FROM tasks 
       WHERE board_id = $1 
       ORDER BY position ASC`,
      [boardId]
    );

    const result = {
      board: BoardSchema.parse(boardResult.rows[0]),
      tasks: tasksResult.rows,
    };

    await redis.setex(cacheKey, CACHE_TTL, JSON.stringify(result));
    return result;
  }

  /**
   * 看板成员权限检查(中间件辅助方法)
   */
  async checkBoardAccess(boardId: string, userId: string): Promise<boolean> {
    const result = await db.query(
      `SELECT 1 FROM board_members 
       WHERE board_id = $1 AND user_id = $2`,
      [boardId, userId]
    );
    return result.rows.length > 0;
  }
}

export const boardService = new BoardService();
6.4.3 路由定义
// src/routes/board.ts
import { Router } from 'express';
import { boardService } from '../services/boardService';
import { authMiddleware } from '../middlewares/auth';
import { validate } from '../middlewares/validate';
import { BoardSchema } from '../models/Board';
import { z } from 'zod';

const router = Router();

// 所有路由都需要鉴权
router.use(authMiddleware);

// 创建看板
router.post('/', validate(z.object({
  projectId: z.string().uuid(),
  name: z.string().min(1).max(100),
  description: z.string().max(500).optional(),
  position: z.number().int().nonnegative(),
})), async (req, res) => {
  try {
    const board = await boardService.createBoard(req.body);
    res.status(201).json(board);
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Unknown error';
    res.status(400).json({ error: message });
  }
});

// 获取看板详情
router.get('/:boardId', async (req, res) => {
  try {
    const { boardId } = req.params;
    
    // 权限检查
    const hasAccess = await boardService.checkBoardAccess(boardId, req.user!.id);
    if (!hasAccess) {
      return res.status(403).json({ error: 'Access denied' });
    }

    const result = await boardService.getBoardWithTasks(boardId);
    res.json(result);
  } catch (error) {
    const message = error instanceof Error ? error.message : 'Unknown error';
    res.status(404).json({ error: message });
  }
});

export default router;

6.5 Step 4 - 鉴权中间件

// src/middlewares/auth.ts
import { Request, Response, NextFunction } from 'express';
import jwt from 'jsonwebtoken';

export interface AuthUser {
  id: string;
  email: string;
  role: string;
}

declare global {
  namespace Express {
    interface Request {
      user?: AuthUser;
    }
  }
}

export function authMiddleware(
  req: Request,
  res: Response,
  next: NextFunction
): void {
  const authHeader = req.headers.authorization;

  if (!authHeader?.startsWith('Bearer ')) {
    res.status(401).json({ error: 'Missing or invalid authorization header' });
    return;
  }

  const token = authHeader.substring(7);

  try {
    const payload = jwt.verify(token, process.env.JWT_SECRET!) as AuthUser;
    req.user = payload;
    next();
  } catch (error) {
    res.status(401).json({ error: 'Invalid or expired token' });
  }
}

6.6 Step 5 - 编写单元测试(Solo Agent 辅助)

/solo 为 boardService 编写 Jest 单元测试:
1. mock db 和 redis 模块
2. 覆盖 createBoard 和 getBoardWithTasks 方法
3. 包含正常流程和异常场景(Board not found)
4. 使用 describe/it 格式,测试命名规范
5. 覆盖率目标:80%+

生成的测试文件 tests/boardService.test.ts:

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { BoardService } from '../src/services/boardService';

// Mock 依赖
vi.mock('../src/config/database', () => ({
  db: {
    query: vi.fn(),
  },
}));

vi.mock('../src/config/redis', () => ({
  redis: {
    get: vi.fn(),
    setex: vi.fn(),
  },
}));

describe('BoardService', () => {
  let boardService: BoardService;

  beforeEach(() => {
    boardService = new BoardService();
    vi.clearAllMocks();
  });

  describe('createBoard', () => {
    it('should create a board and return it', async () => {
      const mockBoard = {
        id: 'mock-uuid',
        projectId: 'project-uuid',
        name: 'Sprint Board',
        description: 'Q1 sprint tasks',
        position: 0,
        created_at: new Date(),
        updated_at: new Date(),
      };

      const { db } = await import('../src/config/database');
      vi.mocked(db.query).mockResolvedValue({ rows: [mockBoard] } as any);

      const result = await boardService.createBoard({
        projectId: 'project-uuid',
        name: 'Sprint Board',
        description: 'Q1 sprint tasks',
        position: 0,
      });

      expect(result.name).toBe('Sprint Board');
      expect(db.query).toHaveBeenCalledTimes(1);
    });
  });

  describe('getBoardWithTasks', () => {
    it('should return cached data if available', async () => {
      const cachedData = {
        board: { id: 'board-1', name: 'Test Board' },
        tasks: [],
      };

      const { redis } = await import('../src/config/redis');
      vi.mocked(redis.get).mockResolvedValue(JSON.stringify(cachedData));

      const result = await boardService.getBoardWithTasks('board-1');
      expect(result).toEqual(cachedData);
    });

    it('should query database if cache miss', async () => {
      const { redis } = await import('../src/config/redis');
      const { db } = await import('../src/config/database');

      vi.mocked(redis.get).mockResolvedValue(null);
      vi.mocked(db.query)
        .mockResolvedValueOnce({
          rows: [{ id: 'board-1', name: 'Test Board', project_id: 'p1', position: 0, created_at: new Date(), updated_at: new Date() }],
        })
        .mockResolvedValueOnce({ rows: [] });

      const result = await boardService.getBoardWithTasks('board-1');

      expect(result.board.name).toBe('Test Board');
      expect(redis.setex).toHaveBeenCalled(); // 写入缓存
    });

    it('should throw error if board not found', async () => {
      const { redis } = await import('../src/config/redis');
      const { db } = await import('../src/config/database');

      vi.mocked(redis.get).mockResolvedValue(null);
      vi.mocked(db.query).mockResolvedValue({ rows: [] });

      await expect(
        boardService.getBoardWithTasks('non-existent-id')
      ).rejects.toThrow('Board not found');
    });
  });
});

6.7 Step 6 - 数据库迁移

Solo Agent 生成的迁移文件 src/migrations/20260117_create_tables.sql:

-- 看板表
CREATE TABLE IF NOT EXISTS boards (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    project_id UUID NOT NULL REFERENCES projects(id) ON DELETE CASCADE,
    name VARCHAR(100) NOT NULL,
    description VARCHAR(500),
    position INTEGER NOT NULL DEFAULT 0,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);

CREATE INDEX idx_boards_project ON boards(project_id);

-- 任务表(支持 JSONB 自定义字段)
CREATE TABLE IF NOT EXISTS tasks (
    id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
    board_id UUID NOT NULL REFERENCES boards(id) ON DELETE CASCADE,
    title VARCHAR(200) NOT NULL,
    description VARCHAR(5000),
    status VARCHAR(20) NOT NULL DEFAULT 'TODO',
    priority VARCHAR(20) NOT NULL DEFAULT 'MEDIUM',
    assignee_id UUID REFERENCES users(id),
    due_date TIMESTAMPTZ,
    custom_fields JSONB NOT NULL DEFAULT '{}',
    position INTEGER NOT NULL DEFAULT 0,
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    CONSTRAINT valid_status CHECK (status IN ('TODO', 'IN_PROGRESS', 'REVIEW', 'DONE')),
    CONSTRAINT valid_priority CHECK (priority IN ('LOW', 'MEDIUM', 'HIGH', 'CRITICAL'))
);

CREATE INDEX idx_tasks_board ON tasks(board_id);
CREATE INDEX idx_tasks_assignee ON tasks(assignee_id);
CREATE INDEX idx_tasks_status ON tasks(status);

-- 看板成员关系表
CREATE TABLE IF NOT EXISTS board_members (
    board_id UUID NOT NULL REFERENCES boards(id) ON DELETE CASCADE,
    user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
    role VARCHAR(20) NOT NULL DEFAULT 'MEMBER',
    created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
    PRIMARY KEY (board_id, user_id)
);

-- 更新时间戳触发器
CREATE OR REPLACE FUNCTION update_updated_at()
RETURNS TRIGGER AS $$
BEGIN
    NEW.updated_at = NOW();
    RETURN NEW;
END;
$$ LANGUAGE plpgsql;

CREATE TRIGGER boards_updated_at BEFORE UPDATE ON boards
    FOR EACH ROW EXECUTE FUNCTION update_updated_at();

CREATE TRIGGER tasks_updated_at BEFORE UPDATE ON tasks
    FOR EACH ROW EXECUTE FUNCTION update_updated_at();

6.8 Step 7 - 部署配置

# docker-compose.yml
version: '3.8'

services:
  api:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=${DATABASE_URL}
      - REDIS_URL=${REDIS_URL}
      - JWT_SECRET=${JWT_SECRET}
    depends_on:
      - postgres
      - redis
    restart: unless-stopped

  postgres:
    image: postgres:16-alpine
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./src/migrations/20260117_create_tables.sql:/docker-entrypoint-initdb.d/001-schema.sql
    environment:
      POSTGRES_DB: kanban
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    restart: unless-stopped

  redis:
    image: redis:7-alpine
    volumes:
      - redis_data:/data
    command: redis-server --appendonly yes
    restart: unless-stopped

volumes:
  postgres_data:
  redis_data:

七、使用技巧与最佳实践

7.1 提示词工程:让 AI 更懂你的需求

Trae SOLO 对中文提示词的支持较好,但同样遵循"好问题 = 好答案"的原则:

✅ 好的提示词(具体 + 结构化):

实现一个带缓存的限流中间件:
- 使用 Redis 滑动窗口算法
- 支持自定义限流阈值和窗口大小
- 返回 429 状态码并包含 Retry-After 头
- 写好 JSDoc 注释

❌ 差的提示词(模糊):

帮我做个限流功能`

7.2 项目级上下文配置

在项目根目录放置 .trae 配置文件,可以给 AI 提供项目级别的背景知识:

// .trae/config.json
{
  "project": {
    "name": "Kanban API",
    "version": "1.0.0",
    "techStack": ["Node.js", "TypeScript", "Express", "PostgreSQL", "Redis"],
    "codingStandards": {
      "typescript": "strict",
      "commits": "conventional-commits",
      "apiStyle": "RESTful"
    },
    "architecture": "Controller-Service-Repository三层架构"
  },
  "ai": {
    "defaultMode": "code",
    "contextWindow": 128000,
    "language": "zh-CN"
  }
}

7.3 效率提升组合拳

我在实际工作中总结了一套高效工作流:

日常开发流程:

1. 早晨规划(MTC模式)→ 分析昨天未解决的问题
2. 功能开发(Code模式)→ 写代码 + AI 辅助补全
3. 代码审查(MTC模式)→ 让 AI 先走查一遍
4. 复杂任务(Solo模式)→ 拆解后交给 Agent 执行
5. 提交前检查(MTC模式)→ 确认无遗漏

八、总结与展望

8.1 核心结论

经过三个月的深度使用,我的评价是:

Trae SOLO 是一款值得认真对待的 AI 编程工具。 它不是 Copilot 的复制品,也不是 Cursor 的廉替,而是一条独特的产品路径——免费 + Agent 驱动 + 中文友好

对于个人开发者和小型团队来说,Trae SOLO 的性价比是无敌的。尤其是 Solo Agent 模式,让我每天节省了约 1-2 小时的"搬砖"时间。

对于中大型团队,建议评估插件生态和调试能力后再做决策。

8.2 期待改进的方向

  • 🔧 更丰富的插件市场
  • 🔧 调试器的深度优化
  • 🔧 多模型可插拔架构的完善
  • 🔧 团队协作功能的加强
  • 🔧 移动端支持(目前没有)

8.3 写在最后

AI 编程工具的终局,不是"哪个工具最强",而是哪个工具最适合你的工作流。Trae SOLO 2026版给出了它的答案——如果你愿意尝试新工具、愿意适应 Agent 驱动的工作方式,它值得你花一个下午认真体验。

工具在进化,开发者在进化,一切才刚刚开始。


相关资源:

  • Trae 官网:https://trae.ai
  • Trae SOLO 文档:https://docs.trae.ai
  • GitHub(示例项目):文中代码均已脱敏,可作为参考实现

本文首发于 CSDN,转载需注明出处。文中观点仅代表作者本人,与任何组织机构无关。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐