- 大模型
- 提示工程
- AI Agent
【免费下载链接】guidance
A guidance language for controlling large language models.
导读
stitch是 guidance 项目官方仓库中附带的一个 Jupyter Widget 包,它提供一条Jupyter(Python 内核)与 JavaScript 之间的双向通信通道:Python 侧可以通过内核往页面里的 iframe 发送消息,iframe 内的 JavaScript 也可以把消息传回内核,从而在 Notebook 中嵌入可交互的 HTML/JS 界面并与之实时交换数据。读完本文,你将掌握 stitch 的安装与前端扩展配置、StitchWidget的完整属性用法、基于postMessage的双向通信协议,以及如何进行开发者模式安装与调试。
一、stitch 是什么:为"内核 ↔ 页面"搭建双向消息桥
stitch 的核心定位一句话即可概括——"Bidirectional comms for Jupyter and JavaScript."(Jupyter 与 JavaScript 的双向通信)。它不是一个通用的 UI 组件库,而是一个纯通信层组件:StitchWidget在 Notebook 输出区创建一个沙箱 iframe,并以postMessage为媒介,把 Python 内核的字符串消息转发进 iframe,同时把 iframe 内产生的消息回传内核。这一点在 Python 侧类定义中写得非常直白:
"Widget that purely handles communication between an iframe and kernel via postMessage." —— stitch/stitch.py
从源码结构看,该包由三部分协作组成:
| 组成部分 | 仓库中的位置 | 职责 |
|---|---|---|
| Python 侧 Widget | stitch/stitch.py | 定义StitchWidget及其同步属性,作为内核侧收发消息的端口 |
| TypeScript 前端 | src/widget.ts | 渲染 iframe、监听message事件、在模型与 iframe 之间转发消息 |
| 扩展注册入口 | stitch/init.py | 向 Jupyter 声明 labextension / nbextension 的安装路径 |
需要特别说明的是:缝合(stitch)只负责"通信"本身,不限制 iframe 里运行什么内容。你可以把任意 HTML/JavaScript 塞进srcdoc属性,由它负责解释和处理消息——这正是它适合在 guidance 这类语言模型项目中被用于渲染可视化界面的原因。
二、安装 stitch:pip / conda 两种方式
1. 基础安装
根据 docs/source/installing.rst 与 docs/source/index.rst,最简单的方式是通过 pip 安装:
pip install stitch或通过 conda 安装:
conda install stitch(仓库 README.md 中还提及包名guidance-stitch,实际以当前发布渠道为准;文档中 pip 与 conda 两种形式均已列出。)
2. 前端扩展配置(重要)
stitch 是双端组件,Python 包装好后,前端扩展是否注册决定了 widget 能否真正渲染。文档给出如下判定规则:
- 使用 conda 安装时:前端扩展通常已随包自动配置,上述命令一般可以省略。
- 使用 pip 安装,且 Notebook 版本 < 5.3 时:必须手动安装并启用前端扩展。
如果是 classic Notebook(区别于 JupyterLab),运行:
jupyter nbextension install [--sys-prefix / --user / --system] --py stitch jupyter nbextension enable [--sys-prefix / --user / --system] --py stitch其中的--sys-prefix / --user / --system是互斥的三选一作用域标志,用于决定扩展装到哪个环境;在 conda 环境中通常应选择--sys-prefix,以确保扩展落在当前虚拟环境对应的 Python 前缀下。
如果是 JupyterLab,则安装 lab 扩展:
jupyter labextension install @guidance-ai/stitch@guidance-ai/stitch这个前端包名与 Python 侧_frontend.py中声明的module_name完全一致(见 stitch/_frontend.py),JS 包当前版本为0.1.5(见 package.json)。
3. 扩展注册的底层依据
为什么需要手动配扩展?因为 Jupyter 通过约定函数发现前端资源。在 stitch/init.py 中定义了两个注册函数:
_jupyter_labextension_paths():返回{"src": "labextension", "dest": "@guidance-ai/stitch"},告诉 JupyterLab 从构建产物labextension目录复制文件到<jupyter path>/labextensions/@guidance-ai/stitch;_jupyter_nbextension_paths():返回{"section": "notebook", "src": "nbextension", "dest": "stitch", "require": "stitch/extension"},告诉 classic Notebook 把nbextension目录安装到<jupyter path>/nbextensions/stitch,并以stitch/extension作为 AMD 模块入口。
可以看到,nbextension 的入口模块正是仓库里的 stitch/nbextension/extension.js:它通过requirejs.config把@guidance-ai/stitch映射到nbextensions/stitch/index,从而让 Notebook 页面能够加载到 widget 的模型/视图实现。这也是文档要求"安装后必须 enable"的原因——只有启用了扩展,这一映射才会被注入页面。
三、快速上手:三分钟跑通内核 → 页面 → 内核的完整回路
仓库自带的示例 Notebook examples/introduction.ipynb 演示了 stitch 的完整用法,下面按它的步骤展开讲解。
1. 创建 Widget 并注入页面 HTML
import stitch w = stitch.StitchWidget() w.srcdoc = """ <html style=""> <script> window.addEventListener("message", function(event) { if (event.source === window.parent) { if (event.data.type === "kernelmsg") { document.getElementById("msgview").innerHTML = event.data.content; window.parent.postMessage({type: "clientmsg", content: event.data.content}, "*"); // Save state for offline render window.parent.postMessage({type: "state", content: event.data.content}, "*"); } else if (event.data.type === "init_state") { document.getElementById("msgview").innerHTML = event.data.content; } } }); window.addEventListener("load", function(){ var prevHeight = 0; setInterval(function() { var body = document.body; var html = document.documentElement; var height = html.getBoundingClientRect().height if (height !== prevHeight && html.checkVisibility()) { msg = { type: 'resize', content: { height: height + 'px', width: '100%' } }; window.parent.postMessage(msg, "*"); prevHeight = height; } }, 100); }); </script> <body style=""> <div> MESSAGE: <span id="msgview" style="background-color: #90ee90;"></span> </div> </body> </html> """ w.initial_width = '100%' w.initial_height = 'auto' display(w)这段代码做了三件事:
- 指定
srcdoc:iframe 内渲染的完整 HTML 文档,其中内嵌的<script>负责监听来自父页面的消息; - 设置初始尺寸:
initial_width = '100%'、initial_height = 'auto'; display(w):把 widget 渲染进 Notebook 输出区(示例输出的 MIME 类型为application/vnd.jupyter.widget-view+json,说明它被识别为标准的 Jupyter Widget v2 模型)。
注意 iframe 内脚本的职责分工:收到kernelmsg类型消息时更新页面内容并回发两条消息(clientmsg用于实时回传、state用于保存离线渲染状态);收到init_state时恢复上次的状态;页面加载后用setInterval每 100ms 检查一次页面高度变化并发送resize消息,实现 iframe 高度自适应内容。
2. 从内核发送消息
w.kernelmsg = """A language model is a probabilistic model of a natural language. ..."""给kernelmsg属性赋值后,消息会经 traitlet 同步机制推送到前端,前端再把消息 postMessage 进 iframe,页面中的msgview立即更新,同时clientmsg/state回传内核。
3. 在内核侧观察回传消息
w.observe(lambda x: print(x['new']), 'kernelmsg') w.kernelmsg = "Wow, a change!"输出:
Wow, a change!observe是 ipywidgets traitlet 的观察接口:这里既演示了内核侧对属性变化的响应,也演示了属性被回写后(如 iframe 回传的clientmsg、state)可以在 Python 侧通过同样的机制捕获。示例的最终 widget 状态里clientmsg、state均为"Wow, a change!",证明了一次完整的"内核 → iframe → 内核"回路已经打通。
四、StitchWidget 核心属性详解
StitchWidget是ipywidgets.DOMWidget的子类,所有通信字段都通过traitlets.Unicode定义并标记sync=True,意味着它们会在 Python 模型与前端 JS 模型之间自动同步(见 stitch/stitch.py)。各属性如下:
| 属性 | 默认值 | 说明 |
|---|---|---|
kernelmsg | "" | 内核 → 客户端消息通道。Python 侧赋值后,前端会把内容以kernelmsg消息 postMessage 进 iframe |
clientmsg | "" | 客户端 → 内核消息通道。iframe 内发送clientmsg消息后回写此属性 |
srcdoc | "<p>srcdoc should be defined by the user</p>" | iframe 渲染的 HTML 源码;赋值后前端会重建 iframe 的srcdoc并立即补发最新的kernelmsg |
initial_height | "1px" | iframe 初始高度 CSS 值,如'auto' |
initial_width | "1px" | iframe 初始宽度 CSS 值,如'100%' |
initial_border | "0" | iframe 初始边框 CSS 值 |
state | "" | 状态快照字段,用于保存/恢复界面状态(如离线渲染场景) |
对应的默认值在 TypeScript 前端 src/widget.ts 的defaults()中逐项一致,Python 与 JS 两侧保持同步。单元测试 stitch/tests/test_example.py 也验证了空实例的默认行为:kernelmsg == ""、clientmsg == ""、srcdoc == "<p>srcdoc should be defined by the user</p>"。
五、双向通信协议:前端到底在转发什么
如果想深度定制 iframe 内的交互逻辑,就必须理解前端StitchView处理的消息类型。查看 src/widget.ts 的recvFromClient回调与render()逻辑,可以梳理出完整的消息清单:
父页面(widget 前端)接收 iframe 发来的消息:
消息类型type | 载荷content | 前端行为 |
|---|---|---|
init_stitch | 无 | iframe 就绪信号;触发初始化流程,首次渲染时会依次发送init_state与当前kernelmsg |
clientmsg | 任意字符串 | 写入模型clientmsg属性并save_changes()同步回内核 |
resize | {height, width} | 动态调整 iframe 的宽高 CSS(用于自适应内容高度) |
state | 任意字符串 | 写入模型state属性并同步回内核 |
父页面发送给 iframe 的消息:
消息类型type | 触发时机 |
|---|---|
init_state | widget 初始化完成且模型非新建状态时,向 iframe 恢复上次的state(见emit_init_state()) |
kernelmsg | 内核侧kernelmsg变化时(change:kernelmsg回调),或srcdoc更新后立即补发一次 |
此外,render()中还有两个值得注意的实现细节:
- 沙箱安全:iframe 被显式加上
sandbox且只放开allow-scripts(src/widget.ts),iframe 内的脚本可以运行,但无法访问父页面 DOM,从机制上隔离了页面与 Notebook 环境; - 事件过滤:所有
message事件都先校验event.source === iframe.contentWindow,确保只处理来自本 widget iframe 的消息,避免被页面中其他来源的 postMessage 干扰。
对应地,StitchModel在 src/widget.ts 中声明了与 Python 侧完全一致的_model_name: 'StitchModel'、_view_name: 'StitchView',模块名取自 src/version.ts,保证了模型注册的双端匹配。
六、开发者模式安装与调试
如果要在本地修改 stitch 源码(尤其是前端 TypeScript 代码),按照 docs/source/develop-install.rst 的流程操作。
1. 克隆仓库并以可编辑模式安装
git clone https://github.com/guidance-ai/stitch cd stitch pip install -e .2. 链接安装前端扩展
如果同时开发 JS/前端代码,需要对扩展做符号链接(symlink)安装,这样源码改动即时生效,无需反复复制:
classic Notebook:
jupyter nbextension install [--sys-prefix / --user / --system] --symlink --py stitch jupyter nbextension enable [--sys-prefix / --user / --system] --py stitchJupyterLab:
jupyter labextension install .3. 构建与热更新
仓库 package.json 提供了完整的构建脚本体系:
jlpm run build:依次执行 TypeScript 编译(tsc)、webpack 打包 nbextension、以及 dev 模式的 labextension 构建;jlpm run watch:并行启动tsc -w、webpack --watch与jupyter labextension watch .,配合jupyter lab即可实现前端改动自动重建、浏览器刷新即生效;- Python 侧改动则需重启 Notebook 内核才能生效(这一点在 README.md 中有明确说明)。
值得一提的是,开发依赖中把@jupyterlab/builder钉在 4.0.11、并在jupyterlab.sharedPackages中将@jupyter-widgets/base标记为bundled: false, singleton: true(见 package.json),这是为了让 lab 扩展与 Notebook 共享同一份 widget 基础库,避免模型注册冲突——在排查"widget 不显示"类问题时,可优先检查这一依赖对齐关系。
七、验证与常见问题排查
1. 用单元测试验证默认行为
仓库在 stitch/tests/test_example.py 提供了最小化的验证用例:
from ..stitch import StitchWidget def test_example_creation_blank(): w = StitchWidget() assert w.kernelmsg == "" assert w.clientmsg == "" assert w.srcdoc == "<p>srcdoc should be defined by the user</p>"该用例确认了StitchWidget()无参创建时的默认状态,可作为开发时回归测试的模板。
2. 常见问题定位思路
- widget 只显示为空白:先确认扩展是否已启用。classic Notebook 运行
jupyter nbextension list,JupyterLab 运行jupyter labextension list,检查stitch/@guidance-ai/stitch是否在列;pip 安装且 Notebook < 5.3 时必须手动执行第二节中的 install + enable 命令。 - 内核消息发不进 iframe:检查
srcdoc内是否监听了kernelmsg类型,且事件源校验为event.source === window.parent;同时确认 iframe 脚本是在init_stitch握手之后才运行(前端只在收到该信号后才开始推送消息)。 - iframe 高度异常:利用
resize协议,参照示例在 iframe 内周期性比较内容高度并回传{type: 'resize', content: {height, width}}。 - Python 收不到回传:确认 iframe 回发的是
clientmsg/state类型,且内容为可序列化字符串;这两个属性与kernelmsg、srcdoc一样,都依赖 traitlets 的sync=True双向同步链路。
八、小结
stitch 以极简的设计解决了 Jupyter 生态中的一个关键痛点:让任意 HTML/JavaScript 界面与 Python 内核之间拥有可靠的实时双向消息通道。它的使用路径清晰——pip/conda 安装、按环境配置前端扩展、用StitchWidget的几个字符串属性完成收发;它的原理同样清晰——DOMWidget + traitlets 同步属性 + 沙箱 iframe +postMessage协议。无论是做交互式可视化、嵌入式工具面板,还是在语言模型工作流中渲染动态结果,这套模式都可以直接复用。
进一步阅读:完整安装说明见 installing.rst,开发安装说明见 develop-install.rst,可运行示例见 introduction.ipynb,Python 与前端实现分别见 stitch.py 与 widget.ts。
- 大模型
- 提示工程
- AI Agent
【免费下载链接】guidance
A guidance language for controlling large language models.
相关推荐
AMD量化模型生产部署终极指南:企业级应用场景与最佳实践 🚀
AMD量化模型生产部署终极指南:企业级应用场景与最佳实践 🚀 在当今AI快速发展的时代, AMD量化模型生产部署 已成为企业降低推理成本、提升效率的关键技术。
大模型提示工程AI Agent终极指南:如何在pywebview中实现JavaScript与Python双向通信
终极指南:如何在pywebview中实现JavaScript与Python双向通信 想要为你的Python应用构建现代化GUI界面?pywebview正是你需要
桌面应用前端Kedro 与 Jupyter Notebook 双向集成实战:渐进式迁移与项目内实验完整指南
Kedro 与 Jupyter Notebook 双向集成实战:渐进式迁移与项目内实验完整指南 本指南基于 Kedro 官方文档的 Notebooks 与 IP
数据工程工作流自动化
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考