Pi 智能体集成:消息解析、重试与取消
在集成基于命令行的智能体时,有三件事是避不开的:如何将其私有事件流转换为稳定的消息、失败后由谁负责重试,以及当用户点击取消时如何干净地停止进程。这三件事本质上归结为“明确职责”——理论上很简单,但只有真正动手做时,你才会意识到水有多深。
背景
最近,我一直在开发一个人工智能编码助手项目,其中需要集成的智能体之一是 pi。它是一个终端用户界面/命令行界面的编码智能体,在运行时将 JSON 事件逐行输出到标准输出。听起来很简单——生成进程、读取输出、解析它——但当你真正开始时,你会发现“集成智能体命令行工具”与“集成普通命令行工具”完全不同。
对于普通的命令行工具,你读取标准输出,获取退出代码,就结束了。但智能体命令行工具有三个特别令人头疼的特征:
首先,它的事件流是一种私有协议。turn_start(回合开始)、session(会话)、message_update(消息更新)、message_end(消息结束)、turn_end(回合结束)、agent_end(智能体结束)——这些是由 pi 自行定义的,而非任何行业标准。每个想要消费它的上层应用都必须单独处理,这实际上导致 pi 的内部细节泄露得到处都是。这就像从远处看一个人——你以为你看清楚了,但其实你只看到了对方想让你看到的一面。
其次,其失败语义特别模糊。智能体在运行过程中可能会遇到网络抖动、模型速率限制或进程崩溃。应该重试吗?在哪里重试?重试是否会搞乱已经输出一半的会话状态?这是一个架构决策,不是随便写一个 for 循环就能解决的问题。
第三,它是长期运行且可中断的。单个回合可能运行数十秒甚至数分钟,用户可能希望随时取消。取消时,进程不能变成孤儿进程,工具调用不能留有一半未完成的状态,已输出的内容也不能丢失。这里的水比想象的要深得多。
为了解决这些痛点,我们花了一些时间梳理集成路径。稍后我会详细介绍具体细节,但先剧透一下:真正的难点不在于“生成进程”,而在于“明确职责”。
关于 HagiCode
本文分享的解决方案来自 HagiCode 项目——一个支持多种模型和多种智能体命令行后端的人工智能编码助手。GitHub 仓库:HagiCode-org/site,欢迎点亮星标。下面提到的所有代码和所有陷阱都实际在这个项目中运行。写出来只是为了给自己留个记忆。
整体分层
HagiCode 将人工智能能力集成分为两层:
- 底层是
Hagicode.Libs,提供可复用的提供商原语ICliProvider<TOptions>,专门负责“生成命令行智能体并将其输出规范化为共享消息流”。 - 上层是
hagicode-core,提供项目级的薄适配器IAIProvider,负责“将业务请求转换为提供商参数,消费共享消息流,并免责声明:本文内容来自互联网,该文观点不代表本站观点。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请到页面底部单击反馈,一经查实,本站将立刻删除。