← 博客
· OLAV 团队

你的 Agent 订阅已经具备网络分析能力 —— 它只是触达不到真实网络

两个开源仓库,为企业已付费的 Agent 平台接入真实网络模型:跳板机上的 olav-collector,工作站上的 olav-skills,中间只通过一个纯文本目录连接。

网络运维 技能包 采集器 Claude Code 企业级 工作流

你的企业很可能已经为某种 AI Agent 平台(如 Claude Code 等)支付了订阅费用。在抽象层面上,这些 Agent 对网络工程逻辑的推理能力非常出色;但面对你自己的实际生产网络,它却一无所知 —— 因为承载这些状态信息的交换机、路由器和防火墙全部深置于跳板机之后、处于无法直连互联网的运维管理网内,而 Agent 运行的笔记本或工作站则根本无法直接访问这些设备。

通常大家会尝试两种方案,但两者走向了两个极端的失败:

  1. 在 DMZ 部署 MCP Server:意味着需要开通新的入站通道、经历漫长严苛的安全审计,还要维护一套常驻的在线服务。
  2. 在聊天窗口里手动粘贴 show 命令输出:这种方式只能单次起效,根本无法沉淀任何网络拓扑与状态模型 —— 下一个问题到来时,一切又必须从零开始。

其实存在第三种架构形态,它像一切优秀基础设施一样朴素且可靠: 在设备所在之处采集原始文本,在 Agent 所在之处解析并施加结构。 在两端之间,只有包含纯文本文件的目录在流动。今天,构成这一工作流的两个核心开源组件均已正式公开:

flowchart LR
    subgraph MGMT["管理网络 —— 无法直连互联网"]
        D1[("交换机<br/>路由器<br/>防火墙")]
        JH["跳板机<br/><b>olav-collector</b><br/>仅依赖 netmiko + pyyaml"]
        D1 -- "SSH(只读)" --> JH
    end
    B[["采集包 bundle/<br/>manifest.yaml<br/>devices/*/*.txt"]]
    JH -- "纯文本输出目录" --> B
    subgraph WS["工程师工作站 —— Agent 运行环境"]
        P["<b>olav-skills 技能包</b><br/>7 项技能 · 32 个脚本"]
        DB[("DuckDB<br/>原始 + 解析结构")]
        A["Agent 平台 (如 Claude Code)"]
        P --> DB
        A -- "自然语言驱动" --> P
    end
    B -- "scp 拷贝" --> P

跳板机甚至不需要知道什么是解析器(Parser)

这是派生出所有其他架构决策的根本原则,值得明确强调:采集端(Collector)从不进行任何解析。 它不依赖 ntc-templates,没有内置模板库,没有模型,也没有任何需要与下游保持同步的状态。它的职责纯粹而专一:登录设备、执行命令、逐字原样保存标准输出,并写入一份清单清单文件(manifest.yaml)。

这种控制反转并非偷懒。在整个网络资产中,跳板机往往是维护窗口最窄、变更控制最严苛、最不适合留存状态的节点。解析能力属于解析器所在的地方 —— 即执行分析任务的工作站。正因为采用了这种架构,一个在 11 月新编写的解析器,可以直接作用于 8 月采集到的历史数据,完全无需重新登录设备采集。

# 在跳板机上运行
pip install -r requirements.txt          # 仅 netmiko + pyyaml,安装即完成
cp tasks/hosts.csv.example tasks/hosts.csv
$EDITOR tasks/hosts.csv                  # 配置 hostname,ip,platform

python collect.py --dry-run              # 仅统计每台设备需采集的命令数,不发起 SSH
python collect.py

在不指定 --task 的情况下,采集器会默认扫描对应设备平台的全量命令库 —— 例如针对 cisco_ios 执行 143 条命令,针对 juniper_junos 执行 23 条命令。这种全量策略经过深思熟虑:因为在实际运维中,最稀缺的资源是设备的访问窗口与授权时限,而不是本地磁盘空间。如果每次只针对特定排障狭隘采集,遇到未预料的问题就必须申请二次访问;而如果一次性全面采集,当未来出现当天没人想到的深层问题时,所有原始语料早已就绪。

这种广度采集在工程上需要解决两个关键挑战,工具均已原生处理:

防止交互式命令卡死:命令库最初衍生自 ntc-templates 索引,但该索引只描述了哪些命令可以被解析,并未考虑哪些命令适合无人值守批量执行。例如在 Cisco IOS 上执行裸 ping 会进入扩展 ping 的交互式问答,导致 SSH 会话阻塞直至读取超时。在 69 个平台中共有 8 类此类交互指令,它们已在 exclusions.csv 中按规则剔除,并配有自动化测试防止回归。

敏感配置明文防范show running-config 包含了明文/哈希口令、SNMP Community 与本地用户账号。默认采集配置是因为配置分析占据了运维诊断的大部分价值,而如果直接静默采集则容易造成安全隐患。因此采集器会在写入前发出醒目标识:

WARNING This sweep collects config bodies — the bundle will contain credentials
        in PLAINTEXT until it is ingested. Treat it as a secret in transit and
        at rest, or re-run with --no-config.

敏感信息的脱敏在工作站导入阶段完成。在此之前,整个文本目录应被视为机密资产安全传输。如果企业策略严格禁止导出配置,传入 --no-config 即可跳过此类命令。

传输只需一次文件拷贝

scp -r output/2026-08-19/041302 you@workstation:~/captures/acme/

这就是全部的数据流转。没有复杂的远程模板同步,没有分布式解析调度,跳板机上更没有任何 Agent API 凭据,无需对外暴露任何入站端口。从安全审计的角度来看,这具备绝佳的合规优势:直接接触网络设备的只是一个约 730 行、仅有两个轻量依赖且除了只读 SSH 之外无任何外网流量的 Python 脚本;而与大模型对话的 Agent,自始至终无法直接触碰任何物理网络设备。

工作站侧仅需一次 pip install 和技能拷贝

python -m venv .venv && . .venv/bin/activate
pip install ./runtime                    # 约 120 MB,无沉重平台依赖
cp -r skills/* ~/.claude/skills/

该技能包在其 runtime/ 目录下打包了所需的全部 45 个核心模块,仅声明纯第三方依赖。它不依赖外部的完整 OLAV 服务端,这意味着无论平台将来如何重构,都不会破坏你几周前下载的技能包行为。

配置完成后,你无需再手动拼接脚本命令,直接使用自然语言提问:

“请导入 ./captures/acme/041302 中的采集包”

Agent 会自动激活 importer 技能,并提取路径参数执行对应的解析导入脚本。导入完成后,它会明确回显写入的数据库路径(db_path),确保状态清晰可见。

首次导入的“未完全解析”是特性而非缺陷

在针对两台真实设备的首轮全量采集实测中,共收集了 166 条命令输出,其中 7 条直接命中内置模板完成解析:

devices 2 | landed 166 | parsed 7 | unparsed 159
by reason {'parser_no_match': 155, 'no_parser_registered': 4}
learn queue:
  recipe  juniper_junos  show bgp summary        x1
  recipe  cisco_ios      show ip ospf neighbor   x1
  -       cisco_ios      show access-list        x1

在首轮扫描中较低的解析率完全正常,绝非系统故障。无论是否存在现成解析器,所有命令的原始文本均已完整落库至 raw_output_store;而未解析的指令则自动聚合成一个待学习工作队列(Learn Queue) —— 拓扑配方(Recipe)所声明的关键命令会被排在最前列,因为它们一旦解析成功,就能立刻转化为可供 SQL 查询的核心结构化视图。

补齐一个缺失的解析器只需要两次简单的交互:

echo '{"platform":"cisco_ios","command":"show access-list",
       "samples":[{"device":"R2","raw_output":"..."}]}' \
  | python learner/scripts/prepare_learn.py     # 生成提示词与样本草稿

echo '{"platform":"cisco_ios","command":"show access-list",
       "parser_response":"# OLAV_DSL: textfsm\nValue ...", "samples":[...]}' \
  | python learner/scripts/finish_learn.py      # 自动校验格式并固化模板

再次执行导入时,完全相同的采集包将解析出更多结构化数据。无需二次登机、无需重新采集 —— 原始文本一直保存在本地。新的 TextFSM 模板在下一次解析时立即生效。

flowchart TD
    C["全量采集 raw text<br/>获取 166 个命令输出"] --> I["导入 import"]
    I --> OK["7 个已匹配 → 生成 SQL 查询视图"]
    I --> GAP["159 个未匹配 → 存入 raw_output_store"]
    GAP --> Q["学习工作队列<br/>拓扑核心命令优先"]
    Q --> W["工程师或 Agent 编写 TextFSM 模板"]
    W --> F["finish_learn: 校验并固化模板"]
    F -. "针对同一数据包重新导入" .-> I
    OK --> ASK["向 Agent 提问分析网络"]

这就是让整套系统产生**复利效应(Compound)**的关键所在:每一次排障或分析都会让工作站学到新的知识,而所学的解析规则可以无缝回溯应用于历史上已经采集的所有数据。

数据入库后可以提问什么?

echo '{"query": "which devices are in the snapshot"}' | python analyzer/scripts/execute_sql.py
echo '{}' | python topology/scripts/query_topology.py

在实际使用中,你只需用自然语言向 Agent 提问,Agent 会在后台执行上述脚本。execute_sql 在仅传入 query 参数时会返回数据库架构元数据供大模型编写 SQL;所有查询均在只读连接上执行,任何带有数据变更性质的语句都会被直接拒绝。技能包涵盖的 7 大核心能力包括:

本架构明确不做的边界

这些明确设立的边界不仅不是缺陷,反而是能够轻松通过企业安全合规审查的核心保障。

标准输入输出设计,不与单一 Agent 绑定

尽管当前技能包以 Claude Code 规范进行分发,但其中的每个脚本均遵循极简原则:从标准输入 stdin 读取一个 JSON 对象,向标准输出 stdout 打印一个 JSON 对象 —— 不存在任何专有框架绑定。任何能够执行 Shell 命令的 Agent 运行时均可驱动这些脚本。

两套仓库均采用 BSL 1.1 协议开源:非生产用途完全免费,并在 2030 年 1 月 1 日自动转为 Apache 2.0 协议。

github.com/james-olavai/olav-collector
github.com/james-olavai/olav-skills

你可以从单台设备的 --dry-run 预览开始体验。首轮导入中那些未被解析的输出恰恰是最有价值的部分 —— 它们正是你的实际网络中独具特色、尚未被标准模板覆盖的真实资产。