为什么要用 Rust 重写?
1. 学习 Rust
首先就是想学 Rust。
我想找一个能持续写下去的项目。Agent 涉及异步请求、流式输出、文件操作和状态管理,后面还有终端界面和插件。这些需求会逼着我把 Rust 用起来:共享状态怎么处理,错误怎么往上传,异步任务怎么取消,接口怎么拆。
选 Pi 来重写,也有一个好处:有现成的项目可以参考。遇到一个功能,可以先看原版怎么做,再考虑在 Rust 里怎么实现。写完以后还有东西可以对照,不至于只凭自己的想象判断是否合理。
2. 想弄明白一个 Agent 是怎么工作的
平时用 AI 编码工具,看到的是输入需求、等它改代码。自己实现一次,就得处理那些界面上看不见的细节。
模型返回一个工具调用以后,谁去执行?工具出错了,要把什么结果交给模型?流式消息还没结束,用户取消了怎么办?程序中断后,下一次启动看到的历史应该是什么?
这些问题在调一次聊天 API 时未必会遇到,做完整 Agent 就绕不过去。
核心循环其实不长:请求模型,发现工具调用,执行工具,回传结果,再请求模型。周围的错误处理、取消、会话保存,才是需要花心思的地方。
3. 想把它做成一个能复用的库
我希望 rpi 除了能在终端里运行,也能直接嵌进自己的 Rust 程序。应用调用接口、订阅事件,就能使用 Agent 的能力。
所以项目用了 Cargo workspace,把模型适配、Agent 循环、工具执行和会话管理拆开。CLI 再把它们组合起来。
最小的 Agent 不需要终端界面,也不一定需要持久化。需要文件工具,就加工具层;需要保存会话和压缩上下文,再接 Harness。这样不同应用能各取所需。
4. 看看原生程序能省下多少开销
终端工具最后能交付一个可执行文件,安装时少管理一套 Node 和 npm 依赖,我觉得值得试。
启动和内存上的收益,前面的测试已经给了一组结果。代价也有:Rust 的异步接口、共享状态和动态插件都需要仔细处理。把原版代码逐行翻译过来,很多地方并不好用,接口也得跟着重新整理。
现在到哪一步了
已经有 CLI、TUI 和 SDK,不只是一个调用模型的 demo。当前工作区版本是 0.3.14;发布状态以仓库 Releases 和 crates.io 为准。
模型侧有 Anthropic 和 OpenAI 兼容接口,也支持通过配置接自定义网关。Agent 能处理流式响应、工具调用和取消,配有文件读写、编辑和命令执行等工具。
会话用 JSONL 保存,支持分支、上下文压缩和中断恢复。这里也一直在修实际问题。比如 CHANGELOG 里记录过:会话中断时,工具调用已经保存,结果还没保存,恢复后的消息就可能被模型服务拒绝。现在会补上表示中断的错误结果,让上下文可以继续使用,而不会直接重跑那个工具。
扩展方面已经有动态库插件 SDK 和加载器。远程模式也有了,可以在一台机器上跑 Agent,另一端用终端连接。
这些功能对应九个产品 crate。主要几层如下:
| crate | 做什么 |
|---|---|
rpi-ai |
模型适配、消息类型和流式响应 |
rpi-agent |
Agent 循环、工具调用、事件和取消 |
rpi-tools |
内置工具和执行环境 |
rpi-harness |
会话、持久化、恢复和上下文压缩 |
rpi-cli |
配置、CLI、TUI 和远程模式 |
想从代码看起,可以先跑两个例子:
cargo run -p minimal
cargo run -p tools-example
它们用模拟 Provider,不需要模型密钥。第二个例子会驱动真实工具,在临时目录写文件,再读取并验证内容。这样可以先检查 Agent 的执行流程,不受真实模型输出影响。目前还有不少需要打磨的地方。
有没有后续的扩展计划
有,接下来想继续做的主要是这些方向。
扩展更容易写和安装。 插件接口和加载器已经有了,但还需要更顺手的模板、版本兼容说明,以及能直接拿来用的扩展。先把开发和使用的流程理顺,比单纯增加插件数量更有用。
继续补模型适配。 现有 Provider 接口可以复用,后面会根据使用需求考虑 Gemini、Bedrock 等适配器。每接一种协议,都要检查流式事件、工具调用和错误处理,不能只验证普通聊天能返回文字。
把性能测试往长任务上补。 下一步值得测的是长会话内存增长、工具循环吞吐、上下文压缩和 TUI 渲染。启动数据已经有了,我也想知道连续用上几个小时以后是什么表现。
更往后的方向包括执行隔离、编辑器集成,以及是否把多 Agent 编排放进核心运行时。这些需要继续设计,暂时没有确定的交付时间。
项目地址:bigfish1913/pi-rust。 希望大家多多支持!!
Ext Link: https://rpi.laofu.online/
评论区
写评论还没有评论