13 个版本

0.1.32 2024 年 6 月 11 日
0.1.31 2024 年 6 月 5 日
0.1.30 2024 年 5 月 24 日
0.1.25 2024 年 4 月 9 日
0.1.0 2024 年 1 月 14 日

#138 in 机器学习

Download history 1/week @ 2024-04-23 245/week @ 2024-05-21 1/week @ 2024-05-28 150/week @ 2024-06-04 158/week @ 2024-06-11

1,026 每月下载量

MIT/Apache

760KB
3K SLoC

简化 Rust 中的 AI 代理 🕵🏼

espionox 是尝试使在 Rust 中构建 AI 应用程序与使用 LangChain 等其他库一样易于接近。

为什么我会使用 Espionox?

  • 在 Rust 中制作 LLM 应用程序
  • 实验复杂的 '提示流程',如链/思维树

入门

首先,您需要初始化一个 AgentAgent::new 接受两个参数

  1. 系统提示的可选内容,如果留空 None,则您的代理将没有系统提示
  2. 一个 CompletionModel,您希望使用哪个提供者(截至写作时,仅支持 OpenAi 和 Anthropic 提供者)。
use espionox::prelude::*;

let api_key = std::env::var("OPENAI_KEY").unwrap();
let agent = Agent::new(Some("This is the system message"), CompletionModel::default_openai(api_key));

现在,为了提示您的代理,您将调用其上的 do_action

let response: String = agent
    .do_action(io_completion, (), Option::<ListenerTrigger>::None)
    .await
    .unwrap();

一开始这可能看起来很可怕,但让我们看看 do_action 的签名

pub async fn do_action<'a, F, Args, Fut, R>(
    &'a mut self,
    f: F,
    args: Args,
    trigger: Option<impl Into<ListenerTrigger>>,
) -> AgentResult<R>
where
    F: for<'l> FnOnce(&'a mut Agent, Args) -> Fut,
    Fut: Future<Output = AgentResult<R>>

do_action 接受 4 个参数

  1. 调用方法的 Agent
  2. 一个异步函数,它修改代理并返回一个 AgentResult,它可以从 anyhow::Result 强制转换。因此,只要函数签名返回任何 AgentResult<T>,只需确保在任何错误返回上调用 .into() 即可,它应该是有效的。
  3. 可选的上述函数的参数
  4. 一个可选的监听器触发器(我们将讨论它)

因此,在我们之前的对 do_action 的调用中,我们传递了函数 io_completion,一个空参数和 None。 espionox 提供以下辅助函数来获取补全或嵌入

  • io_completion
  • stream_completion
  • function_completion

我们使用了这些函数之一,但我们可以轻松地定义自己的 io_completion 函数,并在调用 do_action 时传递它

监听器

Espionox 最好的功能之一是 AgentListener 特性

pub trait AgentListener: std::fmt::Debug + Send + Sync + 'static {
    fn trigger<'l>(&self) -> ListenerTrigger;
    fn async_method<'l>(&'l mut self, _a: &'l mut Agent) -> ListenerCallReturn<'l> {
        Box::pin(async move { Err(ListenerError::NoMethod.into()) })
    }
    fn sync_method<'l>(&'l mut self, _a: &'l mut Agent) -> AgentResult<()> {
        Err(ListenerError::NoMethod.into())
    }
}

您会注意到 3 个方法

  1. trigger:这是定义监听器何时被触发的方式。想想看就像一个 ID。ListenerTrigger 有两种变体
    • ListenerTrigger::String(String)
    • ListenerTrigger::Int(i64) 记住 trigger 参数到 do_action?确保在调用 do_action 时通过传递匹配的 ListenerTrigger 来触发监听器。
  2. async_method。如果实现了,函数体必须被包装在 Box::pin(async move {})
  3. sync_method

每个 async_methodsync_method 都是您定义监听器在触发时实际要做什么的地方。这些都是互斥的,只应实现其中一个方法。如果两个都实现了,则同步方法将是唯一触发的方法。任何实现此特性的结构都可以使用 Agent::insert_listener 插入到代理中。

您如何使用监听器呢??

监听器的用途可能一开始并不明显,但它可以用来创建自洽机制、提示链或甚至 RAG 管道。请参阅示例目录以获取有关 AgentListener 的更多信息

espionox 还处于早期开发阶段,API 中的所有内容都可能发生变化。请随时提问、建议、问题或其他任何事情 :)

依赖关系

~12–31MB
~516K SLoC