AI Agent 多任务协作实战:从单体到分布式工作流
要点
探讨 AI Agent 多任务协作系统设计:主从 vs 对等协作模式、任务编排引擎(超时、重试、状态机)、博客发布工作流实战(写作→构建→部署→社交媒体)、性能优化(并发控制、资源隔离、Token 成本优化)。20+ TypeScript 代码示例,可直接复用。
引言:为什么需要 Agent 协作
当你第一次让 AI Agent 帮你写博客时,你可能会发现它能完成80%的工作:生成内容、修正错误、优化排版。但剩下的20%——部署到服务器、发布到社交媒体、监控访问统计——这些跨系统的复杂任务,单个 Agent 很难优雅地完成。
这不是 Agent 能力的问题,而是任务复杂度的问题。一个博客发布流程涉及:
- 内容写作(需要大模型深度思考)
- 代码构建(需要执行 shell 命令)
- 服务器部署(需要 SSH 连接和文件同步)
- 社交媒体发布(需要调用多个 API)
- 质量校验(需要检查多个维度)
如果让单个 Agent 处理所有环节,你会遇到:
- 上下文爆炸:一个对话轮次需要记住太多状态,token 消耗飙升
- 错误传播:某个环节失败会导致整个流程中断,难以定位问题
- 难以并行:所有任务串行执行,效率低下
- 权限混乱:不同任务需要不同的系统权限,单体设计容易出现安全问题
多任务协作正是解决这些问题的关键:将复杂流程拆解为独立的子任务,每个任务由专门的 Agent 负责,通过消息传递协调执行。
本文将通过实际案例,展示如何设计和实现一个可靠的 AI Agent 协作系统。
架构设计:协作模式选择
主从模式 vs 对等模式
在设计 Agent 协作系统时,首先要选择合适的架构模式:
主从模式(Master-Worker):
- 一个主 Agent 负责任务分解和调度
- 多个从 Agent 各自负责专项任务
- 主 Agent 收集结果并决定下一步
- 适合有明确流程的场景(如博客发布)
// 主从模式示例
class MasterAgent {
async executeWorkflow(task: Task) {
const steps = this.decompose(task);
for (const step of steps) {
const worker = this.selectWorker(step.type);
const result = await worker.execute(step);
if (result.status === 'failed') {
return this.handleFailure(step, result);
}
}
return { status: 'success' };
}
}
对等模式(Peer-to-Peer):
- 所有 Agent 地位平等
- 通过消息总线广播任务
- Agent 自主认领感兴趣的任务
- 适合动态、探索性的场景(如协作研究)
// 对等模式示例
class PeerAgent {
constructor(private messageBus: MessageBus) {
messageBus.subscribe('task.new', this.onNewTask.bind(this));
}
async onNewTask(task: Task) {
if (this.canHandle(task)) {
const result = await this.execute(task);
this.messageBus.publish('task.completed', result);
}
}
}
我们的选择:博客发布是典型的流水线场景,采用主从模式更合适。主 Agent 作为"指挥官",协调写作、构建、部署等专项 Agent。
同步调用 vs 异步消息
任务之间的通信方式也很关键:
同步调用:主 Agent 直接调用子 Agent,等待返回结果
- 优点:实现简单,状态追踪容易
- 缺点:阻塞等待,无法并行
- 适合:前后依赖强的任务(如构建依赖写作完成)
异步消息:通过消息队列解耦,子 Agent 完成后通知主 Agent
- 优点:可以并行执行,资源利用率高
- 缺点:需要维护消息队列,实现复杂
- 适合:可以并行的任务(如同时发布到多个社交平台)
混合方案:对于博客发布,我们采用"同步主线 + 异步分支":
// 混合调用示例
async function publishBlog(article: Article) {
// 同步主线:写作 → 构建 → 部署
await writingAgent.write(article);
await buildAgent.build();
await deployAgent.deploy();
// 异步分支:并行发布到社交媒体
Promise.all([
twitterAgent.publish(article),
juejinAgent.publish(article),
wechatAgent.publish(article)
]); // 不等待结果,主流程继续
}
状态共享策略
多个 Agent 如何共享任务状态?三种方案:
1. 中心化存储(推荐)
class WorkflowState {
private store = new Map<string, any>();
async set(key: string, value: any) {
this.store.set(key, value);
await this.persist(); // 持久化到数据库或文件
}
async get(key: string) {
return this.store.get(key);
}
}
// 使用示例
const state = new WorkflowState();
await state.set('article.content', content);
const content = await state.get('article.content');
2. 消息传递
// 每次任务完成时,将结果通过消息传递给下一个 Agent
const buildResult = await buildAgent.execute({
content: writeResult.content,
metadata: writeResult.metadata
});
3. 共享文件系统
// 通过约定的文件路径共享状态
await fs.writeFile('workspace/article.md', content);
const content = await fs.readFile('workspace/article.md', 'utf8');
选择建议:对于小规模协作(<5个Agent),中心化存储最简单可靠。对于大规模分布式场景,考虑 Redis 或数据库。
核心实现:任务编排引擎
任务定义与序列化
首先定义清晰的任务接口:
interface Task {
id: string; // 唯一标识
type: string; // 任务类型(如 'write', 'build', 'deploy')
input: Record<string, any>; // 输入参数
config?: {
timeout?: number; // 超时时间(毫秒)
retries?: number; // 重试次数
priority?: number; // 优先级
};
}
interface TaskResult {
status: 'success' | 'failed' | 'timeout';
output?: any;
error?: Error;
duration: number; // 执行时长
}
任务必须可以序列化为 JSON,这样才能通过消息队列或 RPC 传递:
// 正确:可序列化
const task: Task = {
id: 'write-001',
type: 'write',
input: {
topic: 'AI Agent 协作',
wordCount: 5000
}
};
// 错误:包含函数,无法序列化
const badTask = {
id: 'write-001',
callback: () => console.log('done') // ❌
};
执行上下文传递
每个 Agent 需要访问共享的执行上下文:
class ExecutionContext {
constructor(
public workflowId: string,
public state: WorkflowState,
public logger: Logger
) {}
// 日志记录
async log(message: string, level: 'info' | 'error' = 'info') {
await this.logger.write(`[${this.workflowId}] ${message}`, level);
}
// 获取共享状态
async getState(key: string) {
return this.state.get(key);
}
// 设置共享状态
async setState(key: string, value: any) {
await this.state.set(key, value);
}
}
Agent 实现时接收上下文:
interface Agent {
execute(task: Task, context: ExecutionContext): Promise<TaskResult>;
}
class WritingAgent implements Agent {
async execute(task: Task, context: ExecutionContext): Promise<TaskResult> {
await context.log(`开始写作:${task.input.topic}`);
const content = await this.write(task.input);
// 保存到共享状态
await context.setState('article.content', content);
await context.log('写作完成');
return {
status: 'success',
output: { content },
duration: 120000 // 2分钟
};
}
private async write(input: any): Promise<string> {
// 实际写作逻辑
return '文章内容...';
}
}
超时与重试机制
任务可能因为网络波动、API 限流等原因失败,需要自动重试:
class TaskExecutor {
async executeWithRetry(
agent: Agent,
task: Task,
context: ExecutionContext
): Promise<TaskResult> {
const maxRetries = task.config?.retries ?? 3;
const timeout = task.config?.timeout ?? 300000; // 默认5分钟
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
await context.log(`第 ${attempt} 次尝试执行任务 ${task.id}`);
// 使用 Promise.race 实现超时控制
const result = await Promise.race([
agent.execute(task, context),
this.createTimeout(timeout)
]);
if (result.status === 'success') {
return result;
}
if (attempt < maxRetries) {
const delay = Math.min(1000 * Math.pow(2, attempt), 10000); // 指数退避
await context.log(`任务失败,${delay}ms 后重试`);
await this.sleep(delay);
}
} catch (error) {
await context.log(`任务执行异常:${error.message}`, 'error');
if (attempt === maxRetries) {
return {
status: 'failed',
error: error as Error,
duration: 0
};
}
}
}
return {
status: 'failed',
error: new Error('达到最大重试次数'),
duration: 0
};
}
private createTimeout(ms: number): Promise<TaskResult> {
return new Promise((_, reject) => {
setTimeout(() => reject(new Error('任务超时')), ms);
});
}
private sleep(ms: number): Promise<void> {
return new Promise(resolve => setTimeout(resolve, ms));
}
}
完整的任务调度器实现
整合上述功能,构建完整的调度器:
class WorkflowScheduler {
private agents = new Map<string, Agent>();
private executor = new TaskExecutor();
// 注册 Agent
registerAgent(type: string, agent: Agent) {
this.agents.set(type, agent);
}
// 执行工作流
async execute(tasks: Task[]): Promise<void> {
const workflowId = crypto.randomUUID();
const state = new WorkflowState();
const logger = new FileLogger(`logs/${workflowId}.log`);
const context = new ExecutionContext(workflowId, state, logger);
await context.log(`开始执行工作流,共 ${tasks.length} 个任务`);
for (const task of tasks) {
const agent = this.agents.get(task.type);
if (!agent) {
throw new Error(`未找到类型为 ${task.type} 的 Agent`);
}
const result = await this.executor.executeWithRetry(agent, task, context);
if (result.status === 'failed') {
await context.log(`工作流中断:任务 ${task.id} 失败`, 'error');
throw new Error(`任务 ${task.id} 执行失败`);
}
await context.log(`任务 ${task.id} 完成,耗时 ${result.duration}ms`);
}
await context.log('工作流执行成功');
}
}
错误处理与恢复
失败检测策略
任务失败有多种形式,需要区分处理:
enum FailureType {
TIMEOUT = 'timeout', // 超时
NETWORK = 'network', // 网络错误
VALIDATION = 'validation', // 校验失败
BUSINESS = 'business', // 业务逻辑错误
UNKNOWN = 'unknown' // 未知错误
}
function classifyError(error: Error): FailureType {
if (error.message.includes('timeout')) {
return FailureType.TIMEOUT;
}
if (error.message.includes('ECONNREFUSED') || error.message.includes('fetch failed')) {
return FailureType.NETWORK;
}
if (error.message.includes('校验') || error.message.includes('validation')) {
return FailureType.VALIDATION;
}
return FailureType.UNKNOWN;
}
不同类型的错误采取不同的恢复策略:
class RecoveryStrategy {
shouldRetry(failureType: FailureType): boolean {
switch (failureType) {
case FailureType.TIMEOUT:
case FailureType.NETWORK:
return true; // 网络问题可以重试
case FailureType.VALIDATION:
case FailureType.BUSINESS:
return false; // 逻辑错误重试无意义
default:
return false;
}
}
getRetryDelay(failureType: FailureType, attempt: number): number {
if (failureType === FailureType.NETWORK) {
return Math.min(2000 * Math.pow(2, attempt), 30000); // 指数退避
}
return 5000; // 其他情况固定延迟
}
}
回滚与补偿机制
某些任务失败后需要撤销之前的操作:
interface CompensatableTask extends Task {
compensate?: (context: ExecutionContext) => Promise<void>;
}
class TransactionalExecutor {
async executeWithCompensation(
tasks: CompensatableTask[],
context: ExecutionContext
): Promise<void> {
const executedTasks: CompensatableTask[] = [];
try {
for (const task of tasks) {
await this.executeTask(task, context);
executedTasks.push(task);
}
} catch (error) {
await context.log('任务失败,开始回滚', 'error');
// 逆序补偿已执行的任务
for (const task of executedTasks.reverse()) {
if (task.compensate) {
await task.compensate(context);
await context.log(`已回滚任务 ${task.id}`);
}
}
throw error;
}
}
}
实际应用示例:
const deployTask: CompensatableTask = {
id: 'deploy-001',
type: 'deploy',
input: { version: 'v1.2.0' },
// 部署失败后的补偿操作:回滚到上一个版本
compensate: async (context) => {
const prevVersion = await context.getState('deploy.prevVersion');
await deployAgent.rollback(prevVersion);
}
};
状态机设计
使用状态机管理任务状态转换:
enum TaskState {
PENDING = 'pending',
RUNNING = 'running',
SUCCESS = 'success',
FAILED = 'failed',
RETRYING = 'retrying',
COMPENSATING = 'compensating'
}
class StateMachine {
private state: TaskState = TaskState.PENDING;
transition(to: TaskState) {
const allowed = this.isValidTransition(this.state, to);
if (!allowed) {
throw new Error(`非法状态转换:${this.state} → ${to}`);
}
this.state = to;
}
private isValidTransition(from: TaskState, to: TaskState): boolean {
const transitions = {
[TaskState.PENDING]: [TaskState.RUNNING],
[TaskState.RUNNING]: [TaskState.SUCCESS, TaskState.FAILED, TaskState.RETRYING],
[TaskState.RETRYING]: [TaskState.RUNNING, TaskState.FAILED],
[TaskState.FAILED]: [TaskState.COMPENSATING],
[TaskState.COMPENSATING]: [TaskState.FAILED]
};
return transitions[from]?.includes(to) ?? false;
}
}
实战案例:博客发布工作流
任务拆解
将博客发布流程拆解为6个独立任务:
const blogWorkflow: Task[] = [
{
id: 'write',
type: 'write',
input: { topic: 'AI Agent 协作', wordCount: 5000 },
config: { timeout: 600000, retries: 2 } // 10分钟超时
},
{
id: 'validate',
type: 'validate',
input: { checks: ['technical', 'format', 'privacy', 'ai-detection'] },
config: { timeout: 120000, retries: 1 }
},
{
id: 'build',
type: 'build',
input: { framework: 'astro' },
config: { timeout: 180000, retries: 3 }
},
{
id: 'deploy',
type: 'deploy',
input: { target: 'production', server: 'your-server-ip' },
config: { timeout: 300000, retries: 2 }
},
{
id: 'publish-twitter',
type: 'social',
input: { platform: 'twitter', generateSummary: true },
config: { timeout: 60000, retries: 3 }
},
{
id: 'publish-juejin',
type: 'social',
input: { platform: 'juejin', generateMD: true },
config: { timeout: 60000, retries: 3 }
}
];
Agent 实现
写作 Agent:
class WritingAgent implements Agent {
async execute(task: Task, context: ExecutionContext): Promise<TaskResult> {
const { topic, wordCount } = task.input;
await context.log(`开始写作:${topic}(目标 ${wordCount} 字)`);
// 调用 LLM API 生成内容
const content = await this.callLLM({
prompt: `写一篇关于 ${topic} 的技术文章,字数约 ${wordCount} 字`,
model: 'claude-sonnet-4-5'
});
// 保存到共享状态
await context.setState('article.content', content);
await context.setState('article.topic', topic);
await context.log(`写作完成,实际字数 ${content.length}`);
return {
status: 'success',
output: { content, wordCount: content.length },
duration: Date.now() - startTime
};
}
private async callLLM(params: any): Promise<string> {
// 实际调用 Claude API
const response = await fetch('https://api.anthropic.com/v1/messages', {
method: 'POST',
headers: {
'x-api-key': process.env.ANTHROPIC_API_KEY,
'content-type': 'application/json'
},
body: JSON.stringify({
model: params.model,
max_tokens: 8000,
messages: [{ role: 'user', content: params.prompt }]
})
});
const data = await response.json();
return data.content[0].text;
}
}
构建 Agent:
class BuildAgent implements Agent {
async execute(task: Task, context: ExecutionContext): Promise<TaskResult> {
const { framework } = task.input;
await context.log(`开始构建:${framework}`);
// 执行构建命令
const { stdout, stderr } = await this.execCommand('npm run build');
if (stderr && !stderr.includes('warning')) {
throw new Error(`构建失败:${stderr}`);
}
await context.log('构建完成');
return {
status: 'success',
output: { stdout },
duration: Date.now() - startTime
};
}
private async execCommand(cmd: string): Promise<{ stdout: string; stderr: string }> {
const { exec } = require('child_process');
const { promisify } = require('util');
const execAsync = promisify(exec);
return execAsync(cmd, { cwd: '/Users/geraldchen/ai/blog' });
}
}
部署 Agent:
class DeployAgent implements Agent {
async execute(task: Task, context: ExecutionContext): Promise<TaskResult> {
const { target, server } = task.input;
await context.log(`开始部署到 ${target}(${server})`);
// 保存当前版本(用于回滚)
const currentVersion = await this.getCurrentVersion();
await context.setState('deploy.prevVersion', currentVersion);
// rsync 部署
await this.rsyncDeploy(server);
// 验证部署
const healthy = await this.healthCheck(server);
if (!healthy) {
throw new Error('部署后健康检查失败');
}
await context.log('部署成功');
return {
status: 'success',
output: { version: 'latest', server },
duration: Date.now() - startTime
};
}
private async rsyncDeploy(server: string): Promise<void> {
const cmd = `rsync -avz --delete dist/ root@${server}:/usr/share/nginx/html/`;
await execCommand(cmd);
}
private async healthCheck(server: string): Promise<boolean> {
try {
const response = await fetch(`https://yourblog.com/`);
return response.status === 200;
} catch {
return false;
}
}
}
完整执行流程
async function main() {
// 初始化调度器
const scheduler = new WorkflowScheduler();
// 注册所有 Agent
scheduler.registerAgent('write', new WritingAgent());
scheduler.registerAgent('validate', new ValidationAgent());
scheduler.registerAgent('build', new BuildAgent());
scheduler.registerAgent('deploy', new DeployAgent());
scheduler.registerAgent('social', new SocialAgent());
// 执行工作流
try {
await scheduler.execute(blogWorkflow);
console.log('✅ 博客发布成功');
} catch (error) {
console.error('❌ 博客发布失败:', error.message);
process.exit(1);
}
}
main();
配置文件设计
将工作流配置外部化,便于调整:
{
"workflow": {
"name": "blog-publish",
"version": "1.0.0",
"tasks": [
{
"id": "write",
"type": "write",
"input": {
"topic": "{{env.TOPIC}}",
"wordCount": 5000
},
"config": {
"timeout": 600000,
"retries": 2
}
},
{
"id": "deploy",
"type": "deploy",
"input": {
"target": "production",
"server": "{{env.SERVER}}"
},
"config": {
"timeout": 300000,
"retries": 2
},
"dependencies": ["write", "validate", "build"]
}
]
}
}
性能优化与最佳实践
并发控制
对于可以并行的任务(如多平台发布),使用并发执行:
class ParallelExecutor {
async executeParallel(
tasks: Task[],
context: ExecutionContext,
maxConcurrency = 3
): Promise<TaskResult[]> {
const results: TaskResult[] = [];
// 分批执行
for (let i = 0; i < tasks.length; i += maxConcurrency) {
const batch = tasks.slice(i, i + maxConcurrency);
const batchResults = await Promise.all(
batch.map(task => this.executeTask(task, context))
);
results.push(...batchResults);
}
return results;
}
}
应用示例:
// 社交媒体发布任务可以并行
const socialTasks = [
{ id: 'twitter', type: 'social', input: { platform: 'twitter' } },
{ id: 'juejin', type: 'social', input: { platform: 'juejin' } },
{ id: 'wechat', type: 'social', input: { platform: 'wechat' } }
];
// 并行执行,最多同时3个
await parallelExecutor.executeParallel(socialTasks, context, 3);
资源隔离
为每个 Agent 分配独立的资源配额:
class ResourceLimiter {
private quotas = new Map<string, ResourceQuota>();
async acquire(agentId: string): Promise<void> {
const quota = this.quotas.get(agentId) ?? { maxMemory: 512, maxCpu: 50 };
// 检查资源使用情况
const usage = await this.getResourceUsage();
if (usage.memory > quota.maxMemory || usage.cpu > quota.maxCpu) {
throw new Error(`Agent ${agentId} 资源配额不足`);
}
}
private async getResourceUsage(): Promise<{ memory: number; cpu: number }> {
const used = process.memoryUsage();
return {
memory: Math.floor(used.heapUsed / 1024 / 1024), // MB
cpu: 0 // 简化示例
};
}
}
Token 成本优化
对于调用 LLM 的 Agent,需要优化 token 消耗:
class TokenOptimizer {
// 1. 压缩上下文
compressContext(context: string): string {
// 移除冗余空白
return context.replace(/\s+/g, ' ').trim();
}
// 2. 缓存常见结果
private cache = new Map<string, string>();
async getCachedResponse(prompt: string): Promise<string | null> {
const hash = this.hashPrompt(prompt);
return this.cache.get(hash) ?? null;
}
// 3. 使用更小的模型
selectModel(taskComplexity: 'low' | 'medium' | 'high'): string {
const models = {
low: 'claude-haiku-3-5', // 便宜
medium: 'claude-sonnet-4-5', // 平衡
high: 'claude-opus-4-5' // 强大
};
return models[taskComplexity];
}
private hashPrompt(prompt: string): string {
const crypto = require('crypto');
return crypto.createHash('md5').update(prompt).digest('hex');
}
}
监控指标设计
关键指标:
interface WorkflowMetrics {
totalDuration: number; // 总耗时
taskCount: number; // 任务数
successRate: number; // 成功率
avgTaskDuration: number; // 平均任务时长
tokenUsage: number; // Token 消耗
retryCount: number; // 重试次数
errors: Array<{ // 错误列表
taskId: string;
type: FailureType;
message: string;
}>;
}
class MetricsCollector {
private metrics: WorkflowMetrics = {
totalDuration: 0,
taskCount: 0,
successRate: 0,
avgTaskDuration: 0,
tokenUsage: 0,
retryCount: 0,
errors: []
};
recordTaskResult(task: Task, result: TaskResult) {
this.metrics.taskCount++;
this.metrics.totalDuration += result.duration;
if (result.status === 'success') {
this.metrics.successRate =
(this.metrics.successRate * (this.metrics.taskCount - 1) + 100) / this.metrics.taskCount;
} else {
this.metrics.errors.push({
taskId: task.id,
type: classifyError(result.error!),
message: result.error!.message
});
}
}
getReport(): WorkflowMetrics {
this.metrics.avgTaskDuration = this.metrics.totalDuration / this.metrics.taskCount;
return this.metrics;
}
}
总结与展望
适用场景
AI Agent 多任务协作适合以下场景:
✅ 流水线式任务:明确的前后依赖关系(如 CI/CD) ✅ 跨系统操作:需要调用多个外部服务(如发布到多平台) ✅ 长时间运行:单个 Agent 上下文无法承载的复杂流程 ✅ 需要隔离:不同任务需要不同权限或资源限制
❌ 不适合:简单的单步任务、需要实时交互的场景
常见陷阱
- 过度拆分:不要为了协作而协作,每增加一个 Agent 都会带来通信开销
- 状态泄漏:确保每个 Agent 只访问必要的状态,避免意外修改
- 错误传播:一个 Agent 的失败可能影响整个流程,需要完善的错误隔离
- 调试困难:多个 Agent 并行运行时,日志交错难以追踪,建议使用 traceId
未来发展方向
- 自适应调度:根据历史数据动态调整任务优先级和资源分配
- 可视化编排:类似 n8n 的拖拽式工作流设计器
- Agent 市场:标准化的 Agent 接口,支持第三方贡献
- 联邦学习:多个 Agent 协同训练,共享知识而不共享数据
多任务协作是 AI Agent 从"工具"走向"智能体"的关键一步。随着技术成熟,我们会看到更多复杂的自动化场景,Agent 之间不仅能协作,还能自主学习和进化。
原文链接:chenguangliang.com/posts/blog0…
相关阅读: