Ohhnews

分类导航

$ cd ..
Jetbrains Blog原文

Rust AI实践:使用Rig构建LLM应用

#rust#rig#人工智能#llm应用开发#ai代理

Rust AI 正从实验阶段走向更实际的应用。我们最近与 Rust 基金会合作推出了一个新的直播系列,探讨 Rust 与 AI 在真实应用中的结合。在第一期节目中,我们的开发者布道师 Orhun Parmaksız 与 0xPlaygrounds 的 Rig 首席维护者 Stephen Korzeniewski 进行了对话。

Orhun 展示了他用 Rig 和 Ratatui 创建的一个小型编码智能体。随后,他和 Stephen 在节目中一起 review 了相关代码。这个演示为我们提供了一个实际的起点,去观察 AI 智能体如何在 Rust 中工作,以及 Rig 能实现哪些能力。

TL;DR

Rig 为 Rust 开发者提供了一种通用接口,用于对接 OpenAI、Anthropic、Gemini 等 LLM 提供商。它支持 AI 智能体、工具、RAG、数据库集成、流式输出和本地模型。在直播过程中,Orhun 展示了一个用 Rig 和 Ratatui 构建的小型编码智能体,Stephen 则详细讲解了该智能体的设置、工具和底层抽象。

Rig 是什么?

Rig 是一个开源的 Rust 库,用于对接不同的大语言模型提供商。OpenAI、Anthropic、Gemini 等提供商都有自己的 API。虽然许多提供商声称兼容 OpenAI,但在实际使用中,每个服务的行为都会有些差异。

Rig 通过为所有提供商提供统一的 Rust 接口来处理这些差异,这样开发者无需重写应用中依赖 LLM 的部分,就能切换提供商。

“Rig 实现了一种统一使用所有这些提供商的方式。”

Stephen Korzeniewski,0xPlaygrounds 的 Rig 首席维护者

它的抽象层既涵盖简单的模型请求,也支持可以调用工具或检索外部上下文的更高级应用。

Rig 如何组织 LLM 应用

Rig 将 LLM 应用围绕几个核心组件来组织:提供商客户端、补全模型、智能体,以及可供智能体使用的工具。提供商客户端负责将应用连接到服务,而所选模型则用于配置智能体。

Stephen 将智能体描述为 LLM 之上的一层抽象。直接请求模型遵循简单的“文本进、文本出”流程;智能体则会在模型调用周围加入指令、Token 限制和能力定义。

[LOADING...]

在 Rig 中,这些指令通过 preamble 提供,其作用类似于系统提示词,并会包含在每个请求的开头。每次运行时,智能体都会与某个提供商保持连接,而 Rig 则通过通用接口处理不同提供商 API 之间的差异。

由于与模型提供商通信涉及网络请求,Rig 会使用异步 API。大部分异步工作都在库内部完成,使应用代码可以专注于自身的配置和行为。

这种拆分为智能体的每个部分赋予了明确职责:Rig 负责与提供商的连接,preamble 定义指令,而工具则让智能体不仅能生成文本,还能与应用中的其他部分交互。

Rig 中的 AI 智能体与工具如何工作

在 Rig 中,工具通过 Rust 的 Tool trait 定义。正如 Stephen 所说:“工具基本上就是一个 AI 智能体可以执行的 Rust 函数。”

实现该 trait 会定义工具的名称、输入、输出和错误类型,以及工具被调用时运行的函数。工具定义通过 JSON Schema 描述其期望参数,为模型提供它能提供的输入的结构化描述。

工具注册到智能体后,支持工具调用的模型可以决定何时使用它,并将结果合并到响应中。底层的 Rust 函数可以执行计算、查询数据库、检索信息,或与其他服务交互。

工具还可以接收 context(上下文),从而访问状态。这可以用于统计调用次数、缓存结果,或保留工具调用之间所需的信息。

Rig 将同样的模式扩展到了智能体本身:一个智能体可以作为工具提供给另一个智能体。这使得智能体可以通过同一个工具接口互相委派任务。

编码智能体演示解析

Orhun 在 Rat Code 中把这些组件组合在了一起。Rat Code 是一个用 Rig 和 Ratatui 构建的小型终端编码智能体。应用提供了简单的提示输入与响应界面,底层由 Rig 来管理智能体。

[LOADING...]

这个项目把主要职责清晰地体现在代码中。在 main.rs 中,应用会设置提供商客户端、模型和智能体。而读取文件、写入文件和运行 shell 命令的能力则分别定义,并通过 Rig 的工具接口注册到智能体。

[LOADING...]

该应用还使用 Rig 的流式 API,在模型生成答案时分块处理响应,并实时更新终端界面。在讲解过程中,Stephen 还讨论了 Rig 的钩子系统、工具调用恢复,以及其抽象设计背后的一些取舍。

你可以在直播回放(从 27:28 开始)中观看完整的代码讲解。

Rust 中的 RAG 与本地模型

Rig 也支持需要访问外部数据,或希望将模型运行在更靠近应用部署位置的应用场景。

通过 RAG 将 LLM 与外部数据连接

检索增强生成(RAG)会在模型生成响应前,向 LLM 提供相关信息。应用会将文档和用户查询转换为向量嵌入,然后通过语义相似度查找最相关的文档,并将其加入模型上下文。

Rig 通过数据库集成和向量存储抽象来支持这一过程。开发者可以连接受支持的数据库;如果希望使用某个不受支持但能存储向量的数据库,也可以实现 Rig 的向量存储 trait。

使用 Rig 运行本地 LLM

Rig 提供多种使用本地模型的方式,包括 Ollama、llama.cpp 和 Candle。它可以通过 Ollama 和 llama.cpp 连接本地模型,这两种方式依赖本机运行的服务;而 rig-candle 集成则直接在 Rust 应用中通过 Candle 运行推理。

Hugging Face 开发了 Candle,这是一个面向机器学习的 Rust 框架。使用 rig-candle 时,用户可以直接将模型权重嵌入应用、在本地执行推理,并让受支持的模型通过 WebAssembly 运行。这种方式让你可以交付不依赖托管模型 API 或单独本地推理服务器的应用。

对托管提供商、数据库和本地推理的支持,让开发者可以更好地控制模型和数据在哪里运行。这也引出了一个重要的实际问题:当模型提供商及其输出都可能变化时,如何测试这些集成?

Rig 如何测试 LLM 集成

测试 LLM 应用面临一个特殊的挑战:模型响应是非确定性的,而集成代码的变更又可能影响应用与不同提供商的通信方式。Rig 将“测试提供商集成”与“评估模型输出质量”分开处理。

在 CI 中回放提供商请求

Rig 主要通过一套 cassette 系统测试其提供商集成。维护人员会针对真实提供商运行测试,记录 HTTP 流量,并将这些交互保存为 YAML 文件。随后,模拟服务器可以回放这些请求与响应,使 Rig 的测试无需访问线上 API 即可运行。

据 Stephen 介绍,Rig 目前已记录了大约 1,700 条提供商交互,而且还在不断增加。项目会在每次 pull request 的 CI 中回放这些记录,整个过程只需几秒钟。

测试真实模型的行为

Cassette 测试可以验证 API 集成是否仍然正常工作,但无法反映模型输出质量是否发生了变化。提供商会定期更新模型,因此即使应用代码没有变化,同一个应用也可能出现不同的行为。

对于依赖响应质量的生产应用,Stephen 认为更高级的做法是定时针对真实模型运行测试。Rig 本身主要关注 API 集成测试,因此主要依赖静态 cassette 系统。

这两种方法共同回答了不同的问题:集成是否仍然可用?真实模型是否仍能产生应用所需的结果?

Rust 与 AI 的下一步是什么?

Rust 可以为 AI 应用提供强大支持,而 AI 也能帮助开发者用 Rust 构建软件。我们与 Rust 基金会的联合系列将同时探讨这两个方向,并邀请来自社区的多元声音。

Rig 为我们提供了一个很实际的起点。它支持从模型提供商、智能体,到工具、RAG、流式输出和本地推理等各类能力。Rat Code 则让我们看到 Rig 的智能体和工具抽象如何在一个小型 Rust 应用中发挥作用。非常感谢 Stephen 接受 Orhun 的邀请,带我们了解 Rig 的设计,并分享他作为 Rig 首席维护者的经验。

完整的 Rat Code 讲解以及更多对话内容,包括 Rig 的钩子系统、工具调用恢复,以及 Stephen 使用 AI 辅助开发的工作流程,欢迎观看 YouTube 完整直播。如果你正在尝试 Rig,或正在用 Rust 构建 AI 智能体,欢迎在评论区告诉我们你在做什么,也可以加入 Rig 的 Discord 社区。关注我们的更新,不错过本系列的下一期。