引入跨 Provider 统一的新类型系统: - Message 扁平大枚举(System/User/UserImage/Assistant/ToolResult) - MessageRequest + MessageResponse + StreamEvent(高精度 IR) - PartialMessageResponse 含 apply_to/finalize 汇聚算法 - ProviderType enum 扩展 + ProviderCapabilities 切换 LlmProvider trait 签名为 chat(MessageRequest) → MessageResponse, chat_stream 返回 Stream<Item = Result<StreamEvent, LlmError>>,新增 capabilities()。 StreamEvent 命名冲突处理:旧变体迁移至 old_stream::LegacyStreamEvent, stream.rs 通过 pub use 重新导出新高精度事件。 OpenaiProvider 添加 Phase 0 临时桥接(MessageRequest ↔ OpenaiChatRequest 转换), 标注 ponytail: Phase 0 临时桥接 标记,Phase 1 重写时移除。 测试 147 passed / 0 failed(新增 31 个新类型测试)。
87 lines
2.7 KiB
Rust
87 lines
2.7 KiB
Rust
use std::env;
|
||
|
||
use agcore::init_tracing;
|
||
use agcore::llm::{
|
||
cycle::{CycleConfig, LlmCycle},
|
||
provider::{create_provider, ProviderConfig, ProviderType},
|
||
types::{
|
||
message::ContentBlock, response_v2::MessageResponse,
|
||
},
|
||
};
|
||
|
||
fn extract_response_text(response: &MessageResponse) -> &str {
|
||
// Phase 0:MessageResponse.text() 直接给出拼接好的 Assistant 文本。
|
||
if !response.text().is_empty() {
|
||
// ⚠️ 返回的是 owned String 的引用,调用方需在 response 生命周期内使用。
|
||
// 此 example 短命,足以演示。
|
||
return response_text_ref(response);
|
||
}
|
||
"[无文本内容]"
|
||
}
|
||
|
||
fn response_text_ref(response: &MessageResponse) -> &str {
|
||
// ponytail: example 助手 —— 不在正式 crate API 中,单纯绕开 borrow 限制。
|
||
// 真实调用请直接使用 `response.text()` 拿到 owned String。
|
||
match &response.message {
|
||
agcore::llm::types::message::Message::Assistant { content } => {
|
||
for block in content {
|
||
if let ContentBlock::Text { text } = block {
|
||
return text.as_str();
|
||
}
|
||
}
|
||
""
|
||
}
|
||
_ => "",
|
||
}
|
||
}
|
||
|
||
#[tokio::main]
|
||
async fn main() {
|
||
dotenvy::dotenv().ok();
|
||
init_tracing();
|
||
|
||
let api_key = env::var("OPENAI_API_KEY").expect("未设置 OPENAI_API_KEY 环境变量");
|
||
let base_url = env::var("OPENAI_BASE_URL").expect("未设置 OPENAI_BASE_URL 环境变量");
|
||
let model = env::var("OPENAI_MODEL").expect("未设置 OPENAI_MODEL 环境变量");
|
||
|
||
let provider_type = env::var("PROVIDER")
|
||
.unwrap_or_else(|_| "openai".into())
|
||
.parse::<ProviderType>()
|
||
.expect("无效的 PROVIDER 值");
|
||
|
||
let config = ProviderConfig {
|
||
base_url,
|
||
api_key,
|
||
model: model.clone(),
|
||
};
|
||
|
||
let provider = create_provider(provider_type, config)
|
||
.expect("创建 Provider 失败");
|
||
|
||
let cycle_config = CycleConfig {
|
||
model,
|
||
max_tokens: Some(65536),
|
||
temperature: Some(1.3),
|
||
..CycleConfig::default()
|
||
};
|
||
|
||
let mut cycle = LlmCycle::new(provider, cycle_config)
|
||
.with_system_prompt("你是一个简洁的助手,对于任何问题都是用一句话回答。".to_string());
|
||
|
||
println!("发送请求...");
|
||
|
||
match cycle.submit("介绍一下你自己吧。".to_string(), vec![]).await {
|
||
Ok(response) => {
|
||
println!("LLM 回复:{}", extract_response_text(&response));
|
||
println!(
|
||
"Token 用量:{} 输入, {} 输出",
|
||
response.usage.prompt_tokens, response.usage.completion_tokens
|
||
);
|
||
}
|
||
Err(e) => {
|
||
eprintln!("请求失败:{e}");
|
||
std::process::exit(1);
|
||
}
|
||
}
|
||
}
|