1. 从“workbuddy 替代”这个念头说起:我到底想解决什么问题
最早动这个念头,是因为我在几个不同项目里反复遇到同一个场景:手头有一堆零散任务,有的要查资料、有的要跑脚本、有的要整理文件、有的要对接内部接口,而 workbuddy 这类工具的思路很吸引人——把日常操作收进一个统一的工作台,用 Agent 的方式去调度。但实际用下来,我总觉得有几个地方不顺手:一是很多能力被封装得太深,想改一个流程要翻半天配置;二是数据流向不透明,任务跑完了我都不确定中间到底调了什么;三是扩展性受限,想接一个自己写的本地工具,往往要等官方支持。
所以“开源版 workbuddy 替代”这个标题,核心不是要做一个一模一样的克隆,而是想验证一件事:能不能用开源组件 + MCP 协议 + Agent 调度,搭出一个自己完全可控、能随时改、能接任意本地能力的工作台。关键词里的“魔力工作台”“Agent”“MCP”“开源”其实已经把方向说清楚了——它不是一个单纯的脚本集合,而是一个以 Agent 为执行核心、以 MCP 为工具接入标准、以开源为底座的个人工作台。
这篇文章适合谁看?如果你正在做 AI Agent 相关开发,或者想给自己搭一个能落地的自动化工作台,又或者你只是好奇 MCP 到底怎么把“模型”和“工具”连起来,那这篇内容应该能给你一些可直接参考的东西。我会尽量把设计取舍、踩坑过程、关键配置都摊开讲,而不是只给一个“跑通了”的结论。
先交代一下整体架构,不然后面细节容易散。我的实现大致分四层:最底层是工具层,用 MCP Server 把本地脚本、文件操作、HTTP 接口包装成标准工具;中间是调度层,也就是 Agent 核心,负责理解任务、选择工具、处理多步依赖;上面是工作台层,提供任务面板、执行日志、结果预览;最外面是接入层,支持命令行、本地 Web 界面,以及后续想加的编辑器插件。这个分层不是一开始就定好的,是踩了几次坑之后才收敛成这样的,后面会细说。
2. 为什么我最终选了 MCP 作为工具接入标准,而不是自己写一套插件协议
2.1 自己定协议看起来自由,实际维护成本高得离谱
一开始我其实想自己定义一套工具描述格式,理由很直接:MCP 当时看起来还在演进,我怕被绑死。于是我先写了一个简单的 JSON Schema,规定每个工具要有 name、description、parameters,然后 Agent 根据这个去调用。跑通第一个 demo 确实很快,但问题在第三天就暴露了:我接入了文件读写、命令执行、HTTP 请求三个工具,每个工具的返回格式都不一样,有的返回字符串,有的返回对象,有的还会抛异常。Agent 在解析结果时经常误判,我得为每个工具单独写适配代码。
更麻烦的是,当我后来想接一个现成的开源工具时,发现它只提供 MCP 接口。那一刻我意识到,工具接入这件事,自己定协议等于把生态挡在门外。MCP 的价值不在于它多完美,而在于它正在成为事实标准,越来越多的工具和平台开始支持它。你选它,等于免费获得了一堆现成能力。
2.2 MCP 到底解决了什么:把“模型能调什么”变成可发现、可描述、可复用
MCP 的全称是 Model Context Protocol,你可以把它理解成一套“模型和外部工具之间的通用插头”。它规定了工具怎么注册、参数怎么描述、调用怎么发起、结果怎么返回。对 Agent 来说,最大的好处是工具是动态发现的:Agent 启动时连接 MCP Server,拉取工具列表,每个工具自带描述和参数 schema,Agent 不需要提前硬编码“有哪些工具可用”。
这带来一个很实际的变化:我新增一个工具,只需要写一个 MCP Server 并注册到工作台,Agent 下次启动就能看到它,不需要改 Agent 核心代码。这个解耦非常关键,因为 Agent 的调度逻辑和工具的具体实现本来就不应该耦合在一起。
2.3 我实际接入的几类 MCP 工具,以及选型时的取舍
我目前工作台里常驻的 MCP 工具大概分四类,每类选型时都做过对比:
| 工具类型 | 代表能力 | 选型考虑 | 实际使用频率 |
|---|---|---|---|
| 文件系统类 | 读写、搜索、目录遍历 | 优先选支持沙箱路径限制的实现,避免 Agent 误操作 | 极高 |
| 命令执行类 | 运行本地脚本、构建命令 | 必须限制工作目录和超时,否则容易卡死 | 高 |
| HTTP 请求类 | 调内部接口、抓取公开数据 | 需要支持自定义 header 和超时 | 中 |
| 文档处理类 | 解析 PDF、Markdown 转换 | 选纯本地实现,避免数据外传 | 中 |
这里有个经验:不要一上来就接十几个工具。工具越多,Agent 选择时的干扰越大,反而容易调错。我一开始接了十几个,结果 Agent 经常在“用文件搜索还是用命令 grep”之间反复横跳。后来砍到核心四类,调度准确率明显上升。
3. Agent 调度层的设计:怎么让模型不瞎调工具
3.1 任务拆解和工具选择是两件事,混在一起做容易崩
我最初把“理解用户意图”和“选择工具”放在一个 prompt 里让模型一次完成,结果很不稳定。比如用户说“帮我把上周的日志整理一下”,模型有时候直接去调文件写入,有时候又去调命令执行,因为它没有先明确“整理”到底包含哪些步骤。
后来我改成两阶段:第一阶段只做任务拆解,把用户请求拆成有序的子任务列表,每个子任务描述清楚输入和期望输出;第二阶段针对每个子任务选择工具。这样模型每次只需要关注一个决策,准确率高很多。拆解阶段的 prompt 里我会明确要求输出结构化 JSON,包含 steps 数组,每个 step 有 description、expected_input、expected_output。
3.2 工具调用的参数校验,不能全信模型
模型生成的工具参数经常有细微问题,比如路径少了斜杠、时间格式不对、必填字段漏了。如果直接透传给 MCP Server,轻则报错,重则产生副作用。所以我在调度层加了一层参数校验和补全:根据 MCP 返回的 schema 检查必填项,对常见格式做规范化,比如把“上周”转换成具体日期范围。
这一步看起来不起眼,但实际减少了很多无效调用。我统计过,加校验之前大概有 20% 的调用因为参数问题失败,加完之后降到 5% 以下。
3.3 多步任务的上下文传递:别让每一步都从零开始
多步任务里,后一步往往依赖前一步的输出。比如先搜索文件,再读取内容,再总结。如果每一步都独立调用模型,前一步的结果很容易丢失。我的做法是在调度层维护一个执行上下文,每个子任务执行完后,把结果按结构化格式存进去,下一步的 prompt 里带上相关上下文片段。
这里要注意上下文长度控制。我一开始把完整结果都塞进去,很快就把 token 撑爆了。后来改成只保留关键字段和摘要,比如文件搜索只保留路径列表,读取内容只保留前若干字符加摘要。这样既保证信息够用,又不会让 prompt 无限膨胀。
4. 工作台界面和交互:为什么我没做成“聊天框”
4.1 纯聊天式交互在复杂任务里会让人失去控制感
workbuddy 这类工具很多是聊天式入口,输入一句话,等结果。简单任务没问题,但一旦任务变复杂,用户就不知道它跑到哪一步了,也没法中途干预。我自己用的时候就经常想:“它到底在干嘛?能不能先看看它准备调什么工具再执行?”
所以我的工作台没有做成纯聊天框,而是任务面板 + 执行日志 + 结果预览三块。任务面板展示拆解后的子任务和状态,执行日志实时输出每一步的工具调用和返回,结果预览展示最终产物。这样用户随时能看到进度,也能在发现方向不对时中止。
4.2 执行日志的设计:既要详细,又不能刷屏
日志太简略没用,太详细又刷屏。我的做法是分两级:默认级别只显示工具名、参数摘要、执行状态和耗时;展开后显示完整参数和返回内容。这样日常使用不干扰,排查问题时又能拿到细节。
另外我给每个子任务加了唯一 ID,日志里带上 ID,方便和任务面板对应。这个细节很小,但实际用起来很提升体验,尤其是任务步骤多的时候。
4.3 结果预览的格式处理:不同工具返回不一样,统一展示是个坑
文件类工具返回路径和内容,命令类返回 stdout 和 stderr,HTTP 类返回状态码和 body。如果直接原样展示,界面会很乱。我加了一层结果渲染适配:根据工具类型选择展示方式,文本直接显示,JSON 格式化,文件路径可点击打开,命令输出区分正常和错误。这层适配不复杂,但让工作台从“能用”变成“好用”。
5. 实际跑起来之后踩到的几个坑,以及我怎么处理的
5.1 MCP Server 启动失败但 Agent 不报错,任务静默卡住
这是最早遇到也最隐蔽的问题。某个 MCP Server 因为端口占用没启动成功,但 Agent 连接时没有明显报错,只是工具列表为空。结果 Agent 以为没有可用工具,任务一直停在“等待工具”状态。我排查了半天才发现是 Server 没起来。
后来我在工作台加了启动健康检查:每个 MCP Server 注册后主动 ping 一次,拉取工具列表,失败就明确提示并标记该 Server 不可用。同时 Agent 在工具列表为空时直接报错,而不是静默等待。
5.2 命令执行类工具的超时和输出截断,差点把内存吃满
有一次 Agent 调了一个会持续输出日志的命令,没有超时限制,结果输出不断累积,内存直接涨上去。我赶紧加了超时和输出上限:命令默认 30 秒超时,输出超过一定大小就截断并标记。这个教训是,任何执行类工具都必须有边界,不能假设模型会调一个“安全”的命令。
5.3 模型偶尔会“幻觉”出不存在的工具名
即使工具列表是动态拉取的,模型有时还是会生成一个不存在的工具名,尤其是在任务描述模糊的时候。我的处理是调用前校验工具名,不在列表里就直接返回错误并让模型重新选择。同时我在 prompt 里强调“只能从给定工具列表中选择”,双管齐下后这种情况基本消失。
5.4 多步任务中途失败,已执行步骤的副作用怎么处理
比如前两步已经写了文件,第三步失败了。如果直接重试整个任务,前两步会重复执行。我的做法是记录每个子任务的执行状态和副作用,失败后支持从失败步骤继续,而不是从头来。对于有副作用的工具,比如文件写入,我会在日志里明确标记,方便用户判断是否需要手动回滚。
6. 开源这件事:我为什么选择开放出来,以及开放后学到了什么
6.1 开源不是把代码扔出去,而是把“可复现的搭建路径”一起给出去
我一开始只放了核心代码,结果收到不少反馈说“跑不起来”。后来我补了详细的 README,包括环境依赖、MCP Server 配置示例、最小可运行 demo。开源项目的价值不在于代码多优雅,而在于别人能不能照着跑起来。这一点我体会很深。
6.2 社区反馈帮我发现了自己没注意到的边界问题
有人反馈在某个系统上路径分隔符处理有问题,有人反馈某个 MCP 工具返回格式和预期不一致。这些问题我自己环境里没遇到,但确实存在。开源之后,相当于多了一群人在不同环境里帮你测试,这对项目健壮性帮助很大。
6.3 关于“替代 workbuddy”这个说法,我现在的理解
严格说,我的工作台不是 workbuddy 的完全替代,它更像是一个可自己掌控的轻量方案。workbuddy 在开箱即用和功能完整度上有优势,而我的方案胜在透明、可改、能接任意本地能力。两者定位不同,适合的场景也不同。如果你需要快速上手,可能现成工具更合适;如果你需要深度定制和数据可控,那自己搭一个开源工作台会更舒服。
7. 如果你也想搭一个,我会建议从这几个点开始
7.1 先跑通一个最小闭环,别一上来就追求功能全
最小闭环就是:一个 MCP Server + 一个 Agent 调度 + 一个简单界面。先让“用户输入 -> 拆解 -> 调工具 -> 返回结果”这条链路跑通,再逐步加工具、加界面、加日志。我见过不少人一开始就设计很复杂的架构,结果卡在某个细节上迟迟跑不起来。
7.2 工具接入优先选现成 MCP Server,别重复造轮子
文件、命令、HTTP 这些基础能力,社区已经有比较成熟的 MCP Server 实现。先用现成的,把精力放在调度层和工作台交互上。等确实有特殊需求,再自己写。
7.3 日志和错误处理要一开始就做,别等出问题再补
这是我最深的体会。Agent 系统的不确定性比传统程序高很多,没有清晰的日志和错误处理,排查问题会非常痛苦。宁可前期多花点时间把日志和校验做好,也不要等线上出问题再回头补。
7.4 控制工具数量,保持 Agent 决策空间干净
工具不是越多越好。每多一个工具,模型的选择空间就大一分,调错的概率也高一分。我的建议是按场景分组,不同场景加载不同工具集,而不是一次性全量加载。
8. 后续我打算继续打磨的几个方向
目前工作台已经能稳定跑日常任务,但还有几个地方我想继续优化。一是任务模板,把常见流程固化成模板,减少每次拆解的开销;二是工具权限控制,不同任务用不同权限级别,避免高权限工具被误用;三是结果持久化,把执行记录存下来,方便回溯和复用。
另外我还在考虑接入更多类型的 MCP 工具,比如文档解析、数据可视化,但前提是不破坏现有的调度稳定性。工具扩展这件事,我现在的原则是先验证调度层能不能扛住,再考虑加新能力,而不是反过来。
如果你也在做类似的东西,或者对 MCP、Agent 调度有自己的想法,欢迎交流。这个领域变化很快,很多经验都是踩坑踩出来的,多交流能少走不少弯路。