Appearance
预备知识:从零认识 Agent
如果你对 "LLM"、"token"、"工具调用" 这些词还比较陌生,请先读完这一篇。它用大白话 + 类比,把看懂本教程需要的基础概念一次讲清楚。已经熟悉的人可以直接跳过。
一、什么是 LLM(大语言模型)
LLM(Large Language Model,大语言模型)是一个根据前文预测下一个词的程序。你给它一段文字,它就接着往下"编":
输入: "今天天气真"
输出: "好"它实际上是在无数文字上训练出来的概率预测器:给定前面的词,算出下一个最可能的词。反复"预测下一个词"几百次,就拼出了一整句话、一整段文章。
一句话类比:LLM 就像一个"接话茬"高手,你不停喂它上文,它不停往下接。接多了,看起来就像在"回答你的问题"。
@pi/ai 的 StreamFunction 做的事情,本质上就是:把一段上文(会话历史)发给 LLM,再流式地接收它"接话茬"吐出来的词。
二、什么是 token
LLM 不直接处理"字",而是把文字切成叫 token 的小块。中文里,一个 token 大致对应一个词或一个常用词片段。
"你好,世界" → ["你好", ",", "世界"] (约 3 个 token)- LLM 的输入、输出都以 token 计费。
@pi/ai的Usage里的input/output就是 token 数。- 判断"会话会不会太长"靠的就是估算 token 数。
三、上下文窗口(Context Window)
模型一次能"记住"的上文是有限的,这个上限叫上下文窗口。
上下文窗口 = 这一次调用模型时,能塞进多少 token- 塞得越多,模型越"记得住"之前的对话,但越贵、越慢。
- 一旦超过窗口,就得压缩(pi 的 compaction,见 6.2)或丢弃/总结旧消息。
@pi/ai 的 Model.contextWindow 字段就记录这个上限。
四、Prompt 与 System Prompt
Prompt(提示词) 就是"你发给模型的那段话"。它包含两类:
- System Prompt(系统提示):对话开始前给模型设的"人设和规则",告诉它"你是谁、要遵守什么"。例如 "你是专业的编码助手,回答要简洁。"
- User Message / Prompt:用户每一次的具体提问。
System: 你是编码助手,回答简洁。 ← 系统提示(人设规则)
User: 帮我重构一下 utils 模块。 ← 用户提问@pi/ai 的 Context 结构正好对应:
ts
interface Context {
systemPrompt?: string; // 系统提示
messages: Message[]; // 用户 / 助手 / 工具的对话历史
tools?: Tool[]; // 可用的工具
}五、工具调用(Tool Calling / Function Calling)
这是 "Agent 能做事" 的核心。
普通的问答,模型只能"说话"。工具调用让模型能"请求调用某个函数",拿到结果后再继续说话:
User: 帮我算 3 + 4
模型: 我需要调用一个计算工具 → { 工具名: "calculator", 参数: {a:3, b:4} }
程序: 执行 calculator(3,4) → 得到 7
程序: 把"7"作为工具结果回填给模型
模型: 最终回答:"3 + 4 = 7"关键点:模型只是"提出想调用哪个工具",真正执行工具的是我们自己的程序。模型提供的是"决策"(调用什么、用什么参数),程序提供的是"执行"(真正跑代码)。
- 模型发来的"工具调用请求"在 pi 里叫
ToolCall(type: "toolCall")。 - 我们执行完回填的结果叫
toolResult消息。 - 模型说"我要调用工具"的信号是
stopReason = "toolUse"。
这就是 2.1 核心 Agent 循环 里那个"循环"在反复做的事。
六、什么是 Agent
把上面几块拼起来,就得到 Agent(智能体):
Agent = LLM + 循环 + 工具
它不像普通问答那样"问一句答一句",而是能自己决定:要不要调用工具、调用哪个、调完再怎么办,直到达成目标。
用户: 帮我改一下 README
Agent 内部的循环:
1. 把整个会话发给 LLM
2. LLM 说:"我要读 README" → 程序执行 read 工具
3. 把读取结果回填给 LLM
4. LLM 说:"我要写入修改" → 程序执行 write 工具
5. 把结果回填
6. LLM 说:"改好了"(stop)→ 结束七、ReAct:Agent 循环的经典范式
pi 的循环遵循一个经典范式 ReAct(Reason + Act):
Reason(思考): 模型根据当前上下文决定下一步
↓
Act(行动): 执行一个工具(或直接回答)
↓
Observe(观察): 程序把工具结果回填给模型
↓
(回到 Reason,直到模型认为完成了)@pi/agent-core 的 agent-loop.ts 就是这个循环的实现(见 2.1)。
八、流式输出(Streaming)
模型生成是一个字一个字吐出来的,不是一次性。流式就是边生成边把已产出的部分发给接收方,让用户不用干等。
- pi 用
文字增量事件(text_delta)逐段推送。 - TUI 据此实现"打字机效果"(见 5.1)。
九、把概念串起来
现在你再看 pi 的架构图,应该不再陌生了:
@pi/ai —— 负责"第 1~5 条":把对话发给 LLM,流式接收,统一各家厂商
@pi/agent-core —— 负责"第 6~7 条":ReAct 循环,决定调哪个工具、执行并回填
@pi/protocol+server+client —— 负责"远程":把会话序列化成字节,跨机器传输
@pi/tui —— 负责"展示":把流式的增量画到终端
@pi/coding-agent —— 负责"产品化":存盘、压缩、内置工具、扩展如果还有疑问
- "token 怎么数?" → 见 1.1 消息模型 的
Usage。 - "工具调用到底怎么实现?" → 2.2 工具系统。
- "循环会不会死循环?" → 有
stopReason、shouldStopAfterTurn等机制,见 2.1。 - "上下文太多怎么办?" → 6.2 上下文压缩。
现在,你可以正式开始了。 → 1.1 统一会话消息模型