[{"data":1,"prerenderedAt":1566},["ShallowReactive",2],{"content-/ai/streaming-generation":3,"related-ai":1536},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"keywords":10,"author":11,"date":12,"category":13,"image":14,"body":15,"_type":1530,"_id":1531,"_source":1532,"_file":1533,"_stem":1534,"_extension":1535},"/ai/streaming-generation","ai",false,"","流式生成技术架构","深入解析基于 SSE 的增量式渲染与实时流式生成引擎","流式生成, SSE, 增量渲染, 实时反馈, 性能优化, HTMLPAGE","HTMLPAGE","2025-11-27","AI 技术","/content-images/ai/ai.jpg",{"type":16,"children":17,"toc":1507},"root",[18,26,33,40,45,188,193,198,233,427,433,439,444,452,847,853,858,891,897,902,915,955,960,965,1002,1008,1014,1019,1236,1242,1247,1270,1276,1281,1286,1441,1446,1451,1457,1488,1492,1501],{"type":19,"tag":20,"props":21,"children":22},"element","p",{},[23],{"type":24,"value":25},"text","HTMLPAGE 的流式生成技术（Streaming Generation）彻底改变了传统的\"请求-等待-响应\"模式。通过 Server-Sent Events (SSE) 和增量渲染引擎，我们实现了毫秒级的首字响应（TTFT），让用户能够实时目睹 AI 的思考与构建过程，就像看着一位设计师在眼前现场作画。",{"type":19,"tag":27,"props":28,"children":30},"h2",{"id":29},"流式传输架构",[31],{"type":24,"value":32},"🌊 流式传输架构",{"type":19,"tag":34,"props":35,"children":37},"h3",{"id":36},"sse-vs-websocket",[38],{"type":24,"value":39},"SSE vs WebSocket",{"type":19,"tag":20,"props":41,"children":42},{},[43],{"type":24,"value":44},"在技术选型上，我们选择了 SSE (Server-Sent Events) 作为主要的流式传输协议，而非 WebSocket。",{"type":19,"tag":46,"props":47,"children":48},"table",{},[49,78],{"type":19,"tag":50,"props":51,"children":52},"thead",{},[53],{"type":19,"tag":54,"props":55,"children":56},"tr",{},[57,63,68,73],{"type":19,"tag":58,"props":59,"children":60},"th",{},[61],{"type":24,"value":62},"特性",{"type":19,"tag":58,"props":64,"children":65},{},[66],{"type":24,"value":67},"SSE (Server-Sent Events)",{"type":19,"tag":58,"props":69,"children":70},{},[71],{"type":24,"value":72},"WebSocket",{"type":19,"tag":58,"props":74,"children":75},{},[76],{"type":24,"value":77},"为什么选择 SSE?",{"type":19,"tag":79,"props":80,"children":81},"tbody",{},[82,110,136,162],{"type":19,"tag":54,"props":83,"children":84},{},[85,95,100,105],{"type":19,"tag":86,"props":87,"children":88},"td",{},[89],{"type":19,"tag":90,"props":91,"children":92},"strong",{},[93],{"type":24,"value":94},"通讯方向",{"type":19,"tag":86,"props":96,"children":97},{},[98],{"type":24,"value":99},"单向 (Server -> Client)",{"type":19,"tag":86,"props":101,"children":102},{},[103],{"type":24,"value":104},"双向",{"type":19,"tag":86,"props":106,"children":107},{},[108],{"type":24,"value":109},"生成过程主要是服务器推送，单向足够",{"type":19,"tag":54,"props":111,"children":112},{},[113,121,126,131],{"type":19,"tag":86,"props":114,"children":115},{},[116],{"type":19,"tag":90,"props":117,"children":118},{},[119],{"type":24,"value":120},"协议复杂度",{"type":19,"tag":86,"props":122,"children":123},{},[124],{"type":24,"value":125},"简单 (基于 HTTP)",{"type":19,"tag":86,"props":127,"children":128},{},[129],{"type":24,"value":130},"复杂 (自定义协议)",{"type":19,"tag":86,"props":132,"children":133},{},[134],{"type":24,"value":135},"SSE 原生支持 HTTP/2 多路复用和防火墙穿透",{"type":19,"tag":54,"props":137,"children":138},{},[139,147,152,157],{"type":19,"tag":86,"props":140,"children":141},{},[142],{"type":19,"tag":90,"props":143,"children":144},{},[145],{"type":24,"value":146},"自动重连",{"type":19,"tag":86,"props":148,"children":149},{},[150],{"type":24,"value":151},"浏览器原生支持",{"type":19,"tag":86,"props":153,"children":154},{},[155],{"type":24,"value":156},"需手动实现",{"type":19,"tag":86,"props":158,"children":159},{},[160],{"type":24,"value":161},"SSE 内置重连机制，更稳定",{"type":19,"tag":54,"props":163,"children":164},{},[165,173,178,183],{"type":19,"tag":86,"props":166,"children":167},{},[168],{"type":19,"tag":90,"props":169,"children":170},{},[171],{"type":24,"value":172},"数据格式",{"type":19,"tag":86,"props":174,"children":175},{},[176],{"type":24,"value":177},"文本流 (Text Stream)",{"type":19,"tag":86,"props":179,"children":180},{},[181],{"type":24,"value":182},"二进制/文本",{"type":19,"tag":86,"props":184,"children":185},{},[186],{"type":24,"value":187},"适合传输 JSON Patch 或 Markdown 片段",{"type":19,"tag":34,"props":189,"children":191},{"id":190},"流式管道设计",[192],{"type":24,"value":190},{"type":19,"tag":20,"props":194,"children":195},{},[196],{"type":24,"value":197},"我们的流式生成管道由三个核心阶段组成：",{"type":19,"tag":199,"props":200,"children":201},"ol",{},[202,213,223],{"type":19,"tag":203,"props":204,"children":205},"li",{},[206,211],{"type":19,"tag":90,"props":207,"children":208},{},[209],{"type":24,"value":210},"Token 生成层",{"type":24,"value":212},"：LLM 逐个 Token 输出。",{"type":19,"tag":203,"props":214,"children":215},{},[216,221],{"type":19,"tag":90,"props":217,"children":218},{},[219],{"type":24,"value":220},"结构化解析层",{"type":24,"value":222},"：将 Token 流实时组装成结构化的 JSON Patch 或 HTML 片段。",{"type":19,"tag":203,"props":224,"children":225},{},[226,231],{"type":19,"tag":90,"props":227,"children":228},{},[229],{"type":24,"value":230},"增量传输层",{"type":24,"value":232},"：通过 SSE 通道将差异数据推送到前端。",{"type":19,"tag":234,"props":235,"children":239},"pre",{"className":236,"code":237,"language":238,"meta":7,"style":7},"language-mermaid shiki shiki-themes github-dark github-dark","sequenceDiagram\n    participant Client\n    participant Gateway\n    participant StreamEngine\n    participant LLM\n\n    Client->>Gateway: POST /api/generate (Stream=true)\n    Gateway->>StreamEngine: Init Generation Task\n    StreamEngine->>LLM: Prompt Request\n    \n    loop Token Streaming\n        LLM-->>StreamEngine: Token \"\u003Cdiv>\"\n        StreamEngine-->>StreamEngine: Buffer & Parse\n        StreamEngine-->>Gateway: SSE Event: { type: \"patch\", data: \"...\" }\n        Gateway-->>Client: SSE Event\n        Client-->>Client: Incremental Render\n    end\n    \n    StreamEngine-->>Gateway: SSE Event: { type: \"done\" }\n    Gateway-->>Client: Close Connection\n","mermaid",[240],{"type":19,"tag":241,"props":242,"children":243},"code",{"__ignoreMap":7},[244,256,265,274,283,292,302,311,320,329,338,347,356,365,374,383,392,401,409,418],{"type":19,"tag":245,"props":246,"children":249},"span",{"class":247,"line":248},"line",1,[250],{"type":19,"tag":245,"props":251,"children":253},{"style":252},"--shiki-default:#E1E4E8;--shiki-dark:#E1E4E8",[254],{"type":24,"value":255},"sequenceDiagram\n",{"type":19,"tag":245,"props":257,"children":259},{"class":247,"line":258},2,[260],{"type":19,"tag":245,"props":261,"children":262},{"style":252},[263],{"type":24,"value":264},"    participant Client\n",{"type":19,"tag":245,"props":266,"children":268},{"class":247,"line":267},3,[269],{"type":19,"tag":245,"props":270,"children":271},{"style":252},[272],{"type":24,"value":273},"    participant Gateway\n",{"type":19,"tag":245,"props":275,"children":277},{"class":247,"line":276},4,[278],{"type":19,"tag":245,"props":279,"children":280},{"style":252},[281],{"type":24,"value":282},"    participant StreamEngine\n",{"type":19,"tag":245,"props":284,"children":286},{"class":247,"line":285},5,[287],{"type":19,"tag":245,"props":288,"children":289},{"style":252},[290],{"type":24,"value":291},"    participant LLM\n",{"type":19,"tag":245,"props":293,"children":295},{"class":247,"line":294},6,[296],{"type":19,"tag":245,"props":297,"children":299},{"emptyLinePlaceholder":298},true,[300],{"type":24,"value":301},"\n",{"type":19,"tag":245,"props":303,"children":305},{"class":247,"line":304},7,[306],{"type":19,"tag":245,"props":307,"children":308},{"style":252},[309],{"type":24,"value":310},"    Client->>Gateway: POST /api/generate (Stream=true)\n",{"type":19,"tag":245,"props":312,"children":314},{"class":247,"line":313},8,[315],{"type":19,"tag":245,"props":316,"children":317},{"style":252},[318],{"type":24,"value":319},"    Gateway->>StreamEngine: Init Generation Task\n",{"type":19,"tag":245,"props":321,"children":323},{"class":247,"line":322},9,[324],{"type":19,"tag":245,"props":325,"children":326},{"style":252},[327],{"type":24,"value":328},"    StreamEngine->>LLM: Prompt Request\n",{"type":19,"tag":245,"props":330,"children":332},{"class":247,"line":331},10,[333],{"type":19,"tag":245,"props":334,"children":335},{"style":252},[336],{"type":24,"value":337},"    \n",{"type":19,"tag":245,"props":339,"children":341},{"class":247,"line":340},11,[342],{"type":19,"tag":245,"props":343,"children":344},{"style":252},[345],{"type":24,"value":346},"    loop Token Streaming\n",{"type":19,"tag":245,"props":348,"children":350},{"class":247,"line":349},12,[351],{"type":19,"tag":245,"props":352,"children":353},{"style":252},[354],{"type":24,"value":355},"        LLM-->>StreamEngine: Token \"\u003Cdiv>\"\n",{"type":19,"tag":245,"props":357,"children":359},{"class":247,"line":358},13,[360],{"type":19,"tag":245,"props":361,"children":362},{"style":252},[363],{"type":24,"value":364},"        StreamEngine-->>StreamEngine: Buffer & Parse\n",{"type":19,"tag":245,"props":366,"children":368},{"class":247,"line":367},14,[369],{"type":19,"tag":245,"props":370,"children":371},{"style":252},[372],{"type":24,"value":373},"        StreamEngine-->>Gateway: SSE Event: { type: \"patch\", data: \"...\" }\n",{"type":19,"tag":245,"props":375,"children":377},{"class":247,"line":376},15,[378],{"type":19,"tag":245,"props":379,"children":380},{"style":252},[381],{"type":24,"value":382},"        Gateway-->>Client: SSE Event\n",{"type":19,"tag":245,"props":384,"children":386},{"class":247,"line":385},16,[387],{"type":19,"tag":245,"props":388,"children":389},{"style":252},[390],{"type":24,"value":391},"        Client-->>Client: Incremental Render\n",{"type":19,"tag":245,"props":393,"children":395},{"class":247,"line":394},17,[396],{"type":19,"tag":245,"props":397,"children":398},{"style":252},[399],{"type":24,"value":400},"    end\n",{"type":19,"tag":245,"props":402,"children":404},{"class":247,"line":403},18,[405],{"type":19,"tag":245,"props":406,"children":407},{"style":252},[408],{"type":24,"value":337},{"type":19,"tag":245,"props":410,"children":412},{"class":247,"line":411},19,[413],{"type":19,"tag":245,"props":414,"children":415},{"style":252},[416],{"type":24,"value":417},"    StreamEngine-->>Gateway: SSE Event: { type: \"done\" }\n",{"type":19,"tag":245,"props":419,"children":421},{"class":247,"line":420},20,[422],{"type":19,"tag":245,"props":423,"children":424},{"style":252},[425],{"type":24,"value":426},"    Gateway-->>Client: Close Connection\n",{"type":19,"tag":27,"props":428,"children":430},{"id":429},"增量渲染引擎",[431],{"type":24,"value":432},"⚡ 增量渲染引擎",{"type":19,"tag":34,"props":434,"children":436},{"id":435},"虚拟-dom-补丁策略",[437],{"type":24,"value":438},"虚拟 DOM 补丁策略",{"type":19,"tag":20,"props":440,"children":441},{},[442],{"type":24,"value":443},"前端接收到流式数据后，并非简单地追加 HTML 字符串，而是通过虚拟 DOM 补丁（Virtual DOM Patching）技术，智能地更新页面结构。",{"type":19,"tag":20,"props":445,"children":446},{},[447],{"type":19,"tag":90,"props":448,"children":449},{},[450],{"type":24,"value":451},"增量更新算法示例",{"type":19,"tag":234,"props":453,"children":457},{"className":454,"code":455,"language":456,"meta":7,"style":7},"language-typescript shiki shiki-themes github-dark github-dark","class IncrementalRenderer {\n  constructor(container) {\n    this.vdom = null;\n    this.container = container;\n  }\n\n  // 处理 SSE 消息\n  onPatchReceived(patch) {\n    // 1. 应用 JSON Patch 到当前状态\n    const nextState = applyPatch(this.currentState, patch);\n    \n    // 2. 生成新的虚拟 DOM\n    const nextVdom = renderToVdom(nextState);\n    \n    // 3. 计算最小差异 (Diff)\n    const diff = diffVdom(this.vdom, nextVdom);\n    \n    // 4. 仅更新变动的 DOM 节点\n    patchDom(this.container, diff);\n    \n    // 5. 更新引用\n    this.vdom = nextVdom;\n    this.currentState = nextState;\n  }\n}\n","typescript",[458],{"type":19,"tag":241,"props":459,"children":460},{"__ignoreMap":7},[461,481,505,534,555,563,570,579,600,608,645,652,660,686,693,701,735,742,750,771,778,787,808,830,838],{"type":19,"tag":245,"props":462,"children":463},{"class":247,"line":248},[464,470,476],{"type":19,"tag":245,"props":465,"children":467},{"style":466},"--shiki-default:#F97583;--shiki-dark:#F97583",[468],{"type":24,"value":469},"class",{"type":19,"tag":245,"props":471,"children":473},{"style":472},"--shiki-default:#B392F0;--shiki-dark:#B392F0",[474],{"type":24,"value":475}," IncrementalRenderer",{"type":19,"tag":245,"props":477,"children":478},{"style":252},[479],{"type":24,"value":480}," {\n",{"type":19,"tag":245,"props":482,"children":483},{"class":247,"line":258},[484,489,494,500],{"type":19,"tag":245,"props":485,"children":486},{"style":466},[487],{"type":24,"value":488},"  constructor",{"type":19,"tag":245,"props":490,"children":491},{"style":252},[492],{"type":24,"value":493},"(",{"type":19,"tag":245,"props":495,"children":497},{"style":496},"--shiki-default:#FFAB70;--shiki-dark:#FFAB70",[498],{"type":24,"value":499},"container",{"type":19,"tag":245,"props":501,"children":502},{"style":252},[503],{"type":24,"value":504},") {\n",{"type":19,"tag":245,"props":506,"children":507},{"class":247,"line":267},[508,514,519,524,529],{"type":19,"tag":245,"props":509,"children":511},{"style":510},"--shiki-default:#79B8FF;--shiki-dark:#79B8FF",[512],{"type":24,"value":513},"    this",{"type":19,"tag":245,"props":515,"children":516},{"style":252},[517],{"type":24,"value":518},".vdom ",{"type":19,"tag":245,"props":520,"children":521},{"style":466},[522],{"type":24,"value":523},"=",{"type":19,"tag":245,"props":525,"children":526},{"style":510},[527],{"type":24,"value":528}," null",{"type":19,"tag":245,"props":530,"children":531},{"style":252},[532],{"type":24,"value":533},";\n",{"type":19,"tag":245,"props":535,"children":536},{"class":247,"line":276},[537,541,546,550],{"type":19,"tag":245,"props":538,"children":539},{"style":510},[540],{"type":24,"value":513},{"type":19,"tag":245,"props":542,"children":543},{"style":252},[544],{"type":24,"value":545},".container ",{"type":19,"tag":245,"props":547,"children":548},{"style":466},[549],{"type":24,"value":523},{"type":19,"tag":245,"props":551,"children":552},{"style":252},[553],{"type":24,"value":554}," container;\n",{"type":19,"tag":245,"props":556,"children":557},{"class":247,"line":285},[558],{"type":19,"tag":245,"props":559,"children":560},{"style":252},[561],{"type":24,"value":562},"  }\n",{"type":19,"tag":245,"props":564,"children":565},{"class":247,"line":294},[566],{"type":19,"tag":245,"props":567,"children":568},{"emptyLinePlaceholder":298},[569],{"type":24,"value":301},{"type":19,"tag":245,"props":571,"children":572},{"class":247,"line":304},[573],{"type":19,"tag":245,"props":574,"children":576},{"style":575},"--shiki-default:#6A737D;--shiki-dark:#6A737D",[577],{"type":24,"value":578},"  // 处理 SSE 消息\n",{"type":19,"tag":245,"props":580,"children":581},{"class":247,"line":313},[582,587,591,596],{"type":19,"tag":245,"props":583,"children":584},{"style":472},[585],{"type":24,"value":586},"  onPatchReceived",{"type":19,"tag":245,"props":588,"children":589},{"style":252},[590],{"type":24,"value":493},{"type":19,"tag":245,"props":592,"children":593},{"style":496},[594],{"type":24,"value":595},"patch",{"type":19,"tag":245,"props":597,"children":598},{"style":252},[599],{"type":24,"value":504},{"type":19,"tag":245,"props":601,"children":602},{"class":247,"line":322},[603],{"type":19,"tag":245,"props":604,"children":605},{"style":575},[606],{"type":24,"value":607},"    // 1. 应用 JSON Patch 到当前状态\n",{"type":19,"tag":245,"props":609,"children":610},{"class":247,"line":331},[611,616,621,626,631,635,640],{"type":19,"tag":245,"props":612,"children":613},{"style":466},[614],{"type":24,"value":615},"    const",{"type":19,"tag":245,"props":617,"children":618},{"style":510},[619],{"type":24,"value":620}," nextState",{"type":19,"tag":245,"props":622,"children":623},{"style":466},[624],{"type":24,"value":625}," =",{"type":19,"tag":245,"props":627,"children":628},{"style":472},[629],{"type":24,"value":630}," applyPatch",{"type":19,"tag":245,"props":632,"children":633},{"style":252},[634],{"type":24,"value":493},{"type":19,"tag":245,"props":636,"children":637},{"style":510},[638],{"type":24,"value":639},"this",{"type":19,"tag":245,"props":641,"children":642},{"style":252},[643],{"type":24,"value":644},".currentState, patch);\n",{"type":19,"tag":245,"props":646,"children":647},{"class":247,"line":340},[648],{"type":19,"tag":245,"props":649,"children":650},{"style":252},[651],{"type":24,"value":337},{"type":19,"tag":245,"props":653,"children":654},{"class":247,"line":349},[655],{"type":19,"tag":245,"props":656,"children":657},{"style":575},[658],{"type":24,"value":659},"    // 2. 生成新的虚拟 DOM\n",{"type":19,"tag":245,"props":661,"children":662},{"class":247,"line":358},[663,667,672,676,681],{"type":19,"tag":245,"props":664,"children":665},{"style":466},[666],{"type":24,"value":615},{"type":19,"tag":245,"props":668,"children":669},{"style":510},[670],{"type":24,"value":671}," nextVdom",{"type":19,"tag":245,"props":673,"children":674},{"style":466},[675],{"type":24,"value":625},{"type":19,"tag":245,"props":677,"children":678},{"style":472},[679],{"type":24,"value":680}," renderToVdom",{"type":19,"tag":245,"props":682,"children":683},{"style":252},[684],{"type":24,"value":685},"(nextState);\n",{"type":19,"tag":245,"props":687,"children":688},{"class":247,"line":367},[689],{"type":19,"tag":245,"props":690,"children":691},{"style":252},[692],{"type":24,"value":337},{"type":19,"tag":245,"props":694,"children":695},{"class":247,"line":376},[696],{"type":19,"tag":245,"props":697,"children":698},{"style":575},[699],{"type":24,"value":700},"    // 3. 计算最小差异 (Diff)\n",{"type":19,"tag":245,"props":702,"children":703},{"class":247,"line":385},[704,708,713,717,722,726,730],{"type":19,"tag":245,"props":705,"children":706},{"style":466},[707],{"type":24,"value":615},{"type":19,"tag":245,"props":709,"children":710},{"style":510},[711],{"type":24,"value":712}," diff",{"type":19,"tag":245,"props":714,"children":715},{"style":466},[716],{"type":24,"value":625},{"type":19,"tag":245,"props":718,"children":719},{"style":472},[720],{"type":24,"value":721}," diffVdom",{"type":19,"tag":245,"props":723,"children":724},{"style":252},[725],{"type":24,"value":493},{"type":19,"tag":245,"props":727,"children":728},{"style":510},[729],{"type":24,"value":639},{"type":19,"tag":245,"props":731,"children":732},{"style":252},[733],{"type":24,"value":734},".vdom, nextVdom);\n",{"type":19,"tag":245,"props":736,"children":737},{"class":247,"line":394},[738],{"type":19,"tag":245,"props":739,"children":740},{"style":252},[741],{"type":24,"value":337},{"type":19,"tag":245,"props":743,"children":744},{"class":247,"line":403},[745],{"type":19,"tag":245,"props":746,"children":747},{"style":575},[748],{"type":24,"value":749},"    // 4. 仅更新变动的 DOM 节点\n",{"type":19,"tag":245,"props":751,"children":752},{"class":247,"line":411},[753,758,762,766],{"type":19,"tag":245,"props":754,"children":755},{"style":472},[756],{"type":24,"value":757},"    patchDom",{"type":19,"tag":245,"props":759,"children":760},{"style":252},[761],{"type":24,"value":493},{"type":19,"tag":245,"props":763,"children":764},{"style":510},[765],{"type":24,"value":639},{"type":19,"tag":245,"props":767,"children":768},{"style":252},[769],{"type":24,"value":770},".container, diff);\n",{"type":19,"tag":245,"props":772,"children":773},{"class":247,"line":420},[774],{"type":19,"tag":245,"props":775,"children":776},{"style":252},[777],{"type":24,"value":337},{"type":19,"tag":245,"props":779,"children":781},{"class":247,"line":780},21,[782],{"type":19,"tag":245,"props":783,"children":784},{"style":575},[785],{"type":24,"value":786},"    // 5. 更新引用\n",{"type":19,"tag":245,"props":788,"children":790},{"class":247,"line":789},22,[791,795,799,803],{"type":19,"tag":245,"props":792,"children":793},{"style":510},[794],{"type":24,"value":513},{"type":19,"tag":245,"props":796,"children":797},{"style":252},[798],{"type":24,"value":518},{"type":19,"tag":245,"props":800,"children":801},{"style":466},[802],{"type":24,"value":523},{"type":19,"tag":245,"props":804,"children":805},{"style":252},[806],{"type":24,"value":807}," nextVdom;\n",{"type":19,"tag":245,"props":809,"children":811},{"class":247,"line":810},23,[812,816,821,825],{"type":19,"tag":245,"props":813,"children":814},{"style":510},[815],{"type":24,"value":513},{"type":19,"tag":245,"props":817,"children":818},{"style":252},[819],{"type":24,"value":820},".currentState ",{"type":19,"tag":245,"props":822,"children":823},{"style":466},[824],{"type":24,"value":523},{"type":19,"tag":245,"props":826,"children":827},{"style":252},[828],{"type":24,"value":829}," nextState;\n",{"type":19,"tag":245,"props":831,"children":833},{"class":247,"line":832},24,[834],{"type":19,"tag":245,"props":835,"children":836},{"style":252},[837],{"type":24,"value":562},{"type":19,"tag":245,"props":839,"children":841},{"class":247,"line":840},25,[842],{"type":19,"tag":245,"props":843,"children":844},{"style":252},[845],{"type":24,"value":846},"}\n",{"type":19,"tag":34,"props":848,"children":850},{"id":849},"渐进式水合-progressive-hydration",[851],{"type":24,"value":852},"渐进式水合 (Progressive Hydration)",{"type":19,"tag":20,"props":854,"children":855},{},[856],{"type":24,"value":857},"为了提升交互性能，我们采用了渐进式水合策略。",{"type":19,"tag":199,"props":859,"children":860},{},[861,871,881],{"type":19,"tag":203,"props":862,"children":863},{},[864,869],{"type":19,"tag":90,"props":865,"children":866},{},[867],{"type":24,"value":868},"骨架屏 (Skeleton)",{"type":24,"value":870},"：连接建立瞬间，立即渲染页面骨架。",{"type":19,"tag":203,"props":872,"children":873},{},[874,879],{"type":19,"tag":90,"props":875,"children":876},{},[877],{"type":24,"value":878},"静态内容 (Static Content)",{"type":24,"value":880},"：优先渲染文本、图片占位符等静态资源。",{"type":19,"tag":203,"props":882,"children":883},{},[884,889],{"type":19,"tag":90,"props":885,"children":886},{},[887],{"type":24,"value":888},"交互逻辑 (Interactivity)",{"type":24,"value":890},"：当组件结构渲染完成后，异步加载并激活对应的 JavaScript 逻辑。",{"type":19,"tag":27,"props":892,"children":894},{"id":893},"️-容错与状态恢复",[895],{"type":24,"value":896},"🛡️ 容错与状态恢复",{"type":19,"tag":34,"props":898,"children":900},{"id":899},"智能断点续传",[901],{"type":24,"value":899},{"type":19,"tag":20,"props":903,"children":904},{},[905,907,913],{"type":24,"value":906},"网络波动是流式传输的大敌。我们设计了基于 ",{"type":19,"tag":241,"props":908,"children":910},{"className":909},[],[911],{"type":24,"value":912},"Last-Event-ID",{"type":24,"value":914}," 的断点续传机制。",{"type":19,"tag":916,"props":917,"children":918},"ul",{},[919,929,945],{"type":19,"tag":203,"props":920,"children":921},{},[922,927],{"type":19,"tag":90,"props":923,"children":924},{},[925],{"type":24,"value":926},"服务端缓存",{"type":24,"value":928},"：服务端会缓存最近 1 分钟的生成流数据。",{"type":19,"tag":203,"props":930,"children":931},{},[932,936,938,943],{"type":19,"tag":90,"props":933,"children":934},{},[935],{"type":24,"value":146},{"type":24,"value":937},"：当连接断开时，浏览器会自动发起重连，并带上 ",{"type":19,"tag":241,"props":939,"children":941},{"className":940},[],[942],{"type":24,"value":912},{"type":24,"value":944},"。",{"type":19,"tag":203,"props":946,"children":947},{},[948,953],{"type":19,"tag":90,"props":949,"children":950},{},[951],{"type":24,"value":952},"无缝恢复",{"type":24,"value":954},"：服务端根据 ID 补发丢失的数据包，前端无感知地继续渲染。",{"type":19,"tag":34,"props":956,"children":958},{"id":957},"乱序处理",[959],{"type":24,"value":957},{"type":19,"tag":20,"props":961,"children":962},{},[963],{"type":24,"value":964},"虽然 TCP 保证了包序，但在复杂的网络环境下（如 HTTP/3 UDP），应用层仍需处理潜在的数据一致性问题。",{"type":19,"tag":916,"props":966,"children":967},{},[968,985],{"type":19,"tag":203,"props":969,"children":970},{},[971,976,978,984],{"type":19,"tag":90,"props":972,"children":973},{},[974],{"type":24,"value":975},"序列号校验",{"type":24,"value":977},"：每个 SSE 事件都带有递增的 ",{"type":19,"tag":241,"props":979,"children":981},{"className":980},[],[982],{"type":24,"value":983},"seq_id",{"type":24,"value":944},{"type":19,"tag":203,"props":986,"children":987},{},[988,993,995,1000],{"type":19,"tag":90,"props":989,"children":990},{},[991],{"type":24,"value":992},"缓冲队列",{"type":24,"value":994},"：前端维护一个缓冲队列，确保严格按 ",{"type":19,"tag":241,"props":996,"children":998},{"className":997},[],[999],{"type":24,"value":983},{"type":24,"value":1001}," 顺序处理事件。",{"type":19,"tag":27,"props":1003,"children":1005},{"id":1004},"性能优化策略",[1006],{"type":24,"value":1007},"🚀 性能优化策略",{"type":19,"tag":34,"props":1009,"children":1011},{"id":1010},"背压控制-backpressure",[1012],{"type":24,"value":1013},"背压控制 (Backpressure)",{"type":19,"tag":20,"props":1015,"children":1016},{},[1017],{"type":24,"value":1018},"当生成速度超过前端渲染速度时（例如在低端移动设备上），会导致 UI 卡顿。我们实现了应用层的背压控制。",{"type":19,"tag":234,"props":1020,"children":1024},{"className":1021,"code":1022,"language":1023,"meta":7,"style":7},"language-javascript shiki shiki-themes github-dark github-dark","// 前端流控制器\nconst streamController = new WritableStream({\n  write(chunk) {\n    // 如果渲染队列过长，暂停读取流\n    if (renderQueue.length > HIGH_WATER_MARK) {\n      return new Promise(resolve => {\n        eventBus.once('drain', resolve);\n      });\n    }\n    processChunk(chunk);\n  }\n});\n","javascript",[1025],{"type":19,"tag":241,"props":1026,"children":1027},{"__ignoreMap":7},[1028,1036,1068,1089,1097,1129,1164,1192,1200,1208,1221,1228],{"type":19,"tag":245,"props":1029,"children":1030},{"class":247,"line":248},[1031],{"type":19,"tag":245,"props":1032,"children":1033},{"style":575},[1034],{"type":24,"value":1035},"// 前端流控制器\n",{"type":19,"tag":245,"props":1037,"children":1038},{"class":247,"line":258},[1039,1044,1049,1053,1058,1063],{"type":19,"tag":245,"props":1040,"children":1041},{"style":466},[1042],{"type":24,"value":1043},"const",{"type":19,"tag":245,"props":1045,"children":1046},{"style":510},[1047],{"type":24,"value":1048}," streamController",{"type":19,"tag":245,"props":1050,"children":1051},{"style":466},[1052],{"type":24,"value":625},{"type":19,"tag":245,"props":1054,"children":1055},{"style":466},[1056],{"type":24,"value":1057}," new",{"type":19,"tag":245,"props":1059,"children":1060},{"style":472},[1061],{"type":24,"value":1062}," WritableStream",{"type":19,"tag":245,"props":1064,"children":1065},{"style":252},[1066],{"type":24,"value":1067},"({\n",{"type":19,"tag":245,"props":1069,"children":1070},{"class":247,"line":267},[1071,1076,1080,1085],{"type":19,"tag":245,"props":1072,"children":1073},{"style":472},[1074],{"type":24,"value":1075},"  write",{"type":19,"tag":245,"props":1077,"children":1078},{"style":252},[1079],{"type":24,"value":493},{"type":19,"tag":245,"props":1081,"children":1082},{"style":496},[1083],{"type":24,"value":1084},"chunk",{"type":19,"tag":245,"props":1086,"children":1087},{"style":252},[1088],{"type":24,"value":504},{"type":19,"tag":245,"props":1090,"children":1091},{"class":247,"line":276},[1092],{"type":19,"tag":245,"props":1093,"children":1094},{"style":575},[1095],{"type":24,"value":1096},"    // 如果渲染队列过长，暂停读取流\n",{"type":19,"tag":245,"props":1098,"children":1099},{"class":247,"line":285},[1100,1105,1110,1115,1120,1125],{"type":19,"tag":245,"props":1101,"children":1102},{"style":466},[1103],{"type":24,"value":1104},"    if",{"type":19,"tag":245,"props":1106,"children":1107},{"style":252},[1108],{"type":24,"value":1109}," (renderQueue.",{"type":19,"tag":245,"props":1111,"children":1112},{"style":510},[1113],{"type":24,"value":1114},"length",{"type":19,"tag":245,"props":1116,"children":1117},{"style":466},[1118],{"type":24,"value":1119}," >",{"type":19,"tag":245,"props":1121,"children":1122},{"style":510},[1123],{"type":24,"value":1124}," HIGH_WATER_MARK",{"type":19,"tag":245,"props":1126,"children":1127},{"style":252},[1128],{"type":24,"value":504},{"type":19,"tag":245,"props":1130,"children":1131},{"class":247,"line":294},[1132,1137,1141,1146,1150,1155,1160],{"type":19,"tag":245,"props":1133,"children":1134},{"style":466},[1135],{"type":24,"value":1136},"      return",{"type":19,"tag":245,"props":1138,"children":1139},{"style":466},[1140],{"type":24,"value":1057},{"type":19,"tag":245,"props":1142,"children":1143},{"style":510},[1144],{"type":24,"value":1145}," Promise",{"type":19,"tag":245,"props":1147,"children":1148},{"style":252},[1149],{"type":24,"value":493},{"type":19,"tag":245,"props":1151,"children":1152},{"style":496},[1153],{"type":24,"value":1154},"resolve",{"type":19,"tag":245,"props":1156,"children":1157},{"style":466},[1158],{"type":24,"value":1159}," =>",{"type":19,"tag":245,"props":1161,"children":1162},{"style":252},[1163],{"type":24,"value":480},{"type":19,"tag":245,"props":1165,"children":1166},{"class":247,"line":304},[1167,1172,1177,1181,1187],{"type":19,"tag":245,"props":1168,"children":1169},{"style":252},[1170],{"type":24,"value":1171},"        eventBus.",{"type":19,"tag":245,"props":1173,"children":1174},{"style":472},[1175],{"type":24,"value":1176},"once",{"type":19,"tag":245,"props":1178,"children":1179},{"style":252},[1180],{"type":24,"value":493},{"type":19,"tag":245,"props":1182,"children":1184},{"style":1183},"--shiki-default:#9ECBFF;--shiki-dark:#9ECBFF",[1185],{"type":24,"value":1186},"'drain'",{"type":19,"tag":245,"props":1188,"children":1189},{"style":252},[1190],{"type":24,"value":1191},", resolve);\n",{"type":19,"tag":245,"props":1193,"children":1194},{"class":247,"line":313},[1195],{"type":19,"tag":245,"props":1196,"children":1197},{"style":252},[1198],{"type":24,"value":1199},"      });\n",{"type":19,"tag":245,"props":1201,"children":1202},{"class":247,"line":322},[1203],{"type":19,"tag":245,"props":1204,"children":1205},{"style":252},[1206],{"type":24,"value":1207},"    }\n",{"type":19,"tag":245,"props":1209,"children":1210},{"class":247,"line":331},[1211,1216],{"type":19,"tag":245,"props":1212,"children":1213},{"style":472},[1214],{"type":24,"value":1215},"    processChunk",{"type":19,"tag":245,"props":1217,"children":1218},{"style":252},[1219],{"type":24,"value":1220},"(chunk);\n",{"type":19,"tag":245,"props":1222,"children":1223},{"class":247,"line":340},[1224],{"type":19,"tag":245,"props":1225,"children":1226},{"style":252},[1227],{"type":24,"value":562},{"type":19,"tag":245,"props":1229,"children":1230},{"class":247,"line":349},[1231],{"type":19,"tag":245,"props":1232,"children":1233},{"style":252},[1234],{"type":24,"value":1235},"});\n",{"type":19,"tag":34,"props":1237,"children":1239},{"id":1238},"智能分块-smart-chunking",[1240],{"type":24,"value":1241},"智能分块 (Smart Chunking)",{"type":19,"tag":20,"props":1243,"children":1244},{},[1245],{"type":24,"value":1246},"服务端不会每生成一个字符就发送一次 SSE 事件，而是采用智能分块策略，平衡实时性与网络开销。",{"type":19,"tag":916,"props":1248,"children":1249},{},[1250,1260],{"type":19,"tag":203,"props":1251,"children":1252},{},[1253,1258],{"type":19,"tag":90,"props":1254,"children":1255},{},[1256],{"type":24,"value":1257},"语义分块",{"type":24,"value":1259},"：尽量在完整的单词、HTML 标签或句子结束时发送数据包。",{"type":19,"tag":203,"props":1261,"children":1262},{},[1263,1268],{"type":19,"tag":90,"props":1264,"children":1265},{},[1266],{"type":24,"value":1267},"自适应频率",{"type":24,"value":1269},"：根据网络 RTT 动态调整发送频率（如：50ms - 200ms）。",{"type":19,"tag":27,"props":1271,"children":1273},{"id":1272},"用户体验设计",[1274],{"type":24,"value":1275},"📊 用户体验设计",{"type":19,"tag":34,"props":1277,"children":1279},{"id":1278},"视觉平滑处理",[1280],{"type":24,"value":1278},{"type":19,"tag":20,"props":1282,"children":1283},{},[1284],{"type":24,"value":1285},"为了避免文字逐字跳动带来的视觉疲劳，前端实现了\"打字机平滑效果\"。",{"type":19,"tag":234,"props":1287,"children":1291},{"className":1288,"code":1289,"language":1290,"meta":7,"style":7},"language-css shiki shiki-themes github-dark github-dark","/* CSS 动画平滑过渡 */\n.streaming-text-cursor::after {\n  content: '|';\n  animation: blink 1s step-end infinite;\n}\n\n.new-content-fade-in {\n  animation: fadeIn 0.3s ease-out;\n}\n","css",[1292],{"type":19,"tag":241,"props":1293,"children":1294},{"__ignoreMap":7},[1295,1303,1315,1337,1378,1385,1392,1404,1434],{"type":19,"tag":245,"props":1296,"children":1297},{"class":247,"line":248},[1298],{"type":19,"tag":245,"props":1299,"children":1300},{"style":575},[1301],{"type":24,"value":1302},"/* CSS 动画平滑过渡 */\n",{"type":19,"tag":245,"props":1304,"children":1305},{"class":247,"line":258},[1306,1311],{"type":19,"tag":245,"props":1307,"children":1308},{"style":472},[1309],{"type":24,"value":1310},".streaming-text-cursor::after",{"type":19,"tag":245,"props":1312,"children":1313},{"style":252},[1314],{"type":24,"value":480},{"type":19,"tag":245,"props":1316,"children":1317},{"class":247,"line":267},[1318,1323,1328,1333],{"type":19,"tag":245,"props":1319,"children":1320},{"style":510},[1321],{"type":24,"value":1322},"  content",{"type":19,"tag":245,"props":1324,"children":1325},{"style":252},[1326],{"type":24,"value":1327},": ",{"type":19,"tag":245,"props":1329,"children":1330},{"style":1183},[1331],{"type":24,"value":1332},"'|'",{"type":19,"tag":245,"props":1334,"children":1335},{"style":252},[1336],{"type":24,"value":533},{"type":19,"tag":245,"props":1338,"children":1339},{"class":247,"line":276},[1340,1345,1349,1354,1359,1364,1369,1374],{"type":19,"tag":245,"props":1341,"children":1342},{"style":510},[1343],{"type":24,"value":1344},"  animation",{"type":19,"tag":245,"props":1346,"children":1347},{"style":252},[1348],{"type":24,"value":1327},{"type":19,"tag":245,"props":1350,"children":1351},{"style":510},[1352],{"type":24,"value":1353},"blink",{"type":19,"tag":245,"props":1355,"children":1356},{"style":510},[1357],{"type":24,"value":1358}," 1",{"type":19,"tag":245,"props":1360,"children":1361},{"style":466},[1362],{"type":24,"value":1363},"s",{"type":19,"tag":245,"props":1365,"children":1366},{"style":510},[1367],{"type":24,"value":1368}," step-end",{"type":19,"tag":245,"props":1370,"children":1371},{"style":510},[1372],{"type":24,"value":1373}," infinite",{"type":19,"tag":245,"props":1375,"children":1376},{"style":252},[1377],{"type":24,"value":533},{"type":19,"tag":245,"props":1379,"children":1380},{"class":247,"line":285},[1381],{"type":19,"tag":245,"props":1382,"children":1383},{"style":252},[1384],{"type":24,"value":846},{"type":19,"tag":245,"props":1386,"children":1387},{"class":247,"line":294},[1388],{"type":19,"tag":245,"props":1389,"children":1390},{"emptyLinePlaceholder":298},[1391],{"type":24,"value":301},{"type":19,"tag":245,"props":1393,"children":1394},{"class":247,"line":304},[1395,1400],{"type":19,"tag":245,"props":1396,"children":1397},{"style":472},[1398],{"type":24,"value":1399},".new-content-fade-in",{"type":19,"tag":245,"props":1401,"children":1402},{"style":252},[1403],{"type":24,"value":480},{"type":19,"tag":245,"props":1405,"children":1406},{"class":247,"line":313},[1407,1411,1416,1421,1425,1430],{"type":19,"tag":245,"props":1408,"children":1409},{"style":510},[1410],{"type":24,"value":1344},{"type":19,"tag":245,"props":1412,"children":1413},{"style":252},[1414],{"type":24,"value":1415},": fadeIn ",{"type":19,"tag":245,"props":1417,"children":1418},{"style":510},[1419],{"type":24,"value":1420},"0.3",{"type":19,"tag":245,"props":1422,"children":1423},{"style":466},[1424],{"type":24,"value":1363},{"type":19,"tag":245,"props":1426,"children":1427},{"style":510},[1428],{"type":24,"value":1429}," ease-out",{"type":19,"tag":245,"props":1431,"children":1432},{"style":252},[1433],{"type":24,"value":533},{"type":19,"tag":245,"props":1435,"children":1436},{"class":247,"line":322},[1437],{"type":19,"tag":245,"props":1438,"children":1439},{"style":252},[1440],{"type":24,"value":846},{"type":19,"tag":34,"props":1442,"children":1444},{"id":1443},"进度预估",[1445],{"type":24,"value":1443},{"type":19,"tag":20,"props":1447,"children":1448},{},[1449],{"type":24,"value":1450},"虽然流式生成没有确定的结束时间，但我们通过训练一个轻量级的预测模型，根据 Prompt 复杂度和当前生成速度，实时估算剩余时间，缓解用户等待焦虑。",{"type":19,"tag":27,"props":1452,"children":1454},{"id":1453},"相关技术文档",[1455],{"type":24,"value":1456},"🔗 相关技术文档",{"type":19,"tag":916,"props":1458,"children":1459},{},[1460,1470,1479],{"type":19,"tag":203,"props":1461,"children":1462},{},[1463],{"type":19,"tag":1464,"props":1465,"children":1467},"a",{"href":1466},"/ai/real-time-generation.md",[1468],{"type":24,"value":1469},"实时生成架构",{"type":19,"tag":203,"props":1471,"children":1472},{},[1473],{"type":19,"tag":1464,"props":1474,"children":1476},{"href":1475},"/ai/content-generation-engine.md",[1477],{"type":24,"value":1478},"内容生成引擎",{"type":19,"tag":203,"props":1480,"children":1481},{},[1482],{"type":19,"tag":1464,"props":1483,"children":1485},{"href":1484},"/ai/quick-prototype.md",[1486],{"type":24,"value":1487},"快速原型技术",{"type":19,"tag":1489,"props":1490,"children":1491},"hr",{},[],{"type":19,"tag":20,"props":1493,"children":1494},{},[1495],{"type":19,"tag":1496,"props":1497,"children":1498},"em",{},[1499],{"type":24,"value":1500},"流式生成不仅是技术的革新，更是交互范式的升级。HTMLPAGE 让等待不再枯燥，让创作过程本身成为一种享受。",{"type":19,"tag":1502,"props":1503,"children":1504},"style",{},[1505],{"type":24,"value":1506},"html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":7,"searchDepth":267,"depth":267,"links":1508},[1509,1513,1517,1521,1525,1529],{"id":29,"depth":258,"text":32,"children":1510},[1511,1512],{"id":36,"depth":267,"text":39},{"id":190,"depth":267,"text":190},{"id":429,"depth":258,"text":432,"children":1514},[1515,1516],{"id":435,"depth":267,"text":438},{"id":849,"depth":267,"text":852},{"id":893,"depth":258,"text":896,"children":1518},[1519,1520],{"id":899,"depth":267,"text":899},{"id":957,"depth":267,"text":957},{"id":1004,"depth":258,"text":1007,"children":1522},[1523,1524],{"id":1010,"depth":267,"text":1013},{"id":1238,"depth":267,"text":1241},{"id":1272,"depth":258,"text":1275,"children":1526},[1527,1528],{"id":1278,"depth":267,"text":1278},{"id":1443,"depth":267,"text":1443},{"id":1453,"depth":258,"text":1456},"markdown","content:ai:streaming-generation.md","content","ai/streaming-generation.md","ai/streaming-generation","md",[1537,1548,1557],{"_path":1538,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1539,"description":1540,"keywords":1541,"schemaType":1542,"author":11,"date":1543,"image":1544,"_type":1530,"_id":1545,"_source":1532,"_file":1546,"_stem":1547,"_extension":1535},"/ai/architecture-overview","AI架构概述 - HTMLPAGE智能网页生成系统","HTMLPAGE AI系统架构深度解析，了解多智能体协作、实时流式生成、模块化组装等核心技术，探索AI如何革新网页设计流程。","AI网页生成, 多智能体系统, 实时流式AI, 智能网页设计, AI架构, 机器学习","TechArticle","2025-11-24","/content-images/ai/architecture-overview.jpg","content:ai:architecture-overview.md","ai/architecture-overview.md","ai/architecture-overview",{"_path":1549,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1550,"description":1551,"keywords":1552,"author":11,"date":12,"category":1553,"image":14,"_type":1530,"_id":1554,"_source":1532,"_file":1555,"_stem":1556,"_extension":1535},"/ai/batch-creation","批量页面创建","模板 + 提示词模式组合进行多页面高效率生成","批量页面创建, 批量生成, 提示词模板, HTMLPAGE","应用场景","content:ai:batch-creation.md","ai/batch-creation.md","ai/batch-creation",{"_path":1558,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":1559,"description":1560,"keywords":1561,"author":11,"date":12,"category":1562,"image":14,"_type":1530,"_id":1563,"_source":1532,"_file":1564,"_stem":1565,"_extension":1535},"/ai/case-studies","AI 案例研究","HTMLPAGE AI 在不同行业和场景中的成功应用案例","AI 案例研究, 成功案例, 页面生成, HTMLPAGE","案例研究","content:ai:case-studies.md","ai/case-studies.md","ai/case-studies",1774945280256]