实习手记 Day:从 ELK 到 Agent 的“最后一公里”——告警消费与上下文富化

实习手记:从 ELK 到 Agent 的"最后一公里"------告警消费与上下文富化实战

背景碎碎念 :上一篇博客梳理完了 AI SOC 的整体宏观架构,老板和导师看后觉得方向没问题,接下来就是"撸起袖子干活"的落地阶段了。这几天我负责的模块正是整个系统的"咽喉要道"------如何把 Elasticsearch (ELK) 里冷冰冰、乱糟糟的原始告警,安全、高效、有条理地送到 DeepAgents 的大模型"嘴里"。今天就来详细复盘一下这段时间的踩坑与实战经验。


01. 痛点:为什么"从 ELK 到 Agent"没你想的那么简单?

在理想的 Demo 里,我们可能会觉得:不就是从 Elasticsearch 里查出一条告警,然后扔给 LangChain 的 LLM 去处理吗?

但真正到了生产环境,我才发现这里面全是细节和坑:

  1. 字段爆炸与噪音太多 :一条标准的 ELK 告警(比如 EDR 报出的某台主机进程注入告警),里面往往包含几十甚至上百个字段(_index, _id, agent.id, host.ip, process.command_line, user.name 等等)。如果把整个原始 JSON 毫无过滤地塞给 LLM,不仅会瞬间吃光你的 Token 额度,还会引入大量的"噪音字段",干扰 LLM 的注意力。
  2. 时效性与消费机制的选择:ELK 里的数据是持续写入的。我们是用定时轮询(Polling)去拉取?还是用 Logstash/Webhook 触发?怎么保证告警既不漏掉,也不会被重复消费导致 AI 重复研判?
  3. 上下文缺失 (Context Deficiency) :Elasticsearch 里的单条告警往往是"孤立"的。LLM 拿到"某 IP 有可疑外联"时,它只知道这个 IP,但它不知道这台机器半小时前还发生过什么(比如有没有中过钓鱼邮件、是不是核心业务服务器)。如果缺乏上下文富化,AI 的研判往往流于表面。

为了解决这些问题,我们在架构上设计了一套告警消费与上下文富化流水线 (Alert Ingestion & Context Enrichment Pipeline)


02. 告警数据消费与富化流向设计

为了让团队内部对这个模块的数据流向达成共识,我画了第一张架构细化图。

在这张图中,数据流经了三个关键阶段:

  1. 数据监听与拉取层:通过自定义的 Python 异步消费脚本,对接 Elasticsearch 的 Scroll API 或 Query 接口,实时捕获符合严重级别的安全告警。
  2. 清洗与标准化层:过滤掉无用的系统元数据字段,只保留安全研判最关心的核心要素(如:事件类型、时间戳、源/目 IP、主机名、进程路径、用户名)。
  3. 富化层 (Enrichment):在送给 Agent 之前,自动去补充一些背景信息(例如通过内部 CMDB 补充资产等级,或者拉取该 IP 最近 1 小时内的历史关联日志)。

03. 代码落地:我是怎么写这个消费与清洗模块的?

在具体的代码实现上,我们使用 Python 编写了这套消费逻辑。这里抽离出一个简化版的架构逻辑,记录一下我是怎么把杂乱的日志变成整洁的上下文的。

1. 定义标准化的告警结构 (Pydantic)

为了让 LangChain 框架和后续的 Agent 工具能完美识别,我们首先用 Pydantic 定义了一个强类型的数据结构:

python 复制代码
from pydantic import BaseModel, Field
from typing import Optional, List

class SecurityAlert(BaseModel):
    alert_id: str = Field(description="告警唯一标识符")
    timestamp: str = Field(description="告警发生时间")
    severity: str = Field(description="告警严重程度: Low, Medium, High, Critical")
    attack_technique: Optional[str] = Field(description="MITRE ATT&CK 战术/技术编号")
    
    # 实体信息
    source_ip: Optional[str] = Field(description="源IP地址")
    destination_ip: Optional[str] = Field(description="目的IP地址")
    hostname: Optional[str] = Field(description="受影响主机名")
    username: Optional[str] = Field(description="操作用户名")
    process_name: Optional[str] = Field(description="触发告警的进程名")
    
    # 上下文补充
    asset_importance: Optional[str] = Field(default="Normal", description="资产重要性: Core, Important, Normal")
    historical_hits_count: int = Field(default=0, description="该IP近期历史告警次数")

2. 清洗与富化核心逻辑 (Data Pipeline)

接下来是消费端的核心代码逻辑。我们从 Elasticsearch 中把原始 JSON 拿出来后,通过一个清洗函数进行字段映射和动态富化:

python 复制代码
class AlertConsumerPipeline:
    def __init__(self, es_client, cmdb_client):
        self.es = es_client
        self.cmdb = cmdb_client

    def process_raw_alert(self, raw_es_doc: dict) -> SecurityAlert:
        source = raw_es_doc.get("_source", {})
        
        # 1. 字段映射与清洗 (只留精华,抛弃噪声)
        alert_id = raw_es_doc.get("_id")
        timestamp = source.get("@timestamp")
        severity = source.get("rule", {}).get("level", "Medium")
        
        # 提取网络与主机实体
        src_ip = source.get("source", {}).get("ip")
        dst_ip = source.get("destination", {}).get("ip")
        hostname = source.get("host", {}).get("name")
        username = source.get("user", {}).get("name")
        process_name = source.get("process", {}).get("name")

        # 2. 上下文富化 (Enrichment)
        # 调用内部 CMDB 接口查询主机资产重要性
        asset_info = self.cmdb.query_by_hostname(hostname) if hostname else {}
        asset_importance = asset_info.get("importance", "Normal")

        # 查询 Elasticsearch 历史关联记录 (比如看这个 IP 最近有没有频繁告警)
        history_count = self.query_recent_alert_count(src_ip) if src_ip else 0

        # 3. 组装成结构化对象
        structured_alert = SecurityAlert(
            alert_id=alert_id,
            timestamp=timestamp,
            severity=severity,
            source_ip=src_ip,
            destination_ip=dst_ip,
            hostname=hostname,
            username=username,
            process_name=process_name,
            asset_importance=asset_importance,
            historical_hits_count=history_count
        )
        
        return structured_alert

    def query_recent_alert_count(self, ip: str) -> int:
        # 模拟在 ES 中聚合查询该 IP 过去 24 小时的历史告警数
        # 实际业务中这里会写一个标准的 ES Aggregation Query
        return 3 

04. LLM 提示词模板的组装

告警清洗完后,怎么把这些结构化数据变成 DeepAgents 能听懂的自然语言/结构化 Prompt?这里我们又踩过坑:如果直接给一堆 JSON,大模型在长文本或多轮对话时容易漏掉关键参数。

为此,我们设计了一套面向安全研判的 Prompt 模板结构

通过这种分层的 Prompt 设计,当 DeepAgents 拿到数据时,它不仅知道"发生了什么告警",还一眼能看出"这台机器是核心资产(Asset Importance: Core)"以及"这个 IP 已经连续 3 次触发告警了",从而在第一步的推理(Reasoning)中就赋予极高的优先级。


05. 实习小结与下一步

通过这一阶段的开发,我深刻体会到了在安全领域做 AI 工程化落地的一个核心真理:垃圾进,垃圾出 (Garbage in, Garbage out)

大模型虽然聪明,但如果你给它的 ELK 原始数据杂乱无章,它根本无法做出精准的安全研判。通过定义严格的 Pydantic 模型、清洗无用字段、并在消费端做资产与历史日志的"富化(Enrichment)",我们才真正为后面的 Agent 自动化研判打下了坚实的地基。

地基打好后,接下来就是最激动人心的部分了------怎么给这个 Agent 装上"眼睛"和"耳朵",让它能够自主去调用外部的威胁情报工具(如 VirusTotal、内部情报库)?

相关推荐
workbuddy小能手1 小时前
用 WorkBuddy 调混元 Hy3 做批量文档摘要:一个可运行的实战示例
人工智能·workbuddy
CDN3601 小时前
俄语区跨境站点优化实战:CDN+Nginx 解决 H5 白屏、交互延迟、链路卡顿问题
运维·nginx·交互·h5 加速·nginx 轻交互调优
梦想的旅途21 小时前
企微私域 AI 创作:文案生成与 AI 配图自动化发布实战
人工智能·自动化·企业微信
Bruce_Liuxiaowei1 小时前
多模态AI在网络安全监控中的创新应用
人工智能·安全·web安全
java修仙传1 小时前
从网页禅道到 AI 能调用的工具:我的禅道 MCP 实现思路分享
java·人工智能·python·ai应用·mcp开发
乌恩大侠1 小时前
图解 AI-RAN开发需要哪些软硬件:O-RU、DGX Spark、Sionna与Aerial
人工智能·spark·o-ru·ai-ran
中电金信1 小时前
中电金信 :一站式企业智能体柔性生产全链路解决方案
大数据·人工智能
智能制造产品经理代码提升2 小时前
全流程自动化部署指南(Push自动构建 → 测试通过自动建PR → Teams通知
运维·flask·自动化