跳转到内容

第 4 课:第一个 SDK 程序

用 createAgentSession、SessionManager.inMemory、session.prompt 和 session.subscribe 写出最小可运行的 headless agent runner。

第一个 Pi SDK 程序只需要四个动作:创建 session、订阅事件、发送 prompt、释放 session。真正要学的不是 API 背诵,而是如何把 SDK 程序组织成一个可控的 headless runner。

SDK runner 将输入、session 和事件流连接起来的教学图

如果要把 Pi 嵌入自己的 CLI、CI 任务或后台服务,第一步应该写出什么最小结构?

  • 输入层只负责得到用户任务。
  • session factory 负责装配模型、资源、工具和会话策略。
  • 事件订阅负责把模型输出和工具状态传给宿主。
  • 生命周期收口负责释放监听器和 runtime 资源。

下面不是完整源码,而是把本课主线压缩成可以在文档里直接阅读的关键形状。读者即使不打开本地源码,也应该能看出运行时如何组织职责。

async function runOnce(input: string) {
const { session } = await createAgentSession({
sessionManager: SessionManager.inMemory(),
});
session.subscribe((event) => {
if (event.type === "message_update") renderDelta(event);
});
try {
await session.prompt(input);
} finally {
await session.dispose();
}
}
  • 这段代码补上了只看路径时缺失的关键细节:runner 的输出来自 subscribe(),不是 prompt() 的返回字符串。
  • inMemory() 让第一版先避开恢复会话的复杂度,适合验证生命周期。
  • finally 是长期运行宿主的基本卫生,否则监听器和 runtime 资源可能泄漏。

复制这个结构,写出一个只执行一次任务的 runner,并说明每一行的职责。

  • 能独立写出最小 runner。
  • 能解释为什么第一版使用内存会话。
  • 能说明事件订阅、prompt 和 dispose 的先后关系。
  1. 实践题:基于本课的省略版源码,补出一个最小实现草图,要求写清输入、输出、副作用和错误处理。
  2. 思考题:本课机制如果只靠 prompt 约束,而不放进 harness 或 runtime,会出现什么工程风险?