从“手机上写代码“的疯狂想法,到一套完整的AI编程平台架构——WebCode深度技术剖析

说实话,当我第一次在地铁上用手机修复了一个线上Bug的时候,我整个人都是懵的。不是因为Bug有多难,而是因为——我TM居然真的在手机上写代码了?

一、那个让我失眠的需求

故事要从去年说起。

当时我们团队接到一个"看起来很简单"的需求:让开发者能够随时随地使用AI编程助手。产品经理信誓旦旦地说:"不就是做个Web版的Claude Code吗?套个壳就行了。"

我当时就笑了。

你知道Claude Code CLI是怎么工作的吗?它是一个本地进程,需要读写文件系统,需要执行Shell命令,需要维护会话状态,需要解析流式JSON输出...把这玩意儿搬到Web上?还要支持手机?

那几天我躺在床上翻来覆去睡不着,脑子里全是问题:

  • 浏览器怎么调用本地CLI工具?

  • 流式输出怎么实时推送到前端?

  • 多个用户同时使用,工作区怎么隔离?

  • 手机上那个破键盘,怎么让人愉快地写代码?

  • Claude Code和Codex的输出格式完全不一样,怎么统一处理?

后来我想明白了一件事:这不是一个"套壳"的活儿,这是要从零设计一套分布式AI编程平台的架构

二、架构设计:我踩过的那些坑

2.1 第一个大坑:CLI工具的"性格"都不一样

你以为所有AI CLI工具的输出格式都一样?太天真了。

Claude Code输出的是stream-json格式,长这样:

{"type":"assistant","message":{"role":"assistant","content":[{"type":"text","text":"让我来帮你..."}]}}

而Codex输出的是JSONL格式,长这样:

{"type":"item.updated","item":{"type":"agent_message","text":"正在分析代码..."}}

更要命的是,它们的会话恢复机制也不一样。Claude Code用--resume session_id,Codex用resume session_id(注意,没有双横线)。

一开始我想的是:写一堆if-else判断不就完了?

// 千万别这么写,我已经替你踩过坑了 if (toolId == "claude-code") { // 处理Claude Code的逻辑 } else if (toolId == "codex") { // 处理Codex的逻辑 } else if (toolId == "copilot") { // 又来一个... }

这种代码写出来,三个月后你自己都不想维护。

最后我选择了适配器模式。每个CLI工具都有自己的适配器,实现统一的接口:

public interface ICliToolAdapter { // 这个工具支持哪些ID string[] SupportedToolIds { get; } // 是否支持流式解析 bool SupportsStreamParsing { get; } // 构建命令行参数(每个工具的参数格式都不一样) string BuildArguments(CliToolConfig tool, string prompt, CliSessionContext context); // 解析输出(每个工具的输出格式都不一样) CliOutputEvent? ParseOutputLine(string line); // 提取会话ID(用于会话恢复) string? ExtractSessionId(CliOutputEvent outputEvent); }

这样做的好处是什么?新增一个CLI工具,只需要写一个新的适配器,核心代码一行不用改

举个例子,Claude Code的适配器是这样处理参数构建的:

public string BuildArguments(CliToolConfig tool, string prompt, CliSessionContext context) { var escapedPrompt = EscapeShellArgument(prompt); // 会话恢复参数 var sessionArg = string.Empty; if (context.IsResume && !string.IsNullOrEmpty(context.CliThreadId)) { sessionArg = $"--resume {context.CliThreadId}"; // Claude Code用双横线 } return $"-p --output-format=stream-json {sessionArg} \"{escapedPrompt}\""; }

而Codex的适配器是这样的:

public string BuildArguments(CliToolConfig tool, string prompt, CliSessionContext context) { var escapedPrompt = EscapeJsonString(prompt); var sessionArg = string.Empty; if (context.IsResume && !string.IsNullOrEmpty(context.CliThreadId)) { sessionArg = $"resume {context.CliThreadId}"; // Codex不用双横线 } return $"exec --json {sessionArg} \"{escapedPrompt}\""; }

看到没?差异被封装在适配器里,上层代码完全不用关心

2.2 第二个大坑:流式输出的"时序地狱"

AI的回复是流式的,一个字一个字往外蹦。这在命令行里看着很酷,但在Web上实现起来简直是噩梦。

问题出在哪儿?异步读取 + 并发渲染 + 状态同步

想象一下这个场景:

  1. 后端从CLI进程读取输出

  2. 通过SSE推送到前端

  3. 前端解析JSON

  4. 更新UI状态

  5. 触发Blazor重新渲染

这五步里,任何一步出问题,用户看到的就是乱码或者卡顿。

我最初的实现是这样的:

// 错误示范:直接在读取循环里更新UI while ((line = await reader.ReadLineAsync()) != null) { var chunk = ParseJsonLine(line); _currentMessage += chunk.Content; StateHasChanged(); // 每读一行就刷新UI }

结果呢?**CPU直接飙到100%**,页面卡得像PPT。

为什么?因为StateHasChanged()会触发整个组件树的重新渲染,而AI输出的速度是每秒几十上百个字符,你让Blazor每秒渲染几十次,它不崩谁崩?

最后的解决方案是防抖 + 批量更新

private System.Threading.Timer? _updateTimer; private readonly object _updateLock = new object(); private bool _hasPendingUpdate = false; private void QueueUIUpdate() { lock (_updateLock) { if (_hasPendingUpdate) return; _hasPendingUpdate = true; // 50ms内的更新合并成一次 _updateTimer?.Dispose(); _updateTimer = new Timer(_ => { _hasPendingUpdate = false; InvokeAsync(StateHasChanged); }, null, 50, Timeout.Infinite); } }

这样一来,不管AI输出多快,UI最多每50ms刷新一次,既保证了流畅度,又不会把浏览器搞崩。

2.3 第三个大坑:工作区隔离的"安全噩梦"

多用户场景下,每个人都有自己的工作区。听起来简单,做起来要命。

最直接的问题:用户A能不能访问用户B的文件?

如果你的回答是"不能",那恭喜你,你需要考虑以下场景:

  • 路径穿越攻击:../../etc/passwd

  • 符号链接攻击:在工作区里创建一个指向系统目录的软链接

  • 命令注入:用户输入里带;rm -rf /

我的解决方案是多层防护

第一层:会话隔离

每个会话有独立的工作目录,目录名是随机生成的UUID:

public string GetOrCreateSessionWorkspace(string sessionId) { lock (_workspaceLock) { if (_sessionWorkspaces.TryGetValue(sessionId, out var existing)) return existing; var workspacePath = Path.Combine( GetEffectiveWorkspaceRoot(), sessionId // UUID,无法猜测 ); Directory.CreateDirectory(workspacePath); _sessionWorkspaces[sessionId] = workspacePath; return workspacePath; } }

第二层:路径验证

所有文件操作都要验证路径是否在工作区内:

private bool IsPathSafe(string workspacePath, string requestedPath) { var fullPath = Path.GetFullPath(Path.Combine(workspacePath, requestedPath)); var normalizedWorkspace = Path.GetFullPath(workspacePath); // 确保解析后的路径仍在工作区内 return fullPath.StartsWith(normalizedWorkspace, StringComparison.OrdinalIgnoreCase); }

第三层:命令白名单

CLI工具只能执行预定义的命令,用户输入会被转义:

private static string EscapeShellArgument(string argument) { // 转义所有可能导致命令注入的字符 return argument .Replace("\\", "\\\\") .Replace("\"", "\\\"") .Replace("$", "\\$") .Replace("`", "\\`"); }

三、上下文管理:AI的"记忆"问题

这是整个项目里我最得意的一块设计。

你有没有遇到过这种情况:跟AI聊了半天,它突然"失忆"了,之前说的话全忘了?

这是因为AI模型有上下文窗口限制。Claude的上下文窗口是100K tokens,听起来很大,但如果你在讨论一个大型项目,贴几个文件进去,分分钟就爆了。

传统的解决方案是"截断"——超过限制就把最早的消息删掉。但这样做的问题是:可能把关键信息删掉了

我设计了一套智能上下文管理系统

3.1 上下文项的优先级

不是所有信息都同等重要。用户的问题比AI的回复重要,错误信息比普通输出重要,最近的消息比很久以前的消息重要。

public class ContextItem { public ContextItemType Type { get; set; } public string Content { get; set; } public int EstimatedTokens { get; set; } public int Priority { get; set; } // 0-10,越高越重要 public bool IsIncluded { get; set; } = true; }

优先级的默认规则:

  • 用户消息:7

  • 错误信息:9(最高,因为通常是当前要解决的问题)

  • AI回复:5

  • 代码片段:6

  • 文件引用:4

3.2 智能压缩策略

当上下文快满的时候,系统会自动触发压缩。但不是简单地删除,而是智能摘要

private async Task CompressSmartSummaryAsync(...) { // 1. 高优先级项永远保留 var highPriorityItems = items.Where(i => i.Priority >= 7); // 2. 最近的用户消息保留 var recentUserMessages = items .Where(i => i.Type == ContextItemType.UserMessage) .OrderByDescending(i => i.CreatedAt) .Take(config.KeepRecentMessages); // 3. 其他内容生成摘要 foreach (var item in itemsToCompress) { if (item.Type == ContextItemType.CodeSnippet) { // 代码片段:保留函数签名,删除实现细节 item.Content = GenerateCodeSnippetSummary(item.Content); item.EstimatedTokens = TokenEstimator.EstimateTokens(item.Content); } } }

这样做的效果是:即使上下文被压缩了,AI仍然知道之前讨论过什么,只是细节没那么清楚了

3.3 Token估算

准确估算Token数量是个技术活。不同语言的Token密度不一样:

public static int EstimateTokens(string text) { // 中文:约1.5字符/Token // 英文:约4字符/Token var chineseChars = text.Count(c => c >= 0x4E00 && c <= 0x9FFF); var otherChars = text.Length - chineseChars; return (int)Math.Ceiling(chineseChars / 1.5 + otherChars / 4.0); }

代码的Token密度更高(因为有很多符号和关键字),所以单独处理:

public static int EstimateCodeTokens(string code) { return (int)Math.Ceiling(code.Length / 3.5); }

四、移动端适配:那些让我抓狂的细节

"支持手机"这四个字,背后是无数个深夜的调试。

4.1 iOS Safari的100vh问题

你知道iOS Safari的100vh不是真正的视口高度吗?它包含了地址栏的高度,导致页面底部会被遮挡。

解决方案:

.container { height: 100vh; height: 100dvh; /* 动态视口高度,iOS 15+支持 */ height: -webkit-fill-available; /* 兼容旧版本 */ }

4.2 虚拟键盘弹出时的布局问题

手机上弹出键盘时,视口高度会变化,如果处理不好,输入框会被键盘遮挡。

我的解决方案是监听visualViewport的变化:

if (window.visualViewport) { window.visualViewport.addEventListener('resize', () => { const keyboardHeight = window.innerHeight - window.visualViewport.height; document.documentElement.style.setProperty('--keyboard-height', `${keyboardHeight}px`); }); }

然后在CSS里使用这个变量:

.input-area { padding-bottom: calc(env(safe-area-inset-bottom) + var(--keyboard-height, 0px)); }

4.3 触摸目标大小

苹果的人机界面指南建议触摸目标至少44x44像素。但很多开发者(包括以前的我)都忽略了这一点。

.touch-target { min-width: 44px; min-height: 44px; padding: 12px; /* 即使内容小,点击区域也要够大 */ }

五、性能优化:从"能用"到"好用"

5.1 文件树的虚拟滚动

工作区可能有成百上千个文件,如果全部渲染到DOM里,页面会卡死。

解决方案是懒加载 + 虚拟滚动

private const int MaxVisibleNodes = 100; private int _currentVisibleNodes = MaxVisibleNodes; // 只渲染可见区域的节点 private List<WorkspaceFileNode> GetVisibleNodes() { return _workspaceFiles .Take(_currentVisibleNodes) .ToList(); } // 滚动到底部时加载更多 private void LoadMoreNodes() { _currentVisibleNodes += 50; StateHasChanged(); }

5.2 Markdown渲染缓存

AI的回复通常包含大量Markdown,每次渲染都要解析一遍很浪费。

private readonly Dictionary<string, MarkupString> _markdownCache = new(); private MarkupString RenderMarkdown(string? markdown) { if (_markdownCache.TryGetValue(markdown, out var cached)) return cached; var html = Markdown.ToHtml(markdown, _markdownPipeline); var result = new MarkupString(html); // 限制缓存大小 if (_markdownCache.Count > 100) _markdownCache.Clear(); _markdownCache[markdown] = result; return result; }

5.3 输出状态的防抖保存

用户的输出结果需要持久化,但不能每次更新都写数据库。

private void QueueSaveOutputState() { lock (_outputStateSaveLock) { if (_hasPendingOutputStateSave) return; _hasPendingOutputStateSave = true; _outputStateSaveTimer?.Dispose(); _outputStateSaveTimer = new Timer(async _ => { _hasPendingOutputStateSave = false; await SaveOutputStateAsync(); }, null, OutputStateSaveDebounceMs, Timeout.Infinite); } }

六、未来的坑(和机会)

这个项目还在持续迭代,有几个方向我特别想做:

6.1 多模型对比

同一个问题,让Claude和GPT同时回答,对比结果。这对于选择最佳方案很有帮助。

技术上的挑战是并行执行 + 结果同步

public async Task<List<ModelResponse>> ExecuteParallelAsync( string prompt, List<string> toolIds) { var tasks = toolIds.Select(toolId => ExecuteSingleAsync(prompt, toolId)); return await Task.WhenAll(tasks); }

6.2 实时协作

多人同时编辑同一个工作区,像Google Docs那样。

这需要引入CRDT(无冲突复制数据类型)或者OT(操作转换)算法,复杂度直接上一个台阶。

6.3 插件系统

让用户可以自己添加新的CLI工具适配器,不需要改核心代码。

架构上已经预留了扩展点:

public interface IPluginService { void RegisterCliAdapter(ICliToolAdapter adapter); List<PluginUIComponent> GetPluginUIComponents(string location); }

七、写在最后

回头看这个项目,最大的收获不是代码本身,而是对复杂系统的理解

一个"简单"的需求背后,可能涉及:

  • 进程管理和IPC

  • 流式数据处理

  • 安全和隔离

  • 跨平台兼容

  • 性能优化

  • 用户体验

每一个点展开都是一个深坑。

但这也是软件开发的魅力所在,不是吗?

你永远不知道下一个Bug会把你带到哪个知识领域。


如果你对这个项目感兴趣,欢迎来GitHub上看看:WebCodehttps://github.com/xuzeyu91/WebCode

有问题可以在评论区讨论,我会尽量回复。

最后,如果这篇文章对你有帮助,点个赞呗?写了一整天,手都酸了 😂

更多AIGC文章

RAG技术全解:从原理到实战的简明指南

更多VibeCoding文章

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1188758.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2026液氧领域佼佼者,哪些厂家值得选择?汽化器/液氧/液氮速冻机/储罐/制氧机/液氩/真空管,液氧企业口碑推荐榜 - 品牌推荐师

引言 液氧作为工业生产中的关键原料,广泛应用于钢铁冶炼、化工合成、医疗急救、电子制造等多个领域,其纯度、稳定性和供应能力直接影响着下游企业的生产效率与产品质量。尤其在医疗、食品等高敏感行业,液氧的质量更…

2026年天津继承纠纷律师联系电话推荐:可靠资源与服务路径 - 品牌推荐

在家庭财产传承的过程中,继承纠纷往往是当事人面临的最为棘手和情感复杂的法律问题之一。特别是在天津这样一座兼具深厚传统与现代都市特点的城市,继承案件往往涉及房改房、借名买房等具有地方特色的财产类型,法律关…

Claude Code Bridge:让多个 AI 模型在终端里组队打怪

Claude Code Bridge&#xff1a;让多个 AI 模型在终端里组队打怪 兄弟伙些&#xff0c;是不是也遇到过这种情况嘛&#xff1f;用 Claude Code 或者 Codex 写代码&#xff0c;单个模型搞着搞着就钻牛角尖了&#xff0c;思路打不开。想多喊几个 AI 来一起商量&#xff0c;结果又得…

付费降AI vs 免费降AI:效果差距到底有多大? - 还在做实验的师兄

付费和免费降AI工具的差距非常大。免费工具(DeepSeek指令、同义词替换)达标率不到30%,付费工具(嘎嘎降AI、比话降AI)达标率99%以上。省下的几十块钱,换来的是无数次返工和可能延期毕业的风险。毕业论文这种事,真…

Alexa Fluor 647-LNT,Alexa Fluor 647标记乳糖-N-四糖,红光荧光染料

Alexa Fluor 647-LNT&#xff0c;Alexa Fluor 647标记乳糖-N-四糖&#xff0c;红光荧光染料Alexa Fluor 647-LNT 是一种功能化荧光糖类分子&#xff0c;由红光荧光染料 Alexa Fluor 647 与 乳糖-N-四糖&#xff08;Lacto-N-tetraose, LNT&#xff09; 通过共价偶联形成。该分子…

Texas Red-LNT,Texas Red标记乳糖-N-四糖,长波红光荧光染料的标记方法

Texas Red-LNT&#xff0c;Texas Red标记乳糖-N-四糖&#xff0c;长波红光荧光染料的标记方法Texas Red-LNT 是将荧光染料 Texas Red 与 乳糖-N-四糖&#xff08;Lacto-N-tetraose, LNT&#xff09; 共价偶联形成的功能化糖类分子。该分子结合了 Texas Red 的红光荧光性能和 LN…

2026年比较好的幕墙三元乙丙胶条,防滑三元乙丙胶条,防火三元乙丙胶条厂家用户优选推荐 - 品牌鉴赏师

引言在建筑行业中,三元乙丙胶条作为重要的密封材料,其性能和质量直接影响到建筑的安全性、舒适性和节能效果。近年来,随着建筑标准的不断提高,市场对幕墙三元乙丙胶条、防滑三元乙丙胶条、防火三元乙丙胶条等产品的…

2026年1月陕西高品质垃圾桶/垃圾箱厂家推荐 鑫洁达领衔公共设施解决方案 - 深度智识库

在陕西环卫设施采购市场中,优质厂家的选择直接关系到项目落地质量与长期使用体验。尤其对于市政、校园、景区等场景,兼具品质、定制能力与服务保障的供应商更为稀缺。本次结合企业实力、项目案例、产品体系等维度,精…

10 个 GitHub 仓库,系统拉满你的 AI Agent 能力(建议收藏)

AI Agent 正在飞速发展&#xff0c;从简单聊天机器人到多代理协作系统&#xff0c;这些开源仓库能帮你从入门到实战&#xff0c;快速提升能力&#xff01;下面精选 10 个高质量 GitHub 仓库&#xff0c;涵盖 LLM 基础、Agent 构建、提示工程、生产部署等全链路&#xff0c;强烈…

基于Java Web的实习招聘系统

目录基于Java Web的实习招聘系统摘要项目技术支持可定制开发之功能亮点源码获取详细视频演示 &#xff1a;文章底部获取博主联系方式&#xff01;同行可合作基于Java Web的实习招聘系统摘要 实习招聘系统是为企业、学生和高校搭建的高效信息交互平台&#xff0c;采用Java Web技…

深入探访:国内几家液氮速冻机核心生产商,液氧/二氧化碳/制氮机/真空管/液氮/制氧机/液氩,液氮速冻机生产厂家推荐排行榜 - 品牌推荐师

在食品加工、医药生产及化工等工业领域,液氮速冻机凭借其超低温快速冻结、保留产品营养与质构的特性,已成为保障安全生产、提升作业效率的关键设备。据国内制冷设备行业协会发布的最新测评数据及《冷冻冷藏行业白皮书…

2026年天津离婚律师联系电话推荐:精选推荐与使用指南 - 品牌推荐

面对婚姻关系的终结,选择一位专业、可靠且富有经验的离婚律师,是保障自身合法权益、平稳度过人生重要阶段的关键一步。特别是在天津这样的大都市,涉及房产分割、子女抚养权争夺、复杂财产认定等情况的离婚案件屡见不…

2026年1月陕西垃圾桶/垃圾箱高品质厂家推荐:鑫洁达环保与新阳光环保实力解析 - 深度智识库

随着城市化进程的加速和环保意识的提升,垃圾桶、垃圾箱等环卫设施在城市环境建设中的重要性日益凸显。作为西北地区重要的环保设备生产基地,陕西省涌现了一批技术先进、质量可靠的环保设备企业。在众多厂家中,西安鑫…

DeepSeek Engram 横空出世!重构 LLM 记忆体系,算力效率再升级

当前技术突破的核心路径&#xff0c;仍集中在扩大模型规模与优化计算调度上。但有没有另一条可行的创新之路&#xff1f;深度求索&#xff08;DeepSeek AI&#xff09;推出的记忆增强技术&#xff08;Engram&#xff09; 给出了答案——这项革命性技术正在颠覆我们对语言模型扩…

GEO赛道榜单:AI营销获客难?看原圈科技如何领跑2026

原圈科技在GEO&#xff08;生成式引擎优化&#xff09;领域表现突出&#xff0c;被普遍视为2026年度领跑者。其核心优势在于&#xff0c;拥有能够兼容国内外主流大模型的自主技术底座&#xff0c;并打造了从洞察、内容到转化的"AI营销员工"产品矩阵。通过在金融、汽车…

2026 年四川果树苗批发实力榜单 全场景覆盖 个性化需求全景参考指南 - 深度智识库

四川凭借得天独厚的盆地气候与山地资源,成为国内果树苗培育与批发的核心产区,产业布局覆盖特色品种研发、规模化育苗、全链条服务等多个维度。当前行业正朝着品种定制化、培育技术智能化、服务体系一体化的方向稳步发…

CFexpress A卡哪个品牌可靠?2026年CFexpress A卡品牌推荐与排名,解决持续写入与兼容性痛点 - 品牌推荐

摘要 在专业影像与内容创作领域,数据存储已从单纯的容量载体演变为保障创作流程连续性与资产安全的核心环节。决策者,尤其是职业摄影师、影视制作团队及机构采购负责人,正面临一个关键抉择:在众多宣称高性能的存储…

2026年国产试验机十大厂家排行榜:力学试验机,教学用试验机,进口配置试验机,大吨位拉力试验机,,线缆拉力试验机 - 品牌推荐大师1

当前,全球制造业正经历一场深刻的智能革命,试验机作为保障产品质量、驱动材料创新的核心装备,其重要性日益凸显。行业发展呈现出三大趋势:一是测试场景从单一静态分析转向复合工况(如高低温、腐蚀环境)下的动态性…

2026年天津继承纠纷律所联系电话推荐:本地化专业团队介绍 - 品牌推荐

在天津这座融合了传统与现代的城市中,家庭财富的传承问题日益凸显,继承纠纷也随之增多。这类纠纷往往不仅涉及复杂的法律条文和财产分割,更交织着深厚的情感与家族关系,处理起来需要极高的专业素养和人文关怀。进入…

GEO服务商榜单

原圈科技如何领跑AI营销 破解获客难题&#xff1f;技术底座 行业知识 端到端方案核心洞察 | 原圈科技GEO服务深度解析&#xff1a;作为2026年榜单的领跑者&#xff0c;原圈科技凭借其"技术底座行业知识端到端方案"三位一体的核心能力脱颖而出。其通过"天眼&qu…