Skip to content

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.tspackages/agent/src/agent-loop.ts:155
agent/agent.tspackages/agent/src/agent.ts
agent/types.tspackages/agent/src/types.ts

理解要点

  • 循环 = 工具调用 + 回填:模型看不到工具结果就想继续,看到结果就给出最终答案。
  • steer 插到下一个回合前followUp 在停止后处理
  • 事件驱动:UI/日志只订阅事件,不碰内核状态。

下一步:3.1 字节定帧