通知 demo 只覆盖普通调用与状态信息,不能代表 Spine 全部机制。面试先用下面四个 demo 讲核心,最后再用通知场景讨论未来方向。
命令与讲解顺序
./demos/core.sh # 列出入口,不自动跑一长串
./demos/core.sh call # 普通调用及 Host 边界
./demos/core.sh plm # 完整程序内提前读取
./demos/core.sh prefix # 源码接收与读取重叠
./demos/core.sh isolation # fresh / prepared-copy / Linux COW
./demos/core.sh info # 可选:通知状态与未来研究
make walkthrough # 四个核心 demo 顺序运行,不含 info
所有 Python 都经真实 CPython Wasm。提前准备 dist/spine.wasm 与 Go 缓存;脚本不会自动重建 Guest。没有付费 API,没有真实交易或通知。脚本可以从其他目录以绝对路径启动。
每个 demo 只回答一个问题。第一次排练可完整运行;现场按追问选用,不要求逐行读完日志。输出中的 PASS 是真实测试断言结果,不是把预期文字打印成验证结果。
Demo 1:Python 怎样调用 Host?
./demos/core.sh call
lookup.py 只有两行:向 Host 取价格,在 Python 中计算总价。默认输入是 book、quantity=2,Host 返回 21,最后得到 42。
Go 注册 lookup 并提交源码
|
v
Runner 创建 Guest,bootstrap 注入 lookup 代理
|
v
Python lookup(key="book")
|
v
C / Wasm import → Go hostCall → manifest 中的函数
|
v
返回 21 → Python 计算 21 * 2 → result 42
随后运行一个真实 Guest 测试:直接调用 _spine.call 请求不存在的 delete 工具,Host 仍拒绝。说明 Python facade 提供便利,工具注册边界仍在 Host。此测试不代表完整安全审计。
开哪些文件: cmd/demo/main.go → runner.go → guest/runtime.c → guest/bootstrap.py → bridge.go。
一句话: Python 保留控制流,Host 决定实际提供哪些能力。
Demo 2:PLM 改变了什么?
./demos/core.sh plm
使用已有的本地模拟交易程序 trading.py:查价格、查现金,条件满足后请求买入。Host 明确允许本地模拟下单。两个读取使用本轮稳定快照,buy 没有提前许可。
脚本先跑 normal,再以相同输入跑 PLM,显示真实 AST 改写与 Host 时间戳日志。
normal: quote start ── quote end ── cash start ── cash end ── 条件 ── buy
PLM: prepare quote ───────────── resolve quote
prepare cash ───────────── resolve cash ── 条件 ── buy
└──────── Host 读取可重叠 ────────┘
看三个地方:
- normal 的 quote 完成后才调用 cash;PLM 可在第一个读取结束前启动第二个读取。
- 改写源码把允许的读取拆为 prepare 与 resolve;Python 仍在原调用位置取得结果或异常。
buy不被提前。提前许可由 Host 的AllowEarlyRead控制,不能从函数名或“只读”提示自行推断。
200ms 是为了看清顺序加入的模拟工具延迟。不要用两次 CLI 总耗时比较性能:其中还包含 Go 启动、Wasm 编译和解释器初始化。
脚本最后运行两个已有握手测试:第一个结果放行前,两项工具均已开始;后一个工具的异常仍在前一个赋值完成后交付。它们比观察一次日志先后更明确。
开哪些文件: guest/plm.py 的 transform → guest/bootstrap.py 的 prepare/resolve helper → bridge.go → future.go。验证见 plm_test.go。
一句话: 对明确允许的稳定读取,把 Host 工作提前,保留 Python 原调用点的结果与错误交付。
Demo 3:Prefix 与 PLM 有什么不同?
./demos/core.sh prefix
继续使用交易程序,但按行通过 channel 发送源码。观察 source.send、tool.start 和 source.closed,而不只看最终结果。
源码片段 → Prefix 收集并识别开头完整、获准的读取
|
+→ Host prepare,后台读取开始
源码继续到达 |
EOF → 最终程序执行 → 原工具调用 claim 对应 Future → resolve
PLM 收到完整程序后进行变换;prefix 允许在源码还没全部接收时准备合格读取。它不执行任意半条 Python,也不承诺发现整个程序里的全部并行性。
CLI 回放很快,日志线程调度会变化,单次 tool.start 与 source.closed 的打印顺序不作为唯一证明。因此脚本再跑 starts_before_source_closes_and_is_claimed_once:测试在源码 EOF 之前等待工具实际开始,再继续输入,并断言已有读取只调用一次。
这是真实 Guest 的文件片段回放,不是实时 LLM 流,也没有证明模型端到端延迟收益。
开哪些文件: cmd/trade-demo/main.go 的 channel producer → prefix.go → guest/prefix.py → future.go。验证见 prefix_test.go。
一句话: PLM 重叠程序内工具工作,prefix 进一步把合格读取与源码接收重叠。
Demo 4:为什么可复用 Runner,但不能串状态?
./demos/core.sh isolation
这一部分用已有真实 Guest 测试作可执行演示,输出测试名与 PASS/FAIL,不另造一个只打印“隔离成功”的脚本。
fresh
同一个 Runner:第一轮写 builtins.secret = 123,第二轮检查 hasattr(builtins, "secret") 必须为 false。另检查 Guest 不能直接读取宿主 /etc/passwd。
prepared-copy
从干净初始化状态复制出 Guest。测试既验证 Python 状态不串轮,也验证两份同时存在的线性内存和保存的基线相互独立。
Linux COW
仅 Linux 运行真实私有映射与 Guest 生命周期测试。macOS 明确跳过此展示,不用 full-copy 冒充 COW。
初始化基线
/ \
prepared-copy: 全量副本 A 全量副本 B
A 的写入不改变 B 或基线
Linux COW: 私有映射 A 私有映射 B
初始页可共享,写入触发页级私有化
“复用”必须说清对象:Runner 复用编译代码;prepared 路径复用初始化成果;每轮可变状态仍需隔离。COW 的线性内存复用不等于保存了 Python 执行栈、Host 对象和所有 WASI 资源。
开哪些文件: runner.go、prepared.go、cow_linux.go。断言见 runner_test.go、prepared_test.go、cow_linux_test.go、cow_test.go。
一句话: 降低重复初始化,与保持请求私有状态,是两个需要分别验证的目标。
可选:用 Python 实现工具
./demos/core.sh python 展示 Guest Python → Go Host → native Python worker。见 Python provider。打开 IDE 类型提示 配置说明可以了解注入工具名怎样补全;现有示例没有增加干扰 prefix 的 import。
可选扩展:连接未来研究
./demos/core.sh info
看 通知状态演示:同一 Python 程序收到 sent、denied、unknown 时采取不同分支。
可以这样过渡:
前面的 demo 说明系统怎样执行与约束程序。下一步我想研究,系统和 provider 已经掌握的能力、效果与结果确定性信息,怎样提供给 Agent 更有用。这个通知例子只展示信息如何跨已有 ABI 传递,尚未验证模型收益。
不要把新的研究设想套回旧机制:Spine 没有通用效果证明、自动业务判断或修改源码后的 durable 恢复。AllowEarlyRead 是窄而明确的 Host 契约,不能自动扩展成“任何标了只读的调用都可提前”。
现场如何选
- 先跑 call,建立执行链。
- 重点讲 plm,再根据兴趣展开 prefix。
- 被问到隔离、复用和 COW 时跑 isolation。
- 有时间讨论新方向才跑 info。
不用照着所有输出念。每次先提出一个问题,再指出一个关键观察,最后进入负责它的函数。旧编号交易脚本保留,主线无需记住它们。