5baa170508
- README 添加 feature 组合表 + 模块级 features 清单 + 升级指南 - 18 个 example 顶部添加 Required features 注释 - roadmap.md 和 roadmap-v0.3.2.md 同步 Phase 26-27 完成状态 - cargo fmt 全量格式化(修复预存格式问题,CI format job 可通过)
206 lines
6.7 KiB
Rust
206 lines
6.7 KiB
Rust
//! knowledge_graph_demo -- 知识图谱 + 双通道检索演示。
|
||
//! Required features: cargo run --example knowledge_graph_demo --features "memory"
|
||
//!
|
||
//! 演示:
|
||
//! 1. 构建 KnowledgeGraph(实体 + 关系)
|
||
//! 2. BFS 图遍历(get_related)
|
||
//! 3. MemoryRetriever 双通道检索(Hybrid / GraphOnly / KnowledgeOnly)
|
||
//! 4. 标签管理(set_entity_tags / find_tags)
|
||
//!
|
||
//! 运行:`cargo run --example knowledge_graph_demo`
|
||
|
||
use std::sync::Arc;
|
||
|
||
use agcore::memory::{
|
||
GraphEntity, GraphRelation, InMemoryGraph, InMemoryStore, KnowledgeGraph, KnowledgePage,
|
||
KnowledgeStore, MemoryRetriever, MemoryStore, RelationDirection, RetrievalItem,
|
||
RetrievalStrategy, RetrieverConfig,
|
||
};
|
||
use time::OffsetDateTime;
|
||
|
||
fn make_page(id: &str, title: &str, content: &str) -> KnowledgePage {
|
||
let now = OffsetDateTime::now_utc();
|
||
KnowledgePage {
|
||
id: id.to_string(),
|
||
title: title.to_string(),
|
||
summary: content.chars().take(40).collect(),
|
||
content: content.to_string(),
|
||
tags: Vec::new(),
|
||
references: Vec::new(),
|
||
created_at: now,
|
||
updated_at: now,
|
||
}
|
||
}
|
||
|
||
#[tokio::main]
|
||
async fn main() {
|
||
// ── 1. 构建知识图谱 ──
|
||
println!("=== 1. 构建知识图谱 ===");
|
||
let graph = Arc::new(InMemoryGraph::new());
|
||
|
||
let mut langchain = GraphEntity::new("langchain", "LangChain", "framework");
|
||
langchain.description = "LLM application framework".to_string();
|
||
let mut langgraph = GraphEntity::new("langgraph", "LangGraph", "framework");
|
||
langgraph.description = "Graph-based agent runtime from LangChain".to_string();
|
||
let mut langsmith = GraphEntity::new("langsmith", "LangSmith", "tool");
|
||
langsmith.description = "Tracing and evaluation platform".to_string();
|
||
let mut python = GraphEntity::new("python", "Python", "language");
|
||
python.description = "Programming language".to_string();
|
||
let mut rust = GraphEntity::new("rust", "Rust", "language");
|
||
rust.description = "Systems programming language".to_string();
|
||
|
||
for e in [&langchain, &langgraph, &langsmith, &python, &rust] {
|
||
graph.add_entity(e.clone()).await.unwrap();
|
||
}
|
||
graph
|
||
.add_relation(GraphRelation::new(
|
||
"langchain",
|
||
"langgraph",
|
||
"includes",
|
||
0.9,
|
||
))
|
||
.await
|
||
.unwrap();
|
||
graph
|
||
.add_relation(GraphRelation::new(
|
||
"langchain",
|
||
"langsmith",
|
||
"includes",
|
||
0.7,
|
||
))
|
||
.await
|
||
.unwrap();
|
||
graph
|
||
.add_relation(GraphRelation::new(
|
||
"langchain",
|
||
"python",
|
||
"built_with",
|
||
0.95,
|
||
))
|
||
.await
|
||
.unwrap();
|
||
graph
|
||
.add_relation(GraphRelation::new("langgraph", "python", "depends_on", 0.8))
|
||
.await
|
||
.unwrap();
|
||
println!("已添加 5 个实体 + 4 条关系");
|
||
|
||
// ── 2. BFS 图遍历 ──
|
||
println!("\n=== 2. BFS 图遍历:从 LangChain 出发,depth=2 ===");
|
||
let related = graph
|
||
.get_related("langchain", 2, RelationDirection::Outgoing, None)
|
||
.await
|
||
.unwrap();
|
||
for se in &related {
|
||
println!(
|
||
" {} (score={:.3}, path={:?})",
|
||
se.entity.name, se.score, se.path
|
||
);
|
||
}
|
||
assert!(!related.is_empty(), "应找到关联实体");
|
||
|
||
// ── 3. 标签管理 ──
|
||
println!("\n=== 3. 标签管理 ===");
|
||
graph
|
||
.set_entity_tags(
|
||
"langchain",
|
||
vec!["ai".into(), "framework".into(), "llm".into()],
|
||
)
|
||
.await
|
||
.unwrap();
|
||
graph
|
||
.set_entity_tags("langgraph", vec!["ai".into(), "agent".into()])
|
||
.await
|
||
.unwrap();
|
||
let tags = graph.find_tags("a").await.unwrap();
|
||
println!("前缀 'a' 查找标签: {:?}", tags);
|
||
let count = graph.entity_count_by_tag("ai").await.unwrap();
|
||
println!("标签 'ai' 下实体数: {}", count);
|
||
|
||
// ── 4. 双通道检索 ──
|
||
println!("\n=== 4. 双通道检索 ===");
|
||
let store: Arc<dyn MemoryStore> = Arc::new(InMemoryStore::new());
|
||
let ks = KnowledgeStore::new(store);
|
||
ks.add_page(make_page(
|
||
"p1",
|
||
"LangChain 框架介绍",
|
||
"LangChain 是用于构建 LLM 应用的开源框架",
|
||
))
|
||
.await
|
||
.unwrap();
|
||
ks.add_page(make_page(
|
||
"p2",
|
||
"Rust 异步编程",
|
||
"Rust 异步基于 tokio 与 futures 抽象",
|
||
))
|
||
.await
|
||
.unwrap();
|
||
|
||
// Hybrid 策略(默认)
|
||
let retriever =
|
||
MemoryRetriever::new(ks, RetrieverConfig::default()).with_knowledge_graph(graph.clone());
|
||
println!("\n--- Hybrid 检索: 'langchain' ---");
|
||
let result = retriever.retrieve("langchain").await.unwrap();
|
||
println!("策略: {:?}", result.strategy);
|
||
for item in &result.items {
|
||
match item {
|
||
RetrievalItem::KnowledgePage { page, score } => {
|
||
println!(" [Store] {} (score={:.3})", page.title, score);
|
||
}
|
||
RetrievalItem::GraphEntity {
|
||
entity,
|
||
score,
|
||
path,
|
||
..
|
||
} => {
|
||
println!(
|
||
" [Graph] {} (score={:.3}, path={:?})",
|
||
entity.name, score, path
|
||
);
|
||
}
|
||
}
|
||
}
|
||
let has_store = result
|
||
.items
|
||
.iter()
|
||
.any(|i| matches!(i, RetrievalItem::KnowledgePage { .. }));
|
||
let has_graph = result
|
||
.items
|
||
.iter()
|
||
.any(|i| matches!(i, RetrievalItem::GraphEntity { .. }));
|
||
assert!(has_store, "Hybrid 应有 Store 结果");
|
||
assert!(has_graph, "Hybrid 应有 Graph 结果");
|
||
|
||
// GraphOnly 策略
|
||
let store2: Arc<dyn MemoryStore> = Arc::new(InMemoryStore::new());
|
||
let ks2 = KnowledgeStore::new(store2);
|
||
ks2.add_page(make_page("p1", "LangChain", "LLM framework"))
|
||
.await
|
||
.unwrap();
|
||
let retriever_g = MemoryRetriever::new(ks2, RetrieverConfig::default())
|
||
.with_knowledge_graph(graph.clone())
|
||
.with_strategy(RetrievalStrategy::GraphOnly);
|
||
println!("\n--- GraphOnly 检索: 'langchain' ---");
|
||
let result = retriever_g.retrieve("langchain").await.unwrap();
|
||
println!("策略: {:?}", result.strategy);
|
||
for item in &result.items {
|
||
match item {
|
||
RetrievalItem::GraphEntity { entity, score, .. } => {
|
||
println!(" [Graph] {} (score={:.3})", entity.name, score);
|
||
}
|
||
RetrievalItem::KnowledgePage { page, score, .. } => {
|
||
println!(" [Store] {} (score={:.3})", page.title, score);
|
||
}
|
||
}
|
||
}
|
||
assert!(
|
||
result
|
||
.items
|
||
.iter()
|
||
.all(|i| matches!(i, RetrievalItem::GraphEntity { .. })),
|
||
"GraphOnly 应只返回 Graph 结果"
|
||
);
|
||
|
||
println!("\n✓ knowledge_graph_demo 完成");
|
||
}
|