项目项目TaskForce:我做的一个多Agent协作平台
JaronTaskForce:我做的一个多 Agent 协作平台
项目地址:https://github.com/codejaron/TaskForce
为什么做这个项目
AI 交互范式的演进
回顾 AI 应用的发展,可以看到一条清晰的演进路径:
最早是网页聊天——ChatGPT 横空出世。但它只能动嘴,无法感知和改变外部世界。
然后有了 Function Calling——2023 年 OpenAI 让模型学会了调用工具,AI 开始能「动手」了。查天气、操作数据库、发邮件。
接着是 MCP 协议——2024 年底 Anthropic 推出 Model Context Protocol,让工具集成有了开放标准。不同平台可以共享同一套工具生态,AI 开始能跨服务协作。
再到 Agent 的爆发——Manus 让大家看到了 AI 自主规划执行任务的可能性,不再是一问一答,而是「给一个目标,AI 自己想办法完成」。紧接着 Microsoft 推出 AutoGen 多 Agent 框架,Google 发布 A2A(Agent-to-Agent)协议,行业开始认真思考 Agent 之间如何协作。
到了现在,Claude Code 成了标杆产品——它展示了一个 AI Agent 可以多么好用。有意思的是,Claude Code 选择了极简的单线程架构:一个主循环、一条消息历史、累积式上下文。简单、可控、易调试。
我在使用中遇到了一些问题
平时用网页 AI 或者类似工具时,经常碰到几个让人抓狂的情况:
上下文污染:聊着聊着,前面说的重点被中间的对话冲淡了,模型开始钻牛角尖
历史包袱:对话越长,无关信息越多,模型反而越容易被带偏
很多时候,单开一个新页面,把重点重新发给它,效果反而更好。
这让我开始想:累积式的上下文真的是最优解吗?
另一种思路:分工协作
Anthropic 在《How we built our multi-agent research system》里提到:
“子 Agent 通过各自独立的上下文窗口实现压缩,同时探索问题的不同方面,再将最重要的信息浓缩给主 Agent。每个子 Agent 也提供了关注点分离——不同的工具、提示词、探索轨迹——减少了路径依赖。”
这启发了我:如果每个步骤都有一个「干净」的上下文,只接收必要的信息,会不会更好?
想象一下人类团队是怎么协作的:
领导拆解任务,分配给不同的人
每个人专注于自己的部分,不需要知道所有细节
通过文档、会议纪要传递关键信息,而不是让每个人都参与所有对话
TaskForce 就是这个思路的实践
Planner 分析需求、生成结构化的执行计划
Worker 各自独立执行,每次调用都是干净的上下文
Artifact 系统在步骤间传递关键结果,而不是完整对话历史
每个 Worker 只知道:当前任务是什么 + 需要的上下文数据
这样做的好处:
上下文干净:每个 Worker 不会被无关历史污染
Token 可控:不会像累积式那样越来越长
二、核心架构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| ┌─────────────────────────────────────────────────────────────────────────────┐ │ 用户界面 (React + SSE) │ └────────────────────────────────┬────────────────────────────────────────────┘ │ ┌────────────────────┼────────────────────┐ │ SSE 连接 │ HTTP 请求 │ SSE 事件推送 │ ↓ │ │ ┌───────────────────────────────┐ │ │ │ GroupChatController │ │ │ │ POST /api/groupchat/submit │ │ │ └───────────────┬───────────────┘ │ │ │ │ │ │ 立即返回 202 │ │ │ (Fire-and-forget) │ │ ↓ │ │ ┌───────────────────────────────┐ │ │ │ EventBus │←───┘ │ │ (事件总线) │ │ └───────────────┬───────────────┘ │ │ ↓ ↓ ┌─────────────────────────────────────────────────────────────────────────────┐ │ │ │ WorkflowEngine (工作流引擎) │ │ │ │ ┌────────────────────────────────────────────────────────────────────────┐ │ │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │ │ │ │ │ StateManager│ ←──→ │StepExecutor │ ←──→ │ SessionContext │ │ │ │ │ │ 状态管理器 │ │ 步骤执行器 │ │ (会话上下文/ThreadLocal) │ │ │ │ │ └─────────────┘ └─────────────┘ └─────────────────────────┘ │ │ │ └────────────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────┬───────────────────────────────────────────┘ │ ┌─────────────────────────┼─────────────────────────┐ │ │ │ ↓ ↓ ↓ ┌───────────────┐ ┌───────────────┐ ┌───────────────┐ │ PlannerAgent │ │ Worker(s) │ │ReplannerAgent │ │ 任务规划器 │ │ 任务执行器 │ │ 重规划器 │ └───────┬───────┘ └───────┬───────┘ └───────┬───────┘ │ │ │ │ ↓ │ │ ┌───────────────┐ │ │ │ MCP 工具层 │ │ │ └───────────────┘ │ │ │ │ └────────────────────────┼────────────────────────┘ │ ↓ ┌─────────────────────────────────────────────────────────────────────────────┐ │ 数据持久层 (MySQL) │ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │ │ │ session │ │execution_plan│ │ message │ │ session_artifact │ │ │ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────────────┘ │ └─────────────────────────────────────────────────────────────────────────────┘
|
简单说就是四层:
- 前端用 React,通过 SSE 实时接收进度
- WorkflowEngine 是核心调度器,控制整个流程
- 三种 Agent 各司其职:Planner 规划、Worker 执行、Replanner 兜底
- 数据都存 MySQL
三、三个核心 Agent
PlannerAgent:规划器
接收用户目标,拆解成具体步骤,分配给 Worker。
它有三种输出:
- 生成计划(目标清晰时)
- 追问用户(目标模糊时)
- 放弃规划(实在搞不定时)
有个小设计:LLM 输出 JSON 经常格式错误,我加了个 Self-Correction 机制,解析失败就把错误信息发回去让它自己改,最多试 3 次。
Worker:执行器
干活的。每个 Worker 只管一个步骤,可以调用 MCP 工具。
执行时可能遇到两种特殊情况:
BLOCKED:技术问题,比如服务挂了
NEED_USER_INPUT:需要用户补充信息
ReplannerAgent:重规划器
Worker 搞砸了就轮到它出场,分析原因,调整后续计划。
四、Artifact 上下文系统
多步骤执行有个头疼的问题:步骤之间怎么传数据?
全塞进 Prompt 里?上下文会爆炸。
我的方案是 Artifact 系统:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| Worker A 执行步骤 1 │ │ LLM 输出: │ "搜索结果如下: │ <artifact key="search_results"> │ 1. 结果A - xxx │ 2. 结果B - yyy │ </artifact>" │ ↓ ┌─────────────────┐ │ ArtifactParser │ 正则提取 <artifact> 标签 └────────┬────────┘ │ │ key: "search_results" │ value: "1. 结果A - xxx\n2. 结果B - yyy" │ ↓ ┌─────────────────┐ │session_artifact │ 存入数据库 │ 表 │ └────────┬────────┘ │ ↓ Worker B 执行步骤 2 │ │ Prompt 里只放预览(前200字符) │ 需要完整数据时调用 query_artifact("search_results") │ ↓ 继续处理...
|
Worker 用 XML 标签输出结构化数据,存到数据库。后续 Worker 的 Prompt 里只放预览,要完整内容就调工具查。
这样上下文长度可控,数据也不会丢。
五、状态流转
执行计划有几个状态:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| ┌───────────┐ │ CREATED │ │ (创建) │ └─────┬─────┘ │ │ PlanGeneratedEvent ↓ ┌───────────┐ ┌────────→│ EXECUTING │←────────┐ │ │ (执行中) │ │ │ └─────┬─────┘ │ │ │ │ │ ┌──────────┼──────────┐ │ │ ↓ ↓ ↓ │ ReplanEvent StepCompleted UserInputReceived │ (继续下一步) │ │ │ │ │ ↓ │ │ ┌───────────────────┐ │ │ │ 还有下一步? │ │ │ └─────────┬─────────┘ │ │ YES │ NO │ │ │ │ │ │ │ ↓ │ │ │ ┌───────────┐ │ │ │ COMPLETED │ │ │ │ (完成) │ │ │ └───────────┘ │ │ │ ↓ │ ┌───────────────────┐ │ │ BLOCKED 或 │ │ │ NEED_USER_INPUT │ │ └─────────┬─────────┘ │ │ │ ├─── BLOCKED ──→ ReplannerAgent ───┐ │ │ │ │ └─── NEED_USER_INPUT │ │ │ │ │ ↓ │ │ ┌───────────────────┐ │ │ │ WAITING_FOR_INPUT │ │ │ │ (等待用户) │ │ │ └─────────┬─────────┘ │ │ │ │ │ │ 用户提交回复 │ │ ↓ │ └────────────────────────┴────────────────────────┘
|
BLOCKED 会触发 Replanner,NEED_USER_INPUT 会暂停等用户回复。
六、完整执行流程
一个请求从头到尾是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| 用户: "帮我搜索 AI 最新进展并写一篇总结" │ │ POST /api/groupchat/submit ↓ ┌─────────────────┐ │ 保存用户消息 │ ──→ 【MessageCreatedEvent】 ──→ 前端显示 └────────┬────────┘ │ ↓ ┌─────────────────┐ │ PlannerAgent │ ──→ 【PlanningStartedEvent】 ──→ 前端显示 "规划中..." └────────┬────────┘ │ │ 生成计划: │ Step 1: 搜索AI新闻 → Worker-1 │ Step 2: 整理结果 → Worker-2 │ Step 3: 写总结 → Worker-3 │ ↓ 【PlanGeneratedEvent】 ──→ 前端渲染计划卡片 │ ↓ ┌─────────────────┐ │ WorkflowEngine │ 开始执行循环 └────────┬────────┘ │ │ ══════ Step 1 ══════ ↓ 【StepStartedEvent】 ──→ 高亮步骤1 │ │ Worker-1 调用搜索工具 │ 输出: <artifact key="search_results">...</artifact> │ ↓ 【StepCompletedEvent】 ──→ 标记完成,Artifact 存库 │ │ ══════ Step 2 ══════ ↓ 【StepStartedEvent】 ──→ 高亮步骤2 │ │ Worker-2 读取 search_results(通过工具查询) │ 输出: <artifact key="organized_data">...</artifact> │ ↓ 【StepCompletedEvent】 │ │ ══════ Step 3 ══════ ↓ 【StepStartedEvent】 ──→ 高亮步骤3 │ │ Worker-3 读取 organized_data │ 输出最终文章 │ ↓ 【StepCompletedEvent】 【SessionCompleteEvent】 ──→ 前端显示完成
|
七、目前的问题和不足
说实话这个项目还比较粗糙,有几个明显的问题:
1. Planner 的规划质量不稳定
LLM 生成的计划有时候很合理,有时候很离谱。比如一个简单任务它能给你拆成 10 步,或者分配 Worker 的时候完全不看能力匹配。
目前只能靠 Prompt 工程硬凑,效果一般。
2. 步骤之间只能串行
现在是一个步骤完了才能执行下一个。但有些步骤其实可以并行,比如「搜索 A」和「搜索 B」完全可以同时跑。
这个后面想加,但涉及到依赖分析和并发控制,有点麻烦。
3. 前端比较简陋
功能是有了,但 UI/UX 还很粗糙,很多交互细节没打磨。
4. 没有代码执行反馈
现在 Worker 产出代码后,没法自动运行、拿到执行结果或报错信息再迭代。就是「写完就完了」,不知道写得对不对。
理想情况应该是:Worker 写完代码 → 自动运行 → 拿到报错 → 继续修 → 直到跑通。这个闭环目前没做。
5. 上下文压缩还不够好
虽然 Artifact 系统解决了步骤间传数据的问题(只放预览,按需查完整内容),但整个会话的上下文管理还是比较粗放。
没有像 Claude Code 那样的 Auto Compact 功能——当上下文快满的时候自动总结、开新会话继续。
八、后续想做的
如果有时间的话:
最后
这是一个探索性项目,项目还在早期阶段,很多地方都不完善。
说实话,这个项目主要是为了学习。最近 Agent 很火,想亲手做一下,看看「角色分离 + 上下文隔离」这条路走起来是什么感觉。
整个项目边做边学,很多设计是摸索出来的,肯定有考虑不周的地方,而且前端是纯 AI 生成的。
如果你也对 Agent 架构感兴趣,欢迎一起交流探讨;如果发现 bug 或者有更好的想法,更欢迎提 issue 或 PR。
项目地址:https://github.com/codejaron/TaskForce