14 KiB
14 KiB
Gemini SDK 开发提示词
项目概述
基于 apps\desktop\src-tauri\src\infrastructure\gemini_service.rs 的现有实现,创建一个独立的 Rust crate gemini-sdk,提供简洁易用的 Gemini AI 服务接口。
核心设计目标
- 简化接口: 提供统一的消息发送接口,支持文本+附件输入
- Agent 系统: 支持多个 AI Agent,每个 Agent 有独立的 system prompt 和配置
- 多轮对话: 支持会话管理和历史记录
- 类型安全: 强类型设计,编译时错误检查
- 易于集成: 最小化外部依赖,易于在其他项目中使用
技术架构
依赖管理
[dependencies]
tokio = { version = "1.0", features = ["full"] }
reqwest = { version = "0.11", features = ["json", "multipart"] }
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
anyhow = "1.0"
uuid = { version = "1.0", features = ["v4"] }
chrono = { version = "0.4", features = ["serde"] }
base64 = "0.22"
rusqlite = { version = "0.31", features = ["bundled", "chrono"] }
核心数据结构
// SDK 主体
pub struct GeminiSDK {
service: GeminiService,
conversation_repo: Option<Arc<ConversationRepository>>,
agents: HashMap<String, Agent>,
}
// Agent 定义
pub struct Agent {
pub id: String,
pub name: String,
pub system_prompt: String,
pub config: AgentConfig,
pub created_at: DateTime<Utc>,
}
pub struct AgentConfig {
pub temperature: f32,
pub max_tokens: u32,
pub timeout: u64,
pub enable_conversation: bool,
}
// 消息结构
pub struct MessageRequest {
pub text: String,
pub attachments: Vec<Attachment>,
pub agent_id: Option<String>,
pub session_id: Option<String>,
pub config: Option<MessageConfig>,
}
pub struct MessageResponse {
pub content: String,
pub session_id: String,
pub message_id: Option<String>,
pub agent_id: Option<String>,
}
// 附件定义
pub struct Attachment {
pub path: String,
pub mime_type: Option<String>,
}
// 会话管理
pub struct ConversationSession {
pub session_id: String,
pub title: Option<String>,
pub created_at: DateTime<Utc>,
}
pub struct HistoryMessage {
pub role: MessageRole,
pub content: String,
pub timestamp: DateTime<Utc>,
pub attachments: Vec<String>,
}
核心功能接口
1. SDK 初始化
impl GeminiSDK {
// 基础初始化
pub fn new() -> Result<Self>;
// 支持多轮对话
pub fn with_conversation_support(db_path: Option<String>) -> Result<Self>;
// 自定义配置
pub fn with_config(config: GeminiConfig) -> Result<Self>;
}
2. 核心消息接口
impl GeminiSDK {
// 主要方法:发送消息+附件,获得回复
pub async fn send_message(&mut self, request: MessageRequest) -> Result<MessageResponse>;
}
3. Agent 管理
impl GeminiSDK {
// Agent CRUD
pub fn create_agent(&mut self, name: String, system_prompt: String, config: Option<AgentConfig>) -> Result<Agent>;
pub fn get_agent(&self, agent_id: &str) -> Option<&Agent>;
pub fn list_agents(&self) -> Vec<&Agent>;
pub fn update_agent(&mut self, agent_id: &str, name: Option<String>, system_prompt: Option<String>, config: Option<AgentConfig>) -> Result<()>;
pub fn delete_agent(&mut self, agent_id: &str) -> Result<()>;
// 预设 Agent
pub fn create_outfit_advisor_agent(&mut self) -> Result<Agent>;
pub fn create_video_analyst_agent(&mut self) -> Result<Agent>;
pub fn create_general_assistant_agent(&mut self) -> Result<Agent>;
}
4. 会话管理
impl GeminiSDK {
// 会话 CRUD
pub async fn create_session(&self, title: Option<String>) -> Result<ConversationSession>;
pub async fn get_session(&self, session_id: &str) -> Result<Option<ConversationSession>>;
pub async fn list_sessions(&self) -> Result<Vec<ConversationSession>>;
pub async fn delete_session(&self, session_id: &str) -> Result<()>;
// 历史记录
pub async fn get_conversation_history(&self, session_id: &str, limit: Option<u32>) -> Result<Vec<HistoryMessage>>;
pub async fn clear_conversation_history(&self, session_id: &str) -> Result<()>;
}
5. 便捷构造函数
impl Attachment {
pub fn new(path: impl Into<String>) -> Self;
pub fn with_mime_type(path: impl Into<String>, mime_type: impl Into<String>) -> Self;
}
impl MessageRequest {
pub fn text_only(text: impl Into<String>) -> Self;
pub fn with_attachments(text: impl Into<String>, attachments: Vec<Attachment>) -> Self;
pub fn with_agent(text: impl Into<String>, agent_id: impl Into<String>) -> Self;
}
实现要求
1. 文件结构
cargos/gemini-sdk/
├── Cargo.toml
├── src/
│ ├── lib.rs # 主入口
│ ├── sdk.rs # SDK 主体实现
│ ├── agent.rs # Agent 相关
│ ├── conversation.rs # 会话管理
│ ├── attachment.rs # 附件处理
│ ├── error.rs # 错误定义
│ └── presets/ # 预设 Agent
│ ├── mod.rs
│ ├── outfit_advisor.rs
│ ├── video_analyst.rs
│ └── general_assistant.rs
├── examples/
│ ├── basic_usage.rs
│ ├── agent_demo.rs
│ └── conversation_demo.rs
└── tests/
├── integration_tests.rs
└── agent_tests.rs
2. 核心实现逻辑
消息发送流程
- 检查是否指定 Agent,获取对应配置和 system prompt
- 处理附件:根据文件类型选择上传(视频)或编码(图片)
- 构建 Gemini API 请求,包含 system prompt
- 如果启用会话,使用多轮对话模式;否则使用单轮模式
- 调用底层 GeminiService 方法
- 返回格式化的响应
Agent 系统
- 内存中维护 Agent 映射表
- 每个 Agent 包含独立的 system prompt 和配置
- 提供预设的专业 Agent(穿搭顾问、视频分析师等)
- 支持动态创建和管理自定义 Agent
会话管理
- 可选的 SQLite 数据库支持
- 自动会话创建和历史记录保存
- 支持会话标题和元数据管理
- 历史消息检索和清理
3. 错误处理
#[derive(Debug, thiserror::Error)]
pub enum SDKError {
#[error("配置错误: {0}")]
Config(String),
#[error("Agent 不存在: {0}")]
AgentNotFound(String),
#[error("会话错误: {0}")]
Session(String),
#[error("附件处理错误: {0}")]
Attachment(String),
#[error("网络错误: {0}")]
Network(#[from] reqwest::Error),
#[error("数据库错误: {0}")]
Database(#[from] rusqlite::Error),
#[error("Gemini 服务错误: {0}")]
GeminiService(#[from] anyhow::Error),
}
4. 使用示例
// 基础使用
let mut sdk = GeminiSDK::with_conversation_support(None)?;
// 创建穿搭顾问 Agent
let agent = sdk.create_outfit_advisor_agent()?;
// 发送消息
let request = MessageRequest {
text: "分析这张穿搭图片".to_string(),
attachments: vec![Attachment::new("./outfit.jpg")],
agent_id: Some(agent.id),
session_id: None,
config: None,
};
let response = sdk.send_message(request).await?;
println!("回复: {}", response.content);
开发指导
1. 代码复用策略
- 直接复用
gemini_service.rs中的核心逻辑 - 提取通用的配置、错误处理和网络请求代码
- 简化接口,隐藏内部复杂性
2. 测试策略
- 单元测试:各个组件的独立功能
- 集成测试:完整的消息发送流程
- 示例代码:展示各种使用场景
3. 文档要求
- 完整的 API 文档
- 使用示例和最佳实践
- 错误处理指南
- 性能优化建议
4. 性能考虑
- 连接池复用
- 合理的超时设置
- 内存使用优化
- 异步操作支持
交付标准
- 功能完整性: 所有设计的接口都能正常工作
- 代码质量: 遵循 Rust 最佳实践,通过 clippy 检查
- 测试覆盖: 核心功能有完整的测试覆盖
- 文档完善: 清晰的 API 文档和使用示例
- 易用性: 简洁的接口,最小化学习成本
详细实现指南
1. 从现有代码迁移的关键组件
需要复用的核心结构
// 从 gemini_service.rs 复用
pub struct GeminiConfig { /* 保持原有字段 */ }
pub struct GenerateContentRequest { /* 保持原有结构 */ }
pub struct ContentPart { /* 保持原有结构 */ }
pub enum Part { /* 保持原有枚举 */ }
pub struct GenerationConfig { /* 保持原有结构 */ }
需要复用的核心方法
get_access_token()- 访问令牌管理upload_video_file()- 视频文件上传generate_content_with_request()- 内容生成query_llm_with_grounding_multi_turn()- 多轮对话extract_json_from_response()- JSON 解析
2. 简化的内部服务层
// 简化的内部服务,封装复杂逻辑
struct InternalGeminiService {
config: GeminiConfig,
client: reqwest::Client,
access_token: Option<String>,
token_expires_at: Option<u64>,
}
impl InternalGeminiService {
// 复用原有的核心方法,但简化接口
async fn send_request(&mut self, parts: Vec<Part>, config: GenerationConfig, system_prompt: Option<String>) -> Result<String>;
async fn upload_file(&mut self, path: &str) -> Result<String>;
async fn send_multipart_request(&mut self, parts: Vec<Part>, config: GenerationConfig, system_prompt: Option<String>, session_id: Option<String>) -> Result<String>;
}
4. 错误恢复和重试机制
impl GeminiSDK {
async fn send_message_with_retry(&mut self, request: MessageRequest, max_retries: u32) -> Result<MessageResponse> {
let mut last_error = None;
for attempt in 0..max_retries {
match self.send_message_internal(request.clone()).await {
Ok(response) => return Ok(response),
Err(e) => {
last_error = Some(e);
if attempt < max_retries - 1 {
let delay = std::time::Duration::from_secs(2_u64.pow(attempt));
tokio::time::sleep(delay).await;
}
}
}
}
Err(last_error.unwrap())
}
}
5. 配置管理
impl GeminiSDK {
pub fn from_env() -> Result<Self> {
let config = GeminiConfig {
base_url: std::env::var("GEMINI_BASE_URL").unwrap_or_else(|_| "https://bowongai-dev--bowong-ai-video-gemini-fastapi-webapp.modal.run".to_string()),
bearer_token: std::env::var("GEMINI_BEARER_TOKEN").unwrap_or_else(|_| "bowong7777".to_string()),
// ... 其他配置
};
Self::with_config(config)
}
}
6. 完整的使用示例
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
// 1. 初始化 SDK
let mut sdk = GeminiSDK::with_conversation_support(None)?;
// 3. 穿搭分析示例
let outfit_request = MessageRequest {
text: "请分析这张穿搭图片,给出专业的搭配建议".to_string(),
attachments: vec![Attachment::new("./examples/outfit.jpg")],
agent_id: Some(outfit_agent.id.clone()),
session_id: None,
config: None,
};
let outfit_response = sdk.send_message(outfit_request).await?;
println!("穿搭顾问分析:\n{}", outfit_response.content);
// 4. 视频分析示例
let video_request = MessageRequest {
text: "请分析这个视频的内容质量和改进建议".to_string(),
attachments: vec![Attachment::new("./examples/video.mp4")],
agent_id: Some(video_agent.id),
session_id: None,
config: Some(MessageConfig {
temperature: Some(0.6),
max_tokens: Some(12000),
timeout: Some(180),
}),
};
let video_response = sdk.send_message(video_request).await?;
println!("视频分析报告:\n{}", video_response.content);
// 5. 多轮对话示例
let session = sdk.create_session(Some("穿搭咨询".to_string())).await?;
let follow_up = MessageRequest {
text: "基于刚才的分析,我想要更正式一些的搭配方案".to_string(),
attachments: vec![],
agent_id: Some(outfit_agent.id),
session_id: Some(session.session_id.clone()),
config: None,
};
let follow_response = sdk.send_message(follow_up).await?;
println!("后续建议:\n{}", follow_response.content);
// 6. 查看对话历史
let history = sdk.get_conversation_history(&session.session_id, Some(10)).await?;
for msg in history {
println!("{}: {}", msg.role, msg.content);
}
Ok(())
}
质量保证要求
1. 代码规范
- 使用
cargo fmt格式化代码 - 通过
cargo clippy静态检查 - 添加适当的文档注释
- 遵循 Rust 命名约定
2. 测试要求
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn test_basic_message_sending() {
// 测试基础消息发送功能
}
#[tokio::test]
async fn test_agent_management() {
// 测试 Agent 创建和管理
}
#[tokio::test]
async fn test_conversation_flow() {
// 测试多轮对话流程
}
#[tokio::test]
async fn test_attachment_processing() {
// 测试附件处理
}
}
3. 文档要求
- 每个公共接口都要有详细的文档注释
- 提供完整的使用示例
- 包含错误处理指南
- 性能和最佳实践说明
请基于这个详细的设计方案和实现指南,创建一个高质量、易用、功能完整的 Gemini SDK crate。