资讯动态

Paseo:手机上指挥AI写代码的编码代理总调度台设计与实战

发布时间:2026/9/20 6:40:51 来源:尧图企业网站定制
最近一个多月我大部分时间都泡在一个叫 Paseo 的项目里。简单说它是一套给编码代理coding agent用的总调度台把 Aider、OpenHands、Cline 这类 AI 写代码工具统一收编进一个控制面板然后你只需要掏出手机打开浏览器就能指挥它们干活下发需求、指定用哪个 Agent、看进度日志、审代码合并结果全程不用坐在电脑前面。Paseo 这个东西最初就是为了解决我自己天天在终端和多个 Agent 之间来回切换的烦琐问题做着做着发现它其实也在回答一个更大的问题当 AI 写代码的思路从单次对话生成一段代码变成多个 Agent 协作完成一个项目之后到底谁在中间做调度和兜底这篇文章就把这套调度台的设计思路、部署步骤、实操中踩过的坑都摊开讲适合已经在用 AI 编程工具、又开始觉得单打独斗不够用的人。1. 我为什么非要做这个总调度台1.1 编码代理井喷之后管理成了新的瓶颈这两年 AI 写代码的工具多到数不过来常见的有终端里跟你一问一答的 Aider有能自己跑命令的 OpenHands有 IDE 里的 Cline、Continue还有各家云平台内置的编码代理。工具一多问题也跟着来了每个 Agent 都有自己的会话、自己的工作目录、自己的上下文习惯我在服务器上同时跑两三个任务时经常要开好几个终端窗口切来切去一会儿忘了这个 Agent 用的是什么模型一会儿又忘了那个任务跑到哪一步了。更麻烦的是Agent 之间互相不知道对方的存在如果在同一个仓库里作业很容易出现两个人改同一个文件、互相覆盖代码的惨剧。这种局面其实就是典型的工具多但缺调度并发症。单个 Agent 的能力再强它也只负责自己眼前的一个窗口期没有人站在更高一层去统筹哪个任务先做、哪个 Agent 适合做哪类活、哪些任务可以并行、代码改完怎么进版本库。这个时候我就特别需要一块总调度台能把所有编码代理收拢到一个视角里统一派单、统一监控、统一收口。1.2 为什么非要手机上指挥可能有人会问做个 Web 后台在电脑上不行吗干嘛非得在手机上指挥我实话实说这个需求是被一次出差逼出来的。当时我在高铁上笔记本屏幕小、续航紧张远程服务器上刚起了一个代码重构任务跑到一半报错了我得赶紧看日志判断是继续跑还是回滚。我打开手机 SSH 客户端黑底白字地翻了半天日志那一刻我就在想如果有个专门给移动端设计的操作界面把最关键的任务状态、错误摘要、重试/回滚按钮都摆在台面上这事就应该是五分钟内解决的问题。手机上指挥 AI 写代码本质上不是让你用手机写代码而是让你在脱离电脑的环境里依然能掌控编码代理的运转。它需要的是一个很轻的前端入口、一套健壮的后端调度、以及把复杂信息降维成可操作卡片的设计思路。Paseo 最初的定位就是这个移动优先的编码代理控制平面。它不是要替代电脑上的编程工具而是把这些工具的值守层搬到一个随处可及的地方。2. Paseo 的核心架构与调度思路2.1 整体长什么样任务队列、调度器和适配器三层Paseo 的架构并不复杂核心只有三层。最外层是移动端 Web UI采用 PWA 方案这样不用上架应用商店手机浏览器直接加到桌面就能用。中间是控制平面服务负责所有 Agent 的注册、任务的接收与排队、状态机的流转、日志的聚合与推送。最底层是适配器层adapter每个 Agent 对应一个适配器把 Aider、OpenHands、Cline 这些工具的命令行接口统一封装成 Paseo 可以调用的协议。这个分层设计一开始是被我简化过的。最早版本我直接把 Agent 当成一个黑盒用进程方式启动然后靠读 stdout 来判断进度。但后来发现不同 Agent 的输出格式差异极大Aider 喜欢输出浓缩的 diff 摘要OpenHands 会吐出一大段事件日志Cline 又走 JSON 结构化输出。如果没有适配器层把它们的输出全部标准化上层 UI 根本没法统一渲染。所以现在每个适配器要做三件事把 Paseo 的任务标准结构翻译成该 Agent 能理解的指令把 Agent 的实时输出转成统一的进度事件流把 Agent 的退出码和产物路径转成可审计的任务结果。# 一个简化版的适配器接口示意 class AgentAdapter(ABC): async def start(self, task: Task) - str: ... async def events(self, session_id: str) - AsyncIterator[AgentEvent]: ... async def cancel(self, session_id: str) - None: ...为什么要做成标准事件流而不是直接暴露一行行日志因为任务状态对用户更有意义。我关心的是它现在是在读代码、改文件还是在跑测试而不是它又输出了 50 行解释。适配器层把底层的嘈杂信息提炼成thinking、editing、running_tests、finished、failed这类有限状态手机屏幕上只需要渲染状态徽章和关键动作体验就完全不一样了。2.2 任务队列为什么要单独存在不少人在实现类似系统时都会问为什么不直接调 Agent反正我下发一个任务它执行完返回结果就行了。但如果真的这样做调度台就变成了一个遥控器而不是一个管理平台。现实中的编码任务经常是多个且并发的比如我早上会给同一个仓库派两个不同模块的修改任务还可能同时给另一个仓库指派一份 Code Review 任务。如果直接调 Agent 而没有队列层并发一上来资源不受控、日志串位、Agent 之间的冲突也没人管。Paseo 在控制平面里内置了一个基于 Redis Stream 的任务队列。所有任务一进来先落库再进队列调度器会根据每个 Agent 的忙闲状态、仓库锁、优先级做分配。优先级这块我踩过不少坑一开始只按创建时间排序结果一个紧急 bug 修复任务要排在一个两小时的性能优化任务后面气得我直接加了 urgent 优先级的抢占逻辑。现在任务队列支持 low、normal、high、urgent 四级urgent 任务可以插队并暂定当前低优先级任务。这个能力在手机上尤其有价值你收到告警说生产环境有个 API 报错直接在手机上下一个 urgent 任务让 Agent 去排查它会把当前仓库上的其他杂活先挂起腾出资源干活。多 Agent 并发时的文件锁也是调度器必须管的。我按照仓库维度挂读写锁同一时刻每个仓库最多允许一个写型任务在跑只读型任务比如 Code Review、日志分析可以并行。第一次没加锁的时候两个 Agent 同时改我项目里的config.py互相覆盖导致整个配置报废自那以后这个锁成了我心中的铁律。2.3 状态机是所有 UI 渲染的基础调度台能不能让用户一眼看懂全局关键看状态机定义是否清晰。Paseo 里每个任务的生命周期分这么几段queued排队中、assigned已分配给某个 Agent、runningAgent 正在处理、reviewing代码改动已完成等待人工确认、applying改动正在合入分支、succeeded / failed / cancelled终态。手机上展示的就是这条清晰的流水线任何时候打开 Paseo 首页你都能看出哪几个任务在跑、哪几个在等、哪几个出了问题。有人可能觉得 state 多反而复杂但实际操作下来这非常必要。尤其是 reviewing 这个中间态它是人和机器之间的一个缓冲带。Agent 改完代码不会直接推分支而是先停在那个状态等我看一眼 diff我在手机上确认没问题了它才继续合入。这样既保住了速度又保留了人工闸门。最初我图省事把 Agent 改成完事自动 commit 并 push结果有一次它把一个测试文件里的断言删了还自动合进去了CI 直接红教训相当深刻。3. 实操部署把调度台跑起来3.1 服务端搭建一条命令起全部依赖Paseo 部署这块我把它打包成了 Docker Compose 的方式整合了三个服务control-plane调度主服务、worker执行器实际拉起 Agent 进程的地方、redis队列与缓存。如果你只想在自己的服务器上快速跑起来直接 clone 仓库后编辑.env文件里的端口和密钥然后执行docker compose up -d就行。# docker-compose.yml 的核心片段 services: redis: image: redis:7-alpine restart: unless-stopped control-plane: build: ./control-plane ports: - 8080:8080 environment: REDIS_URL: redis://redis:6379 JWT_SECRET: ${PASEO_JWT_SECRET} DATABASE_URL: sqlite:///data/paseo.db volumes: - paseo-data:/app/data worker: build: ./worker environment: REDIS_URL: redis://redis:6379 DOCKER_HOST: unix:///var/run/docker.sock volumes: - /var/run/docker.sock:/var/run/docker.sock - workspace:/workspaceworker 会通过 Docker 拉起真正的 Agent 容器每个任务分配一个独立 workspace 目录这样保证了仓库隔离。这里有三个环境变量必须自己改掉别偷懒PASEO_JWT_SECRET换成随机长字符串DATABASE_URL如果机器上已有 PostgreSQL 可以切换PASEO_PUBLIC_URL要填你实际访问的域名或 IP因为 PWA 的 manifest 和 Service Worker 都要基于这个字段生成。3.2 接入第一个编码代理拿 Aider 当样板接入 Agent 在手册里叫注册适配器实际做起来其实就是往config.yaml里加一段配置。我最常用的样板是 Aider它本身就是一个命令行工具适配器封装得最省事。下面这段配置表示注册一个名为aider-default的 Agent工作目录是/workspace/repos/myproject模型用 Claude 的 Sonnet 系列单任务超时 900 秒。# config.yaml agents: - name: aider-default type: aider model: claude-sonnet-4-20250514 workdir: /workspace/repos/myproject timeout_seconds: 900 allowed_commands: - pytest - python - git auto_commit: false这里我特别强调auto_commit: false。这个开关的意思是 Agent 改完代码后不自动提交而是等用户在界面上点确认并入分支后再由 worker 执行 git commit 和 push。看配置你可能觉得这点小事无关紧要但实际上它是安全感的来源。AI 改代码的自主性已经很高了如果连提交合入也全自动那等于把生产分支的钥匙也交给了一个可能产生幻觉的模型。保留人工确认这一步长期看能替你挡掉非常多的麻烦。OpenHands 的接入稍微复杂一点因为它的启动参数多还需要设置 sandbox 权限。不过配置结构是一致的只是在type: openhands下多了sandbox_type、max_iterations这些专有字段。我的建议是第一批接入先用 Aider它最简单跑通之后再按同一条路径加其他工具。3.3 手机端访问与 PWA 落地细节服务端起来之后电脑上浏览器先访问一遍http://服务器IP:8080确认能正常登录。Paseo 的移动端优先策略体现在 UI 上默认视图就是卡片流大按钮、大字体没有特别复杂的仪表盘。手机浏览器打开同一个地址登录后系统会提示添加到主屏幕选择添加之后桌面就会出现一个 Paseo 图标点击全屏运行基本等于一个独立 App。PWA 最需要注意的坑是 HTTPS。Service Worker 只有在 HTTPS 环境或 localhost 下才能注册普通 http 协议在手机上基本不工作。所以如果你是家庭服务器或临时 VPS建议直接用 Caddy 或 Nginx 配一个反向代理自动申请 Lets Encrypt 证书。Caddy 的配置极其简单paseo.example.com { reverse_proxy localhost:8080 }至于 PWA 的离线能力我没有追求全量离线。移动网络环境里弱网是常态Paseo 的策略是保证断网可看、联网可操作任务列表、Agent 状态等静态数据会缓存到本地但接受任务、确认合并这类写操作必须联网避免因为离线缓存导致状态不一致。实际体验下来这样做足够稳定也不会把 PWA 做得太重。4. 用手机指挥 Agent 的一线实战4.1 下发一个任务从卡片到 Agent 手里这一天我在地铁上看了一眼项目监控发现某个接口的平均响应时间从 200ms 涨到了 800ms。我打开手机上的 Paseo找到项目仓库点右下角的新建任务输入标题排查 /v1/orders 接口响应变慢的原因定位并修复补充一个回归测试然后选择指派给aider-default任务等级选了 high提交。这个操作背后发生的事很有意思。Paseo 收到任务后并没有马上启动 Agent而是先把任务落进队列然后调度器检查myproject这个仓库的写锁是否空闲。确认空闲后任务变成 assigned 状态worker 开始在独立 workspace 里拉起 Aider 容器并把任务标题转换成一句 Aider 能理解的 prompt你被要求调查并修复 /v1/orders 接口响应变慢的问题请先分析代码、运行性能测试、定位瓶颈修改后新增回归测试不要改变数据库结构。这里的细节是任务标题和真实 prompt 之间不是直接照搬而是 Paseo 在模板里加了一些安全护栏。比如不要改变数据库结构这种约束可以在任务下发界面用约束条件字段填写系统会把它拼进给 Agent 的指令里。每次命令的 prompt 我都在 config 里维护了一组默认约束包含禁止提交密钥、禁止修改迁移文件、禁止删除测试等这些是长期实践总结出来的保命条款。4.2 实时监控手机上怎么看出 Agent 在干嘛任务跑起来之后我在手机上看 Paseo 的任务详情页能看到一个和桌面上差不多的实时状态流。当前 Paseo 的详情页从上到下分三块最上面是任务基本信息和状态徽章中间是 Agent 的事件流底部是操作按钮区会根据状态动态变化比如 running 的时候显示暂停/取消reviewing 的时候显示查看 diff / 确认合入 / 驳回。事件流是适配器标准化之后的样子每条事件都带时间戳、事件类型和摘要比如10:23:12 editing file: app/services/order_service.py10:24:30 running command: pytest tests/test_order_api.py -q。它不会显示 Agent 输出的完整原文除非你主动点开某条事件查看详情。这个默认折叠细节的设计特别适合手机屏幕我在地铁上扫一眼就知道它大概在做哪一步不用像看终端日志一样在手机上疯狂滚动。如果任务跑到 30 分钟没有任何新事件Paseo 会推送一条提醒到手机通知栏里写任务 x 可能卡住了已超过 10 分钟无进展。阈值的默认值是 10 分钟但像大项目重构这类任务Agent 可能长时间思考不输出事件我就把这个仓库级阈值调大到了 20 分钟。这个功能不是花架子它真的有用。有一次我半夜被通知吵醒打开一看Agent 由于某个网络请求一直阻塞任务卡死我在手机上直接点了取消重跑反正第二天起来看结果就行。4.3 审代码与动态开启的人工闸门Agent 把代码改完事件流里会出现waiting for human review的字样任务状态同步变成 reviewing。这时候我在地铁上打开详情页会看到一个查看 diff按钮。点击之后手机上会以现代浏览器的 diff 渲染能力展示改动对比支持按文件查看、展开上下文、跳过空行差异。屏幕虽然不大但配合只显示改动行的默认模式审一个小修复足够了。我审这一段的时候核心逻辑是改动是否符合任务描述、测试是否真的运行通过、有没有夹带和任务无关的改动。Paseo 在 diff 视图右侧会加一个与原始代码 diff 签名的校验标签如果 Agent 顺手改了配置类文件标签会高亮提示检测到非任务相关文件变更这个信号非常鸡贼但极其有助于发现问题。确认没问题后我点确认合入worker 那边会在仓库执行git add -A git commit -m ...并 push 到目标分支。整个合入过程又是靠事件流反馈回手机上我不用刷新页面就能看到结果。审不过的情况也常见直接点驳回并附一句话原因比如这个优化会影响缓存一致性请改成延迟写。这句话会被拼接进 Agent 的后续 prompt任务状态从 reviewing 跳回 assignedAgent 会继续修改。经历过一次成功驳回后你可能就明白这个人工闸门不是形式主义它恰恰是 AI 写代码能不能安全落地到实际项目里的关键机制。5. 常见问题与排查实录5.1 任务卡在 queued 不动这个我遇到得最频繁十次里有六次都是仓库锁没有释放。Paseo 的调度器如果检测到某个仓库有写任务还在 running新的任务就得排队。但在早期版本里如果 Agent 进程被 kill -9 强杀锁状态没被清理就会一直锁着。后来的解决方案是给所有任务锁加心跳超时worker 每 30 秒上报一次心跳调度器发现超过 120 秒没有心跳就自动释放锁并把任务标记为 failed。这个机制上线后再也没出现过锁死问题。如果你也遇到 queued 不动先看任务归属的仓库是不是有别的任务还在跑再在锁管理页面里看一眼锁的持有者心跳时间。5.2 Agent 权限太大改坏了文件怎么办AI 写代码思路再成熟模型终归有幻觉的一面。之前有一个任务是让 Agent 做性能优化结果它为了消除 linter 警告顺手把三个 import 语句删了其中一个还是运行时依赖导致整个服务退出。遇到这种事故最有效的止损手段就是容器隔离和文件快照。Paseo 在一开始就在 workspace 层面对原始仓库做了一次只读快照实际上是把 git 仓库完整 clone 到一个私有目录Agent 改的是这个私有目录不是真实仓库。合入之前我可以一键比较Agent 的改动 vs 真实仓库并且可以把任何文件的差异一键回滚。所以我的建议永远是别让 Agent 直接操作真实工作的 repo一定要经过一层工作副本。5.3 手机端收不到推送通知PWA 的推送在 iOS 上一直不算顺滑Android 上也有不同浏览器的差别。Paseo 目前的策略是优先使用 Web Push API在浏览器不支持的场景下降级为应用内通知抽屉展示配合顶部状态栏的轮询角标。如果你发现收不到推送先确认三个点是不是通过 HTTPS 访问、浏览器权限设置里是否允许通知、App 是否处于后台并且没被系统省电策略杀掉。在这些基础都满足的情况下Web Push 的成功率在 Android Chrome 上很高iOS 后面会好一点但短时间不必指望它像原生 App 一样稳定。5.4 不同模型在同一任务上的表现差异还有个很有意思的事同一个任务Aider 某个模型跑出来的方案和 OpenHands 另一个模型完全不一样。现在 Paseo 支持一个实验性的多 Agent 竞答模式就是你下发同一个任务系统会同时派给两个不同配置的 Agent分别在工作副本里干活谁先产出并校验通过谁胜出。这个模式很耗资源但适合那种高风险、方向不明确的重构任务相当于多个思路并行试探。平时不建议开因为资源占用是双份甚至多份的。5.5 资源占用与扩容如果你的调度台同时跑好几个任务真正的瓶颈不是调度器本身而是 Agent 容器占用的 CPU 和内存。每个 Agent 容器跑一个模型推理客户端内存占用轻轻松松上 1-2GB。我现在的经验是4 核 8GB 的服务器同时跑 2 个 Agent 任务并尽量打散仓库是舒适区。如果需要在同一台机器上跑更多记得在 config 里给每个 Agent 配置max_parallelism和memory_limit别让它们把服务器拖垮。写在最后的体会距离 Paseo 第一个可用版本出来差不多六周了我自己已经习惯了每天早上掏出手机看一眼任务面板在地铁上审几段 diff下午到工位再处理真正需要大键盘大屏幕的编码活。它不一定适合所有人但如果你认同AI 写代码的思路正在从单点对话走向多智能体协作这个方向那么一个高效的调度台迟早会成为刚需。手机上指挥 AI 写代码这件事技术上并不神秘核心还是把状态、约束和反馈设计得足够清晰。目前 Paseo 依然是我个人维护的实验项目代码写得不完美有很多地方是能跑就行但它已经在真刀真枪地处理我日常工作里最烦琐的调度环节。如果你也刚好被多个编码代理同时折腾到抓狂不妨自己照着这个思路搭一个或者直接盯住 Paseo 的进展后续我会把 Webhook 接入和更多 Agent 类型的适配器补上到时候手机上指挥 AI 写代码这件事能力边界又会再大一圈。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价