ARTICLE · 1197581
Pi 上下文管理机制源码分析
摘要
Pi 将持久化会话历史与模型可见上下文分离,通过会话树、上下文投影、压缩检查点、结构化摘要和模型调用前的消息转换,实现长会话的容量控制与执行连续性。其工程设计轻量、边界清晰,提供了上下文编辑和扩展入口,本文主要梳理上述机制核心源码的实现原理。
关键词:Pi;Agent Loop;上下文管理;会话投影;上下文压缩;长程任务
一、概述
Pi 是面向软件研发的开源 AI 智能体,本报告分析其会话管理与上下文处理相关源码,重点覆盖会话历史组织、模型上下文构建、压缩与恢复、扩展机制和运行时调用链;分析范围为 Pi 1.3.0 代码路径。
经分析,其核心设计是将完整历史 Hₜ 与当前上下文 Cₜ 分离:Cₜ = P(Hₜ)。P 表示沿当前会话分支、压缩检查点与上下文编辑记录执行的投影与重建操作,而不是完整的语义相关性规划。
二、总体架构与数据模型
上下文逻辑主要分布在 SessionManager、AgentSession 和 Agent Loop 三层。SessionManager 管理会话历史与投影;AgentSession 负责运行调度、阈值检测和压缩恢复;Agent Loop 完成模型请求前的上下文变换与消息格式处理。
模块 | 主要职责 | 核心文件 |
SessionManager | 会话树、持久化、分支、上下文投影 | session-manager.ts |
AgentSession | 会话执行、自动压缩、异常恢复 | agent-session.ts |
Agent Loop | 模型调用前的上下文变换与规范化 | agent-loop.ts |
用户输入 → AgentSession → SessionManager → buildSessionProjection()
→容量检测 / 压缩 → Agent Loop → transformContext()
→convertToLlm() → normalizeContext() → LLM → 工具执行
会话以树形记录保存,每条记录具有 id、parentId、timestamp 和 type 等字段,支持当前分支追溯。压缩检查点通过 summary 和 firstKeptEntryId 记录摘要与原样保留边界,避免对原始会话内容进行破坏性覆盖。
interface SessionEntryBase {
type:string;
id:string;
parentId:string | null;
timestamp:string;
}
interface CompactionEntry
type:"compaction";
summary:string;
firstKeptEntryId:string;
tokensBefore:number;
details?:T;
usage?:Usage;
fromHook?:boolean;
systemMessage?:SystemMessage;
}
源码:packages/coding-agent/src/core/session-manager.ts(SessionEntryBase、CompactionEntry)。
三、上下文关键实现机制
(一)上下文投影与历史编辑
buildSessionProjection() 先通过 buildSessionPath() 追溯当前叶子节点所在的历史路径,再由 buildContextEntries() 定位压缩检查点与有效消息范围,最后应用上下文编辑记录,得到模型当前可见的消息列表。
const path = buildSessionPath(entries, leafId, byId);
const { thinkingLevel, model } = getSessionContextSettings(path);
const contextEntries = buildContextEntries(entries, leafId, byId);
较早历史以摘要代替,近期消息保持原样,会话树使不同分支的数据不会自动混合;ContextEditEntry 可以指向一条原始消息,设置新的内容,或使用 null 将其从当前投影中省略,原始记录仍然保留;适合用来压缩冗长的工具输出、替换过时上下文和清理重复信息。
interface ContextEditEntry extends SessionEntryBase {
type:"context_edit";
targetId:string;
replacement:{ content: ContextEditableContent } | null;
}
if (!edit) return messages;
if (edit.replacement === null) return [];
源码:session-manager.ts(buildSessionPath、buildContextEntries、buildSessionProjection、projectContextEntry)。
(二)容量检测与压缩触发
Pi 根据模型上下文窗口 W、预留 Token 数 R 和当前估算使用量 Uₜ 判断是否压缩,触发条件为 Uₜ > W − R。除阈值触发外,还具备模型上下文溢出后的压缩与恢复路径。
export function shouldCompact(
contextTokens:number,
contextWindow:number,
settings:CompactionSettings
): boolean {
if(!settings.enabled) return false;
returncontextTokens > contextWindow - settings.reserveTokens;
}
estimateProjectedContextTokens() 优先使用模型调用的实际用量;当压缩或上下文编辑导致历史用量失效时重新估算。纯文本估算中使用过按字符数除以四的近似方法,不能视为所有模型的精确 Token 计数。
源码:compaction.ts(shouldCompact、estimateProjectedContextTokens);agent-session.ts(_runAutoCompaction、_compactBeforeNextAssistantResponse)。
(三)压缩切分与结构化摘要
prepareCompaction() 基于当前上下文投影确定压缩范围。findProjectedCutPoint() 等函数从最新消息向前累计 Token,按照 keepRecentTokens 预算保留近期历史,同时处理单轮交互内部大量工具调用造成的超长上下文。
accumulatedTokens += messageTokens;
if (accumulatedTokens >= keepRecentTokens) {
cutIndex= cutPoints.find(candidate => candidate >= i)
??cutPoints[cutPoints.length - 1];
break;
}
压缩摘要由模型生成,模板要求保留 Goal、Constraints & Preferences、Progress(Done / In Progress / Blocked)、Key Decisions、Next Steps 和 Critical Context 等信息。对于重复压缩,系统根据是否存在 previousSummary 选择初次摘要或增量更新提示词。
let basePrompt = previousSummary
?UPDATE_SUMMARIZATION_PROMPT
:SUMMARIZATION_PROMPT;
Sₜ = Update(Sₜ₋₁, ΔHₜ)
相较于原始消息的简单截断,结构化摘要更有利于保持任务连续性,但仍是有损转换。关键约束、精确代码定位和校验结果在反复压缩中可能遗漏,不宜完全依赖摘要承担权威任务状态。压缩还跟踪文件读取、修改等操作信息,为后续编程任务提供背景。
源码:compaction.ts(findCutPoint、findProjectedCutPoint、prepareCompaction、generateSummaryWithUsage、compact)。
(四)模型调用前转换及扩展
Agent Loop 在调用模型前依次执行 transformContext、convertToLlm 和 normalizeContext,分别承担可选上下文变换、内部消息格式转换和请求规范化。transformContext 是二次开发的基础扩展点,但 Pi 默认接口并不自动提供目标规划、知识检索与信息相关性排序。
let messages = context.messages;
if (config.transformContext) {
messages= await config.transformContext(messages, signal);
}
const llmMessages = await config.convertToLlm(messages);
const llmContext = normalizeContext({ messages: llmMessages });
此外,session_before_compact 扩展事件允许在压缩前介入,按业务规则取消压缩或提供自定义压缩结果;此机制能够承载对审计规则、编程约束、本体建模规范等关键信息的保护策略。
源码:packages/agent/src/agent-loop.ts(streamAssistantResponse);packages/agent/src/agent.ts(transformContext);agent-session.ts(session_before_compact)。
四、总结
Pi 通过会话树、上下文投影、压缩检查点、结构化摘要与调用前转换,实现了工程上较为完整的上下文基础管理体系,其主要价值是将“完整历史”和“模型当前可见信息”分离,并为压缩与编辑提供轻量、可扩展的实现。其优势在于:会话历史与运行时视图解耦,保留可追溯性;使用 Token 预算和增量摘要控制开销;通过树形会话和检查点支持分支与恢复;为上下文编辑、转换及压缩预留可扩展入口。
分析维度 | 已有机制 | 主要不足 |
目标管理 | 摘要保留 Goal | 缺少独立、可校验的目标状态 |
历史组织 | 会话树、投影、编辑 | 默认缺少任务语义相关性评分 |
执行状态 | 会话记录与摘要 | 缺少统一的结构化进度与证据模型 |
压缩质量 | 保留近期消息、增量摘要 | 多轮压缩存在信息损失风险 |
知识与记忆 | 支持扩展接入 | 缺少默认的统一精准供给策略 |
闭环纠偏 | 工具执行反馈 | 缺少目标偏差驱动的上下文重规划 |
附录:关键源码索引
会话管理、投影和编辑·packages/coding-agent/src/core/session-manager.ts
压缩算法、摘要及切分·packages/coding-agent/src/core/compaction/compaction.ts
压缩运行调度·packages/coding-agent/src/core/agent-session.ts
Agent Loop 请求前转换·packages/agent/src/agent-loop.ts
Agent 配置与转换接口·packages/agent/src/agent.ts
分支摘要·packages/coding-agent/src/core/compaction/branch-summarization.ts















































































