//! document_demo —— Document + RecursiveCharacterSplitter + MockEmbedding + VectorRetriever 完整衔接示例。 //! //! 演示 RAG 管线前置流程: //! 1. 创建多段落 Document //! 2. RecursiveCharacterSplitter 分割为 chunk //! 3. MockEmbedding 嵌入所有 chunk //! 4. 与 InMemoryVectorRetriever 手动 zip 衔接 //! 5. 模拟查询做语义检索 //! //! 运行:`cargo run --example document_demo`(离线,零配置) use agcore::document::{Document, RecursiveCharacterSplitter}; use agcore::llm::embedding::{Embedding, MockEmbedding}; use agcore::memory::vector::{InMemoryVectorRetriever, VectorRetriever}; #[tokio::main] async fn main() { agcore::init_tracing(); // 1. 创建多段落 Document(含中英文混合) let doc = Document::new( "rust-intro", "Rust 是一门系统编程语言,注重安全、并发和性能。\n\n\ Rust 通过所有权系统管理内存,无需垃圾回收器。\ 所有权规则让内存安全在编译期就能得到保证。\n\n\ Rust 的并发模型通过类型系统区分线程间共享与独占数据,\ 避免数据竞争。Send 和 Sync 两个 trait 标记了类型的线程安全性。\n\n\ Rust 的性能与 C/C++ 相当,但提供了更现代的开发体验。\ Cargo 是官方的构建系统和包管理器,使用简单直观。", "text/markdown", ); println!("输入文档: {} 字符", doc.content.chars().count()); // 2. RecursiveCharacterSplitter 分割 let splitter = RecursiveCharacterSplitter::new(200, 30); let chunks = splitter.split(&[doc]); println!("\n分割为 {} 个 chunk:", chunks.len()); for (i, chunk) in chunks.iter().enumerate() { println!( " [{:02}] id={}, 长度={}", i, chunk.id, chunk.content.chars().count() ); } // 3. MockEmbedding 嵌入所有 chunk let embedder = MockEmbedding::new(4); let texts: Vec = chunks.iter().map(|c| c.content.clone()).collect(); let vectors = embedder.embed(&texts).await.unwrap(); println!("\n嵌入维度: {},向量数: {}", embedder.dim(), vectors.len()); // 4. 与 InMemoryVectorRetriever 手动 zip 衔接 let retriever: std::sync::Arc = std::sync::Arc::new(InMemoryVectorRetriever::new()); for (chunk, vec) in chunks.iter().zip(vectors.iter()) { retriever.index(chunk.id.clone(), vec.clone()).await.unwrap(); } println!("已索引 {} 个 chunk", chunks.len()); // 5. 模拟查询:复用第一个 chunk 的 embedding 作为查询向量 let query_vec = vectors[0].clone(); let results = retriever.search(query_vec, 3).await.unwrap(); println!("\nTop 3 检索结果(与 chunk 0 相似度):"); for (id, score) in &results { println!(" id={}, score={:.4}", id, score); } assert_eq!(chunks.len(), vectors.len(), "chunks 与 vectors 数量必须一致"); assert!(!results.is_empty(), "至少应返回 1 条检索结果"); assert!(results[0].0.starts_with("rust-intro:chunk:0000"), "Top 1 应为 chunk 0 自身"); println!("\n✓ document_demo 完成"); }