<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh">
    <title>bigfish的网络博客 - rpi</title>
    <subtitle>记录技术和生活</subtitle>
    <link rel="self" type="application/atom+xml" href="https://blog.bigfisharc.cn/tags/rpi/atom.xml"/>
    <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-10-15T09:00:00+08:00</updated>
    <id>https://blog.bigfisharc.cn/tags/rpi/atom.xml</id>
    <entry xml:lang="zh">
        <title>从一个 helloworld 动态库到 rpi package：ABI 插件是怎样被加载的</title>
        <published>2026-10-15T09:00:00+08:00</published>
        <updated>2026-10-15T09:00:00+08:00</updated>
        
        <author>
          <name>bigfish</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn/blog/20261015-0900-rpicha-jian-abijia-zai-ji-zhi/"/>
        <id>https://blog.bigfisharc.cn/blog/20261015-0900-rpicha-jian-abijia-zai-ji-zhi/</id>
        
        <summary type="html">&lt;p&gt;很多人第一次看到 rpi 的 Rust 插件，会把它理解成“编译出一个动态库，然后让 rpi 找到它”。这句话方向没错，但省略了最关键的部分：动态库如何证明自己是一个 rpi 插件？注册的工具如何跨过 Rust 边界？一次调用结束后，插件里的内存由谁释放？源码目录里的 crate 又是怎样变成项目里的 package 的？&lt;/p&gt;
&lt;p&gt;这篇文章从 &lt;code&gt;examples/plugin-stub&lt;/code&gt; 这样的最小 demo 开始。我们可以先从这个简单例子入手，再沿着 &lt;code&gt;rpi-plugin-sdk&lt;/code&gt;、&lt;code&gt;rpi-extensions&lt;/code&gt; 和 &lt;code&gt;rpi-cli&lt;/code&gt; 的实现，解释这条链路：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;mermaid&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;flowchart&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-6&quot;&gt; LR&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    A&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;插件源码\nRust crate&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt; --&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; B&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;cdylib\n.dll / .so / .dylib&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    B &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; C&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;rpi 加载器\nlibloading&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    C &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; D&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;rpi_plugin_register&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    D &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; E&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;HostApi + ExtensionRegistry&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    E &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; F&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;RegistrySnapshot&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt;    F &lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;--&amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-10&quot;&gt; G&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-12 z-d-5&quot;&gt;Agent 会话中的工具\n事件与其他扩展能力&lt;/span&gt;&lt;span class=&quot;z-l-13 z-d-8&quot;&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这里的“插件”指 rpi 的 Rust 原生 ABI 扩展，不是 MCP Server，也不是一个通过 HTTP 或 stdio 运行的外部进程。我们可以先把它看成宿主进程里的一段本机可信代码：它和宿主运行在同一个进程里，因此能力强、开销低，但也意味着 ABI、内存所有权和生命周期必须非常明确。&lt;/p&gt;
&lt;p&gt;本文讨论的是 rpi 的原生 ABI 插件机制。由于 ABI、loader 和 package 命令会随仓库版本变化，下面的文件名、符号名和命令都应与所读源码版本一起核对；代码块中明确标注为“示意”的部分，不等于可直接复制运行的最小插件。文章关注一条主线：插件如何从动态库进入注册表，再被会话驱动；不把它扩展成完整的 Rust FFI 教程。&lt;/p&gt;</summary>
        
    </entry>
    <entry xml:lang="zh">
        <title>rpi-acp 源码解读：以 Zed 为例，一个 ACP Client 如何启动并驱动 rpi Agent</title>
        <published>2026-10-14T00:04:00+08:00</published>
        <updated>2026-10-14T00:04:00+08:00</updated>
        
        <author>
          <name>bigfish</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn/blog/20261014-0004-acpshi-shen-me/"/>
        <id>https://blog.bigfisharc.cn/blog/20261014-0004-acpshi-shen-me/</id>
        
        <summary type="html">&lt;p&gt;在 &lt;code&gt;rpi-package&lt;/code&gt; 的 &lt;code&gt;rpi-acp&lt;/code&gt; 中，ACP 指的是 &lt;strong&gt;Agent Client Protocol&lt;/strong&gt;。这个 package 的实际用途很具体：让 Zed 这样的 ACP Client 通过标准输入输出启动 rpi，并把 rpi 当作一个可以发送 prompt、接收流式更新和处理权限请求的外部 Agent。&lt;/p&gt;
&lt;p&gt;本文以 Zed 作为具体客户端，因为仓库提供了完整的 Zed 注册、配置和排错路径；但 &lt;code&gt;rpi-acp&lt;/code&gt; 并不是 Zed 专用实现。只要其他客户端支持 ACP v1、JSON-RPC 2.0 和 stdio，并能处理本文介绍的会话与更新方法，同样可以通过 &lt;code&gt;rpi-acp-bridge&lt;/code&gt; 启动 rpi。&lt;/p&gt;
&lt;p&gt;本文对应 &lt;code&gt;rpi-packages&lt;/code&gt; 中的 &lt;code&gt;rpi-acp&lt;/code&gt; &lt;strong&gt;0.1.3&lt;/strong&gt;，主要源码如下：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;packages/rpi-acp/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/lib.rs       插件生命周期、ownsStdio、启动服务&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/main.rs      独立 rpi-acp-bridge 二进制&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/protocol.rs  ACP v1 JSON-RPC 服务与请求分发&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/session.rs   每个 ACP session 对应的 rpi RPC 子进程&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/history.rs   session 历史保存与回放&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── src/zed.rs       Zed settings.json 注册&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;源码仓库：&lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/pi-rust/rpi-package/tree/master/packages/rpi-acp&quot;&gt;https://github.com/pi-rust/rpi-package/tree/master/packages/rpi-acp&lt;/a&gt;&lt;/p&gt;</summary>
        
    </entry>
    <entry xml:lang="zh">
        <title>rpi-mcp-adapter 源码解读：一个 Rust MCP 适配器如何管理工具调用</title>
        <published>2026-10-14T00:04:00+08:00</published>
        <updated>2026-10-14T00:04:00+08:00</updated>
        
        <author>
          <name>bigfish</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn/blog/20261014-0004-mcpshi-shen-me/"/>
        <id>https://blog.bigfisharc.cn/blog/20261014-0004-mcpshi-shen-me/</id>
        
        <summary type="html">&lt;p&gt;很多 MCP 文章讲的是“Host、Client、Server”三个概念，但真正接入一个 MCP Server 时，代码要处理的事情远不止发一条 JSON-RPC：配置如何解析？本地进程如何启动？远程 HTTP 会话如何保存？超时后能不能安全退出？工具列表变化后是否重新发现？&lt;/p&gt;
&lt;p&gt;这篇文章不再从 MCP 规范泛讲，而是直接阅读 &lt;code&gt;rpi-mcp-adapter&lt;/code&gt; 的代码，回答一个具体问题：&lt;strong&gt;rpi 是如何把外部 MCP Server 接进自己的工具循环的？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;本文对应 &lt;code&gt;rpi-packages&lt;/code&gt; 中的 &lt;code&gt;rpi-mcp-adapter&lt;/code&gt; &lt;strong&gt;0.2.1&lt;/strong&gt;，源码范围主要是：&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;packages/rpi-mcp-adapter/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/lib.rs          插件入口和三个宿主工具&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/config.rs       mcpServers 配置解析&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/connection.rs   MCP 初始化与 tools 请求构造&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/runtime.rs      连接缓存、发现、调用和关闭&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;├── src/transport.rs    stdio 子进程传输&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;└── src/http.rs         Streamable HTTP 传输&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;源码仓库：&lt;a rel=&quot;noopener noreferrer external&quot; target=&quot;_blank&quot; href=&quot;https://github.com/pi-rust/rpi-package/tree/master/packages/rpi-mcp-adapter&quot;&gt;https://github.com/pi-rust/rpi-package/tree/master/packages/rpi-mcp-adapter&lt;/a&gt;&lt;/p&gt;</summary>
        
    </entry>
    <entry xml:lang="zh">
        <title>如果你想拥有自己的 Agent，为什么值得从 rpi 开始</title>
        <published>2026-10-12T23:30:00+08:00</published>
        <updated>2026-10-12T23:30:00+08:00</updated>
        
        <author>
          <name>bigfish</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn/blog/20261012-rpi-runtime/"/>
        <id>https://blog.bigfisharc.cn/blog/20261012-rpi-runtime/</id>
        
        <summary type="html">&lt;p&gt;如果你只是想找一个好用的 coding agent，直接安装一个现成产品通常是最省事的选择。&lt;/p&gt;
&lt;p&gt;但如果你要把 Agent 放进自己的产品、服务或开发工具里，问题就变了：你需要的可能不是一个只能通过命令行使用的工具，而是一套&lt;strong&gt;自己能够拥有和控制的 Agent runtime&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这正是 rpi 的定位。&lt;/p&gt;</summary>
        
    </entry>
    <entry xml:lang="zh">
        <title>rpi 这些扩展到底怎么选？一张工具地图看懂 16 个 Rust 插件</title>
        <published>2026-10-11T09:03:00+08:00</published>
        <updated>2026-10-11T09:03:00+08:00</updated>
        
        <author>
          <name>bigfish</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn/blog/20261011-0903-rpigong-ju-di-tu/"/>
        <id>https://blog.bigfisharc.cn/blog/20261011-0903-rpigong-ju-di-tu/</id>
        
        <summary type="html">&lt;p&gt;rpi 已经有一批常见的原生 Rust 插件。数量上还没有成熟生态那么多，但任务规划、代码分析、网络访问、运行观测、消息渠道和语音交互等日常场景，基本都已经有对应能力可以使用。&lt;/p&gt;
&lt;p&gt;如果只看包名，&lt;code&gt;rpi-packages&lt;/code&gt; 很容易变成一张“功能名词表”：&lt;code&gt;todo&lt;/code&gt;、&lt;code&gt;goal&lt;/code&gt;、&lt;code&gt;lens&lt;/code&gt;、&lt;code&gt;MCP&lt;/code&gt;、&lt;code&gt;Langfuse&lt;/code&gt;、&lt;code&gt;voice&lt;/code&gt;……每个词都认识，真正要装哪个却不容易判断。&lt;/p&gt;
&lt;p&gt;这篇文章先把目前已有的扩展整体展示出来，再按使用场景说明它们分别解决什么问题。你可以把它当成一张选型地图：先从任务找到需要的能力，再决定安装哪些包，而不是把整个扩展目录全部装上。后续如果你正在使用其他原生 Rust 插件，也欢迎补充。&lt;/p&gt;</summary>
        
    </entry>
    <entry xml:lang="zh">
        <title>我用 100 行核心代码，做了一个能接入飞书的 Hermes 式智能体</title>
        <published>2026-10-08T00:00:00+00:00</published>
        <updated>2026-10-08T00:00:00+00:00</updated>
        
        <author>
          <name>bigfish</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn/blog/20261008-100xing-dai-ma-yong-rpifu-ke-hermeshe-xin-zhi-neng-ti/"/>
        <id>https://blog.bigfisharc.cn/blog/20261008-100xing-dai-ma-yong-rpifu-ke-hermeshe-xin-zhi-neng-ti/</id>
        
        <summary type="html">&lt;p&gt;很多人看到 Hermes Agent 的体验，第一反应是：&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;我也要把自己的 Agent 接进飞书。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;然后就开始设计 Webhook、消息签名、事件回调、会话表、流式输出和重试队列。还没让 Agent 回第一句话，网关已经先写了一半。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;其实，最简单的方式不是再造一个飞书机器人服务，而是直接让 rpi 接管这条长连接。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;rpi 的 &lt;code&gt;rpi-im-message&lt;/code&gt; 扩展已经把飞书接入层包起来：飞书消息通过官方 Rust SDK 的 WebSocket 长连接进入 rpi，rpi 负责调用 Agent，模型的最终回复再发回原来的会话。你需要配置飞书应用和模型，不需要从零实现一套消息网关。&lt;/p&gt;
&lt;p&gt;这篇文章会分成两层：先用约 100 行代码把 Hermes 式 Agent 的核心循环讲清楚，再告诉你真正接入飞书时为什么不必自己写网关。&lt;strong&gt;代码用来理解原理，扩展用来减少接入成本。&lt;/strong&gt;&lt;/p&gt;</summary>
        
    </entry>
    <entry xml:lang="zh">
        <title>如果要给 Agent 搭一套可观测平台，应该从哪里开始？</title>
        <published>2026-10-05T13:28:00+08:00</published>
        <updated>2026-10-05T13:28:00+08:00</updated>
        
        <author>
          <name>bigfish</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn/blog/20261005-1328-langfusebao-wen-jie-xi/"/>
        <id>https://blog.bigfisharc.cn/blog/20261005-1328-langfusebao-wen-jie-xi/</id>
        
        <summary type="html">&lt;p&gt;假设你让一个编码 Agent“读一下配置文件，再把超时时间改成 30 秒”。它最后回复“已经改好了”，但你打开文件，发现内容没变。&lt;/p&gt;
&lt;p&gt;问题出在哪一步？模型理解错了要求，工具读错了文件，还是写入失败了？如果只保存用户输入和最终回答，这几个原因很难分辨。&lt;/p&gt;
&lt;p&gt;给 Agent 做可观测，就是把中间过程也记录下来：每次模型收到了什么、返回了什么，每次工具用了什么参数、执行结果如何，以及每一步花了多长时间。这样出了问题，就能沿着同一次任务往回查，而不是从一堆日志里猜。&lt;/p&gt;</summary>
        
    </entry>
    <entry xml:lang="zh">
        <title>Pi 的 Rust 实现来了：rpi，不止一个终端 Agent</title>
        <published>2026-10-01T23:11:04+08:00</published>
        <updated>2026-10-01T23:11:04+08:00</updated>
        
        <author>
          <name>bigfish</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://blog.bigfisharc.cn/blog/20261006-2311-pide-rustshi-xian-lai-liao-rpi-bu-zhi-yi-ge-zhong-duan-agent/"/>
        <id>https://blog.bigfisharc.cn/blog/20261006-2311-pide-rustshi-xian-lai-liao-rpi-bu-zhi-yi-ge-zhong-duan-agent/</id>
        
        <summary type="html">&lt;p&gt;如果你熟悉 Pi，rpi 可以理解为它的 Rust 实现：同样能在终端里读文件、改代码、执行命令，也能作为库嵌入自己的程序。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;rpi 用 Rust 重新实现 Pi SDK，并在这套运行时之上提供终端 CLI 和原生扩展。&lt;/strong&gt; 想直接使用编码助手，可以安装后运行；想构建自己的 Agent，则可以选择需要的模型接入、工具循环和会话管理组件。&lt;/p&gt;</summary>
        
    </entry>
</feed>
