从“手机上写代码”这个念头冒出来那天起我几乎被所有同行当成异类。一块五六英寸的屏幕一个虚拟键盘连个像样的Ctrl键都没有怎么跟桌面IDE比但真正让我坚持做下来的是一次至今难忘的线上事故人在出差路上客户环境报了一个致命bug我身边只有手机笔记本开热点死活连不上内网最后只能干着急。那之后我开始认真琢磨一件事——如果云端基础设施足够强、AI辅助足够聪明手机是不是也能成为一个“随时能写代码”的终端WebCode这个AI编程平台架构就是从这句“如果”开始的。这篇文章我不打算讲概念而是把这套平台从想法、MVP到完整架构的演进过程全部摊开聊透里面的架构取舍、AI落地方案和移动端体验设计。1. 为什么说“手机上写代码”不是伪需求1.1 我最初是怎么被逼出这个想法的那次出差事故之后我做了个小调研问了周围十几个开发朋友同一个问题“你有没有过不得不用手机改代码的时刻”结果比我预想的多得多。有人在地铁上刷到CI挂了着急看日志有人在休假途中被拉去改一个配置项还有人纯粹是带娃时灵光一现想赶紧把思路记下来。大家一致的反应是桌上那套重型工作流在移动场景里完全不成立但“想改点什么”的冲动又真实存在。之后我又观察到一个细节这些场景里用户需要的不是完整IDE而是一块能立刻进入状态的“数字便签”。它要能看代码、能改代码、能运行代码并且最好有一个足够聪明的AI在背后兜底。传统思路是把桌面IDE原样搬到手机上这注定失败——屏幕、输入、多任务能力全都拧着来。真正可行的方向是把计算重心放到云端把智能能力交给AI让手机只做“交互终端”。所以我在规划WebCode的雏形时给自己定了一条原则与其做一个“缩水版IDE”不如做一个“优先为移动场景设计的云端开发环境”。这条原则直接决定了后面整套架构的走向——前端可以很薄但云端执行和AI编排必须厚。1.2 手机写代码的真实场景不是替代桌面是补充桌面我把真实需求拆成了三类典型场景。第一类是“通勤碎片时间”。程序员在通勤路上往往不想纯刷手机心里还会惦记某个模块的逻辑。这时候如果能打开手机看一眼相关代码、改个小参数、或者让AI把一段纠结的逻辑梳理成注释时间利用效率会提升很多。这类场景对延迟不敏感但要求启动快、续航省。第二类是“紧急修复窗口”。服务器告警、客户反馈、测试环境挂掉手上没有电脑时需要在最短时间内定位问题并提交一个修复。这类场景非常苛刻它要求平台具备完整的代码修改、提交、运行验证链路最好还能通过AI快速定位可疑代码。我经历过几次之后才明白这种场景拼的不是编辑器手感而是“全链路响应速度”。第三类是“随时到来的灵感”。相信不少人有这种体验——刚躺下准备睡觉脑子里突然冒出一个算法设计思路或者发现某段逻辑有个更好的写法。手机就在枕边但桌面IDE不在。这类用户需要的是极低的记录成本最好打开App就能用一个临时文件把思路写下来AI顺手补齐实现细节。这三类场景有个共同点它们的核心价值在于“把等待时间变成可用的开发时间”。手机不是要取代桌面而是在桌面的能力辐射不到的时间碎片里接住这些需求。想明白这层逻辑你会发现这个场景的潜力比第一印象大得多。1.3 这个场景对架构提出的隐含要求一旦把“移动优先”作为设计前提传统单体应用就会处处露馅。手机端有四个先天约束必须正视网络不稳定地铁、电梯、地下车库连接随时可能断开屏幕空间小一块编辑器最多同时展示二三十行代码计算资源有限大型编译任务不可能在本机完成续航敏感不能让一个后台任务把手机电量榨干。这四个约束共同指向同一个架构策略后端承担更多计算前端保持轻量。具体来说代码的编译、测试、运行都应该搬到云端沙箱手机只负责编辑和展示文件同步、AI流式响应、执行结果推送全部通过稳定长连接完成断网时允许本地继续编辑恢复后自动合并。这套思路听起来像标配的云IDE方案但当我们真正进入实现时才发现AI编程平台的加入会让架构复杂度再翻一倍——因为AI不只是一个“补全接口”而是一个需要上下文、工具和状态管理能力的分布式子系统。2. WebCode整体架构一条从浏览器到智能体的链路2.1 前端与移动端的选型博弈Monaco还是CodeMirror首先是编辑器内核选型这是第一个让人纠结的决策点。桌面端几乎没悬念直接用Monaco Editor——VSCode就是它生态成熟、语法高亮丰富、补全体验一流。但移动端一上手就发现问题了Monaco的包体积较大低端手机上加载白屏时间太长触摸场景下光标定位和软键盘弹出逻辑很难调教。这里我做了个听起来有点“分裂”的决定桌面保留Monaco移动端单独用CodeMirror 6重做了一个轻量壳。CodeMirror 6的模块化设计很贴合移动端诉求核心包只有几百KB需要什么功能再按需挂载插件。虚拟滚动让大文件也能流畅滚动状态树清晰方便做diff patch级别的同步。两套编辑器共存的代价是它们之上必须抽象出一层协议文件树、光标位置、选中区域、折叠状态、补全请求全部统一成标准消息。这样A用户在手机上用CodeMirror编辑B用户在桌面上用Monaco打开同一个文件两边看到的内容、修改的结果完全一致。内核选型看着是技术细节实际上决定了整个前端架构的松散程度。2.2 后端微服务拆分为什么编辑器服务要和AI服务解耦WebCode的后端不是一步到位拆成微服务的而是被逼出来的。最早单体版本把文件存储、WebSocket同步、AI调用全塞在一个服务里结果出现了一个很尴尬的现象某个用户发起一段AI流式补全生成长文本还没吐完同进程里其他人的文件保存请求全被堵住响应直接慢了几秒。我那时才意识到文档同步是高频低延迟的IO密集型任务AI推理是长耗时高吞吐的计算密集型任务这两类负载混在一起就像把高速公路收费站建在了火车站里面。现在后端拆成了六大域每个域独立部署、独立扩缩容接入网关负责鉴权、限流、协议转换工作区服务管文件树、版本快照、权限校验执行引擎服务管沙箱生命周期负责拉镜像、分配资源、回收VMAI会话服务管对话历史、prompt组装、模型调用Agent编排服务管复杂任务的拆解、工具调用、状态机流转事件总线贯穿所有服务负责文档变更、执行结果、AI token的异步分发。拆开之后我把同步通道和AI通道做了物理隔离。即使AI服务因为模型供应商故障导致大量超时用户的文件编辑和保存也完全不受影响。这是移动端产品的一个基本盘——任何时刻都不能让用户写的内容丢失或卡死。2.3 网关和消息通道弱网环境下的连接管理移动端连接管理比桌面复杂得多核心痛点是网络切换。手机从WiFi切到4GIP直接变TCP连接瞬间断掉可能还伴随着几秒到几十秒的信号盲区。为了不让用户感知断连我设计了一套“双通道重连回放”机制。第一通道是WebSocket专门推文档变更、光标位置、运行结果这类需要低延迟的消息第二通道是普通HTTPS负责文件上传下载、模型调用等一次性请求。WebSocket在断网时会自动进入重连退避算法客户端本地维护一个“未确认消息队列”连接恢复后先重放未确认的变更再拉取服务端最新diff合并。这套机制保证用户在电梯里写几行代码出电梯以后不会丢也不会和电脑上的修改互相覆盖。事件总线选型我用的NATS理由是轻量且支持JetStream持久化。文件同步事件、执行结果、AI流式块都可以作为消息流动后续审计和重放都很方便。我们在网关层做了一套基于JWT的临时凭证续期方案切换网络后不需要重新登录体验上能做到几乎无感。3. AI编程能力层不是“接个API”那么简单3.1 从LLM API到可用的代码生成中间还差三层封装很多团队做AI编程功能习惯直接把LLM API接到编辑器事件上谁触发了补全就传一段代码过去把返回文本填回来。这样做的结果大概率是模型经常给出语法正确但语义完全跑偏的代码因为模型根本不知道你的项目结构、文件依赖、编码规范。WebCode在LLM API之上做了三层封装。第一层是协议适配层把OpenAI、Anthropic以及几家国产大模型的接口统一屏蔽上层服务只需要用一套请求结构体模型供应当成可替换组件管理。第二层是领域上下文层负责从工作区解析出仓库地图、最近修改文件、当前文件符号表、lint错误列表再按权重组装成Prompt。第三层是产品策略层区分三种调用模式单行补全、inline chat解释/重构、Agent多轮任务不同模式使用不同的运行参数和prompt模板。这三层缺一不可。协议适配解决的是“能调通”领域上下文解决了“答得准”产品策略解决了“用得好”。只有三层都就位用户才会觉得AI像个真正懂项目的结对程序员而不是一个偶尔聪明的文本补全器。3.2 Agent的ReAct循环任务拆解、工具调用与自我纠错WebCode里最复杂的AI功能不是补全而是Agent模式。比如用户输入“帮我看看登录超时为什么频繁出现”这显然不是一个补全能搞定的Agent需要把它拆成一系列动作检索登录相关代码、检查超时配置、运行测试、读取日志、给出修改方案。我们实现的是经典ReAct循环Plan任务拆解→ ToolCall工具调用→ Observe观察结果→ Reflect反思修正循环直到用户确认或达到最大迭代次数。为了让Agent稳定工作我给它定义了一组工具read_file、write_file、list_files、run_test、git_diff、search_symbol。工具返回结果全部做结构化处理比如测试输出会被解析成JSON数组标明每个用例的通过/失败状态而不是把一坨日志文本直接塞给模型。这个设计的背后有个容易被忽略的原因模型对长文本的注意力衰减很严重。一次测试可能输出几百行日志如果原样塞给模型让它找失败原因它可能只注意到最后几行把真正失败的用例忽略了。结构化成JSON之后模型一眼就能拿到失败清单思考效率完全不同。Agent运行还需要硬性约束。我设置了max_iterations上限默认15轮超过就进入人工确认模式连续三次工具调用失败会自动暂停提醒用户补充信息。这样即便模型在某个循环里钻牛角尖整个系统也不会无限消耗你的token。3.3 上下文工程怎么让AI在手机小屏幕上也能理解整个项目手机屏幕本来就小用户不可能像桌面端那样手动拖拽一堆代码文件进对话窗口。因此WebCode必须让AI自己“知道”该看哪些代码。我采用的方案是“仓库地图按需取用”。启动一个工作区会话时AI服务会先生成一份模块级依赖图包含每个文件的导出符号和引用关系。这会形成一个压缩版的仓库地图每次对话开始时附带给模型。当模型需要具体实现细节时再通过read_file工具按需拉取完整源码。这个过程对用户完全透明但从模型视角看它天生就知道该往哪里看。关键技术点在于两级缓存。高频代码片段用户最近打开的文件、光标所在符号的上下文预热在高速缓存中超长文件则先做分块摘要模型提问命中哪块才把那一块原文取出来。这个“望远镜放大镜”的组合策略既避免了把整个仓库倒进prompt导致的超大上下文开销也保证了回答质量——模型不会因为看到太多无关代码而迷失。3.4 多模型路由与成本控制别让一个会话烧掉一个月预算AI编程平台烧钱速度非常吓人这是上线后才真切感受到的。一次Agent复杂任务可能调用模型二三十次如果每次都传完整上下文一次任务的token消耗就能顶几十次普通补全。因此WebCode做了一个模型路由层核心思路是“让合适模型干合适活”单行补全/缩进预测用低延迟小模型几百ms内返回成本很低interleaved inline chat中端模型负责解释代码、生成小段函数Agent链路和重大重构高端模型负责任务拆解和复杂推理代码审查/安全检查走专用微调模型延迟要求不高。路由之外还有两道成本闸门。第一道是上下文预算每次请求前计算prompt预估token数超出阈值就自动做截断或摘要避免无脑传一堆历史消息。第二道是流式终止当模型开始输出连续重复片段或者明显跑题时前端可以提前终止流式请求不用等它把整段废话吐完。我特别提醒所有做类似平台的朋友要在Context Caching上花心思。模型供应商现在普遍支持服务端缓存相同前缀的prompt可以大幅降低费用。WebCode把会话历史按固定结构缓存同一用户连续会话之间重复引入仓库地图时命中缓存后成本几乎可以忽略。4. 代码执行与分布式底座安全的“云电脑”怎么搭4.1 沙箱选型在Firecracker、gVisor和容器之间做取舍用户在手机上点了“运行”代码是在云端执行的云端就必须提供一个隔离、安全、可回收的执行环境。沙箱选型我做了三组对比方案和技术考量如下方案启动速度隔离强度资源开销适用场景Docker容器秒级较弱共享宿主内核低内部测试、低安全要求gVisor数百毫秒中等用户态内核拦截中等需要系统和文件访问兼容性Firecracker100-300ms强每实例微VM隔离略高多租户公开平台选型逻辑很直接。Docker虽然方便但多租户场景下让用户代码直接跑在共享内核上一旦有容器逃逸漏洞整个宿主都暴露了。Firecracker的microVM方案每个任务一个轻量虚拟机网络、文件系统、内存全部独立隔离出问题最多销毁一台VM不影响邻居。当前WebCode默认走Firecracker少数需要完整内核模块兼容的任务落到gVisor。实际部署中我们给每个租户维护了一个沙箱资源池冷启动时从池里挑一台空闲VM挂载工作区快照后立刻执行。池子水位不足时提前15秒预热新VM尽量对冲创建延迟。4.2 任务队列与事件驱动为什么异步执行是移动端的生命线移动端运行代码最怕的是前端一个HTTP请求等几十秒遇到网络抖动就直接超时。所以WebCode的执行链路从一开始就设计成异步事件驱动的。用户点运行按钮后前端不会直接等执行完而是做三件事提交任务、订阅结果、渲染中间事件。提交任务时API网关把请求写到NATS的execution任务队列执行引擎消费队列、启动沙箱、执行命令然后把执行状态变化启动中、编译中、运行中、成功/失败逐条推送到用户订阅的WebSocket通道。前端收到哪种状态就渲染哪种界面整个体验像看直播而不是看幻灯片。这个设计还带来一个额外价值可审计性。每个执行任务的状态流转都是持久化事件什么时候启动、用了哪个镜像、消耗多少CPU、退出码是什么全都能回放。用户如果质疑“上次跑成功了这次为什么失败”我们能把当时的执行轨迹完整找出来分析。队列配合背压机制后即便沙箱集群瞬间收到超出处理能力的任务请求也只会排队而不会击穿后端。移动端用户看到的是“任务排队中前面还有2个”而不是“请求超时请重试”。4.3 状态同步与多端一致性手机改一行电脑立刻看到多端同步是这类平台的生死线。用户很可能先用手机改了仓库里的一个文件回到家打开电脑接着改。如果同步机制不严谨就会出现文件互相覆盖、改动丢失的严重事故。WebCode选择的是OT操作转换服务端权威版本。前端每次编辑产生一个diff patch实时推送到工作区服务服务端按时间顺序合并patch并广播给其他在线端。编辑冲突时服务端根据操作位置做转换保证两端的文档最终收敛到同一个版本。这里没有用CRDT原因是当前编辑器模型下OT的成熟度更高调起来更可控。还有一个容易踩的坑文件状态必须和AI上下文同步。我遇到过用户手机上改完文件AI助手后台缓存却还是旧版导致Agent生成的新代码基于错误前提。后来我强制规定Agent每次调用工具前read_file/write_file都必须从工作区服务读取最新版本不允许使用对话历史里的旧文件快照。这个约束彻底根除了“AI把旧代码当新代码”的恶心bug。4.4 可观测性给每个AI动作打上traceAI编程平台之所以难运维是因为传统监控指标CPU、内存、QPS没法回答“AI为什么这一次回答错了”。我们必须从链路层面做全链路trace。WebCode引入了OpenTelemetry所有服务统一上报trace。每个AI请求生成一个traceId从用户输入开始穿过网关、AI会话、模型路由、prompt组装、工具调用直到最终渲染回前端。每一步的耗时、token消耗、模型名、返回内容截断都会落盘。代码执行同样绑定traceId这样当用户抱怨“AI生成的代码跑挂了”我可以把模型输出、沙箱执行日志、退出码串成一条完整证据链。可观测性的价值不只在排查问题还在算法优化。通过聚合trace数据我能统计出哪些工具调用最频繁、哪类任务token消耗最大、哪些模型的补全常常被用户主动拒绝。这些数据直接反哺prompt优化和路由策略让整个AI平台越跑越聪明。5. 移动端体验的细节打磨虚拟键盘、屏幕空间与性能5.1 虚拟键盘侵占屏幕如何重构移动端布局手机上最让人头疼的就是软键盘一弹出直接占掉一半屏幕。如果编辑器布局不做适应你会发现键盘弹起来后光标正在编辑的那一行恰好被遮住。WebCode对移动端布局做了几条硬性规则编辑器主体固定在软键盘上方输入框始终不高于视口的一半代码补全列表改为键盘上方的横滑卡片而不是传统IDE里的底部面板监听resize事件在软键盘弹出瞬间同步调整编辑区高度做到光标永远可见。还有一种容易被忽略的情况当用户连接蓝牙键盘或折叠屏形态变化时软键盘不会弹出此时要给出一键切换UI模式的能力把屏幕空间还给编辑器。这些细节看起来零碎但对移动端留存率的影响是决定性的。一个连打字都被遮挡的编辑器用户只会给一次机会。5.2 渲染性能优化百万行文件在手机上怎么打开网页编辑器打开几百KB的小文件性能还行一旦切到动辄几万行甚至几十万行的源码普通渲染方案直接卡死。移动端CPU更弱问题被放大。我的方案是“虚拟列表分块加载增量高亮”。编辑器只渲染可视区域内的行不管文件有多大DOM节点都稳定在一个数量级。文件内容按块从服务端按需拉取每一块拉到本地后缓存在内存里向上滚动时提前请求下一块。语法高亮采用增量reparse输入修改只对受影响的行重新计算不做全文件高亮。这套组合让几万行文件的滚动在手机上也能保持在60帧左右。我还把文本布局计算放进了Web Worker主线程只负责渲染和事件处理保证输入时不掉帧。5.3 离线优先策略地铁里写代码不丢一行离线场景是移动端平台绕不过去的坎。地铁、飞机、地下车库网络信号随时抽风。如果只能在线编辑用户早晚会在一个关键时刻丢内容然后永久卸载。WebCode的离线策略是“本地快照操作日志回放”。客户端启动时就拉取工作区当前版本建立本地快照。用户编辑时每个diff patch除了发往服务端还会写入本地IndexedDB日志。断网状态下编辑照常进行所有patch累积在日志队列里。网络恢复后客户端先发一个同步请求把日志队列按顺序回放到服务端服务端再返回合并后的最新版本。这个机制保证了离线写代码不会丢但它也反过来要求同步通道和AI通道彻底分离——离线时AI补全功能可以降级成简单的本地模板和缩进辅助但文件编辑必须一直可用。千万不要让AI服务的可用性绑架编辑器核心功能。5.4 触控交互设计手势、快捷指令和语音输入移动端没有快捷键这是必须接受的事实但可以通过手势和语音补偿。我在WebCode里做了一套面向触控的交互协议。比较实用的是长按选中唤出的浮动快捷条上面直接放“解释这段代码”“提取变量”“生成测试”三个高频AI动作编辑器两侧分别支持左右滑手势左滑切换文件右滑打开文件树双指捏合调整字体大小让低亮度场景下也能看清。真正让我意外的是语音输入的接受度。移动端输入代码注释或者发指令时语音往往比虚拟键盘快得多。用户只要说“给这个函数加上参数类型说明”系统就会自动把语音转成文本触发inline chat。这不是一个花哨功能而是移动端AI编程体验里最被低估的效率神器。6. 从MVP到完整平台的演进路线以及我踩过的坑6.1 第一版只是一个网页编辑器为什么后来重构了三次坦白讲WebCode第一版非常简陋就是一个单服务的网页编辑器用全局变量保存文件内容前端靠轮询拉取最新状态。当时只想着快速验证“手机上打开编辑器”这个场景根本没有考虑多人协同和AI能力。结果内测阶段就翻车了——两个人同时编辑一个文件后面的保存直接覆盖前面的改动当即就有人反馈“改了半天代码全没了”。第一次重构加了WebSocket和简单的文档锁文件同步不再靠轮询冲突问题缓解了。但AI功能是硬塞进编辑服务里的一个流式补全请求长跑几秒钟整个服务的线程池被卡住别的请求排队排到超时。于是第二次重构把AI拆分了出去做成独立会话服务。再后来随着沙箱执行、Agent编排的加入才逐步演进成现在这套六域架构。这段经历的教训是小团队起步别一上来上大架构但一定要在早期识别出“哪两个模块天生不能放在一起”。对我来说文档同步和AI推理就是最早发现的“八字不合”组合要是从一开始就分开能省掉两轮痛苦重构。6.2 演进中处理过的三个典型架构问题第一个问题是并发编辑冲突。乐观锁加版本号只能解决“整文件覆盖”解决不了“两个人在不同位置各自修改后再合并”的诉求。最终我选了OT方案把编辑操作转成带位置偏移的patch序列服务端做合并后广播。第二个问题是Agent无限循环。模型偶尔会在工具调用里绕圈比如反复查看同一个文件、反复运行同一组测试。我们加了最大迭代次数和失败冷却机制一旦连续几次工具调用没有产生实质进展Agent就会暂停并向用户请求确认。第三个问题是沙箱冷启动慢。一开始执行引擎每次现拉镜像现起VM用户等到花儿都谢了。后来做了沙箱预热池常驻一批空闲VM用户提交任务时直接调度给它们启动时间从十秒级降到一秒级。这三个问题都不是从教科书上看来的都是线上被真实用户捶出来的。6.3 我建议后来者怎么规划节奏如果让我给正在做类似AI编程平台的朋友一个路线建议我会说从单机原型开始但第一周就要做三件事——定义清晰的前后端同步协议、把AI调用封装成独立服务、从第一天接入可观测性。同步协议是地基后面做离线、做多端、做Agent都要依赖它AI服务独立是防爆胎避免一个流式响应拖垮整个后端可观测性是方向盘没有trace你会在AI黑盒面前完全失去方向。至于微服务、Kubernetes、多集群分布式这些等你有十个真实用户并且知道自己系统瓶颈在哪再上完全不迟。分布式的意义是解决增长问题而不是在只有自己一个人用的时候表演技术优美。回头看WebCode这套架构的每一次演进都是被“手机上写代码”这个场景里的真实痛点推着走的。从最初只想在浏览器里打开一个编辑器到后来发现必须做云端沙箱、Agent编排、弱网同步、多模型路由一步步把一个疯狂的想法变成了能稳定运行在手机端的AI编程平台。如果你也在琢磨类似的方向希望这篇文章里的架构取舍和踩坑记录能让你少走几次弯路。最后分享一个小心得做移动端的AI编程产品先忘掉桌面IDE给你养成的习惯站在“用户在地铁上用拇指改代码”的视角重新想一遍很多架构决策会变得无比清晰。
阅读完成 · 觉得有帮助?