Files
agcore/examples/simple_visit.rs
T
徐涛 9e4f50c955 feat(llm): LlmCycle 切换 IR 消息类型,移除 Phase 0 桥接层
核心改动:
- LlmCycle.messages 从 Vec<OpenaiChatMessage> 切换为 Vec<Message>,
  移除 Phase 0 引入的 chat_message_to_message / message_to_chat_message
  转换函数
- 移除 LlmCycle.system_prompt 字段(FIX-D),调用方通过
  Message::system_text() + with_messages() 管理系统提示;
  with_system_prompt() 标记 #[deprecated] 保留为过渡期 shim
- submit_stream 简化(FIX-E):Item = StreamEvent 不再带 Result 包装,
  错误用 StreamEvent::Error 传出;self.messages 不再自动 push_message,
  调用方在收到 MessageComplete 后手动调用 cycle.push_message()
- compact.rs 适配 Message 类型 + ContentBlock 估算;microcompact
  跳过 is_error:true 的 ToolResult(FIX-F),保留 LLM 错误诊断
- ConversationMemory 持久化从 OpenaiChatMessage 切换为 Message
- ToolInvocation 增加 tool_call_id 字段(FIX-A),
  invoke/invoke_all 签名增加 tool_call_id 参数

调用方迁移:
- AgentSession::submit_turn 用 Message::system_text() + with_messages()
- simple_visit example 同步迁移

测试 177 passed / 0 failed(compact 新增 5 个单元测试覆盖 FIX-F + 估计全变体)。
2026-07-02 22:48:00 +08:00

86 lines
2.8 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use std::env;
use agcore::init_tracing;
use agcore::llm::{
cycle::{CycleConfig, LlmCycle},
provider::{create_provider, ProviderConfig, ProviderType},
types::{message::ContentBlock, message::Message, response_v2::MessageResponse},
};
fn extract_response_text(response: &MessageResponse) -> &str {
// Phase 0MessageResponse.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_messages(vec![
Message::system("你是一个简洁的助手,对于任何问题都是用一句话回答。"),
]);
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);
}
}
}