一个基于 Rust 和 Tauri 构建的 AI 聊天平台,参考了 AstrBot 的设计理念。
- 🚀 多 LLM 提供商支持: 支持 OpenAI、Anthropic、Gemini、Ollama 等多个 LLM 提供商
- 🔌 插件系统: 强大的插件系统,支持自定义命令、钩子和扩展
- 🌊 流式响应: 基于 Pipeline 的流式文本生成,实时显示 AI 回复
- 🎨 现代 UI: 基于 Tauri 的跨平台桌面应用
- 📦 模块化设计: 低耦合的模块设计,每个模块封装 API 供插件调用
iris/
├── Cargo.toml # Workspace 配置
├── crates/
│ ├── core/ # 核心模块 - 应用状态、会话管理
│ ├── provider/ # LLM 提供商模块 - 多模型支持
│ ├── plugin/ # 插件系统模块
│ └── pipeline/ # 流式处理管道
└── ui/
├── src/ # 前端代码 (TypeScript)
└── src-tauri/ # Tauri 后端
管理多个 LLM 提供商配置:
use iris_provider::{ProviderManager, ProviderConfig, ProviderId};
// 创建提供商配置
let config = ProviderConfig::openai("My OpenAI", "sk-xxx", "gpt-4");
// 添加到管理器
let manager = ProviderManager::new();
let id = manager.add_provider(config).await?;
// 插件可以通过 ID 调用
let provider = manager.get_provider(&id).await?;
let response = provider.chat(request).await?;生成文本向量用于语义搜索和 RAG:
use iris_provider::{
OpenAIEmbeddingProvider, EmbeddingProvider,
EmbeddingRequest, ProviderConfig
};
// 创建 Embedding 提供商
let config = ProviderConfig::openai("Embeddings", "sk-xxx", "text-embedding-3-small");
let provider = OpenAIEmbeddingProvider::new(config, "text-embedding-3-small")?;
// 生成单个文本的向量
let request = EmbeddingRequest::new("Hello, world!");
let response = provider.embed(request).await?;
println!("Embedding dimensions: {}", response.data[0].embedding.len());
// 批量生成向量
let batch_request = EmbeddingRequest::new_batch(vec![
"First document".to_string(),
"Second document".to_string(),
]);
let batch_response = provider.embed(batch_request).await?;对检索结果重新排序提高 RAG 精度:
use iris_provider::{
CohereRerankProvider, RerankProvider,
RerankRequest, RerankApiStyle
};
// 创建 Cohere Rerank 提供商
let provider = CohereRerankProvider::cohere("cohere-api-key", "rerank-v3.5")?;
// 或使用 Jina AI
let jina_provider = CohereRerankProvider::jina("jina-api-key", "jina-reranker-v2-base-multilingual")?;
// 对文档进行重排序
let request = RerankRequest::new(
"What is the capital of France?",
vec![
"Paris is the capital of France.".to_string(),
"London is the capital of England.".to_string(),
"The Eiffel Tower is in Paris.".to_string(),
]
).with_top_n(2);
let response = provider.rerank(request).await?;
for result in response.results {
println!("Doc {}: score {:.4}", result.index, result.relevance_score);
}插件系统支持:
- 注册自定义命令
- 钩子(BeforeChat, AfterChat, OnStreamChunk 等)
- 访问 Provider API
- 持久化数据存储
use iris_plugin::{PluginApi, PluginMetadata, Command, HookType};
struct MyPlugin {
metadata: PluginMetadata,
}
#[async_trait]
impl PluginApi for MyPlugin {
fn metadata(&self) -> &PluginMetadata {
&self.metadata
}
fn commands(&self) -> Vec<Command> {
vec![Command::new("/hello", "Say hello")]
}
fn hooks(&self) -> Vec<HookType> {
vec![HookType::AfterChat]
}
// ... 实现其他方法
}流式处理管道:
use iris_pipeline::{Pipeline, PipelineChunk, Stage, Middleware};
let pipeline = Pipeline::builder()
.middleware(LoggingMiddleware::new())
.middleware(MetricsMiddleware::new())
.stage(TransformStage::new("transform", |s| s.to_uppercase()))
.build();
let output = pipeline.process(input_stream).await;整合所有模块:
use iris_core::{App, AppConfig};
// 初始化应用
let app = App::with_config(config).await?;
// 使用聊天服务
let response = app.chat_service
.send_message(&mut session, "Hello!")
.await?;
// 访问提供商 API (供插件使用)
let provider_api = app.provider_api();- Rust 1.70+
- Node.js 18+
- Tauri CLI
# 安装依赖
cd ui && npm install
# 开发模式
npm run tauri dev
# 构建发布版本
npm run tauri build- 在设置中添加新提供商配置
- 指定 API 地址、密钥、模型名称
- 系统会自动分配一个唯一 ID
- 插件可以通过此 ID 调用该提供商
配置文件位于 ~/.iris/config.json:
{
"providers": [
{
"id": "uuid-xxx",
"name": "OpenAI GPT-4",
"provider_type": "openai",
"api_base": "https://api.openai.com/v1",
"api_key": "sk-xxx",
"model": "gpt-4",
"default_temperature": 0.7
}
],
"default_provider_id": "uuid-xxx",
"chat": {
"system_prompt": "You are a helpful assistant.",
"enable_streaming": true
}
}MIT License