218、【AI】【模型部署】Notebook 源码拆解:输出 data 的多格式与前端择优渲染
2026/9/12 19:41:02 网站建设 项目流程

【声明】本博客所有内容均为个人业余时间创作,所述技术案例均来自公开开源项目(如Github,Apache基金会),不涉及任何企业机密或未公开技术,如有侵权请联系删除

标题

218、【AI】【模型部署】Notebook 源码拆解:输出 data 的多格式与前端择优渲染

背景

上篇 blog
【AI】【模型部署】Notebook 源码拆解:.ipynb 文档到底长什么样
解剖了.ipynb:outputs 有 execute_result/display_data/stream 等类型;execute_result 与 display_data 的data是"按 mime 类型分键"的字典(IMimeBundle,index.ts:71-73);validateMimeValue规定"JSON 型 mime 只许对象、非 JSON 型许字符串/数组"(只一句带过);真实样例里 data 同时出现text/htmlimage/svg+xmlimage/jpeg等 mime。217 到此为止——"为什么同一份结果要存多个 mime 版本、前端到底怎么挑、挑完怎么渲染"三个问题没展开。本篇补上:先讲清 mime 是什么,再用源码把"多格式 data → 择优 → 渲染"这条链拆开

模型部署

在 Notebook 里,一个display_data可以既带网页版又带纯文本版,文件里存的不是"一份输出",而是一组按格式分键的候选。为什么这么设计、代码怎么选的——从"mime 是什么"讲起。


💡mime 是什么:给数据贴"怎么解读"的标签

mime 是Multipurpose Internet Mail Extensions(多用途互联网邮件扩展)的缩写,起源于电子邮件——用它给附件/正文标格式;后来被 HTTP 借去当Content-Type,成为互联网通用约定。写法是"类别/子类":

mime中文含义在 Notebook 里出现于
text/plain纯文本所有输出的兜底
text/html网页标记(可渲染富内容)富文本输出
text/markdown标记文本Markdown 渲染
image/png/image/jpeg位图图片输出
image/svg+xml矢量图矢量图形
application/pdf文档PDF 渲染

一句话:mime 是数据的"格式身份证",告诉接收方"这段内容该按什么格式解读"。


🔍同一份结果,为什么存多个格式

解剖 jupyterlab 自带的examples/notebooks/OutputExamples.ipynb(统计共16 个输出带 ≥2 个 mime),挑 cell 12 的execute_result,它的data长这样:

{"text/html":["<div style=\"width:100px;height:100px;background:red\"></div>"],"text/plain":["<IPython.core.display.HTML object>"]}

两份值表达的是同一个 HTML 对象text/html版是可渲染的网页片段(这里是一个红色方块 div),text/plain版是对象的普通字符串表示(<IPython.core.display.HTML object>)。设计意图是给"不会渲染 HTML"的接收端留退路——终端、老版本界面看到 plain 版也能知道"这里有个 HTML 对象"。这就是"多格式并存"存在的理由:富表达优先、兜底保底。


🧩data 的字段树与值类型约束

data在源码里是"mime 为键、值为内容"的字典(nbformatindex.ts:71-73):

exportinterfaceIMimeBundleextendsPartialJSONObject{[key:string]:MultilineString|PartialJSONObject;}

值允许两种:**多行字符串(string | string[])**或JSON 对象。哪个 mime 允许哪种值,由validateMimeValue(nbformatindex.ts:101-140)裁决,核心逻辑可用一段伪码还原:

jsonTest = mime 形如 application/json 或 application/*+json? 若 值是数组 → 仅当 非 JSON 型 mime,且元素全是字符串,才合法 若 值是字符串 → 仅当 非 JSON 型 mime 若 值是对象 → 仅当 JSON 型 mime,且是合法 JSON 对象

规则本质是防错位:JSON 型 mime 的数据就该是结构化的 JSON 对象,不能塞字符串;图片/文本类 mime 的值才允许是字符串或多行字符串。真实样例里的值都是"单元素数组"——["<div…>"]["<IPython…>"],正是多行字符串的数组形态。


🧩前端侧一:每种 mime 挂一个"渲染工厂"

数据侧定了格式,前端侧要有能渲染每种格式的工人——rendermime/src/factories.ts注册了一批标准工厂,每种 mime 声明它服务哪些类型、安不安全、默认排第几(数值越小越优先):

渲染器mimedefaultRanksafe说明
RenderedHTMLtext/html50富文本最高优先
RenderedMarkdowntext/markdown60
RenderedLatextext/latex70
RenderedSVGimage/svg+xml80SVG 可嵌脚本
RenderedImageimage/png 等90
RenderedTexttext/plain 等120兜底
RenderedJavaScripttext/javascript110能执行代码
// factories.ts:11-15 的 HTML 工厂结构(示意关键字段){mimeTypes:['text/html'],defaultRank:50,safe:true,createRenderer:options=>newwidgets.RenderedHTML(options)}

safe是关键标记:能跑脚本/嵌入外链的格式(HTML、SVG、JavaScript)被标记为不安全,渲染与否取决于文档是否受信任——后面择优逻辑会用到。


🧩前端侧二:择优算法 preferredMimeType

"挑哪个格式渲染"的核心在rendermime/src/registry.ts:105-129preferredMimeType:它按排序后的 mime 列表从前到后找,谁的键在 data 里出现就返回谁。下面是该函数去掉注释后的主体(registry.ts:110-125):

if(safe==='ensure'||safe==='prefer'){for(constmtofthis.mimeTypes)if(mtinbundle&&this._factories[mt].safe)returnmt;// 第一轮只认安全}if(safe!=='ensure'){for(constmtofthis.mimeTypes)if(mtinbundle)returnmt;// 第二轮全放行}returnundefined;

“排序后的列表"由sortedTypes(registry.ts:645-654)决定:rank 小的在前,rank 相同按注册先后;工厂注册时若没给 rank 默认取 100(registry.ts:225-237)。回看 cell 12 的{text/html, text/plain}:text/html rank=50、text/plain rank=120,html 排前面且 data 里有 → 返回text/html。整条判断就是一次"排好序的查表”。


🧩渲染主链与"信任"开关

择优结果在哪一步被用上?outputarea/src/widget.ts:785-800createRenderedMimetype是主链:

// outputarea/src/widget.ts:786-794(略注释)constmimeType=this.rendermime.preferredMimeType(model.data,model.trusted?'any':'ensure'// 信不信任决定放行范围);if(!mimeType){returnnull;}// 一个都渲染不了 → 跳过letoutput=this.rendermime.createRenderer(mimeType);

信任开关在此落地:cell 元数据里的trusted(217 提过的字段)为真时用'any'(html/svg/js 都能渲染),否则用'ensure'(只允许安全工厂)。拿 cell 29 的{image/svg+xml, text/plain}推演:svg rank=80 但在第一轮 safe 检查中被跳过,text/plain rank=120 反而胜出——于是未信任的 Notebook 里 SVG 图不会渲染、只显示文本;点"信任"后才轮到 svg 渲染。安全不是靠禁止,而是靠"信任前只给看安全版本"。


📊小结:一条 data 的一生

环节位置干了什么
数据侧nbformatIMimeBundle一份结果存成 {mime: 值} 字典
校验nbformatvalidateMimeValue保证值与 mime 类型匹配
候选rendermime 工厂表每种 mime 绑一个渲染器 + rank + safe
择优registrypreferredMimeType按 rank 排序,信任决定放行范围
渲染outputareacreateRenderedMimetype挑中 → createRenderer → 塞进 cell

📌一句话记忆

mime(Multipurpose Internet Mail Extensions,多用途互联网邮件扩展)是数据的"格式身份证";Notebook 的 output data 是 {mime: 值} 字典,一份结果可存 HTML 富版 + plain 兜底版;前端每种 mime 挂一个带 rank 与 safe 标记的渲染工厂,preferredMimeType按 rank 排序查表、trusted为真才放行 html/svg/js 等不安全渲染——多格式是为了"富表达 + 降级兜底",择优与信任开关保证安全。


OK,本篇先到这里,如有疑问,欢迎评论区留言讨论,祝各位功力大涨,技术更上一层楼!!!更多内容见下篇 blog
【AI】【模型部署】装库前先“隔离“:venv 虚拟环境从概念到落地

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询