← 博客
· OLAV Team

OLAV vs 日志 AI 系统:为什么网络运维需要的不是更聪明的 grep

大多数'AI for operations'工具不过是在日志搜索上加了一层 LLM。OLAV 走了相反的路:将网络工程师的完整工作流——采集、解析、分层排障、快照对比、仿真验证、变更规划——建模为一个 AI 专家团队。本文将剖析两者的架构本质差异。

架构 NetOps AI Agent 日志分析 根因分析

日志陷阱

目前市场上大多数 “AI for operations” 工具做的是这样一件事:

  1. 把日志灌入向量数据库
  2. 在前面放一个 LLM
  3. 出问题时,LLM 搜相关日志行,总结一下

这有用,但它的架构和 2023 年的文档问答聊天机器人一模一样——只是把 PDF 换成了日志文件。凌晨 3 点网络断了,你得到的是这样的答案:

“在 02:47 到 03:12 之间,BGP 邻居 10.0.0.2 四次进入 Idle 状态。R3 上出现 ‘BGP-5-ADJCHANGE’ 事件。这可能表示网络连通性问题。建议:检查 R3 与 BGP 邻居之间的物理连通性。”

这是一个更聪明的 grep。它告诉了你已经知道的事,建议了你本来就会做的事,却无法告诉你为什么邻居进入了 Idle——因为它只有一个数据源(日志)和一种分析手段(模式匹配)。它在回答表象,而不是状态。

真正的网络工程师怎么做排障

当一个真正的网络工程师排查 “R3 BGP 邻居 down” 时,他不会从读日志开始。他遵循的是分层、证据驱动的过程:

  1. 状态检查——R3 当前接口状态如何?物理链路 up 吗?show ip bgp summary 现在输出什么?
  2. 拓扑检查——R3 连接了谁?通过哪些接口?用的什么发现协议(LLDP/CDP)?
  3. L1→L4 自底向上诊断——接口是否被管理性关闭?MTU 是否匹配?到邻居 loopback 的 IGP 路由还在吗?ACL 是否阻断了 TCP 179?
  4. 历史关联——BGP 震荡前是否有拓扑变更?接口 last-change 时间戳是否与 BGP down 时间吻合?
  5. 跨快照对比——上一个已知正常的快照和现在之间,有什么变化?新配置行?不同的邻居列表?
  6. 根因定位——不是 “BGP 邻居 down 了”,而是 “04:00 维护窗口移除了 R3 Gi0/2 链路,导致到邻居 loopback 的 IGP 路径丢失,进而使 BGP 转为 Idle”。

这本质上是一个多数据源、跨层、时序关联问题。日志是其中一个关键输入——但单独远不够用。工程师需要结构化的设备状态、拓扑、路由表、配置文本,以及跨时间对比所有这些的能力。

两种根本不同的架构

flowchart LR
    subgraph A["日志 AI 系统"]
        L[日志 / Syslog] --> VDB[向量数据库]
        Q[用户查询] --> LLM1[LLM]
        VDB --> LLM1
        LLM1 --> R1["'BGP down——检查连通性'"]
    end

    subgraph B["OLAV NetOps"]
        direction TB
        SSH[Nornir SSH 采集] --> P[TextFSM / PaC 解析]
        P --> DB[(DuckDB<br/>12+ 结构化视图)]
        S[Syslog Parquet] --> EVD[query_evidence]
        DB --> AG[NetOps 编排器]
        EVD --> AG
        AG --> RP[Reporter<br/>L1→L4 调查]
        AG --> AN[Analyzer<br/>变更规划]
        AG --> SM[Simulator<br/>Batfish 仿真验证]
        AG --> TP[Topology Engine<br/>CDP/LLDP/BGP]
        RP --> R2["根因:<br/>'R3 Gi0/2 04:00被移除 →<br/>IGP 路径丢失 → BGP Idle'"]
        AN --> R2
        SM --> R2
        TP --> R2
    end

    style A fill:#1a1a2e,stroke:#e94560,color:#eee
    style B fill:#0f3460,stroke:#16c79a,color:#eee

日志系统是一个单代理 RAG 管道:嵌入、检索、总结。它完全运行在文本相似度空间里。它无法回答 “昨天和今天有什么不同”,因为昨天的结构化状态根本不存在于它的向量数据库中。

OLAV 是一个网络工程的多人操作系统:每个专家代理负责一个能力域,编排器负责意图路由,每个代理都同时扎根于结构化状态(DuckDB,设备 show 输出的 12+ 自动视图)和非结构化证据(syslog、命令输出、配置文本)。

数据层:结构化状态,而非日志行

这是最深层的差异,也是凌晨 3 点最关键的差异。以下是两个系统各自拥有的数据维度:

数据层日志 AI 系统OLAV NetOps
设备清单❌ 无netops.devices — 主机名、平台、厂商、角色、站点、管理 IP
接口状态❌ 无v_show_interfaces_auto / v_show_interfaces_terse_auto — admin/oper 状态、IP、MTU、last-change
BGP 状态❌ 无v_bgp_neighbors_auto — 邻居、状态、接收前缀数、运行时间、AS
OSPF 状态❌ 无v_ospf_neighbors_auto — 邻居、状态、区域、接口
拓扑❌ 无topology_links — CDP/LLDP 邻接关系、源/目的设备+接口
路由表❌ 无v_show_ip_route_auto — 目的网段、下一跳、协议、出接口
日志(syslog)✅ 主要数据源query_evidence(source="syslog") — 辅助证据,与结构化状态交叉验证
配置文本⚠️ 如果被采集query_evidence(source="config") — running/startup 配置搜索
CLI 输出❌ 无query_evidence(source="command_output") — 原始 show 命令输出文本搜索
快照(时序)❌ 无parsed_outputs 中按快照保存历史;diff_snapshots 做行级对比

当 BGP 邻居震荡时,日志系统只能告诉你 “它震荡了”。OLAV 可以告诉你:

  1. 接口全程是 UP 的(v_show_interfaces_terse_auto
  2. 但到邻居 loopback 的 IGP 路由在两个快照之间消失了(v_show_ip_route_auto + diff_snapshots
  3. 拓扑显示 R3 的 Gi0/2 链路是到该邻居子网的唯一条 L2 路径(topology_links
  4. 04:00 的维护窗口与 Gi0/2 的 updated_at 时间戳吻合(netops.devices

这就是告警和根因之间的差距。

知识注入:专家团队并非每次从零开始

还有一个结构性缺口。日志 AI agent 每次查询都从零开始:它只有 prompt、用户问题、以及检索到的日志行。仅此而已。

OLAV 的 agent 在每次查询开始前,都会自动注入三层预制知识

flowchart TD
    subgraph Inject["知识注入(Agent 执行前)"]
        direction TB
        L1["第一层:guide.yaml<br/>领域专家知识<br/>例:'BGP Idle → 先查接口状态'<br/>例:'L1→L4 自底向上诊断序列'"]
        L2["第二层:memory_primer<br/>入库时预计算的数据画像<br/>例:'v_bgp_neighbors_auto 的列:peer, state, ...'<br/>例:'state 列取值分布:Established(8), Idle(1)'"]
        L3["第三层:AutoRecall<br/>历史失败教训<br/>例:'上次:过滤条件太宽 → 限制 LIMIT 20'<br/>例:'本拓扑:R3-R4 链路是冗余的'"]
    end

    subgraph Agent["子代理执行"]
        AG[Reporter / Analyzer / Simulator]
    end

    L1 --> AG
    L2 --> AG
    L3 --> AG
    Q[用户查询] --> AG

    style Inject fill:#16213e,stroke:#0f3460,color:#eee
    style Agent fill:#0f3460,stroke:#16c79a,color:#eee

第一层——guide.yaml 文件是编码为可检索、作用域过滤指令的领域专业知识。当用户问 “为什么 BGP 在震荡”,fault_analysis_workflow.guide.yaml 自动注入。它告诉 agent:“先收集 L1 证据(接口状态),再 L3(到邻居的路由),然后 L4(TCP 179)。只有在 L1-L4 都正常后才检查协议层属性。”

第二层——memory_primer 在数据入库时运行,而非查询时。每次采集设备数据后,它预计算每个自动视图的 schema 和每个状态列的值分布,写入 LanceDB。当 agent 醒来回答问题,它已经知道有哪些表、表里有哪列、哪些值是正常的——无需执行一次 DESCRIBE TABLE

第三层——AutoRecall 捕获历史运行的失败模式并注入为约束。如果 agent 上周跑了一个过滤太宽的查询,返回了 12000 行(撑爆上下文),下周同类查询时会携带教训:“上次在此拓扑上,WHERE state='Established' 配合 LIMIT 20 返回 8 行。沿用此限制。”

这不是 RAG。RAG 检索的是相似文档。OLAV 的知识注入检索的是可执行的约束——告诉 agent 如何思考的指南、告诉 agent 存在什么数据的 schema、告诉 agent 不要再犯什么错误的经验反思。

“团队”架构:一个编排器,七个专家

一个拿着 30 个工具的 agent 在本地小模型上根本不能工作——光是工具定义就吃掉了半个上下文窗口,选错工具的概率倍增。OLAV 反其道而行之:

flowchart TD
    U["用户:'R3 的 BGP 为什么 down 了?'"] --> ORCH["NetOps 编排器<br/>3 工具:memory, search, delegate"]

    ORCH --> R["task('reporter', ...)<br/>L1→L4 调查"]
    ORCH --> A["task('analyzer', ...)<br/>变更规划草案"]
    ORCH --> S["task('simulator', ...)<br/>Batfish 仿真验证"]
    ORCH --> C["task('collector', ...)<br/>SSH 采集"]
    ORCH --> I["task('importer', ...)<br/>离线包导入"]
    ORCH --> T["task('topology', ...)<br/>拓扑查询"]
    ORCH --> L["task('learner', ...)<br/>解析器学习"]

    R --> DB[(DuckDB<br/>结构化状态)]
    R --> SL[Syslog Parquet]
    A --> DB
    S --> DB

    style ORCH fill:#1a1a2e,stroke:#e94560,color:#eee
    style R fill:#0f3460,stroke:#16c79a,color:#eee
    style A fill:#0f3460,stroke:#16c79a,color:#eee
    style S fill:#0f3460,stroke:#16c79a,color:#eee

每个专家只持有 4-7 个工具——正好是其领域所需的。Reporter 有 execute_sqlinspect_blast_radiusformat_and_export,以及 execute_skill_script——后者用来运行 query_evidencediff_snapshots 这类领域脚本。它不能 SSH 到设备。它不能写变更计划。Analyzer 有另一套工具。Simulator 又是另一套。这是最小权限原则在 AI agent 上的应用。

编排器是一个纯路由器:只持有记忆(olav_recall_memory / olav_store_memory)与 web_search(网络搜索),外加框架注入的 task()(委派)。它的全部工作就是分类意图、分派到一个专家。它不推理问题,不合成结果。它把专家的输出原样返回。

对比日志 AI 系统:一个 agent,一个 prompt,一套工具——“搜日志,然后解释”。那是一个拿着手电筒的单兵。OLAV 是一整个 NOC 值班团队。

自改进闭环:每次调查都让系统变得更聪明

这是日志系统从根本上做不到的事:从自己的错误中学习,并自动应用教训。

sequenceDiagram
    participant U as 用户
    participant A as Agent
    participant TL as trace_learner
    participant M as LanceDB 记忆库
    participant AR as AutoRecall

    U->>A: "R3 的 BGP 为什么震荡?"
    A->>A: 执行查询:LIMIT 100 → 返回 12000 行 → 上下文溢出
    A-->>U: 超时 / 部分回答

    Note over TL: 事后分析:捕获失败模式
    TL->>M: 写入 reflection:<br/>"此舰队 BGP 查询必须用 LIMIT 20,<br/>按 device_name 过滤。LIMIT 100 返回了 12K 行。"

    U->>A: "R3 的 BGP 为什么震荡?"(下周)
    AR->>M: AutoRecall:拉取相关 reflection
    M-->>AR: "BGP 查询:LIMIT 20,按 device_name 过滤"
    AR-->>A: 在执行前注入 prompt
    A->>A: 执行查询:LIMIT 20, device_name='R3' → 8 行
    A-->>U: 根因分析完成

这就是 trace_learnerreflectionAutoRecall 闭环。每一次失败的工具调用、每一次上下文溢出、每一次超时都会留下痕迹。learner 将其提炼为紧凑、可执行的约束(每行一条,30 天 TTL)。下一次类似查询时,AutoRecall 在 agent 开始工作之前就注入约束——错误永不重演。

这个闭环无需任何人工干预。不需要改 prompt,不需要”收集错误样例做微调”。系统观察失败 → 捕获教训 → 自动应用。这才是 AI 原生的运维工程,不是 RAG 加装饰。

当日志不够用:Parser-as-Code 的解法

还有一个硬差距。当传统日志 AI 系统遇到一台 show 输出格式无法识别的设备时,会发生什么?

它失败了。可能优雅地失败,但终究失败——“未知格式”或”无可用解析器”。

OLAV 的 learner 子代理选择了不同的路。当一台新设备的 show 命令输出无法解析时:

  1. 多设备样本训练——learner 按 (平台, 命令) 汇总所有设备的原始输出,一次性喂给 LLM
  2. PaC(Parser-as-Code)生成——LLM 输出的是一个 Python 函数,而非配置文件
  3. AST 白名单沙箱——生成的代码被验证:不能 import os、不能 subprocess、不能 open()——只能使用 rejsonipaddress 等少数安全模块
  4. 多设备交叉验证——解析器必须在所有设备上产生 ≥70% 预期数据行数的有效记录
  5. 单样本隔离——仅在一台设备上验证通过的解析器进入 _quarantine/,等待第二台设备的确认样本

这意味着 OLAV 无需人工编写 TextFSM 模板就能适配新硬件。系统通过观察多个样本学习格式,用机械手段验证解析器,对不确定的结果进行隔离。日志系统做不到这一点——它没有将非结构化设备输出转化为结构化状态的机制。

总结:完整能力矩阵

能力日志 AI 系统OLAV NetOps
数据源SyslogSyslog + 12+ 结构化 show 命令视图 + 拓扑 + 设备配置
结构化状态完整 DuckDB schema:设备、接口、BGP、OSPF、路由、拓扑、原始/解析输出
时序分析时间范围日志搜索跨快照行级 diff(diff_snapshots
根因方法模式匹配 → LLM 总结L1→L4 分层诊断 → 跨层矛盾检测 → 证据链
知识管理RAG(检索相似日志行)三层注入:guide.yaml + memory_primer + AutoRecall 反思
Agent 架构单 agent,所有工具暴露1 编排器 + 7 专家,每个 4-7 工具,最小权限原则
未知格式处理”无可用解析器”PaC 自学习解析器(AST 沙箱 + 多设备验证 + 隔离区)
变更规划完整管线:分析状态 → 逐设备 CLI + 回滚 → Batfish 仿真 → ContainerLab 验证
自我改进trace_learner → reflection → AutoRecall:失败被捕获为约束,自动应用
上下文预算控制无(全量日志倾泻)按模型分级:small=8K / medium=32K / large=200K,自动截断,50% 预算时触发压缩
写操作安全7 层纵深防御:默认只读、按服务控制、预演审核、人工确认、沙箱、网络隔离、审计追踪

结语

日志 AI 系统是一个搜索引擎上面加了一层礼貌的摘要。它告诉你发生了什么,有时猜测可能哪里不对,但始终局限在日志模式的狭隘视角里。

OLAV 是一个 AI 原生的网络工程操作系统。它采集的是结构化状态,而不只是日志行。它做到跨层诊断,而不只是模式匹配。它做跨时间对比,而不只看当下。它从失败中学习,并自动应用教训。而且——它在你自己已有的硬件上运行,不需要云端 GPU 集群。

这之间的差距不是增量式的。是告警和诊断之间的差距。是表象和根因之间的差距。是一个更聪明的 grep,和一个永不休眠的网络工程师之间的差距。