Trae SOLO实战:用字节AI编程工具打造端到端开发流水线(2026版)
前言:字节跳动也来做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。这意味着你可以:
- 打开一个包含 10+ 文件的项目
- 询问"这个模块的接口与哪个服务对接"
- 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 会:
- 创建迁移文件(包含事务支持)
- 写 Redis 缓存逻辑(带分布式锁防并发)
- 实现路由处理器(带参数校验和限流)
- 挂载路由
- 编写 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 目前的主要短板
说真话:
- 插件生态薄弱:相比 VS Code,Trae SOLO 的插件市场还很小,很多常用插件找不到替代品。
- 调试体验一般:断点调试、变量监视等功能不如 IntelliJ IDEA/VS Code 完善。
- 大项目性能:打开超过 50 个文件的巨型项目时,内存占用较高(实测约 1.5GB)。
- 模型能力上限:字节自研模型在某些复杂推理任务上不如 Claude-3.5-Sonnet。
- 文档稀缺:目前社区资源少,遇到问题主要靠官方文档和自我摸索。
六、真实项目实战:从需求到部署
这一节用一个完整案例,串联前面介绍的所有功能。目标是:用 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,转载需注明出处。文中观点仅代表作者本人,与任何组织机构无关。
更多推荐



所有评论(0)