User Input: pi "帮我改个 bug" ↓ cli.ts (Parse CLI args) ↓ main.ts (Create session, select run mode) ↓ AgentSession (Load tools & extensions) ↓ Agent (Manage state & logic) ↓ agentLoop() (Core execution loop)Agent 出 demo 只要一周,上线却要一年
- Demo:选定靠谱的模型 + 设定系统提示词 + 配上工具
- 上线:会出现各种意想不到的坑
70K Star 的开源项目pi-agent以极简著称,可以借助其来进行工程化学习
- 如何维护 Agent 的循环
- 如何进行上下文管理
- 如何有效地管理工具调用
二、Loop Maintenance
2.1 Agent 的本质:循环调用模型
Agent 的本质是一个不断调用模型的循环:
用户输入 → 模型决策 ├─ 调用工具 → 执行工具 → 将结果告诉模型 → 回到模型决策 └─ 不调用工具 → 直接返回文本 → 终止循环模型只有两种决定:调用工具或不调用工具。不断重复,直到模型单纯返回文本,循环终止。
2.2 Trace & Turn
- Trace,从用户输入一个问题,到模型
最终答复的完整过程 - Turn,在一个 Trace 中,每一次
模型调用称为一个 Turn
每个 Turn 又可拆解为两个环节:
- 模型调用环节
- 工具执行环节
2.3 pi-agent 的 10 个干预节点
设计:一个 Trace 从开始到结束,有 10 个地方可以干预循环:
- Trace 开始:记录开始时间
- Turn 开始:判断当前轮数,达到上限(如 100 轮)则停止,防止无线循环
- 模型调用前:准备上下文
- 模型调用时:实际发起 API 请求
- 模型调用后:敏感词检测,防止模型输出违规内容
- 工具执行前:判断工具是否危险(如 delete/drop),危险操作直接拦截
- 工具执行时:实际执行工具逻辑
- 工具执行后:对返回结果做脱敏等后处理
- Turn 结束:记录本轮运行结果
- Trace 结束:记录整体响应耗时,支撑后续性能优化
这 10 个干预节点的设计极其优雅——大部分 Agent 框架都有这个功能
三、Context Engineering
3.1 为什么上下文工程是关键
Agent 效果取决于两点:
- 模型本身的能力
- 每一轮提交给模型的提示词(即上下文)
上下文工程:
- 该给的信息要给齐
- 不用给的信息不要给:占用上下文会分散模型注意力
员工的作用或许是帮领导补充上下文
如果领导转发消息时什么都不说,全靠员工猜测,做错了就说是没悟性——这样的领导大概是不会喜欢 AI 的。AI 没有足够上下文就干不了活,而员工会自动帮领导补齐上下文。
pi-agent 的上下文处理
工具输出截断
有些工具输出很长(如read读文档、bash执行命令),可能一下子撑爆上下文
处理方法:
- 完整结果保存在本地文件
- 提供给模型的只有**
截断后的文本 + 本地文件路径** - 由模型自己评估要不要去读完整内容
tips
- 按字符截断还是按字节截断?
- 保留前面还是保留后面?
- 需要根据不同场景具体分析
上下文压缩
为什么压缩
- 防止超限:模型上下文有限,Agent 多轮循环中上下文累积很快,容易超限报错
- 性能:上下文越长模型越笨,但历史信息密度越来越低
什么时候压缩?
- pi-agent 会设定一个
token 阈值 - 结合模型上下文长度与当前上下文长度,计算剩余可用量
- 当剩余可用量低于阈值时,主动发起压缩
tips:实际上下文压缩应**提前进行**——在模型完成上一轮任务后就判断是否压缩。如果等到下一轮任务开始时才压缩,用户会陷入无聊的等待。
压缩成什么样子?
pi-agent 的建议是按结构化模板压缩(以 coding agent 为例):
1. 用户目标 2. 约束条件 3. 工作流程 4. 关键决策 5. 下一步计划不同场景的模板需要自己思考(如 data agent 场景)。或者直接给模型一个方向让它自由发挥,效果也不错。
压缩后怎么用?
在下一轮对话中,将压缩后的结果替代被压缩的那部分上下文,完成上下文重组
Context Caching
合理编排来提升 prompt cache 命中率:
- 系统提示词的分区:什么信息放前面,什么信息放后面
- 尽量避免提示词的**
前缀变化**
Claude Code 在这一点上做得很好,花了很多心思处理。
四、Tool Calling Management
4.2 基础技巧
- 写清楚工具的 schema—— 降低模型的理解负担
- 选一个靠谱的模型—— 至少具备 function calling 能力的模型
经过这两步,模型依然传回错误的工具指令,就要进入 pi-agent 的工具调用管理流程。
4.3 工具调用
参数验证
pi-agent 做两种参数验证:
- JSON 格式修复:有些模型返回调用指令时会把 JSON 序列化成字符串,pi-agent 检测到后会自动转化为正确的 JSON 格式
- Schema 验证:参数要求传数字型却返回文本型时,pi-agent 帮忙
直接转化
原则:尽量给模型兜底,能解决的问题就都给解决掉。
调用前安全检查
- 对应"工具执行前"干预节点
- 判断是否有危险指令
- 是否访问了不该访问的文件
eg:data agent 场景中,模型想delete甚至drop,就把它reject。
调用时错误处理
原则:工具执行失败时,把报错信息当成结果返回给模型,而不是终止循环。
这样 Agent 循环不会被中断,模型根据报错信息重新生成准确的调用指令。
eg:data agent 场景中,模型用 SQL 查了不存在的字段,把报错信息返回给模型,模型会意识到要重新读表结构,生成准确的 SQL。
实践:
- 根据不同工具**
预定义可能的错误信息**,说明这是什么错误、要怎么处理 - 穷举不了,就返回一条通用的报错信息
- 给模型**
继续纠错的机会**,Agent 才会更稳定和智能
调用后结果调整
- 对应"工具执行后"干预节点
- 对返回的结果进行后处理
- 例:data agent 场景中,校验返回结果中有无敏感信息,必要时脱敏
下篇预告
参考:
https://github.com/earendil-works/pi
https://dg-ai-notes.pages.dev