第9章 编程接口与 RPC 协议

第9章 编程接口与 RPC 协议

9.1 CLI 参数完整分类速查

分类 参数 说明
运行模式 -p "..." 非交互打印模式
--mode json JSONL 事件流
--mode rpc RPC 服务模式
--offline 关闭所有启动期联网操作
模型与思考 --provider / --model 指定 Provider / 模型
--model sonnet:high 模型+思考等级快捷写法
--thinking <level> 指定本次思考等级
工具与扩展 --tools a,b,c 工具白名单
--no-extensions 关闭所有扩展
-e ./path.ts 加载指定的单个 Extension
会话 -c 继续最近会话
--session-dir <path> 自定义会话目录
--no-session 不落盘
包管理 pi install npm:<pkg> / git:<repo> 安装社区包
pi list / pi update 查看/升级
杂项 -v / -h 版本 / 帮助

9.2 三层编程接口对比:createAgentSession / createAgentSessionRuntime / RPC 子进程

Pi 真实的 SDK 文档明确指出:CLI 内置的交互模式、打印模式、RPC 模式,本质上用的是同一套底层 Runtime 层,可以选择在哪个层级接入:

层级 关键 API 适合场景
最简单 createAgentSession() + ModelRuntime/SessionManager 快速在 Node.js 里跑一个一次性 Session
进阶 createAgentSessionRuntime() + createAgentSessionServices() 需要自己控制多会话生命周期、接自定义传输层(如 HTTP+SSE 转发给浏览器)
跨语言 pi --mode rpc 非 Node.js 技术栈(Python、Go、Java 等)集成
ts 复制代码
import {
  type CreateAgentSessionRuntimeFactory,
  createAgentSessionFromServices,
  createAgentSessionRuntime,
  createAgentSessionServices,
  getAgentDir,
  runRpcMode,
  SessionManager,
} from '@earendil-works/pi-coding-agent';

const createRuntime: CreateAgentSessionRuntimeFactory = async ({ cwd, sessionManager, sessionStartEvent }) => {
  const services = await createAgentSessionServices({ cwd });
  return {
    ...(await createAgentSessionFromServices({ services, sessionManager, sessionStartEvent })),
    services,
    diagnostics: services.diagnostics,
  };
};

const runtime = await createAgentSessionRuntime(createRuntime, {
  cwd: process.cwd(),
  agentDir: getAgentDir(),
  sessionManager: SessionManager.create(process.cwd()),
});

// 甚至可以把这个 Runtime 直接跑成 RPC 服务,而不需要另开子进程
await runRpcMode(runtime);

💡 官方特别提示:Node.js 应用优先直接用 AgentSession/createAgentSessionRuntime(),不要为了用 RPC 而把 pi 当子进程 spawn 出来------只有非 Node.js 技术栈才需要走"子进程 + RPC"这条路。

9.3 RPC 协议细节:LF 分隔 JSONL、extension_ui_request/response 子协议

RPC 模式是严格的 LF(\n)分隔 JSONL 协议------每一行是一个独立 JSON 对象。

⚠️ 关键工程提醒不要用 Node.js 的 readline 模块解析 RPC 输出 ------它会在 JSON 字符串内部合法的 Unicode 行分隔符 U+2028/U+2029 处误断行,把一个完整的 JSON 对象切成两半。正确做法是自己写只按 \n 分割的解析逻辑。

命令支持可选的 id 字段用于请求/响应关联:

jsonl 复制代码
{"id": "req-1", "type": "prompt", "message": "Hello, world!"}

Extension 触发的 UI 交互在 RPC 协议里转成一套子协议:

方法类型 行为
对话框类(select/confirm/input/editor 发出 extension_ui_request,阻塞等待客户端在 stdin 回传匹配 idextension_ui_response
即发即弃类(notify/setStatus/setWidget 发出 extension_ui_request,但不等待响应

Extension 内部报错作为独立事件类型上抛:

json 复制代码
{ "type": "extension_error", "extensionPath": "/path/to/extension.ts", "event": "tool_call", "error": "..." }

9.4 流式输出:Agent.subscribe() / --mode json

编程接口场景:

ts 复制代码
agent.subscribe((event) => {
  if (event.type === 'message_update' && event.assistantMessageEvent.type === 'text_delta') {
    process.stdout.write(event.assistantMessageEvent.delta);
  }
});
await agent.prompt('...');

CLI 场景的等价方式:

bash 复制代码
pi --mode json -p "..." > events.jsonl

每一行是独立事件对象(文本增量、工具调用、工具结果),可以直接消费。

📌 校订:Pi 没有一个单独叫 generate() 的方法,真实调用是 prompt(),流式输出靠事件订阅而不是一个"流式开关配置项"。

9.5 自定义消息类型:声明合并 + convertToLlm

pi-agent-coreAgentMessage 类型支持通过 TypeScript 声明合并扩展自定义消息角色:

ts 复制代码
declare module '@earendil-works/pi-agent-core' {
  interface CustomAgentMessages {
    notification: { role: 'notification'; text: string; timestamp: number };
  }
}

再用 convertToLlm 在真正发给模型前过滤/转换这些自定义消息:

ts 复制代码
const agent = new Agent({
  convertToLlm: (messages) => messages.flatMap((m) => (m.role === 'notification' ? [] : [m])),
});

📌 校订:网传版本"from 参数三种用法"是虚构描述,真实的动态数据注入方式是这套"自定义消息类型 + convertToLlm 转换"机制,或者简单地把数据拼进 prompt 字符串(作为 stdin 管道输入也可以:cat file.md | pi -p "总结这段内容")。


相关推荐
互联网江湖1 小时前
一加、realme“分家”,OPPO更宠谁?
人工智能
A15362551 小时前
国内进销存软件排名2026 电商&零售企业选型指南
大数据·人工智能·零售
网易云信1 小时前
AI 提效的"组织悖论"——为什么个人越用越强,组织却看不到效果?
人工智能
魔镜er1 小时前
03-张量
人工智能·pytorch·python
后端小肥肠2 小时前
做个人 IP 不用真人出镜,我做了个一键生成 IP 动画视频的 Skill
人工智能·aigc·agent
墨舟的AI笔记2 小时前
大模型游戏剧情评测:用自动化指标抑制幻觉与 OOC 出戏
人工智能
武子康2 小时前
从世界状态到可执行控制:Cosmos 3 Edge 与机器人控制器之间应建立什么合同
人工智能·agent·nvidia
我是大卫2 小时前
【图】解LLM:用图理解大语言模型
人工智能
勇叔2 小时前
从 LangChain SQLAgent 天生缺陷到五把安全锁落地 — 牧场 AI 查询实战踩坑指南
人工智能