资讯详情

资讯详情

Rig 的 WebSocket 传输后端:rig-tungstenite 源码与实战指南

AI AgentAgent 框架RAG后端【免费下载链接】rig⚙️ Build modular and scalable LLM Applications in Rust项目地址https://gitcode.com/GitHub_Trending/rig2/rig点击查看免费下载本篇指南聚焦 Rig 仓库中crates/rig-tungstenite这一官方捆绑的 WebSocket 传输后端它基于tokio-tungstenite实现rig_http::ws_client::WebSocketClientExt契约让 OpenAI Responses 会话可以无缝运行在 WebSocket 之上。读完本文你将掌握如何在 Rig 中开启 WebSocket 会话、如何显式注入自定义后端、该后端在有无 Tokio 运行时两种场景下的工作机制以及升级拒绝、超时与帧序等边界行为是如何被设计与验证的。分层架构协议归 rig-core契约归 rig-httpSocket 归 rig-tungsteniteRig 对 WebSocket 支持做了清晰的三层切分rig-tungstenite只是其中负责物理 Socket的最底层rig-core拥有 WebSocket 协议OpenAI Responses 会话、事件信封event envelope以及整个 turn 状态机都位于rig_core::providers::openai::responses_api::websocket见 crates/rig-core/src/providers/openai/responses_api/websocket.rs。这一层面向传输无关的rig_http::ws_client契约编写并在rig_core::ws_client处重新导出。rig-http持有传输契约包括WebSocketClientExt、WebSocketConnection、Frame、ConnectOptions等抽象见 crates/rig-http/src/ws_client.rs。rig-tungstenite只拥有 SocketTungsteniteClient是该契约的一个具体实现内部驱动tokio-tungstenite完成握手、收发帧与关闭握手。正如rig-reqwest只拥有 HTTP 传输一样这个 crate 不关心任何会话协议细节。这种协议与传输分离的设计带来一个直接好处WebSocket 后端是可插拔的。只要实现WebSocketClientExt任何自定义后端例如基于web_sys::WebSocket的浏览器实现都可以接入 Rig 的 Responses WebSocket 会话。从依赖关系看rig-tungstenite只依赖rig-http开启websocketfeature外加futures与thiserror见 crates/rig-tungstenite/Cargo.toml。tokio与tokio-tungstenite则被限定在cfg(not(target_family wasm))条件下引入因为这本质是一个面向原生环境的实现。快速上手一行代码打开 Responses WebSocket 会话方式一启用tungstenitefeature免指定后端在rig-core中启用tungstenitefeature 后ResponsesWebSocketSessionBuilder::connect()会自动使用内置的TungsteniteClient无需命名后端let session model.responses_websocket().connect().await?;对应的实现位于 crates/rig-core/src/providers/openai/responses_api/websocket.rs#L251-L258#[cfg(all(feature tungstenite, not(target_family wasm)))] pub async fn connect(self) - ResultResponsesWebSocketSession, ProviderError { self.connect_with(rig_tungstenite::TungsteniteClient::new()) .await }也就是说connect()本质上就是connect_with(TungsteniteClient::new())的便捷封装。TungsteniteClient是一个无状态后端#[derive(Clone, Copy, Debug, Default)]见 crates/rig-tungstenite/src/lib.rs握手配置URI、认证头、超时全部来自每次请求本身。方式二显式传入后端未启用tungstenitefeature例如在 wasm 目标上或需要注入自定义后端时使用connect_withlet session model.responses_websocket().connect_with(TungsteniteClient::new()).await?;connect_with接受任意W: WebSocketClientExt见 crates/rig-core/src/providers/openai/responses_api/websocket.rs#L262-L276。responses_websocket()入口本身不依赖任何特定后端见 crates/rig-core/src/providers/openai/responses_api/websocket.rs#L870-L878。会话时间配置ResponsesWebSocketSessionBuilder提供两类超时配置见 crates/rig-core/src/providers/openai/responses_api/websocket.rs#L202-L248配置项默认值说明connect_timeout(Duration)30 秒DEFAULT_CONNECT_TIMEOUT定义于同文件第 34 行建立 WebSocket 连接的握手超时without_connect_timeout()—禁用连接超时event_timeout(Duration)禁用None等待下一条 WebSocket 事件的最大时长without_event_timeout()—禁用事件超时注意连接超时是由后端在握手阶段强制执行的见ConnectOptions.timeout与会话层的事件超时相互独立。Cargo feature 与 TLS 选择rig-tungstenite自身的 feature见 crates/rig-tungstenite/Cargo.tomlFeature默认作用default [rustls]是默认启用 rustls TLSrustls是启用tokio-tungstenite/rustls-tls-webpki-roots基于 webpki-roots 的 rustls 证书栈native-tls否切换为tokio-tungstenite/native-tls在rig-core侧feature 的联动关系见 crates/rig-core/Cargo.tomltungstenite [websocket, dep:rig-tungstenite]同时拉起传输无关的websocket契约与捆绑后端rustls [rig-reqwest?/rustls, rig-tungstenite?/rustls]、native-tls [...]为 HTTP 与 WebSocket 两个传输统一选择 TLS 栈恰好启用其中一个默认rustls。wasm 目标的明确限制rig-tungstenite是原生后端tokio-tungstenite需要 Tokio reactor。在 wasm 目标上该 crate 会在编译期直接报错见 crates/rig-tungstenite/src/lib.rs#L22-L29#[cfg(target_family wasm)] compile_error!( rig-tungstenite is a native websocket backend (tokio-tungstenite). On wasm, implement \ rig_http::ws_client::WebSocketClientExt over web_sys::WebSocket and open sessions with \ connect_with(..). );即浏览器场景应基于web_sys::WebSocket自行实现WebSocketClientExt再通过connect_with(..)打开会话。rig-http的ws_client契约正是为这种可插拔场景准备的接缝seam。这也解释了为什么rig-core将rig-tungstenite依赖放在[target.cfg(not(target_family wasm)).dependencies]下且 feature 层面做了降级处理见 crates/rig-core/Cargo.toml#L59-L62。传输契约详解Frame、CloseFrame 与 ConnectOptionsWebSocketClientExt与WebSocketConnection两个 trait 是后端实现的唯一入口定义见 crates/rig-http/src/ws_client.rsWebSocketClientExt::connect(self, request: RequestNoBody, options: ConnectOptions)打开一条连接升级被拒绝时必须保留 HTTP 状态码、响应头和响应体。WebSocketConnection提供send(Frame)、recv()返回Ok(None)表示对端结束流、close(OptionCloseFrame)三个方法以WasmBoxedFuture返回保证会话的线程安全契约在 wasm 下也可编译。Frame枚举覆盖 WebSocket 的全部数据与控制帧变体含义Text(String)UTF-8 文本帧Binary(Bytes)二进制帧Ping(Bytes)Ping 帧携带应用载荷Pong(Bytes)Pong 帧携带应用载荷Close(OptionCloseFrame)关闭帧Some时携带对端的 RFC 6455 状态码与原因CloseFrame { code: u16, reason: String }直接对应 RFC 6455 的关闭码与关闭原因。ConnectOptions { timeout: OptionDuration }只负责握手超时可通过ConnectOptions::new().with_timeout(...)构造。值得注意的细节在 crates/rig-tungstenite/src/connection.rs 的from_message中Message::Frame(_)原始帧不承载会话级协议载荷会被跳过并返回None而不是把一段会被会话当作 JSON 解析的裸字节交上去同时DirectConnection::recv会用循环持续读取直到拿到一个有效帧见 crates/rig-tungstenite/src/connection.rs#L40-L55。connection/tests.rs中的测试逐一验证了 Text/Binary/Ping/Pong/Close 六种帧在 tungstenite 表示间的往返一致性并确认原始帧被正确丢弃见 crates/rig-tungstenite/src/connection/tests.rs。rig-http还提供了websocket_url(base_url, path)辅助函数将https/http基地址转换为wss/ws地址并拼接路径例如https://example.com/v1responses→wss://example.com/v1/responses不支持的 scheme 会返回错误见 crates/rig-http/src/ws_client.rs#L117-L144。运行时策略Direct 与 Forwarded 两条路径TungsteniteClient::connect的核心逻辑见 crates/rig-tungstenite/src/lib.rs#L66-L87会根据调用方是否处于 Tokio 运行时选择两种截然不同的连接实现connect() ├─ 调用方在 Tokio 运行时内 → 握手后返回 DirectConnection由调用方运行时轮询 socket └─ 调用方无 Tokio 运行时 → 握手移入 fallback runtime 返回 ForwardedConnectionchannel 转发的 actor 连接DirectConnection调用方自己的 Tokio 运行时当runtime::in_tokio()为真即Handle::try_current()成功见 crates/rig-tungstenite/src/runtime.rs#L37-L39握手直接在当前运行时上执行返回的DirectConnection直接包装WebSocketStreamMaybeTlsStreamTcpStream由调用方运行时轮询。注意in_tokio()只能检测是否存在运行时句柄无法检测 I/O 与 timer driver 是否启用——缺失 driver 时 socket I/O 可能 panic宿主需要自行保证。ForwardedConnection懒启动的 fallback runtime这是该 crate 最值得一提的设计。当调用方没有 Tokio 运行时典型场景是 Bevy task pools、smol、futures::executor连接不会要求调用方提供 reactor而是通过LazyLock懒启动一个共享的单 worker Tokio 多线程运行时线程名为rig-tungsteniteenable_all()启用全部 driver启动失败会被缓存后续连接直接复用该失败结果见 crates/rig-tungstenite/src/runtime.rs#L13-L31。握手与 socket 生命周期全部留在该 fallback runtime 上调用方与连接之间只通过一对futureschannel 通信命令通道容量为 1oneshot用于应答调用方完全不需要亲自轮询 socket I/O见 crates/rig-tungstenite/src/connection.rs#L179-L207。连接持有OwnedTask句柄drop 即 abort被取消的连接会立刻释放传输资源即使 actor 正阻塞在对端不读的写操作上见 crates/rig-tungstenite/src/runtime.rs#L42-L59。off_runtime_ownership集成测试专门用真实 loopback socket 验证了这一点见 crates/rig-tungstenite/tests/off_runtime_ownership.rs。连接 actorselect 驱动的帧与命令仲裁run_actor是 channel 转发连接的核心见 crates/rig-tungstenite/src/connection.rs#L97-L177它把 socketsplit()成 sink 与 stream 后进入事件循环并通过futures::select!同时监听命令与入站帧。这一结构带来三个关键行为空闲 receive 不会饿死 close即使没有待处理的命令actor 也会持续轮询入站帧因此一个挂起的 receive 不会阻塞后续的 close 命令取消的 receive 保留结果若应答通道的接收端已取消reply.send失败未送达的帧或错误会被重新压回队首inbound.push_front下一次recv仍能观察到原始结果见 crates/rig-tungstenite/src/connection.rs#L106-L124有界 read-ahead 施加背压入站队列上限READ_AHEAD 256见 crates/rig-tungstenite/src/connection.rs#L94-L95。队列满或流结束时actor 暂停读 socket 只处理命令避免慢消费者导致无界缓冲同时轮询 socket 本身会驱动 tungstenite 的自动 Pong 回复维持心跳。错误处理升级拒绝与超时的保真WebSocket 握手被服务端拒绝如 API key 无效时tungstenite 会给出Error::Http(response)。from_tungstenite会把它还原为携带完整 status、headers、body 的Error::non_success_with_details而不是退化为一条没有上下文的字符串错误见 crates/rig-tungstenite/src/lib.rs#L133-L148。这是有实测依据的src/tests.rs中的测试使用真实端点录制的拒绝体401x-request-id OpenAI 错误信封 JSON断言三者完整保留并验证429时retry-after、x-ratelimit-remaining等限流头原样存活见 crates/rig-tungstenite/src/tests.rs#L24-L88。而握手超时则产生专门的ConnectTimeout错误消息形如timed out connecting the websocket after 30s同样被测试固定下来防止意外变更见 crates/rig-tungstenite/src/tests.rs#L138-L150。另一条保真边界是请求头的透传client_request会把调用方请求包括认证头覆盖到 tungstenite 生成的握手请求上而Sec-WebSocket-Key等握手专用头由后端自己补齐调用方不应提供。the_client_request_keeps_the_callers_headers测试用wss://api.openai.com/v1/responses的Bearer头验证了这一点见 crates/rig-tungstenite/src/tests.rs#L154-L174。非Http的传输错误ConnectionClosed、Io、Protocol、Url等则一律映射为Error::Instance不携带任何不存在的 provider 响应——every_transport_failure_is_left_alone测试枚举了全部此类变体以钉死这条边界见 crates/rig-tungstenite/src/tests.rs#L100-L132。会话层随后通过websocket_provider_error从保留的响应头中提取request_id并合入ProviderError见 crates/rig-core/src/providers/openai/responses_api/websocket.rs#L861-L868。无 Tokio 运行时的完整会话验证rig-core 的集成测试websocket_off_runtime是整个后端能力最直接的证据它用futures::executor::block_on在没有 Tokio 运行时的调用线程上驱动连接 → 发送 → 接收 → 关闭的完整会话服务端则在独立线程的 Tokio 运行时上接受连接并回应response.create并验证事件超时在服务端静默时依然生效见 crates/rig-core/tests/websocket_off_runtime.rs。此外streaming_conformance_websocket、websocket_handshake_rejection等测试均以required-features [tungstenite]的方式 gate 在 feature 之后见 crates/rig-core/Cargo.toml#L120-L134。从使用角度总结接入路径就是两条默认环境启用rig-core/tungstenite后直接connect()特殊环境wasm 浏览器、自定义传输、无 Tokio 运行时则实现WebSocketClientExt后走connect_with()。协议层你完全不必关心——会话协议在 rig-coreSocket 在 rig-tungstenite两者之间只隔着一层由rig-http定义的薄契约。赞分享AI AgentAgent 框架RAG后端【免费下载链接】rig⚙️ Build modular and scalable LLM Applications in Rust项目地址https://gitcode.com/GitHub_Trending/rig2/rig点击查看免费下载相关推荐rig-http 传输契约详解为 Rig LLM 应用构建可替换的 HTTP 与 WebSocket 传输层rig http 传输契约详解为 Rig LLM 应用构建可替换的 HTTP 与 WebSocket 传输层 rig http 是 Rig 项目中所有模型提供AI AgentAgent 框架RAG后端rig-surrealdb 实战指南在 Rust 中为 Rig 框架构建 SurrealDB 向量检索RAG后端rig surrealdb 实战指南在 Rust 中为 Rig 框架构建 SurrealDB 向量检索RAG后端 导读 rig surrealdb 是 RAI AgentAgent 框架RAG后端rig-reqwest 深度解析Rig 框架的 reqwest HTTP 传输层与运行时语义rig reqwest 深度解析Rig 框架的 reqwest HTTP 传输层与运行时语义 导读 本文围绕 rig reqwest https://linkAI AgentAgent 框架RAG后端上一篇Zotero插件市场在文献管理软件中打造你的专属插件生态系统下一篇Zotero插件市场终极指南一键安装插件提升文献管理效率创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →