
1. 这个项目到底在解决什么问题1.1 从“守着电脑等编译”说起但凡用 Claude Code 或者 Codex 这类命令行 AI 编程助手干过活的人大概都经历过这种场景你在终端里敲下一段提示词让它帮你重构一个模块、跑一遍测试、生成几张数据图表然后你就只能坐在电脑前干等。它跑得快还好几十秒出结果要是碰上大项目编译加测试跑个三五分钟很正常你就被钉在椅子上了想倒杯水、上个厕所、去阳台透口气都得惦记着屏幕。更别扭的是这类工具的输出往往是纯文本的。它说“我已经生成了图表”你还得自己切到文件管理器里去找那张 PNG它说“模拟器已经启动”你还得把模拟器窗口从一堆窗口里翻出来。整个交互链路是割裂的指挥在终端产物在别处人被困在电脑前。我做的这个 App核心就一件事把“指挥 AI 编程助手”和“查看它产出的可视化结果”这两件事从电脑前解放到手机上。你人可以在客厅、在通勤路上、在咖啡馆掏出手机发一条指令电脑那头的 Claude Code 或 Codex 就开始干活干完把图表、模拟器截图、运行日志直接推到你手机屏幕上。这不是远程桌面那种笨重的方案而是专门为“AI 编程助手工作流”定制的一条轻量通道。1.2 它适合谁不适合谁先说清楚定位免得有人装完发现不是自己想要的。适合的人日常用 Claude Code / Codex 做开发、跑数据脚本、做算法验证的开发者经常需要让 AI 跑长时间任务比如批量生成图表、跑仿真、训练小模型的人手头有一台常开的开发机或者家里有台性能还行的台式机的人。不太适合的人完全不用命令行 AI 助手的人期望的是完整 IDE 体验、要在手机上改代码的人对延迟极度敏感、要求毫秒级响应的人。这个 App 的定位是“指挥 监看”不是“在手机上写代码”。理解了这个边界后面的技术选型和实现思路就顺理成章了。2. 整体架构设计为什么这么搭2.1 三层结构手机端、中转层、执行端整个系统我拆成了三层这个划分不是拍脑袋定的而是被实际需求逼出来的。第一层是手机端 App负责展示会话列表、输入指令、渲染图表和截图。它不直接跟电脑通信因为手机网络环境太复杂直连电脑会碰到一堆问题家里路由器没做端口映射、公司网络限制入站、电脑 IP 动态变化等等。所以手机端只跟中转层打交道。第二层是中转层这是整个架构的关键。它承担三个职责消息队列把手机指令排队发给电脑、状态同步电脑的执行进度回传给手机、文件中转图表和截图通过它转发。中转层可以是一台云服务器也可以是一个内网穿透服务。我实测下来用一台最低配的云主机跑中转层完全够用因为传输的都是文本指令和压缩后的图片带宽压力很小。第三层是执行端也就是你电脑上跑的一个常驻小进程。它监听中转层的指令收到后调用本地的 Claude Code 或 Codex 命令行把输出捕获下来遇到图片文件就读取并压缩上传遇到模拟器就截屏上传。为什么不让手机直连电脑我试过坑太多。手机切到 4G/5G 网络后跟电脑不在同一个局域网直连基本没戏就算在同一 WiFi 下电脑休眠、IP 变动、防火墙拦截都会让连接断掉。中转层虽然多了一跳但换来的是稳定性——只要电脑能上网手机能上网这条链路就通。2.2 为什么选“命令包装”而不是“API 对接”有人可能会问Claude Code 和 Codex 不是有 API 吗为什么不直接调 API非要在电脑上跑命令行这个问题我认真权衡过。直接调 API 看起来更干净但会丢掉一大堆本地能力。Claude Code 和 Codex 的价值恰恰在于它们能操作你本地的文件系统、能跑你本地的编译器和测试、能访问你本地的 GPU 和模拟器。如果改成调 API那 AI 就变成了一个纯文本生成器它没法真正帮你跑代码、生成图表、启动模拟器。而这些“本地副作用”正是我想要在手机上看到的东西。所以我的方案是手机端只负责发指令和收结果真正的执行还是在你电脑上的原生环境里跑。App 做的事情是给这个命令行进程套一层“遥控外壳”把 stdin/stdout 和文件系统变化桥接到手机上。这样既保留了本地执行的全部能力又获得了远程指挥的便利。2.3 通信协议的选择WebSocket 为主HTTP 为辅通信这块我用的是 WebSocket 长连接加 HTTP 短请求的混合模式。WebSocket 负责实时性要求高的部分指令下发、执行日志流式回传、进度百分比更新。这些数据的特点是“持续、小包、要求低延迟”用 WebSocket 最合适。我实测下来一条指令从手机发出到电脑开始执行端到端延迟大概在 200 到 500 毫秒之间取决于中转服务器的地理位置。HTTP 负责大文件传输图表 PNG、模拟器截图、较长的日志文件。这些数据的特点是“一次性、大包、可以容忍几秒延迟”。用 HTTP 的好处是可以利用标准的断点续传和缓存机制图片加载失败还能重试。这里有个细节值得说图片上传前一定要压缩。我一开始偷懒直接传原图一张 4K 截图好几兆手机端加载慢得要命。后来改成上传前统一压到长边 1280 像素、JPEG 质量 80%体积降到一两百 KB加载体验立刻顺畅了。这个压缩在执行端做不占用手机流量。3. 核心功能拆解与实操要点3.1 指令下发怎么把一句话变成电脑上的执行指令下发看起来简单其实里面有不少讲究。手机端输入框里敲的内容不能直接原样丢给命令行得先做一层处理。首先是会话隔离。你可能有多个项目同时在跑每个项目对应一个独立的 Claude Code 会话。App 里用“会话”这个概念来管理每个会话绑定电脑上的一个工作目录。你切到哪个会话指令就发到哪个目录下执行。这个设计避免了指令串台——总不能让重构 A 项目的指令跑到 B 项目目录里去执行。其次是指令模板。常用的操作我做了快捷模板比如“跑一遍测试”“生成数据图表”“启动模拟器并截图”。这些模板本质上就是预置的提示词点一下直接发送省得每次手打。模板内容可以在设置里改我自己的习惯是把项目里最常用的几条固定下来。第三是执行确认。有些指令是有破坏性的比如让 AI 删文件、改配置。App 里对这类指令做了二次确认弹个框让你确认一下再发。这个功能救过我好几次有一次手滑差点让 AI 把整个 build 目录清了。实操上指令下发的完整链路是这样的手机端把指令文本加上会话 ID、时间戳通过 WebSocket 发给中转层中转层根据会话 ID 找到对应的执行端连接转发过去执行端收到后把指令写入对应工作目录下的 Claude Code 进程的 stdin同时在本地记录一条执行日志。注意执行端要处理好“指令排队”。如果上一条指令还在跑你又发了一条不能直接覆盖得排队。我的做法是维护一个先进先出的队列当前指令执行完再取下一个。界面上会显示队列长度让你心里有数。3.2 图表回传让 AI 产出的图直接出现在手机上这是整个项目里我觉得最实用的功能。以前让 Claude Code 生成一张图表它跑完 Python 脚本图存在本地某个目录我还得自己去翻。现在执行端会自动监控指定的输出目录一旦发现有新的图片文件生成立刻读取、压缩、上传。监控目录这块我用的是文件系统事件监听不是轮询。轮询虽然实现简单但要么频率高了费 CPU要么频率低了有延迟。文件系统事件监听能在文件写入完成的瞬间触发响应快而且几乎不占资源。不过要注意有些程序写文件是“先写临时文件再重命名”监听的时候要处理这种情况不然会读到不完整的文件。我的做法是监听“重命名”和“关闭写入”这两个事件而不是“创建”事件。图片上传后手机端按时间倒序排列展示。每张图下面标注生成时间、对应的指令、文件大小。点开可以看大图支持双指缩放。对于数据图表这种需要看细节的缩放功能很重要。这里有个经验图片的命名和归档要规范。我让执行端在上传时自动按“日期/会话名/时间戳.png”的规则重命名这样手机端展示的时候天然就是有序的找起来也方便。如果直接用原始文件名一堆output.png、figure1.png混在一起根本分不清哪张是哪次跑的。3.3 模拟器画面截屏 推流两种模式模拟器画面的回传比分发图表复杂一些因为它是动态的。我做了两种模式适应不同场景。截屏模式适合“我就想看一眼当前状态”的场景。执行端调用系统的截屏命令把模拟器窗口截下来压缩上传。这个模式延迟低、流量小但只能看到某一瞬间的画面。推流模式适合“我要持续观察模拟器运行”的场景。执行端以每秒 2 到 5 帧的频率连续截屏并上传手机端按顺序播放形成类似视频的效果。帧率可以调网络好的时候调到 5 帧看起来比较流畅网络差的时候降到 2 帧至少能看个大概。推流模式有个坑连续截屏很吃 CPU。我一开始用系统截屏命令每秒截 5 次电脑风扇直接起飞。后来改成用模拟器自带的截图接口性能好很多。如果你的模拟器没有提供接口那就只能降低帧率或者只在需要的时候开推流平时用截屏模式。提示推流模式下手机端要做帧缓冲。因为网络抖动帧到达的时间不均匀直接播放会卡顿。我的做法是缓冲 3 到 5 帧再开始播放这样即使某一帧晚到了播放也能保持流畅。3.4 执行日志的流式回传日志这块我纠结过要不要做因为 Claude Code 的输出有时候很长全传过来手机上也看不过来。但后来发现日志对于排查问题太重要了——AI 说“执行失败”你得知道失败在哪一步。所以最后还是做了但做了取舍。日志分两级摘要级和详细级。摘要级只传关键节点比如“开始执行”“编译完成”“测试通过”“生成图表 3 张”“执行结束”。详细级传完整的 stdout 和 stderr。默认显示摘要级你想看细节的时候点一下展开再拉取详细日志。这样设计的好处是日常使用的时候手机端很清爽不会被刷屏出问题的时候又能拿到完整信息。详细日志在执行端会保留最近若干次超过的自动清理避免占满磁盘。日志回传用 WebSocket 流式发送每条日志带一个序号手机端按序号拼接。如果中间有丢包手机端能发现序号不连续主动请求补发。这个机制保证了日志的完整性不会出现“中间少了一段”的情况。4. 实操过程从零把这条链路跑通4.1 执行端的部署与配置执行端是整个系统的“手脚”部署在你电脑上。我用的是常驻进程的方式开机自启后台运行。部署步骤大致是这样先把执行端程序放到一个固定目录然后配置一个配置文件里面填中转服务器的地址、认证令牌、工作目录列表。工作目录列表就是你想让 App 能操作的那些项目目录每个目录配一个显示名称。配置好之后启动进程它会主动连接中转服务器建立 WebSocket 长连接。这里有个关键点认证令牌一定要设。中转服务器如果暴露在公网上没有认证的话任何人都能连上来发指令那你的电脑就成别人的了。令牌用一长串随机字符配置在执行端和手机端两边对上才放行。我还会定期轮换令牌虽然麻烦点但安全第一。执行端启动后会在日志里打印连接状态。看到“已连接中转服务器”就说明通了。如果一直连不上先检查网络再检查令牌最后检查中转服务器是否正常运行。4.2 中转层的搭建中转层我用的是一台最低配的云主机1 核 1G 内存跑一个轻量的 WebSocket 服务加一个静态文件服务。这个配置应付个人使用绰绰有余因为同时只有一个执行端和一个手机端连接并发压力很小。中转层的核心逻辑是“按会话 ID 路由”。每个执行端连接上来的时候会注册自己支持的会话列表手机端连接上来的时候会订阅某个会话。中转层维护一张路由表把手机端的指令转发到对应的执行端把执行端的结果转发回对应的手机端。文件传输走 HTTP中转层提供一个上传接口和一个下载接口。执行端上传图片后拿到一个 URL把这个 URL 通过 WebSocket 发给手机端手机端再用这个 URL 去下载图片。这样图片不占用 WebSocket 通道不会阻塞指令和日志的传输。注意中转层的磁盘空间要留意。图片文件会越积越多得定期清理。我的做法是设置一个保留期限比如 7 天超过的自动删除。反正图片在执行端本地还有备份中转层只是临时中转。4.3 手机端的界面与交互手机端我做得比较克制没有堆太多功能核心就是三个页面会话列表、指令输入、结果展示。会话列表页显示所有配置的会话每个会话显示名称、当前状态空闲/执行中、最近一次执行的时间。点进去就是指令输入页上面是历史指令记录下面是输入框和快捷模板按钮。执行结果页分两个标签图表和日志。图表标签展示图片日志标签展示执行日志。交互上我特别在意一点状态要实时。执行中的时候会话列表页那个会话要显示一个转圈的进度指示执行完了要变成“完成”并显示耗时。这些状态通过 WebSocket 实时推送不需要手动刷新。我试过手动刷新的版本用起来很别扭总担心自己看到的是不是最新状态。4.4 一次完整的执行流程实录拿一个真实场景走一遍我在手机上想让电脑跑一个数据可视化脚本生成三张图表。第一步打开 App进入“数据分析”会话点“生成图表”快捷模板。指令内容是预置好的提示词大意是“运行 visualize.py生成三张图表到 output 目录”。第二步指令通过 WebSocket 发到中转层中转层转发到执行端。执行端把指令写入 Claude Code 进程同时回传一条“开始执行”的日志。第三步Claude Code 开始跑脚本。执行端监控 output 目录发现第一张图生成立刻读取、压缩、上传。手机端收到图片 URL下载并展示。接着第二张、第三张陆续到达。第四步脚本跑完Claude Code 输出“完成”。执行端回传“执行结束”日志和总耗时。手机端把会话状态改回“空闲”。整个过程从点按钮到三张图全部显示大概十几秒。这十几秒里我人可以不在电脑前手机揣兜里图生成完了会有通知提醒。5. 踩过的坑与排查技巧5.1 连接不稳定先查这三处连接问题是反馈最多的。手机端显示“连接中”转半天或者用着用着突然断了。排查顺序我总结成三步。第一步查中转服务器。登录云主机看服务进程还在不在看端口有没有被占用。有时候服务莫名其妙挂了重启一下就好。我后来加了个守护脚本进程挂了自动拉起来。第二步查执行端。看执行端的日志有没有报错。常见的是网络波动导致 WebSocket 断开执行端要能自动重连。我一开始没做重连断了就得手动重启很烦。后来加了指数退避重连断了之后隔 1 秒、2 秒、4 秒、8 秒依次重试基本能自动恢复。第三步查手机网络。手机切到弱网环境WebSocket 容易断。App 里做了断线提示断了会显示“连接已断开正在重连”重连成功自动恢复。用户不用做任何操作。5.2 图片显示不出来多半是这三个原因图片上传了但手机上看不到我遇到过几次原因基本就三种。一是压缩失败。执行端的图片压缩依赖一个图像处理库如果库没装好或者版本不对压缩会报错图片就传不上去。解决办法是检查依赖确保图像库正常。我在执行端启动的时候加了个自检压缩库有问题直接日志报错省得后面抓瞎。二是 URL 拼错。中转层返回的图片 URL 如果拼接有误手机端下载会 404。这个排查简单把 URL 复制到浏览器里访问一下就知道。我后来在中转层加了 URL 校验生成的时候确保格式正确。三是手机端缓存。有时候图片其实下载成功了但手机端缓存了旧的失败状态一直显示占位图。清一下 App 缓存就好。这个体验不好后来我改成下载失败自动重试两次还失败才显示错误。5.3 模拟器截屏黑屏权限和时机问题模拟器截屏截出来是黑的这个坑我踩得比较深。权限问题有些系统对截屏有权限限制执行端进程如果没有相应权限截出来就是黑的。解决办法是把执行端加到截屏权限白名单里或者用模拟器自带的截图接口绕过系统截屏。时机问题模拟器刚启动的时候画面还没渲染出来这时候截屏就是黑的。我的做法是截屏前先检测模拟器窗口是否已经渲染完成没完成就等一会儿再截。检测方法因模拟器而异有的是查窗口句柄有的是查进程状态。多显示器问题如果电脑接了多个显示器截屏的时候要指定截哪个屏不然可能截到别的屏幕上。这个在执行端配置里指定显示器编号就行。5.4 常见问题速查表现象可能原因排查方法解决方式手机端一直显示连接中中转服务挂了登录云主机看进程重启服务加守护脚本指令发出后电脑没反应执行端断连看执行端日志等待自动重连或手动重启图片上传失败压缩库异常看执行端报错检查图像库依赖图片显示 404URL 拼接错误浏览器访问 URL修正中转层 URL 生成逻辑模拟器截屏黑屏权限或时机问题换截屏方式测试加权限或用模拟器接口日志中间缺失WebSocket 丢包看日志序号是否连续手机端请求补发推流卡顿帧率过高或网络差看帧率和网络降帧率或改截屏模式6. 几个提升体验的细节设计6.1 通知机制干完活主动告诉你这个功能看起来小但用起来幸福感提升很大。执行端在任务完成或者失败的时候会通过中转层给手机端推一条通知。手机端收到后弹一个系统通知你锁屏状态下也能看到。通知内容我做了精简只包含会话名、状态、耗时。比如“数据分析完成耗时 12 秒”。点通知直接跳到对应的结果页。失败的通知会带上错误摘要方便你判断要不要立刻处理。这里要注意通知的频率。如果任务很多通知刷屏会很烦。我加了个设置可以按会话开关通知也可以设置“只在失败时通知”。默认是全部通知你可以按自己的习惯调。6.2 历史记录找回上次的结果有时候你想看昨天跑的那张图或者想对比两次执行的结果。App 里做了历史记录按时间倒序保存每次执行的指令、日志摘要、生成的图片。历史记录存在手机本地不占中转层空间。图片是懒加载的你翻到哪张才下载哪张不会一打开就下载几百张图。历史记录可以按会话筛选也可以搜索指令关键词。我自己的用法是每次跑完重要的任务如果结果不错就手动标记一下加个星标。这样以后要找的时候直接看星标记录就行不用在几百条历史里翻。6.3 多电脑支持一台手机管多台机器如果你有多台电脑比如一台台式机跑重任务一台笔记本随身带App 支持配置多个执行端。每个执行端注册到中转层的时候带一个设备名手机端可以按设备筛选会话。这个功能实现上不难就是路由表里多一个设备维度。但用起来很实用。我在台式机上跑训练任务在笔记本上跑日常开发手机上切换一下就能分别指挥不用装两个 App。提示多设备的时候设备名要起得清楚比如“台式机-训练”“笔记本-开发”。不然时间长了你自己都忘了哪台是哪台。7. 后续可以扩展的方向这套东西跑通之后我发现能扩展的地方还挺多。一是支持更多 AI 助手。目前接的是 Claude Code 和 Codex但架构上是通用的——只要一个命令行工具能从 stdin 读指令、往 stdout 写输出就能接进来。后面想试试接其他的命令行 AI 工具把选择权交给用户。二是增加语音指令。手机上打字毕竟不如说话快尤其是长指令。可以加个语音输入转成文字后发送。这个技术上不难主要是要处理好语音识别的准确率尤其是技术术语的识别。三是做执行结果的自动分析。现在图片传回来是给人看的但有些场景下可以让 AI 自己分析结果。比如跑完测试让 AI 读一下测试报告直接告诉你“通过了 95%有 3 个失败用例分别是……”。这样你连图都不用看直接看结论。四是支持定时任务。有些任务你想让它每天固定时间跑比如每天早上跑一遍回归测试。可以在执行端加个定时调度到点自动执行结果推送到手机。这个功能我还在琢磨主要是要处理好任务失败的重试和告警。这套方案我从有想法到跑通大概花了两三个周末中间踩的坑基本都写在上面了。核心思路其实不复杂用中转层解决网络连通性用命令包装保留本地能力用 WebSocket 加 HTTP 的混合模式兼顾实时性和大文件传输。真正花时间的是各种边界情况的处理——断线重连、图片压缩、日志补发、权限问题这些才是决定好不好用的关键。如果你也在用命令行 AI 助手又经常被绑在电脑前可以试试这个思路。不一定非要照搬我的实现理解了这个架构用你熟悉的技术栈搭一套自己的版本可能更顺手。