正在统计访客…
浏览全部文档
开始 · 9找到适合你的 Runifold 学习路径45 分钟掌握 Runifold理解完整的 Runifold 平台第一次可信运行选择正确的执行 API选择 Crate 与 Cargo Feature构建常见 Runifold 应用Runifold 常见问题排查 Runifold 应用故障
执行内核 · 7理解 RunContext安全协调外部副作用使用预算与取消限制工作安全地处理错误与重试事件、Journal 与执行证据设计 Capability 安全执行从 Checkpoint 安全恢复
模型与服务商 · 7在避免重复输出的前提下路由模型选择并配置模型服务商使用服务商中立的模型协议基于 Provider Runtime 契约构建使用 OpenAI 控制面与 Realtime API测试与 Benchmark Provider Adapter配置 OpenAI、Anthropic、Gemini 与 Ollama
Agent · 7构建并配置 Agent为 Agent 添加类型化工具加入会话与语义记忆安全地委派给子 Agent返回结构化 Rust 值在不丢失语义的前提下流式输出使用检索为 Agent 提供事实依据
持久工作流 · 7组合确定性工作流让工作流持久化运行持久工作流 Worker协调 Timer、Signal 与持久等待运行多租户工作流基础设施运行并行 Branch 与安全 Race对持久 Workflow 进行版本管理
集成 · 7通过 MCP 连接外部能力选择存储与持久化边界通过 MCP Tasks 暴露持久工作构建并评估检索流水线使用 MCP Resources、Prompts 与 Sampling在不跨越权限的前提下缓存 MCP 响应在 Rust Web Service 中部署 Runifold
质量与运维 · 10在没有网络的情况下测试评估质量并阻止回归观测完整运行树在浏览器与边缘环境安全运行准确理解可靠性声明在 CI 中运行可复现评测使用 SLO 运维 Runifold治理 Task 保留与删除把审计证据归档到 S3-Compatible WORM 存储管理兼容性与可信发布
文档/集成
第一次使用?通过 45 分钟核心课程建立完整心智模型
集成

构建并评估检索流水线

组合 Embedding Model 与 Vector Store,保存文档身份与归因,执行租户过滤,并衡量检索质量。

实践指南·16 min

流水线边界

Runifold 提供服务商中立的 EmbeddingModelVectorStoreRetriever、Document、 Query、Usage、Deadline、取消与 Capability 契约。它不负责 Chunking、Document 授权、 Source-of-truth Sync、Reranking 或一套固定 RAG 流水线。

明确区分 Ingestion 与 Query Path;它们通常需要不同 Authority、Budget、Task Hint 与运维 计划。

构建并查询一个可运行的 Index

Cargo.toml
[dependencies]
runifold = "=0.9.0"
runifold-providers = { version = "=0.9.0", features = ["openai"] }
runifold-retrieval-text = "=0.9.0"
use std::sync::Arc;
 
use runifold::{
    Document, InMemoryVectorIndex, RetrievalContext, RetrievalQuery, Retriever,
};
use runifold_providers::openai::OpenAiClient;
 
let client = OpenAiClient::from_api_key(std::env::var("OPENAI_API_KEY")?)?;
let embedder = Arc::new(client.embedding_model("text-embedding-3-small")?);
let built = InMemoryVectorIndex::build(
    "product-help",
    embedder,
    vec![
        Document::new("returns", "Returns are accepted within 30 days.")?,
        Document::new("shipping", "Standard shipping takes 3–5 business days.")?,
    ],
    RetrievalContext::new(),
)
.await?;
 
let response = built
    .index
    .retrieve(
        RetrievalQuery::new("How long can I return an order?", 2)?,
        RetrievalContext::new(),
    )
    .await?;
 
for hit in response.documents {
    println!("{}: {}", hit.document.id, hit.document.text);
}

built.usage 是摄取 Embedding 用量,response.usage 属于查询。内存 Index 不可变, 适合测试或小型静态语料;文档变化后需要重建。持久 Upsert 和共享访问请使用 pgvector 或 Qdrant。

使用 .dynamic_context(4, built.index) 把它连接到 Agent。这个 Limit 只限制单次模型 轮次可注入的文档数,不能替代 Adapter 自己的 Top-K、Tenant Filter、Score Threshold 与 Context Size Limit。

Embedding Model

OpenAI-Compatible、Gemini 与 Ollama Client 提供 Embedding Adapter。Request 保存 Batch 顺序并区分 Document 与 Query Task。Adapter 拒绝空 Model Name、无效 Vector 与默认静默 截断,同时报告可归因 Usage。

记录 Provider、Model、Dimension、Task Mode、Normalization 与 Index Version。不要在一个 Search Space 混合不兼容配置产生的 Vector。

索引与查询

VectorRetriever 可以组合任意 Embedding Model 与 Vector Store。内存 Index 是确定性 参考。Qdrant 把应用 Document ID 映射到稳定 Point ID;pgvector 使用显式 Setup 与参数化 Query。

Upsert 稳定 Document Identity、Text、Source Metadata、Tenant Namespace 与 Embedding Version。在 Adapter 与组合层都限制 Top-K。

安全与归因

Retrieval 是外部 ReadOnly Authority。显式授权,在 Similarity Ranking 前执行 Tenant 与 ACL Filter,保存 Source Attribution,并把检索文本标为不可信数据。它不能创建 System Instruction。

Checkpointed Execution 在首次模型调用前持久化成功准备的 Context,因此 Resume 不会重复 检索或静默改变证据。

检索评测

把检索与答案生成分开评测。稳定 Relevance Judgment 可以衡量 Precision@K、Recall@K、 Reciprocal Rank、nDCG、Usage 与 Host-observed Latency,并保存 Case Order 与 Dataset Version。

之后再评测 Grounded Answer Quality、Citation Correctness 与 Refusal。好 Answer Score 可能掩盖低 Recall;高 Recall 仍可能给 Agent 提供恶意或无关文本。

生产摄取顺序

  1. 读取正文前先授权数据源;
  2. 确定性地归一化和切块,同时保留 Source 与 ACL Identity;
  3. 分配稳定 Document / Chunk ID 与明确 Index Version;
  4. 使用 RetrievalDocument Task Mode 分批 Embedding;
  5. 写入前拒绝数量或维度不匹配;
  6. 一起 Upsert 正文、归因、Tenant Namespace、ACL、模型与版本;
  7. 验证完成后才发布新 Index Version;
  8. 按 Source Identity 删除旧 Chunk,不要按相似度删除。

查询时,从已认证应用状态派生 Tenant 与 ACL Filter,创建带 Deadline 的 RetrievalContext,用 RetrievalQuery 模式生成 Embedding,执行有界 Top-K,按需 Rerank,再把带归因证据作为不可信 Context 交给 Agent。

检索故障排查

排查生产质量前,先验证 0.9 的摄取与排序契约。使用 runifold-retrieval-text 完成有界 UTF-8 加载,并生成稳定、保留 Unicode 与来源的 Chunk ID:

use std::num::NonZeroUsize;
use runifold_retrieval_text::{
    DEFAULT_MAX_TEXT_BYTES, TextChunkPolicy, chunk_document, load_text,
    split_markdown_sections,
};
 
let source = load_text("handbook", markdown_bytes, DEFAULT_MAX_TEXT_BYTES)?;
let sections = split_markdown_sections(&source)?;
let policy = TextChunkPolicy::new(NonZeroUsize::new(800).expect("non-zero"), 80)?;
let chunks = sections
    .iter()
    .map(|section| chunk_document(section, policy))
    .collect::<Result<Vec<_>, _>>()?
    .into_iter()
    .flatten()
    .collect::<Vec<_>>();

HybridRetriever 会并发查询两个独立 Retriever,再进行有界、带权的 Reciprocal Rank Fusion。需要 Provider-neutral Reranker 对扩展 Candidate 集重排时,把它包进 RerankingRetriever。Chunk Policy、Embedding Model、Fusion Weight 与 Reranker Descriptor 必须一起版本化,否则一次 Index 重建就可能静默让评测数据失效。

现象常见原因修复
结果为空Filter 太严、Namespace 错误或阈值过高记录各阶段安全计数并检查 Index Version
Dimension MismatchQuery 与 Corpus 使用不同模型重建或路由到匹配 Index
Duplicate Document IDChunk Identity 不稳定从 Source Identity + Chunk 位置/版本派生
相关来源排名低切块或 Embedding 不匹配修改 Answer Prompt 前先单独评估 Retrieval
跨租户证据Ranking 后才过滤在 Store Query 内绑定 Tenant / ACL
延迟高Top-K 太大、串行 Rerank 或 Provider 慢分别测量 Embed / Search / Rerank
文档 Prompt Injection把证据当成指令保留信任标签,并把 System Policy 分开