第320篇:LLM 辅助网络排障

关键词

LLM、大语言模型、网络排障、智能分析、日志分析、配置审查、根因定位、RAG


一、LLM 在网络排障中的应用

1.1 传统排障 vs LLM 辅助排障

传统排障方式:
  ┌─ 工程师 SSH 登录设备
  ├─ 逐条查看日志和状态
  ├─ 依赖个人经验和记忆
  ├─ 范围受限(只能查几台设备)
  ├─ 耗时:从分钟到小时
  └─ 知识传承困难

  LLM 辅助排障:
  ┌─ 收集多设备数据自动聚合
  ├─ 分析日志自动识别异常
  ├─ 基于知识库给出建议
  ├─ 生成排障报告
  ├─ 耗时:秒到分钟
  └─ 知识可积累复用

  LLM 在排障中的角色:
  ┌─ 不是替代工程师,而是"超级助手"
  ├─ 提供数据分析和模式识别
  ├─ 给出根因建议
  └─ 最终决策由工程师确认

1.2 典型应用场景

LLM 辅助排障的十大场景:

  1. 日志分析
  ┌─ 从海量日志中提取关键错误
  ├─ 识别日志模式(周期性错误/故障前兆)
  └─ 关联多个设备的时间序列

  2. 配置审查
  ┌─ 检查配置是否符合最佳实践
  ├─ 发现配置冲突(如 BGP/OSPF 参数不一致)
  └─ 对比基线找差异

  3. 故障根因分析
  ┌─ 基于告警和拓扑推断根因
  ├─ 给出排查路径
  └─ 推荐修复方案

  4. 命令建议
  ┌─ 根据问题描述推荐排障命令
  ├─ 解释命令输出
  └─ 生成修复配置

  5. 知识检索
  ┌─ 基于文档/案例检索解决方案
  ├─ 匹配相似历史故障
  └─ 提供处理建议

二、RAG 知识库排障

2.1 RAG 架构

RAG(检索增强生成)排障架构:

用户问题:接口 GE0/0/1 flapping ↓ ┌────────────────────────────────────┐ └────────────────────────────────────┘ ↓ ┌────────────────────────────────────┐ └────────────────────────────────────┘ ↓ 回答:接口 flapping 可能原因列表 ┌─ 1. 检查光模块功率 ├─ 2. 查看 CRC 错误计数 ├─ 3. 检查对端接口状态 └─ 4. 建议更换光模块 向量检索(Embedding) ↓ 向量数据库 ┌──────────────────────────────┐ └──────────────────────────────┘ LLM 生成(GPT/文心/盘古) 基于检索到的相关知识生成回答 知识片段 1: interface flap 知识片段 2: CRC error check 知识片段 3: 光模块故障案例

2.2 知识库构建

#!/usr/bin/env python3
# llm_knowledge_base.py — 排障知识库构建

import json
import hashlib
from typing import List, Dict

class KnowledgeBase:
    """排障知识库"""

    def __init__(self):
        self.articles: List[Dict] = []
        self.index: Dict[str, List[int]] = {}

    def add_article(self, title: str, symptoms: List[str],
                    causes: List[str], solutions: List[str],
                    tags: List[str], source: str = ""):
        """添加知识文章"""
        article = {
            "id": hashlib.md5(title.encode()).hexdigest()[:8],
            "title": title,
            "symptoms": symptoms,
            "causes": causes,
            "solutions": solutions,
            "tags": tags,
            "source": source,
        }
        self.articles.append(article)

        # 建立关键词索引
        keywords = set()
        for s in symptoms + tags + causes:
            keywords.update(s.lower().split())
        for kw in keywords:
            if kw not in self.index:
                self.index[kw] = []
            self.index[kw].append(len(self.articles) - 1)

    def search(self, query: str, top_k: int = 3) -> List[Dict]:
        """检索相关知识"""
        query_words = set(query.lower().split())

        # 简单关键词匹配检索
        scores = {}
        for word in query_words:
            if word in self.index:
                for idx in self.index[word]:
                    scores[idx] = scores.get(idx, 0) + 1

        # 排序
        ranked = sorted(scores.items(), key=lambda x: -x[1])
        return [self.articles[idx] for idx, _ in ranked[:top_k]]

    def to_dict(self) -> dict:
        return {"articles": self.articles}

    def save(self, path: str):
        with open(path, "w", encoding="utf-8") as f:
            json.dump(self.to_dict(), f, indent=2, ensure_ascii=False)


# ===== 构建排障知识库 =====
kb = KnowledgeBase()

# 添加常见故障知识
kb.add_article(
    title="接口频繁 Flapping(震荡)",
    symptoms=["interface flapping", "interface up/down",
              "端口频繁UP DOWN", "端口震荡"],
    causes=["光模块故障/老化", "光纤损坏/弯曲半径过小",
            "对端设备接口故障", "配置协商不匹配"],
    solutions=[
        "display interface 检查 CRC 错误计数",
        "display transceiver 检查光模块功率",
        "检查两端双工/速率协商模式",
        "更换光模块或光纤测试",
        "如果 CRC 持续增长,建议更换光模块",
    ],
    tags=["接口", "flapping", "光模块", "物理层"],
    source="华为排障手册"
)

kb.add_article(
    title="BGP 邻居不能建立",
    symptoms=["BGP down", "bgp peer flapping",
              "BGP 邻居无法建立", "BGP 状态 Idle",
              "bgp active"],
    causes=[
        "TCP 连接不通(路由缺失/ACL 阻断)",
        "AS 号配置错误",
        "更新源地址不匹配",
        "EBGP 多跳未配置",
        "TTL 不足",
    ],
    solutions=[
        "ping 对端更新源地址验证连通性",
        "display bgp peer 查看状态",
        "检查 peer as-number 是否正确",
        "检查 update-source 配置",
        "EBGP 跨跳需配置 ebgp-max-hop",
    ],
    tags=["BGP", "邻居", "路由", "TCP"],
    source="华为BGP排障"
)

kb.add_article(
    title="OSPF 邻居无法建立",
    symptoms=["OSPF down", "ospf neighbor flapping",
              "OSPF 邻居无法建立", "OSPF INIT/EXSTART",
              "邻居卡在 INIT"],
    causes=[
        "Hello/Dead 间隔不一致",
        "区域 ID 不匹配",
        "网络类型不匹配",
        "MTU 不匹配",
        "认证配置不一致",
        "二层链路故障",
    ],
    solutions=[
        "display ospf peer 查看邻居状态",
        "检查两端 ospf timer hello/dead",
        "检查 area 配置",
        "检查 network-type (P2P/Broadcast)",
        "检查 ip mtu 是否一致",
        "检查 authentication-mode",
    ],
    tags=["OSPF", "邻居", "IGP", "路由协议"],
    source="华为OSPF排障"
)

kb.save("knowledge_base.json")
print(f"知识库已构建: {len(kb.articles)} 篇文章")

# 测试检索
query = "接口一直没有BGP邻居"
print(f"\n查询: {query}")
results = kb.search(query)
for r in results:
    print(f"\n标题: {r['title']}")
    print(f"可能原因: {', '.join(r['causes'][:3])}")
    print(f"解决方案: {', '.join(r['solutions'][:3])}")

2.3 LLM 排障助手

#!/usr/bin/env python3
# llm_troubleshooter.py — LLM 排障助手

import json
from typing import Optional

class TroubleshootEngine:
    """排障引擎"""

    def __init__(self, knowledge_path: str = "knowledge_base.json"):
        with open(knowledge_path, "r", encoding="utf-8") as f:
            self.kb = json.load(f)

    def analyze_device_data(self, device_name: str,
                            logs: str, config: str,
                            commands: dict) -> str:
        """分析设备数据生成排障建议"""
        findings = []
        recommendations = []

        # 1. 日志分析
        error_patterns = {
            "CRC": "接口 CRC 错误,可能光纤/光模块问题",
            "flapping": "接口震荡,检查物理链路",
            "down": "接口 DOWN,检查对端和物理连接",
            "error": "出现错误日志",
            "BGP.*Down": "BGP 邻居中断",
            "OSPF.*Down": "OSPF 邻居中断",
            "authenticat": "认证失败",
            "timeout": "连接超时",
        }

        for line in logs.split("\n"):
            for pattern, hint in error_patterns.items():
                import re
                if re.search(pattern, line, re.IGNORECASE):
                    findings.append(f"- {line.strip()[:80]}")
                    recommendations.append(f"  → {hint}")
                    break

        # 2. 接口状态分析
        if "display interface brief" in commands:
            intf_output = commands["display interface brief"]
            down_interfaces = []
            for line in intf_output.split("\n"):
                if "down" in line.lower() and "GigabitEthernet" in line:
                    down_interfaces.append(line.split()[0])
            if down_interfaces:
                findings.append(f"DOWN 接口: {', '.join(down_interfaces)}")
                recommendations.append("检查 DOWN 接口的物理连接和配置")

        # 3. 配置分析
        if "display current-configuration" in commands:
            cfg = commands["display current-configuration"]
            # 检查常见配置问题
            if "ntp-service" not in cfg:
                findings.append("未配置 NTP,可能导致时间不同步问题")

        # 4. 生成报告
        report = [
            f"## {device_name} 排障分析",
            f"### 发现的问题",
        ]
        report.extend(findings if findings else ["未发现明显异常"])

        report.append("\n### 建议措施")
        report.extend(recommendations if recommendations else [
            "1. 检查设备基本状态(CPU/内存/温度)",
            "2. 确认链路物理状态",
            "3. 查看系统日志寻找更多线索",
        ])

        return "\n".join(report)

    def suggest_commands(self, problem: str) -> list:
        """根据问题推荐排查命令"""
        cmd_map = {
            "接口": [
                ("接口状态", "display interface brief"),
                ("接口统计", "display interface GigabitEthernet0/0/1"),
                ("光模块信息", "display transceiver interface GigabitEthernet0/0/1"),
                ("接口 CRC", "display interface GigabitEthernet0/0/1 | include CRC"),
            ],
            "BGP": [
                ("BGP 邻居摘要", "display bgp peer"),
                ("BGP 邻居详情", "display bgp peer 10.0.0.1 verbose"),
                ("BGP 路由", "display bgp routing-table"),
                ("BGP 统计", "display bgp statistics"),
            ],
            "OSPF": [
                ("OSPF 邻居", "display ospf peer"),
                ("OSPF 接口", "display ospf interface"),
                ("OSPF LSDB", "display ospf lsdb"),
                ("OSPF 路由", "display ospf routing"),
            ],
            "路由": [
                ("路由表", "display ip routing-table"),
                ("路由协议", "display ip routing-table protocol"),
                ("Fib 表", "display fib"),
            ],
            "设备": [
                ("设备版本", "display version"),
                ("CPU 使用率", "display cpu-usage"),
                ("内存使用率", "display memory-usage"),
                ("环境状态", "display environment"),
                ("系统日志", "display logbuffer"),
            ],
        }

        suggestions = []
        for keyword, cmds in cmd_map.items():
            if keyword.lower() in problem.lower():
                suggestions.extend(cmds)

        if not suggestions:
            for cmds in cmd_map.values():
                suggestions.extend(cmds)

        return suggestions[:8]  # 最多返回 8 条

# 使用示例
if __name__ == "__main__":
    engine = TroubleshootEngine()

    # 模拟数据
    logs = """
Jan 15 10:30:22 CORE-SW01 %%01IFNET/4/LINK_STATE(l)[0]:The line protocol
IP on the interface GigabitEthernet0/0/1 has entered the DOWN state.
Jan 15 10:30:25 CORE-SW01 %%01IFNET/4/LINK_STATE(l)[1]:The line protocol
IP on the interface GigabitEthernet0/0/1 has entered the UP state.
Jan 15 10:30:28 CORE-SW01 %%01IFNET/4/LINK_STATE(l)[2]:The line protocol
IP on the interface GigabitEthernet0/0/1 has entered the DOWN state.
    """

    config = """
sysname CORE-SW01
interface GigabitEthernet0/0/1
 description UPLINK
 port link-type trunk
 port trunk allow-pass vlan all
    """

    commands = {
        "display interface brief": "GigabitEthernet0/0/1 down",
    }

    report = engine.analyze_device_data("CORE-SW01", logs, config, commands)
    print(report)

    print("\n=== 推荐排查命令 ===")
    problem = "接口 flapping,怀疑光模块问题"
    for name, cmd in engine.suggest_commands(problem):
        print(f"  {name}: {cmd}")

三、LLM 配置审查

3.1 配置评审

#!/usr/bin/env python3
# llm_config_review.py — LLM 配置审查

class ConfigReview:
    """配置审查引擎"""

    RULES = [
        {
            "name": "SSH 版本",
            "check": lambda c: "ssh version 2" in c or "ssh server port" in c,
            "severity": "error",
            "message": "SSH v2 未配置,存在安全风险",
        },
        {
            "name": "密码加密",
            "check": lambda c: "cipher" in c or "hash" in c,
            "severity": "warning",
            "message": "密码未使用加密存储",
        },
        {
            "name": "NTP 配置",
            "check": lambda c: "ntp-service" in c or "ntp server" in c,
            "severity": "warning",
            "message": "未配置 NTP 服务器,时间可能不准确",
        },
        {
            "name": "SNMP v3",
            "check": lambda c: "snmp-agent" in c,
            "severity": "info",
            "message": "建议配置 SNMP v3 增强安全性",
        },
        {
            "name": "空闲超时",
            "check": lambda c: "idle-timeout" in c or "exec-timeout" in c,
            "severity": "warning",
            "message": "未配置空闲超时,SSH 会话可能长期挂起",
        },
    ]

    def review(self, device_name: str, config: str) -> list:
        """执行审查"""
        findings = []
        for rule in self.RULES:
            passed = rule["check"](config)
            if not passed:
                findings.append({
                    "device": device_name,
                    "rule": rule["name"],
                    "severity": rule["severity"],
                    "message": rule["message"],
                })
        return findings

    def generate_report(self, device_name: str, config: str) -> str:
        """生成审查报告"""
        findings = self.review(device_name, config)

        lines = [f"## 配置审查: {device_name}"]
        lines.append(f"检查规则: {len(self.RULES)} 条")

        errors = [f for f in findings if f["severity"] == "error"]
        warnings = [f for f in findings if f["severity"] == "warning"]
        infos = [f for f in findings if f["severity"] == "info"]

        lines.append(f"错误: {len(errors)}, 警告: {len(warnings)}, 提示: {len(infos)}")

        if findings:
            lines.append("\n### 发现的问题")
            for f in findings:
                icon = {"error": "❌", "warning": "⚠", "info": "ℹ"}
                lines.append(f"{icon[f['severity']]} {f['message']}")
        else:
            lines.append("\n✓ 所有检查通过")

        return "\n".join(lines)

# 示例
review = ConfigReview()
sample_config = """
sysname CORE-SW01
interface GigabitEthernet0/0/1
 description UPLINK
 port link-type trunk
 port trunk allow-pass vlan all
"""
print(review.generate_report("CORE-SW01", sample_config))

四、RAG 增强排障流程

4.1 完整排障流程

#!/usr/bin/env python3
# rag_troubleshoot_flow.py — RAG 增强排障

"""
RAG 排障流程:
1. 用户描述问题
2. 自动收集相关设备数据
3. RAG 检索相似案例
4. LLM 分析生成诊断
5. 给出排查建议
"""

class RAGTroubleshooter:
    """RAG 增强排障器"""

    def __init__(self, knowledge_base: str = "knowledge_base.json"):
        self.kb = TroubleshootEngine(knowledge_base)

    def diagnose(self, device: str, problem: str,
                 auto_collect: bool = True) -> dict:
        """诊断流程"""
        result = {
            "device": device,
            "problem": problem,
            "steps": [],
        }

        # Step 1: 推荐排查命令
        result["steps"].append({
            "step": 1,
            "action": "推荐排查命令",
            "commands": self.kb.suggest_commands(problem),
        })

        # Step 2: 检索知识库
        result["steps"].append({
            "step": 2,
            "action": "检索知识库",
            "articles": [a["title"] for a in self.kb.kb.get("articles", [])
                        if any(k in problem for k in a.get("tags", []))],
        })

        # Step 3: 生成排查计划
        result["steps"].append({
            "step": 3,
            "action": "排查计划",
            "plan": [
                "1. 检查物理层:接口状态、光模块功率",
                "2. 检查链路层:CRC 错误、协商状态",
                "3. 检查网络层:IP 连通性、路由表",
                "4. 检查协议层:BGP/OSPF 邻居状态",
                "5. 综合判断定位根因",
            ],
        })

        # Step 4: 预防建议
        result["steps"].append({
            "step": 4,
            "action": "预防建议",
            "suggestions": [
                "配置接口联动检测(BFD)",
                "启用 gRPC Telemetry 监控接口状态",
                "配置日志告警推送",
                "定期检查光模块健康状态",
            ],
        })

        return result

    def print_diagnosis(self, result: dict):
        """打印诊断结果"""
        print(f"=== 排障诊断报告 ===")
        print(f"设备: {result['device']}")
        print(f"问题: {result['problem']}\n")

        for step in result["steps"]:
            print(f"Step {step['step']}: {step['action']}")
            if "commands" in step:
                for name, cmd in step["commands"]:
                    print(f"  {name}: {cmd}")
            if "plan" in step:
                for p in step["plan"]:
                    print(f"  {p}")
            if "suggestions" in step:
                for s in step["suggestions"]:
                    print(f"  • {s}")
            print()

if __name__ == "__main__":
    troubleshooter = RAGTroubleshooter()
    result = troubleshooter.diagnose(
        device="CORE-SW01",
        problem="接口GE0/0/1频繁flapping并伴随CRC错误",
    )
    troubleshooter.print_diagnosis(result)

五、最佳实践

LLM 辅助排障最佳实践:

  1. 数据质量
  ┌─ 确保输入数据的准确性和完整性
  ├─ 过滤敏感信息
  ├─ 标准化数据格式
  └─ 标注数据来源和时效

  2. 知识库维护
  ┌─ 持续更新排障案例
  ├─ 验证 LLM 输出的准确性
  ├─ 标注置信度等级
  └─ 定期清理过期知识

  3. 人机协作
  ┌─ LLM 提供建议,工程师决策
  ├─ 关键操作需要人工确认
  ├─ 反馈机制改进模型
  └─ 保留人工干预通道

  4. 安全
  ┌─ 不向 LLM 发送明文密码
  ├─ 控制 API 调用频率
  ├─ 审计所有 AI 辅助操作
  └─ 敏感数据本地处理

下篇预告:第321篇 — 网络知识图谱与 AI Ops,将介绍如何构建网络知识图谱实现智能运维,以及 AI Ops 的实践路径。