用 Pi 写第一个 Agent
最后更新:2026-10-10
这一节我们从 pi-agent-core 出发,写一个能调用工具的最小 Agent。读完你应该能理解 Pi 的核心循环长什么样、AgentSession 和 Agent 各管什么,以及怎么观察它的一举一动。
建议先扫一眼 总体架构 与 核心概念,会更快上手;工具与包的边界在 核心包 里有详细说明。
核心思路
Pi 的运行时把「不稳定的外部世界」和「稳定的核心循环」分开:
把业务能力封装成工具,把目标写进 prompt。
Agent 持有工具与模型;Session 持有对话上下文;Loop 驱动「请求模型 → 执行工具 → 写回」。
屏蔽各家模型差异,AgentLoop 通过它请求模型。
分步实现
- 定义工具:用装饰器声明一个可被 Agent 调用的函数,写清名称、用途与参数。下面是一个「读文件」工具的示例。
- 构造 Agent:把模型实例与工具列表交给 Agent,得到会调用工具的运行时。
- 构造 AgentSession:用 Agent 创建一次会话,写入系统提示与用户消息。
- 运行并观察事件:订阅
AgentEvent流,实时看到模型回复与toolCall的调用与返回。 - 理解核心循环:循环反复「请求模型 → 执行工具 → 写回结果」,直到模型给出不含工具调用的最终答案。
最小代码示例(TypeScript 风格)
import { Agent, tool, AgentSession } from '@earendil-works/pi-agent-core';
import { createModel } from '@earendil-works/pi-ai';
// 1) 定义一个工具:读取文件内容
const readFile = tool({
name: 'read_file',
description: '读取指定路径的文件内容',
parameters: { path: { type: 'string', description: '文件绝对或相对路径' } },
async run({ path }) {
return await fs.readFile(path, 'utf8');
},
});
// 2) 构造 Agent(选定模型 + 工具列表)
const model = createModel('openai/gpt-4o');
const agent = new Agent({ model, tools: [readFile] });
// 3) 构造一次会话并写入消息
const session = new AgentSession(agent);
session.pushSystem('你是一个谨慎的编码助手,先读文件再回答。');
session.pushUser('读一下 ./package.json 并告诉我用了哪些脚本。');
// 4) 运行并观察事件
for await (const event of session.run()) {
if (event.type === 'text') console.log('模型:', event.text);
if (event.type === 'toolCall') console.log('调用:', event.name, event.args);
if (event.type === 'toolResult') console.log('结果:', event.result);
}
核心循环到底是什么
上面那段 session.run() 内部跑的就是 Pi 的稳定内核:
- 把系统提示、历史消息和工具定义打包成上下文;
- 通过
pi-ai请求模型; - 如果模型返回
toolCall,就执行对应工具,把结果写回上下文; - 带着新结果再次请求模型,直到模型不再调用工具、给出最终答案。
试着扩展
- 再加一个
run_shell工具,让 Agent 能跑命令; - 把模型换成
MockModel,离线跑通上面整段逻辑; - 给 Session 接上 架构 里提到的 JSONL 会话树,观察每一次 toolCall 与分支。
实战建议:从最小任务开始
第一次跑真机,不要同时接入多个 Provider、扩展和自动化脚本。按这个顺序来:
- 最小任务:让 Agent 解释当前目录结构,确认模型响应和会话状态正常;
- 逐步加工具:先启用目录读取,再启用单个文件编辑,一次只加一种能力;
- 再谈自动化:等上面都稳了,再接多 Provider 和自动化脚本。
故障速查:
- 没有模型响应 → 检查 Provider、模型名、网络和环境变量;
- 工具调用失败 → 检查工具是否启用、参数 schema、当前目录;
- 上下文过长 → 缩小工作目录、拆分任务、清理日志。
✅ 验收标准:能稳定完成一个小任务,并知道如何查看会话、日志和错误信息,才算完成入门配置。
常见问题(FAQ)
Agent 和 AgentSession 有什么区别?
Agent 是「会调用工具的运行时」本身,定义行为与能力;AgentSession 是一次具体对话的上下文容器,持有消息历史、状态与分支。一个 Agent 可以创建多个 Session。
工具函数需要返回什么?
工具只需是普通异步函数,用装饰器标注名称、描述与参数 schema;返回值会被 Pi 序列化后作为 toolCall 结果回传给模型,进入下一轮循环。
没有真实模型能调试吗?
可以。pi-ai 提供 MockModel,能离线模拟模型回复,让你专注验证工具定义与核心循环逻辑,不消耗真实 token。
AgentEvent 里能看到哪些信息?
典型的 AgentEvent 包含模型流式文本、toolCall 的调用与返回、会话状态变更等。订阅它就能在 UI 或日志里实时呈现代理的思考与动作。