超越单一检索路径:企业智能体的规范知识、RAG与实时查询
为何单一检索流程无法满足各类企业知识的需求,以及路由器如何实现规范概念的分割、RAG检索与安全实时查询。
来源: **I Don’t Think OKF Replaces RAG. I Think We’re Asking RAG to Do Too Much.**
有报道称一种新的开放格式正在取代向量数据库,这一说法令人怀疑。其中值得关注的部分并非关于替代的事实,而是一个更重要的架构问题:是否有太多不同类型的企业知识被强制通过同一种检索机制来处理?
在企业内部,“知识”涵盖的内容千差万别。一张支持工单算,60页的设计文档算,数据库架构图算,指标定义算,事故处理手册也算。当前延迟发货的数量同样算在内。这些事物的特性各不相同,因此让一个AI代理以相同方式处理所有这些内容实在不合常理。
正确的视角并非将OKF与RAG对立起来,也并非向量数据库已经过时。实际上应该采用一种实用的分类方法,将知识分为三类:需要检索的知识、需作为标准存储的知识,以及需要实时查询的知识。
一个普通的企业问题
想象一家拥有约120名工程师的虚构物流SaaS公司。和许多正在尝试使用智能体的企业一样,它将内部文档、支持工作流程、操作系统、指标数据以及操作手册都接入了智能体平台。对于大多数问题,这种做法效果不错。
但后来有人询问准时交付率,系统却给出了三种不同的定义:
- 数据团队统计的是在承诺日期前送达的货物数量。
- 产品控制面板则采用略有不同的计算方式。
- 面向客户的文档则未将已取消的订单和退货计入其中。
这些都不是无稽之谈。不同的团队出于不同的原因编写了它们。问题出现在需要由智能体来决定哪一个是权威版本时。向量数据库能够识别语义上相近的内容,但它无法知晓公司指定哪一版本为标准定义,这是另一个问题。
相关性不等于权威性
标准的RAG流程会返回所有匹配的文档。如果三份文档从三种不同角度描述同一指标,那么这三份都会被返回。通过优化排序、添加额外元数据、重新排序、增大top_k值或扩展上下文窗口,都可能有所帮助。但这些方法都无法回答哪个定义才是官方标准这一组织层面的问题。
因此,真正的缺陷并非仅仅在于RAG会产生幻觉。相关性与权威性是不同的属性,而企业级智能体越来越需要同时具备这两者。
当结构即意义
并非所有知识都适合用同一套检索流程处理的另一个原因与数据结构有关。以一个有十行七列的表格为例,其含义并不仅仅存在于文字之中,而是源于表头、行标签、数值、单位以及周围上下文之间的相互关系。
若将这个表格分割成256个标记的片段,某个片段可能只包含一对表头,比如“地区”和“收入”,而另一个片段则可能包含“东部210万”和“西部180万”。模型或许能够正确重建这些关系,也有可能无法做到。
对于散文类文本,通常采用分块处理的方式;但对于结构化知识而言,这却成了一种奇怪的迂回路径:
- 先从结构入手
- 将其转换为文本
- 再将文本分割成片段
- 嵌入这些片段
- 检索少量片段
- 让模型重建原有的结构
在某个时候,人们会思考这个事物是否根本就不应该被拆分。数据库模式、连接路径、配置规则、指标公式、服务级别协议以及操作流程也同样如此。RAG 并不禁止使用结构化内容,关键在于当结构丢失后会改变含义时,就需要对结构进行特殊处理。
向量数据库从来都不是事实的来源
这家虚构的公司还面临另一个常见的问题:知识分散在各处。数据库注释、GitHub 维基、Confluence 以及迁移文件中都有关于模式的描述;指标定义则分布在分析仪表板、产品规格书、数据团队文档以及旧版演示文稿中。运行手册则散见于 Notion、事件工单、Slack 和 GitHub 中。有些连接逻辑则主要存在于负责该项目时间最长的那个人的记忆中。
在その基礎上构建向量数据库并不能产生权威的真实数据源,而只是生成了现有不一致信息的可搜索索引。这固然有价值,但并不等同于治理机制。
OKF的贡献
Open Knowledge Format的独特之处并不在于已存在的Markdown格式,而在于它提出了这样一个理念:让企业知识既能被机器清晰读取,同时又便于人类使用。从概念上讲,一个概念文件是以结构化元数据开头的:
type: metric
name: on_time_delivery_rate
owner: data-platform
reviewer: product
trust_tier: verified
stale_after: 1 day
related:
- shipments
- sla_definition
接着是为普通人撰写的解释:
# On-Time Delivery Rate
Percentage of shipments delivered on or before the current
promised delivery date.
## Excludes
- cancelled shipments
- test orders
- returns
该代理不再仅接收关于准时交付的简单文本,它还能了解该定义的归属者、其是否为最新版本、是否经过验证、它依赖于哪些内容以及还有哪些相关概念。问题从“哪段文本与哪个概念最相似”转变为“哪个概念才是标准版本,以及使用它是否安全”。
OKF并不能替代RAG
这里的结论与标题有所不同。更准确的描述是:标准知识存储在OKF中,探索性知识存储在RAG中,而当前状态则存在于实时系统中。
标准知识包括数据库架构、指标定义、服务级别协议、业务规则、操作手册以及归属信息。人们通常会询问的是其官方的、最新的定义是什么。
探索性知识包括历史报告、事件记录、支持对话、设计文档、案例研究以及客户反馈。关键在于判断哪些信息与查询目标相关。而这正是RAG的优势所在。
实时状态涉及今日的准时交付率、当前客户余额、正在处理的事件、未完成的订单以及库存水平。问题在于如何获取当前的真实数据,而向量索引很可能无法满足这一需求,应由存储这些数据的操作系统直接提供。
有些数据不应被检索出来
这就是架构变得更为有趣的地方。假设用户询问本季度收入最高的五位客户。有一种设计方式是将文档和数据导入索引,再让模型对其进行排序。虽然这可行,但还有更好的处理流程:智能体先查找“收入”的标准含义,构建查询语句,然后将其应用于记录系统。例如:
SELECT
customer_name,
SUM(revenue) AS total_revenue
FROM sales_data
WHERE quarter = 'Q3_2026'
GROUP BY customer_name
ORDER BY total_revenue DESC
LIMIT 5;
该智能体现在从两个来源获取信息:含义来自标准知识层,而当前数值则来自实际拥有数据的系统。它不再直接检索数据,而是先获取数据结构,再向实时系统查询。
一个智能体,三种知识路径
基于这种区别,一些示例问题的处理方式也有所不同:
- 准时交付是什么意思?请查阅标准定义。
- 今天的准时交付率是多少?先使用标准定义中的计算逻辑,再向实时仓库查询。
- 为何上个季度的准时交付率下降了?需将标准定义与历史仓库数据结合,可能还需参考事故报告和承运商记录中的相关内容。
处理人员不变,只是路径不同。与其讨论向量数据库是否会被替代,不如探讨如何更高效地处理这些问题。
路由器走向中心
由于存在多条知识路径,必须要有某种机制来选择路径。最初的路由器可以设计得相对简单。
class HybridKnowledgeRouter:
def __init__(self, okf, rag):
self.okf = okf
self.rag = rag
def classify(self, query: str) -> str:
q = query.lower()
if any(word in q for word in [
"schema", "column", "definition",
"metric", "sla", "runbook"
]):
return "canonical"
if any(word in q for word in [
"history", "report", "example",
"case study", "what happened"
]):
return "exploratory"
if any(word in q for word in [
"today", "current", "now",
"latest value", "how many"
]):
return "live"
return "hybrid"
其上下文方法如下:
def get_context(self, query: str):
query_type = self.classify(query)
if query_type == "canonical":
return self.okf.lookup(query)
if query_type == "exploratory":
return self.rag.search(query)
if query_type == "live":
concept = self.okf.lookup_relevant_schema(query)
return {
"concept": concept,
"requires_live_query": True
}
return {
"okf": self.okf.search(query),
"rag": self.rag.search(query)
}
这并非生产级的分类系统,但这样的结果也是可以接受的。首要目标仅仅是判断这种分离方式是否有用。
为何不直接使用BM25或更优的元数据?
在引入另一种机制之前,这个想法还需要经过充分的验证。
BM25。 对于结构化文本而言,它表现极为出色。精确的字段名称、关键词以及确定的排序方式都能提升效果。对于类似模式化的查询,它甚至可能优于嵌入模型。但它并不会改变底层架构——存储在搜索索引中的表格仍需以某种方式被表示和检索,最终得到的也只是更好的片段而已,本质上依然只是片段。BM25能够提升检索效率,却无法赋予内容权威性、所有权、新鲜度或规范的语义。
更多RAG元数据。这也很合理。可以附加诸如以下的字段,并在其上应用严格的过滤机制:
document_type
owner
version
effective_date
trust_tier
source
对许多系统而言,这可能已经足够。但一旦元数据成为告诉智能体什么内容是权威的、最新的、相关的以及安全的机制,结构化的知识层就已经开始形成。到那时,直接明确表述这个概念会比将其作为一份孤立的文档埋藏在通用索引中更为清晰。
实时查询带来安全问题
一旦允许大型语言模型针对操作系统构建查询,风险就会急剧上升。没人希望出现这种情况:
DROP TABLE shipments;
这个也不行:
SELECT * FROM shipments;
由于模型过于好奇,它会对包含5000万行的表格进行查询。更好的做法是不要让智能体访问数据库,而应赋予其受限的查询能力。模式概念可以用来描述允许的查询格式:
data_source: analytics.shipments
allowed_columns:
- shipment_id
- customer_id
- carrier_id
- status
- promised_delivery_date
- actual_delivery_date
required_filters:
- tenant_id
max_result_rows: 1000
access_mode: read_only
随后会根据该策略对生成的查询进行验证:
def validate_query(query, policy):
checks = [
uses_allowed_table(query, policy),
selects_allowed_columns(query, policy),
contains_required_filters(query, policy),
respects_row_limit(query, policy),
is_read_only(query),
]
if not all(checks):
raise UnsafeQueryError()
return True
在实际应用中,还需要进一步采取以下措施:独立的执行凭证、在模型外部实现的租户隔离、数据库级别的权限控制、行数与成本限制,以及对每条执行查询的记录。其核心原则是:模型提出执行请求,而基础设施负责判断该请求是否可以运行。
标准化的知识需要负责人
单一的真实数据源听起来很理想,但问题在于没人会去更新它。拥有者身份和数据更新频率比文件格式更为重要。一个概念可能包含如下字段:
owner: data-platform@company.io
reviewer: product-analytics@company.io
stale_after: 7 days
每当度量定义被修改时,相应的知识更新也应包含在同一份文档中。当模式发生变化时,应重新生成或审查其标准形式。人们不应重复输入数据库已有的信息,因此由机器来生成已知事实:
for table in database.tables():
generated = generate_okf_schema(table)
save(generated)
随后,人们需要审核哪些内容需要判断:业务含义、所有权、敏感字段、允许的使用方式、关联关系以及注意事项。如果跳过这些步骤,唯一的真实数据源就会变成另一个过时的存储库。
版本控制的重要性超出想象
“规范”并不意味着永恒不变。试想,如果公司将“准时交付”的定义从“按订单总数计算的准时发货比例”改为“按实际交付总数计算的准时发货比例”,那么若直接覆盖旧定义,回答历史问题的人员就可能会用今天的逻辑来分析去年的报告。因此,相关概念需要设置版本或生效日期:
versions:
- version: "2.0"
active: true
effective_from: 2026-06-10
change: "Denominator changed to delivered shipments"
- version: "1.0"
active: false
effective_from: 2025-01-01
effective_to: 2026-06-09
现在有两个问题得到了不同的答案。一个关于OTD定义的问题使用的是当前版本,而另一个关于为何2026年第一季度的报告采用不同计算方式的问题则使用当时有效的版本。所谓“规范版本”并不意味着不可更改,而是指受到控制。
当RAG与规范知识出现分歧时
迟早,智能体会检索到一份旧文档,其中将OTD定义为准时交付的货物数量占订单总数量的比例,而规范概念则将其定义为准时交付的货物数量占实际交付货物总数的比例。系统需要明确的优先级规则,对于此类矛盾情况,应给出如下回应:
if contradiction(okf_context, rag_context):
log_conflict(…)
prefer(okf_context)
它甚至可以告知用户:某个较旧的文档与当前的度量定义存在冲突,因此系统使用了当前已验证的定义。这样一来,该智能体所做的就不仅仅是回答问题,还在揭示知识缺陷,这或许是该设计最宝贵的副作用之一。
衡量不止最终答案
在这种架构中,仅跟踪幻觉率是不够的。还应衡量系统得出答案的过程,例如:
% queries routed to correct source
% canonical lookups with stale concepts
% live queries rejected by policy
% RAG/OKF conflicts detected
% concepts past stale_after
% concepts with no active owne
错误的最终答案可能源于多种不同的故障。模型可能推理有误;在需要标准知识的情况下,路由器却选择了RAG;标准概念可能已经过时;实时查询可能是正确的,但指标定义有误。这些都是不同的工程问题,可观测性应有助于将它们区分开来。
何时属于过度设计
一个仅有五名成员且只有少量内部文档的工程团队,很可能无需知识治理平台。如果主要需求是在数千份文档中查找相关信息,RAG或许就足够了。如果知识很少变动,那么更新机制可能并无必要。如果目前没有人负责文档管理,添加YAML前置信息也无法培养出相应的责任意识。
当出现以下多种情况时,这种设计模式才具有吸引力:
- 多个团队各自定义相同的概念
- 智能体执行操作任务
- 架构与指标会频繁变更
- 错误的知识会给企业带来实际损失
- 定义需要明确负责人并保留审计轨迹
- 实时数据必须与标准语义对应
符合的情况越多,采用分离式架构的收益就越大。
MCP的适用场景
当智能体需要调用多个知识与数据源时,MCP便成为理想的集成点。智能体可能具备以下功能:
get_canonical_metric_definition
get_schema
search_historical_documents
query_warehouse
get_runbook
路由器会选择合适的方案。OKF负责定义概念与约束条件,MCP提供工具与资源,实时系统保留当前数据的控制权,而RAG则继续承担非结构化历史数据的检索功能。除非有充分的理由,否则这些职责最好保持分离。
合理的初始构建方案
从300个概念开始是错误的做法。10个更为合适,尤其是那些人们已经存在争议的10个概念。例如:
3 metrics
2 schemas
2 SLAs
2 runbooks
1 business rule
接着需要测量几项指标。智能体能否找到标准概念?它能否判断该概念何时已过时?路由机制是否能选择正确的路径?实时查询能否安全运行?是否有人真正维护这些概念?良好的结果可作为扩大应用范围的依据,而糟糕的结果则说明应该停止。架构实验应当能够在几乎不造成损失的情况下失败。
更重要的启示
最有价值的收获并非新的文件格式,而是企业知识存在不同的真实度表现形式。有些是权威性的,有些是探索性的,还有些反映当前状态,每种形式都应采用相应的访问方式。有一个实用的对应关系可将每种问题与相应的形式关联起来:
- 官方定义:标准知识。
- 相关信息:检索。
- 当前真实状态:实时查询。
- 智能体应采取的行动:根据策略整合以上所有信息。
RAG依然有价值,向量数据库依然有价值,OKF同样也可能具有价值。架构上的错误在于认为其中某一种技术就应该能解决所有问题。未来并非要取代RAG,而是要明白何时该使用RAG,何时不该使用。一旦智能体在企业内部开始执行实际操作,选择信息来源就不再仅仅是知识管理的问题,而变成了架构层面的决策。
相关阅读
- 实用笔记:OKF远不止是Markdown——我对可移植性的理解 —— 对“实用笔记:OKF远不止是Markdown——我对可移植性的理解”这一内容的详细操作指南,包括适用于采用该模式的团队的合同、检查项以及可直接插入的代码片段。