Appearance
Demo:最小 Agent
工程化复现 @pi/agent-core 的核心:Agent 循环 + 工具 + 事件 + steer/followUp 队列。源码在 pi-principles/src/agent/,离线演示入口在 pi-principles/play/mini-agent.ts(真实模型版见 bun cli.ts agent)。
工程化结构
text
pi-principles/src/agent/
├── types.ts # AgentTool、AgentEvent、AgentState
├── agent-loop.ts # 核心循环(ReAct)+ 工具执行
└── agent.ts # MiniAgent 类:subscribe / steer / followUp / prompt关键实现
工具契约(types.ts)
ts
export interface AgentTool {
name: string;
description: string;
execute(args: Record<string, any>): string; // 我们负责执行
}核心循环(agent-loop.ts)
ts
export async function runAgentLoop(context, config, emit, signal): Promise<Message[]> {
// 外层:处理 follow-up
while (true) {
let hasTool = true;
// 内层:工具调用 + steering
while (hasTool || pending.length > 0) {
// 1. 注入 steering
// 2. 调模型拿 assistant 消息
// 3. 若含 toolCall → 执行工具 → 回填 toolResult → hasTool=true(继续)
// 否则 hasTool=false(停)
}
// 拉 follow-up;无则退出
}
}会调用工具的假模型(agent/decider.ts)
createDeciderStreamFn()(离线假模型)返回一个 StreamFn,根据用户输入模拟真实模型的"函数调用":
ts
// 输入含"计算 X + Y" → 返回 toolCall(stopReason = toolUse)
// 否则 → 返回文本(stopReason = stop)真实模型版用
createOpenAIStreamFn(loadConfig())(src/ai/api/openai-responses.ts),走 OpenAI Responses 协议。
MiniAgent(agent.ts)
ts
const agent = new MiniAgent({ streamFn, systemPrompt, tools });
agent.subscribe(fn); // 订阅事件
agent.steer(msg); // 插队消息
agent.followUp(msg); // 完成后消息
await agent.prompt("..."); // 发起对话入口与运行
离线演示(无需 .env,用假模型):play/mini-agent.ts 演示一次带工具调用的对话 → 中途 steer → 结束时 followUp。
bash
cd pi-principles
bun play/mini-agent.ts # 或 npm run mini-agent真实模型版:
bun cli.ts agent "请计算 123 + 456"(或play/agent.ts)会用真实 OpenAI(需 .env),演示同一个循环驱动真实工具调用。
输出(注意 steer 被中途采纳、followUp 最后处理):
== agent_start ==
[assistant] (调用 calculator:{"a":3,"b":4})
→ 调用工具: calculator
[toolResult] = 7
[assistant] 答案:= 7
== agent_end ==
--- 措一条 steer + followUp ---
== agent_start ==
[user] 计算 10 + 4 ← steer 中途注入
→ 调用工具: calculator
[toolResult] = 14
[assistant] 答案:= 14
[user] 最后把答案乘以 10 ← followUp 最后处理
[assistant] 答案:最后把答案乘以 10
== agent_end ==对应到真实源码
| 工程化 Demo | 真实 pi 源码 |
|---|---|
agent/agent-loop.ts | packages/agent/src/agent-loop.ts:155 |
agent/agent.ts | packages/agent/src/agent.ts |
agent/types.ts | packages/agent/src/types.ts |
理解要点
- 循环 = 工具调用 + 回填:模型看不到工具结果就想继续,看到结果就给出最终答案。
- steer 插到下一个回合前,followUp 在停止后处理。
- 事件驱动:UI/日志只订阅事件,不碰内核状态。
下一步:3.1 字节定帧。