feat(llm): 添加 LLM 调用周期核心模块
新增 LLM 调用生命周期引擎,包含 Provider 抽象、OpenAI 兼容实现、 可重试机制及 Token 用量追踪。移除原有的占位测试代码。 添加所需的 Rust 依赖(tokio、reqwest、serde 等)。
This commit is contained in:
@@ -0,0 +1,149 @@
|
||||
mod retry;
|
||||
pub mod usage;
|
||||
|
||||
pub use retry::RetryConfig;
|
||||
pub use usage::{CostTracker, Usage};
|
||||
|
||||
use crate::llm::cycle::retry::should_retry;
|
||||
use crate::llm::error::LlmError;
|
||||
use crate::llm::provider::LlmProvider;
|
||||
use crate::llm::types::{ChatRequest, ChatResponse, ContentBlock, Message, Role, ToolDefinition};
|
||||
|
||||
/// LLM 生命周期引擎的配置。
|
||||
pub struct CycleConfig {
|
||||
/// 使用的模型名称。
|
||||
pub model: String,
|
||||
/// 最大输出 token 数。
|
||||
pub max_tokens: Option<u32>,
|
||||
/// 采样温度。
|
||||
pub temperature: Option<f32>,
|
||||
/// 最大对话轮数(预留,暂未使用)。
|
||||
pub max_turns: Option<u32>,
|
||||
/// 重试策略配置。
|
||||
pub retry: RetryConfig,
|
||||
}
|
||||
|
||||
impl Default for CycleConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
model: String::from("gpt-4o"),
|
||||
max_tokens: None,
|
||||
temperature: None,
|
||||
max_turns: None,
|
||||
retry: RetryConfig::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// LLM 调用生命周期引擎。
|
||||
///
|
||||
/// 管理一次多轮交互的完整生命周期,包括:
|
||||
/// - 消息历史维护
|
||||
/// - Token 用量追踪
|
||||
/// - 自动重试
|
||||
pub struct LlmCycle {
|
||||
provider: Box<dyn LlmProvider>,
|
||||
config: CycleConfig,
|
||||
usage: CostTracker,
|
||||
messages: Vec<Message>,
|
||||
system_prompt: Option<String>,
|
||||
}
|
||||
|
||||
impl LlmCycle {
|
||||
/// 创建新的生命周期引擎。
|
||||
pub fn new(provider: Box<dyn LlmProvider>, config: CycleConfig) -> Self {
|
||||
Self {
|
||||
provider,
|
||||
config,
|
||||
usage: CostTracker::default(),
|
||||
messages: Vec::new(),
|
||||
system_prompt: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// 设置系统提示词(Builder 模式)。
|
||||
pub fn with_system_prompt(mut self, prompt: String) -> Self {
|
||||
self.system_prompt = Some(prompt);
|
||||
self
|
||||
}
|
||||
|
||||
/// 获取 Token 用量追踪器引用。
|
||||
pub fn usage(&self) -> &CostTracker {
|
||||
&self.usage
|
||||
}
|
||||
|
||||
/// 获取当前消息历史。
|
||||
pub fn messages(&self) -> &[Message] {
|
||||
&self.messages
|
||||
}
|
||||
|
||||
/// 清空消息历史。
|
||||
pub fn clear_messages(&mut self) {
|
||||
self.messages.clear();
|
||||
}
|
||||
|
||||
/// 重置 Token 用量统计。
|
||||
pub fn reset_usage(&mut self) {
|
||||
self.usage.reset();
|
||||
}
|
||||
|
||||
/// 提交一条用户消息并获取模型响应。
|
||||
///
|
||||
/// 流程:
|
||||
/// 1. 将用户消息追加到消息历史
|
||||
/// 2. 构建 ChatRequest
|
||||
/// 3. 使用重试循环调用 provider.chat()
|
||||
/// 4. 将助手回复追加到消息历史
|
||||
/// 5. 累计 token 用量
|
||||
/// 6. 返回 ChatResponse
|
||||
pub async fn submit(
|
||||
&mut self,
|
||||
prompt: String,
|
||||
tools: Vec<ToolDefinition>,
|
||||
) -> Result<ChatResponse, LlmError> {
|
||||
self.messages.push(Message {
|
||||
role: Role::User,
|
||||
content: vec![ContentBlock::Text { text: prompt }],
|
||||
});
|
||||
|
||||
let mut attempts = 0;
|
||||
|
||||
loop {
|
||||
let request = self.build_request(&tools);
|
||||
|
||||
match self.provider.chat(request).await {
|
||||
Ok(response) => {
|
||||
self.messages.push(Message {
|
||||
role: Role::Assistant,
|
||||
content: response.message.content.clone(),
|
||||
});
|
||||
|
||||
self.usage.add(&response.usage);
|
||||
|
||||
return Ok(response);
|
||||
}
|
||||
Err(e) if should_retry(&e) && attempts < self.config.retry.max_retries => {
|
||||
attempts += 1;
|
||||
let delay = self.config.retry.compute_delay(attempts);
|
||||
tokio::time::sleep(delay).await;
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// 根据当前状态构建 ChatRequest。
|
||||
fn build_request(&self, tools: &[ToolDefinition]) -> ChatRequest {
|
||||
ChatRequest {
|
||||
model: self.config.model.clone(),
|
||||
messages: self.messages.clone(),
|
||||
system_prompt: self.system_prompt.clone(),
|
||||
tools: tools.to_vec(),
|
||||
max_tokens: self.config.max_tokens,
|
||||
temperature: self.config.temperature,
|
||||
extra_body: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user