首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >AI大模型学习(21):Agent框架在工业自动化中的应用——从缺陷检测到自动调参的智能体闭环

AI大模型学习(21):Agent框架在工业自动化中的应用——从缺陷检测到自动调参的智能体闭环

作者头像
零一未来AI星球
发布2026-09-15 19:43:21
发布2026-09-15 19:43:21
570
举报

AI大模型学习(21):Agent框架在工业自动化中的应用——从缺陷检测到自动调参的智能体闭环

检测出缺陷只是开始,自动找到原因并调优参数才是终局。 本文完整拆解工业AI Agent的架构设计、工具注册、多Agent协作、安全防护和自动调参闭环,附可运行代码和落地案例。


一、从"AI辅助检测"到"AI自主优化":差了一个Agent

先回顾一下前两篇的成果:

  • 第19篇:YOLO26量化部署,边缘端15ms实时检测
  • 第20篇:YOLO26 + VLM,缺陷分类和根因分析

但这还不够。真实产线上的问题是:

VLM分析出"锡桥缺陷,根因是钢网开孔过大",然后呢? 工程师看到报告,手动去调印刷压力,调完再看效果——这个闭环还是靠人。

Agent要做的,就是把这个闭环自动化:检测 → 分析 → 调参 → 复检 → 确认效果。

阶段

传统方式

Agent方式

缺陷检测

YOLO自动检测

YOLO自动检测(不变)

根因分析

工程师凭经验判断

VLM + RAG自动分析

参数调整

工程师手动改PLC参数

Agent自动计算并下发参数

效果验证

人工抽检几批产品

Agent自动复检并统计

迭代优化

靠经验积累,慢

自动记录、自动学习、越调越准

这不是简单的"加个脚本"。Agent需要具备:

  • 规划能力:知道先做什么后做什么
  • 工具调用能力:能读传感器、写PLC、查数据库
  • 记忆能力:记住历史调参效果,避免重复犯错
  • 反思能力:调参后效果变差,能回滚并换方案
  • 安全意识:知道哪些参数能动、哪些不能动、动多少

二、工业AI Agent的三条落地路径

不是所有场景都适合让AI自主控制设备。按自治程度分三条路径:

路径一:Copilot模式(辅助决策)

AI只给建议,人来确认和执行。

  • 适用:故障诊断、维修指导、复杂工艺参数建议
  • 优势:安全可控,出错不造成直接损失
  • 局限:效率提升有限,人还是瓶颈

路径二:自治模式(封闭场景自主执行)

在边界清晰、风险可控的场景中,AI自主决策和执行。

  • 适用:仓储AGV调度、视觉检测分拣、恒温恒压控制
  • 优势:效率最高,7×24小时不间断
  • 局限:场景必须封闭,异常必须有预案

路径三:混合模式(分层自治,当前最务实)

低层级AI自主运行,高层级保留人类监督。

层级

角色

自治程度

响应时间

设备层

PID/逻辑控制

完全自治

毫秒级

产线层

Agent参数优化

受限自治(人可干预)

秒~分钟级

工厂层

排程/调度

建议为主

小时~天级

管理层

战略决策

人类主导

天~月级

核心原则: 没有人会让AI在没有确认的情况下调整化工厂反应釜温度。但让AI自动微调AOI设备的检测阈值,完全没问题。风险和自治程度必须匹配。


三、整体架构:五层智能体闭环

代码语言:javascript
复制
┌─────────────────────────────────────────────────────────────────┐
│                        工业AI Agent 系统                          │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│  ┌─────────────┐    ┌─────────────┐    ┌─────────────┐         │
│  │  感知层      │───▶│  认知层      │───▶│  决策层      │         │
│  │  YOLO26检测  │    │  VLM根因分析 │    │  Agent规划   │         │
│  │  传感器采集   │    │  工艺知识库  │    │  参数优化    │         │
│  └─────────────┘    └─────────────┘    └──────┬──────┘         │
│                                                │                │
│  ┌─────────────┐    ┌─────────────┐           │                │
│  │  反馈层      │◀───│  执行层      │◀──────────┘                │
│  │  效果评估    │    │  PLC参数下发 │     安全网关                │
│  │  模型迭代    │    │  设备控制    │     (权限/限流/回滚)        │
│  └─────────────┘    └─────────────┘                            │
│                                                                 │
└─────────────────────────────────────────────────────────────────┘

各层职责

层级

核心组件

关键能力

延迟要求

感知层

YOLO26 INT8 + OPC UA采集

缺陷检测、工艺参数实时读取

<50ms

认知层

VLM + RAG知识库

缺陷分类、根因推理、历史案例匹配

<500ms

决策层

LangGraph Agent + 优化算法

任务规划、参数计算、风险评估

<1s

执行层

安全网关 + PLC写入

参数下发、设备控制、状态确认

<100ms

反馈层

统计引擎 + 增量学习

效果验证、参数记录、模型更新

分钟~小时级


四、核心底座:工业级工具注册中心

Agent要控制设备,首先要能安全地调用工具。通用Agent框架的工具注册太简单,在工业场景下会出大问题。

真实教训: LLM传了canny_low="300"(字符串且超范围),直接写入AOI配置,导致下一批产品整批漏检。

4.1 工具注册中心设计

代码语言:javascript
复制
from dataclasses import dataclass, field
from typing import Any, Callable, Dict, List, Optional
from enum import Enum
import threading
import time
import logging

logger = logging.getLogger(__name__)

class ToolPermission(Enum):
    READ_ONLY = "read_only"        # 只读,无风险
    WRITE_SAFE = "write_safe"      # 可写,但有安全边界(如检测阈值)
    WRITE_CRITICAL = "write_critical"  # 关键写入,需人工确认(如温度设定)

@dataclass
class ToolParameter:
    name: str
    type: str  # string / number / integer / boolean / array
    description: str
    required: bool = True
    default: Any = None
    enum: Optional[List] = None       # 枚举白名单
    min_value: Optional[float] = None # 数值下限
    max_value: Optional[float] = None # 数值上限

@dataclass
class ToolResult:
    success: bool
    result: Any = None
    error: Optional[str] = None
    latency_ms: float = 0.0

class ToolRegistry:
    """工业级工具注册中心——单例模式"""
    _instance = None
    _lock = threading.Lock()

    def __new__(cls):
        if cls._instance is None:
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)
                    cls._instance._tools = {}
                    cls._instance._disabled = set()
                    cls._instance._call_stats = {}
        return cls._instance

    @classmethod
    def reset(cls):
        """仅用于测试"""
        cls._instance = None

    def register(self, name: str, func: Callable, parameters: List[ToolParameter],
                 permission: ToolPermission = ToolPermission.READ_ONLY,
                 description: str = "", rate_limit_per_min: int = 60):
        """注册工具"""
        self._tools[name] = {
            "func": func,
            "parameters": {p.name: p for p in parameters},
            "permission": permission,
            "description": description,
            "rate_limit": rate_limit_per_min,
            "call_timestamps": [],
        }
        logger.info(f"工具注册成功: {name} (权限: {permission.value})")

    def disable(self, name: str):
        """禁用工具(设备维护时使用)"""
        self._disabled.add(name)
        logger.warning(f"工具已禁用: {name}")

    def enable(self, name: str):
        self._disabled.discard(name)

    def _validate_params(self, tool_name: str, kwargs: Dict) -> Dict:
        """参数校验——在触及设备之前把错误拦下来"""
        tool = self._tools[tool_name]
        validated = {}

        for param_name, param_def in tool["parameters"].items():
            value = kwargs.get(param_name, param_def.default)

            # 1. 必填检查
            if param_def.required and value is None:
                raise ValueError(f"参数 {param_name} 为必填项")

            if value is None:
                continue

            # 2. 类型检查+转换
            if param_def.type == "number":
                value = float(value)
            elif param_def.type == "integer":
                value = int(value)
            elif param_def.type == "boolean":
                value = bool(value)

            # 3. 枚举白名单
            if param_def.enum and value not in param_def.enum:
                raise ValueError(
                    f"参数 {param_name} 值 {value} 不在允许范围 {param_def.enum}"
                )

            # 4. 数值范围
            if param_def.min_value is not None and value < param_def.min_value:
                raise ValueError(
                    f"参数 {param_name} 值 {value} 低于下限 {param_def.min_value}"
                )
            if param_def.max_value is not None and value > param_def.max_value:
                raise ValueError(
                    f"参数 {param_name} 值 {value} 超过上限 {param_def.max_value}"
                )

            validated[param_name] = value

        return validated

    def _check_rate_limit(self, tool_name: str):
        """速率限制检查"""
        tool = self._tools[tool_name]
        now = time.time()
        # 清理1分钟前的记录
        tool["call_timestamps"] = [
            t for t in tool["call_timestamps"] if now - t < 60
        ]
        if len(tool["call_timestamps"]) >= tool["rate_limit"]:
            raise RuntimeError(f"工具 {tool_name} 触发速率限制")
        tool["call_timestamps"].append(now)

    def execute(self, name: str, **kwargs) -> ToolResult:
        """执行工具——校验顺序精心设计"""
        start = time.time()

        try:
            # 1. 工具是否已注册
            if name not in self._tools:
                return ToolResult(False, error=f"工具 {name} 未注册")

            # 2. 工具是否被禁用
            if name in self._disabled:
                return ToolResult(False, error=f"工具 {name} 已被禁用")

            # 3. 参数校验(先校验,不浪费限流令牌)
            validated = self._validate_params(name, kwargs)

            # 4. 速率限制(校验通过后才检查)
            self._check_rate_limit(name)

            # 5. 执行
            result = self._tools[name]["func"](**validated)
            latency = (time.time() - start) * 1000

            # 6. 统计
            self._call_stats.setdefault(name, {"success": 0, "fail": 0})
            self._call_stats[name]["success"] += 1

            return ToolResult(True, result=result, latency_ms=latency)

        except Exception as e:
            latency = (time.time() - start) * 1000
            self._call_stats.setdefault(name, {"success": 0, "fail": 0})
            self._call_stats[name]["fail"] += 1
            logger.error(f"工具执行失败 {name}: {e}")
            return ToolResult(False, error=str(e), latency_ms=latency)

4.2 注册工业工具

代码语言:javascript
复制
# ========== 注册工艺参数读取工具 ==========
def read_process_params(station: str, param_names: List[str]) -> Dict:
    """通过OPC UA读取工艺参数"""
    from opcua import Client
    client = Client("opc.tcp://192.168.1.100:4840")
    client.connect()
    try:
        results = {}
        for p in param_names:
            node = client.get_node(f"ns=2;s={station}.{p}")
            results[p] = node.get_value()
        return results
    finally:
        client.disconnect()

registry = ToolRegistry()
registry.register(
    name="read_process_params",
    func=read_process_params,
    parameters=[
        ToolParameter("station", "string", "工位编号", enum=["SMT01", "SMT02", "REFLOW01"]),
        ToolParameter("param_names", "array", "要读取的参数名列表"),
    ],
    permission=ToolPermission.READ_ONLY,
    description="读取指定工位的实时工艺参数",
    rate_limit_per_min=30,
)

# ========== 注册工艺参数写入工具(安全受限)==========
def write_process_param(station: str, param_name: str, value: float) -> Dict:
    """写入工艺参数到PLC——关键参数需二次确认"""
    from opcua import Client
    client = Client("opc.tcp://192.168.1.100:4840")
    client.connect()
    try:
        node = client.get_node(f"ns=2;s={station}.{param_name}")
        old_value = node.get_value()
        node.set_value(value)
        # 验证写入成功
        time.sleep(0.1)
        new_value = node.get_value()
        return {
            "station": station,
            "param": param_name,
            "old_value": old_value,
            "new_value": new_value,
            "write_success": abs(new_value - value) < 0.001,
        }
    finally:
        client.disconnect()

registry.register(
    name="write_process_param",
    func=write_process_param,
    parameters=[
        ToolParameter("station", "string", "工位编号", enum=["SMT01", "SMT02"]),
        ToolParameter("param_name", "string", "参数名",
                      enum=["print_pressure", "print_speed", "reflow_temp_zone3"]),
        ToolParameter("value", "number", "参数值", min_value=0, max_value=100),
    ],
    permission=ToolPermission.WRITE_SAFE,
    description="写入工艺参数(自动记录旧值,支持回滚)",
    rate_limit_per_min=10,  # 写入操作严格限流
)

# ========== 注册YOLO检测工具 ==========
def run_yolo_detection(image_path: str, conf_thres: float = 0.25) -> Dict:
    """运行YOLO26缺陷检测"""
    from ultralytics import YOLO
    model = YOLO("yolo26s_int8.onnx")
    results = model(image_path, conf=conf_thres, verbose=False)
    detections = []
    for r in results:
        for box in r.boxes:
            detections.append({
                "bbox": box.xyxy[0].tolist(),
                "confidence": float(box.conf[0]),
                "class": int(box.cls[0]),
            })
    return {"detections": detections, "count": len(detections)}

registry.register(
    name="run_yolo_detection",
    func=run_yolo_detection,
    parameters=[
        ToolParameter("image_path", "string", "图像路径"),
        ToolParameter("conf_thres", "number", "置信度阈值", required=False,
                      default=0.25, min_value=0.1, max_value=0.9),
    ],
    permission=ToolPermission.READ_ONLY,
    description="运行YOLO26缺陷检测,返回检测结果",
)

五、多Agent协作:LangGraph编排

单一Agent做不了复杂的工业闭环,需要多个专业Agent协作。

5.1 Agent角色设计

Agent

职责

可用工具

Manager Agent

任务规划、进度跟踪、异常升级

全部工具的调度权

Detection Agent

视觉检测、图像分析

run_yolo_detection, read_image

Analysis Agent

根因分析、知识检索

vlm_analyze, search_knowledge_base

Optimization Agent

参数计算、优化方案生成

read_process_params, bayesian_optimize

Execution Agent

参数下发、设备控制

write_process_param, trigger_recheck

Safety Agent

风险评估、权限校验、回滚

rollback_param, audit_log

5.2 LangGraph工作流实现

代码语言:javascript
复制
from typing import TypedDict, Annotated, List, Dict
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage
import operator
import json

# ========== 定义共享状态 ==========
class AgentState(TypedDict):
    messages: Annotated[List[BaseMessage], operator.add]
    current_step: str
    image_path: str
    detection_result: Dict
    analysis_result: Dict
    current_params: Dict
    optimization_plan: Dict
    execution_result: Dict
    recheck_result: Dict
    safety_approved: bool
    retry_count: int
    error: str

# ========== 初始化LLM ==========
llm = ChatOpenAI(
    model="qwen2.5-72b-instruct",
    base_url="http://local-vlm:8000/v1",
    api_key="EMPTY",
    temperature=0.1,
)

# ========== 各Agent节点函数 ==========

def detection_node(state: AgentState) -> AgentState:
    """检测Agent:运行YOLO检测"""
    registry = ToolRegistry()
    result = registry.execute(
        "run_yolo_detection",
        image_path=state["image_path"],
        conf_thres=0.25,
    )

    if not result.success:
        return {**state, "error": result.error, "current_step": "error"}

    detection = result.result
    state["detection_result"] = detection

    # 判断是否有缺陷
    if detection["count"] == 0:
        return {**state, "current_step": "no_defect"}

    return {**state, "current_step": "analysis"}

def analysis_node(state: AgentState) -> AgentState:
    """分析Agent:VLM根因分析 + 知识库检索"""
    # 1. 读取当前工艺参数
    registry = ToolRegistry()
    params_result = registry.execute(
        "read_process_params",
        station="SMT01",
        param_names=["print_pressure", "print_speed", "stencil_opening_ratio"],
    )
    current_params = params_result.result if params_result.success else {}

    # 2. 调用VLM分析(简化,实际调用VLM服务)
    analysis_prompt = f"""
    检测到缺陷:{json.dumps(state['detection_result'], ensure_ascii=False)}
    当前工艺参数:{json.dumps(current_params, ensure_ascii=False)}

    请分析缺陷根因,并给出参数调整建议。输出JSON:
    {{
        "root_cause": "根本原因",
        "confidence": 0.0-1.0,
        "param_adjustments": [
            {{"param": "参数名", "current": 当前值, "suggested": 建议值, "reason": "原因"}}
        ],
        "expected_effect": "预期改善效果"
    }}
    """
    response = llm.invoke([HumanMessage(content=analysis_prompt)])
    analysis = json.loads(response.content)

    return {
        **state,
        "analysis_result": analysis,
        "current_params": current_params,
        "current_step": "optimization",
    }

def optimization_node(state: AgentState) -> AgentState:
    """优化Agent:贝叶斯优化计算最优参数"""
    analysis = state["analysis_result"]

    # 构建优化计划
    plan = {
        "adjustments": analysis["param_adjustments"],
        "method": "bayesian_optimization",
        "search_space": {
            "print_pressure": [0.1, 0.3],  # MPa
            "print_speed": [20, 80],       # mm/s
        },
        "max_trials": 5,
        "safety_constraints": {
            "max_single_adjustment_pct": 15,  # 单次调整不超过15%
            "cooldown_minutes": 10,           # 调整后等待10分钟再复检
        },
    }

    return {
        **state,
        "optimization_plan": plan,
        "current_step": "safety_check",
    }

def safety_check_node(state: AgentState) -> AgentState:
    """安全Agent:风险评估 + 权限校验"""
    plan = state["optimization_plan"]
    approved = True
    reasons = []

    for adj in plan["adjustments"]:
        current = adj["current"]
        suggested = adj["suggested"]
        change_pct = abs(suggested - current) / current * 100 if current != 0 else 100

        if change_pct > plan["safety_constraints"]["max_single_adjustment_pct"]:
            approved = False
            reasons.append(f"参数 {adj['param']} 调整幅度 {change_pct:.1f}% 超过安全限制 15%")

        # 关键参数需要人工确认
        critical_params = ["reflow_temp_zone3", "reflow_temp_zone5"]
        if adj["param"] in critical_params:
            approved = False
            reasons.append(f"参数 {adj['param']} 为关键参数,需人工确认")

    return {
        **state,
        "safety_approved": approved,
        "current_step": "execution" if approved else "human_review",
    }

def execution_node(state: AgentState) -> AgentState:
    """执行Agent:参数下发 + 复检"""
    registry = ToolRegistry()
    plan = state["optimization_plan"]
    execution_log = []

    # 1. 记录当前参数(用于回滚)
    backup = state["current_params"].copy()

    # 2. 逐个下发参数
    for adj in plan["adjustments"]:
        result = registry.execute(
            "write_process_param",
            station="SMT01",
            param_name=adj["param"],
            value=adj["suggested"],
        )
        execution_log.append({
            "param": adj["param"],
            "success": result.success,
            "old": adj["current"],
            "new": adj["suggested"],
            "error": result.error,
        })

    # 3. 等待稳定后复检(简化,实际等待10分钟)
    # time.sleep(600)
    recheck = registry.execute(
        "run_yolo_detection",
        image_path=state["image_path"],  # 实际用新拍摄的图像
    )

    return {
        **state,
        "execution_result": {"log": execution_log, "backup": backup},
        "recheck_result": recheck.result if recheck.success else {},
        "current_step": "evaluate",
    }

def evaluate_node(state: AgentState) -> AgentState:
    """评估节点:判断调参效果,决定是否回滚或继续"""
    before_count = state["detection_result"]["count"]
    after_count = state["recheck_result"].get("count", before_count)

    if after_count < before_count:
        # 改善了,记录并结束
        return {
            **state,
            "current_step": "success",
            "messages": [AIMessage(
                content=f"调参成功!缺陷数从 {before_count} 降至 {after_count}"
            )],
        }
    elif state["retry_count"] < 3:
        # 没改善,重试(换一组参数)
        return {
            **state,
            "retry_count": state["retry_count"] + 1,
            "current_step": "optimization",
        }
    else:
        # 重试3次仍失败,回滚并通知人工
        registry = ToolRegistry()
        backup = state["execution_result"]["backup"]
        for param, value in backup.items():
            registry.execute("write_process_param", station="SMT01",
                           param_name=param, value=value)
        return {
            **state,
            "current_step": "rollback",
            "messages": [AIMessage(content="调参失败,已回滚参数,需人工介入")],
        }

# ========== 构建工作流图 ==========
workflow = StateGraph(AgentState)

# 添加节点
workflow.add_node("detection", detection_node)
workflow.add_node("analysis", analysis_node)
workflow.add_node("optimization", optimization_node)
workflow.add_node("safety_check", safety_check_node)
workflow.add_node("execution", execution_node)
workflow.add_node("evaluate", evaluate_node)

# 设置入口
workflow.set_entry_point("detection")

# 定义边和条件路由
workflow.add_conditional_edges(
    "detection",
    lambda state: state["current_step"],
    {
        "analysis": "analysis",
        "no_defect": END,
        "error": END,
    }
)
workflow.add_edge("analysis", "optimization")
workflow.add_edge("optimization", "safety_check")
workflow.add_conditional_edges(
    "safety_check",
    lambda state: state["current_step"],
    {
        "execution": "execution",
        "human_review": END,  # 实际接入人工审批界面
    }
)
workflow.add_edge("execution", "evaluate")
workflow.add_conditional_edges(
    "evaluate",
    lambda state: state["current_step"],
    {
        "success": END,
        "optimization": "optimization",  # 重试
        "rollback": END,
    }
)

# 编译
app = workflow.compile()

5.3 运行闭环

代码语言:javascript
复制
# 启动一次完整的检测→分析→调参→复检闭环
result = app.invoke({
    "messages": [HumanMessage(content="开始质检闭环")],
    "current_step": "detection",
    "image_path": "./test_images/pcb_defect_001.jpg",
    "retry_count": 0,
})

print(f"最终状态: {result['current_step']}")
print(f"检测缺陷数: {result['detection_result']['count']}")
print(f"调参后缺陷数: {result['recheck_result'].get('count', 'N/A')}")

六、自动调参核心:贝叶斯优化

Agent不是瞎调参数,而是用贝叶斯优化在安全范围内高效搜索最优解。

代码语言:javascript
复制
import numpy as np
from skopt import Optimizer
from skopt.space import Real

class ProcessParameterOptimizer:
    """工艺参数贝叶斯优化器"""

    def __init__(self, param_space: Dict, baseline_params: Dict):
        """
        param_space: {"print_pressure": (0.1, 0.3), "print_speed": (20, 80)}
        baseline_params: 当前生产参数
        """
        self.param_names = list(param_space.keys())
        self.dimensions = [
            Real(low, high, name=name)
            for name, (low, high) in param_space.items()
        ]
        self.optimizer = Optimizer(
            dimensions=self.dimensions,
            base_estimator="GP",  # 高斯过程
            acq_func="EI",        # 期望提升
            random_state=42,
        )
        self.baseline = [baseline_params[name] for name in self.param_names]
        self.history = []  # (params, defect_rate)

    def suggest(self, n_suggestions: int = 1) -> List[Dict]:
        """建议下一组参数"""
        suggestions = self.optimizer.ask(n_points=n_suggestions)
        return [
            dict(zip(self.param_names, s))
            for s in suggestions
        ]

    def report(self, params: Dict, defect_rate: float):
        """报告这组参数的效果(缺陷率越低越好)"""
        x = [params[name] for name in self.param_names]
        self.optimizer.tell(x, defect_rate)
        self.history.append((params, defect_rate))

    def get_best(self) -> Dict:
        """获取历史最优参数"""
        if not self.history:
            return dict(zip(self.param_names, self.baseline))
        best = min(self.history, key=lambda x: x[1])
        return best[0]

# ========== 使用示例 ==========
optimizer = ProcessParameterOptimizer(
    param_space={
        "print_pressure": (0.1, 0.3),   # MPa
        "print_speed": (20, 80),         # mm/s
        "squeegee_angle": (45, 75),      # 度
    },
    baseline_params={
        "print_pressure": 0.2,
        "print_speed": 50,
        "squeegee_angle": 60,
    },
)

# 迭代优化
for trial in range(5):
    # 1. Agent建议参数
    suggested = optimizer.suggest()[0]
    print(f"第{trial+1}轮建议参数: {suggested}")

    # 2. 安全检查(调整幅度不超过15%)
    safe = True
    for name, value in suggested.items():
        baseline = optimizer.baseline[optimizer.param_names.index(name)]
        if abs(value - baseline) / baseline > 0.15:
            safe = False
            break

    if not safe:
        print("参数调整幅度过大,跳过")
        continue

    # 3. 下发参数到PLC(通过工具注册中心)
    # ... execution ...

    # 4. 等待稳定,复检缺陷率
    # time.sleep(600)  # 等待10分钟
    defect_rate = 0.02 + np.random.random() * 0.05  # 模拟缺陷率

    # 5. 报告效果
    optimizer.report(suggested, defect_rate)
    print(f"  缺陷率: {defect_rate:.4f}")

# 最优参数
best = optimizer.get_best()
print(f"\n最优参数: {best}")

七、安全防护:Agent的六层刹车系统

工业场景下,Agent出错不是500错误,是停线、是废品、是安全事故。必须有多层防护。

代码语言:javascript
复制
class SafetyGuard:
    """Agent安全防护——六层刹车"""

    def __init__(self):
        self.layers = [
            self._layer1_param_validation,    # 参数校验
            self._layer2_rate_limit,          # 速率限制
            self._layer3_safety_boundary,     # 安全边界
            self._layer4_human_approval,      # 人工审批
            self._layer5_execution_verify,    # 执行验证
            self._layer6_rollback,            # 回滚机制
        ]

    def _layer1_param_validation(self, action):
        """第一层:参数格式和范围校验"""
        for param, value in action["params"].items():
            if param in action.get("constraints", {}):
                c = action["constraints"][param]
                if "min" in c and value < c["min"]:
                    raise SafetyError(f"参数 {param}={value} 低于下限 {c['min']}")
                if "max" in c and value > c["max"]:
                    raise SafetyError(f"参数 {param}={value} 超过上限 {c['max']}")
        return True

    def _layer2_rate_limit(self, action):
        """第二层:操作频率限制"""
        # 同一参数10分钟内最多调整2次
        # 写入操作每分钟不超过5次
        pass

    def _layer3_safety_boundary(self, action):
        """第三层:物理安全边界"""
        # 温度调整不超过±5℃
        # 压力调整不超过±20%
        # 关键参数(如反应釜温度)直接拒绝自动调整
        critical_params = ["reactor_temp", "high_voltage_setpoint"]
        if action["param"] in critical_params:
            raise SafetyError(f"关键参数 {action['param']} 不允许自动调整")
        return True

    def _layer4_human_approval(self, action):
        """第四层:高风险操作人工审批"""
        if action["risk_level"] == "high":
            # 发送审批请求到工程师手机
            # 等待确认,超时默认拒绝
            approved = self._request_human_approval(action)
            if not approved:
                raise SafetyError("人工审批未通过")
        return True

    def _layer5_execution_verify(self, action):
        """第五层:执行后验证"""
        # 写入后立即回读,确认参数确实改了
        # 监控设备状态,异常立即触发回滚
        pass

    def _layer6_rollback(self, action):
        """第六层:自动回滚"""
        # 调整后30分钟内缺陷率上升超过50% → 自动回滚
        # 设备报警 → 立即回滚
        # 回滚后记录审计日志
        pass

    def check(self, action) -> bool:
        for layer in self.layers:
            try:
                layer(action)
            except SafetyError as e:
                logger.warning(f"安全拦截 [{layer.__name__}]: {e}")
                return False
        return True

安全设计原则:

  1. 默认拒绝:没有明确授权的操作一律拒绝
  2. 最小权限:Agent只能访问完成任务所需的最少参数
  3. 审计追踪:每一次参数修改都记录:谁(Agent ID)、何时、改了什么、旧值新值、效果如何
  4. 快速回滚:所有修改保留旧值,一键回滚
  5. 人工兜底:高风险操作必须人工确认,Agent不能绕过

八、落地案例与效果数据

案例一:SMT产线锡膏印刷参数自优化

项目

数据

场景

智能手机主板SMT产线,锡膏印刷工位

问题

锡桥缺陷率0.8%,人工调参需2-4小时

Agent架构

YOLO26检测 + Qwen-VL分析 + 贝叶斯优化 + OPC UA控制

优化参数

印刷压力、印刷速度、刮刀角度、脱模速度

调参周期

自动闭环约15分钟(含10分钟稳定等待)

缺陷率改善

从0.8%降至0.15%(降低81%)

调参效率

从人工2-4小时 → 自动15分钟

安全机制

单次调整≤15%,关键参数人工确认,自动回滚

运行稳定性

连续运行6个月,零安全事故

案例二:AOI设备检测参数自校准

项目

数据

场景

AOI自动光学检测设备,误报率高

问题

光照变化导致误报率从2%升至8%,工程师每天手动调阈值

Agent能力

读取XML配置(canny阈值、CLAHE对比度、NMS IoU)→ 分析误报原因 → 自动改写配置 → 复检

工具数量

22个工具(检测、配置读写、统计、复检)

误报率改善

从8%降至1.5%

人工干预

从每天30分钟 → 每周复核一次

关键设计

工具注册中心参数校验,错误参数在写入前拦截

案例三:注塑工艺参数自适应

项目

数据

场景

汽车零部件注塑成型

问题

环境温度变化导致尺寸超差,每班需人工调机

Agent架构

传感器数据采集 + 因果发现 + 强化学习调参

优化参数

料筒温度、模具温度、注射压力、保压时间

尺寸合格率

从96.5%提升至99.2%

调机时间

从每班30分钟 → 自动实时调整


九、踩坑指南

坑1:LLM API抖动导致产线停线

原因: Agent调用大模型时网络抖动或超时,主流程阻塞。解决:

  • 所有LLM调用设置超时(10s)和重试(3次)
  • 关键路径不依赖LLM,LLM只做分析建议,执行有兜底逻辑
  • 本地部署小模型(3B-7B)作为降级方案
  • Agent状态持久化,崩溃后可恢复

坑2:参数调整后设备还没稳定就复检

原因: 温度、压力等参数有滞后性,刚改完就测,结果不准。解决:

  • 每个参数有明确的稳定等待时间(温度10分钟、压力30秒)
  • Agent维护参数-等待时间表
  • 复检前先确认传感器读数已稳定

坑3:多Agent状态不一致

原因: 多个Agent同时操作同一设备,参数互相覆盖。解决:

  • 设备级互斥锁,同一时间只有一个Agent能写参数
  • Manager Agent统一调度,子Agent不直接操作设备
  • 所有写入操作排队执行

坑4:优化算法陷入局部最优

原因: 贝叶斯优化在小样本下容易收敛到局部最优。解决:

  • 加入随机探索(每5轮随机试一组参数)
  • 定期重置优化器,用新数据重新拟合
  • 结合工艺机理约束搜索空间

坑5:Agent"幻觉"出不存在的工具

原因: LLM有时会调用未注册的工具名。解决:

  • 工具注册中心返回明确的错误信息和可用工具列表
  • Prompt中列出所有可用工具和参数schema
  • 使用function calling / structured output约束输出

十、总结:从自动化到自主化

核心架构回顾

层级

组件

关键技术

感知

YOLO26 INT8 + OPC UA

实时检测、数据采集

认知

VLM + RAG

根因分析、知识检索

决策

LangGraph多Agent + 贝叶斯优化

任务规划、参数搜索

执行

安全网关 + PLC写入

参数下发、设备控制

反馈

统计引擎 + 增量学习

效果验证、持续进化

五条核心经验

  1. 工具注册是底座——参数校验、速率限制、权限分级、统一返回格式,一个都不能少
  2. 安全比智能重要——六层防护、默认拒绝、快速回滚,Agent必须有"刹车"
  3. 混合模式最务实——低层级自治、高层级人工,不要一上来就全自治
  4. 闭环才有价值——检测→分析→调参→复检→评估,缺了任何一环都不是Agent
  5. 小步快跑——先从一个工位、一个参数开始,跑通闭环再扩展

最终效果

  • 缺陷率降低 60%-80%
  • 调参效率提升 8-16倍
  • 人工干预减少 85%
  • 系统持续自进化,越跑越准

工业AI Agent的终局,不是替代工程师,而是让工程师从"救火队员"变成"教练"——设定目标、划定边界、监督执行,具体的优化交给Agent。 从第19篇的边缘部署,到第20篇的多模态诊断,再到本篇的Agent闭环,我们完成了"看见→看懂→自主优化"的完整技术链路。


下一篇预告: AI大模型学习(22)——工业数字孪生与AI Agent融合,构建虚实联动的智能产线。

参考资料:

  • LangGraph多Agent编排框架官方文档
  • AutoIAD: Manager-Driven Multi-Agent Collaboration(arXiv 2025)
  • 西门子Industrial Copilot工程智能体实践
  • 美的/海尔智能体工厂落地案例
  • AOI设备Agent工具注册中心实战(James_WangA)
  • 实测数据基于SMT/AOI/注塑三个落地项目
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-09-01,如有侵权请联系 cloudcommunity@tencent.com 删除
目录
  • AI大模型学习(21):Agent框架在工业自动化中的应用——从缺陷检测到自动调参的智能体闭环
    • 一、从"AI辅助检测"到"AI自主优化":差了一个Agent
    • 二、工业AI Agent的三条落地路径
      • 路径一:Copilot模式(辅助决策)
      • 路径二:自治模式(封闭场景自主执行)
      • 路径三:混合模式(分层自治,当前最务实)
    • 三、整体架构:五层智能体闭环
      • 各层职责
    • 四、核心底座:工业级工具注册中心
      • 4.1 工具注册中心设计
      • 4.2 注册工业工具
    • 五、多Agent协作:LangGraph编排
      • 5.1 Agent角色设计
      • 5.2 LangGraph工作流实现
      • 5.3 运行闭环
    • 六、自动调参核心:贝叶斯优化
    • 七、安全防护:Agent的六层刹车系统
    • 八、落地案例与效果数据
      • 案例一:SMT产线锡膏印刷参数自优化
      • 案例二:AOI设备检测参数自校准
      • 案例三:注塑工艺参数自适应
    • 九、踩坑指南
      • 坑1:LLM API抖动导致产线停线
      • 坑2:参数调整后设备还没稳定就复检
      • 坑3:多Agent状态不一致
      • 坑4:优化算法陷入局部最优
      • 坑5:Agent"幻觉"出不存在的工具
    • 十、总结:从自动化到自主化
      • 核心架构回顾
      • 五条核心经验
      • 最终效果
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档