app:
  description: ''
  icon: 🤖
  icon_background: '#FFEAD5'
  icon_type: emoji
  mode: workflow
  name: 通信网络故障智能诊断工作流
  use_icon_as_answer_icon: false
dependencies:
- current_identifier: null
  type: marketplace
  value:
    marketplace_plugin_unique_identifier: langgenius/siliconflow:0.0.61@f0952b183715405503a23ccef015e5d43948591fd10b60690f24c07873eed723
    version: null
- current_identifier: null
  type: marketplace
  value:
    marketplace_plugin_unique_identifier: bowenliang123/md_exporter:3.6.0@11b39de742c7f3d61db183ff8e938f08fc14b98549e4b5159551e82aa74f7b41
    version: null
- current_identifier: null
  type: marketplace
  value:
    marketplace_plugin_unique_identifier: langgenius/tongyi:0.2.1@0924de1d15a8a35b0cc64ff396c68d5edddcfbc495a1e52ea57e8648434eff4b
    version: null
kind: app
version: 0.7.0
workflow:
  conversation_variables: []
  environment_variables: []
  features:
    file_upload:
      allowed_file_extensions:
      - .JPG
      - .JPEG
      - .PNG
      - .GIF
      - .WEBP
      - .SVG
      allowed_file_types:
      - image
      allowed_file_upload_methods:
      - local_file
      - remote_url
      enabled: false
      fileUploadConfig:
        attachment_image_file_size_limit: 2
        audio_file_size_limit: 50
        batch_count_limit: 10
        file_size_limit: 30
        file_upload_limit: 20
        image_file_batch_limit: 10
        image_file_size_limit: 10
        single_chunk_attachment_limit: 10
        video_file_size_limit: 100
        workflow_file_upload_limit: 15
      image:
        enabled: false
        number_limits: 3
        transfer_methods:
        - local_file
        - remote_url
      number_limits: 3
    opening_statement: ''
    retriever_resource:
      enabled: true
    sensitive_word_avoidance:
      enabled: false
    speech_to_text:
      enabled: false
    suggested_questions: []
    suggested_questions_after_answer:
      enabled: false
    text_to_speech:
      enabled: false
      language: ''
      voice: ''
  graph:
    edges:
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: start
        targetType: document-extractor
      id: 1788329510283-source-1788330698134-target
      source: '1788329510283'
      sourceHandle: source
      target: '1788330698134'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: document-extractor
        targetType: code
      id: 1788330698134-source-1788330733325-target
      source: '1788330698134'
      sourceHandle: source
      target: '1788330733325'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: start
        targetType: if-else
      id: 1788329510283-source-1788331739155-target
      source: '1788329510283'
      sourceHandle: source
      target: '1788331739155'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: if-else
        targetType: code
      id: 1788331739155-true-1788331843557-target
      source: '1788331739155'
      sourceHandle: 'true'
      target: '1788331843557'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: if-else
        targetType: document-extractor
      id: 1788331739155-false-1788331807537-target
      source: '1788331739155'
      sourceHandle: 'false'
      target: '1788331807537'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: code
        targetType: code
      id: 1788331843557-source-1788331982688-target
      source: '1788331843557'
      sourceHandle: source
      target: '1788331982688'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: document-extractor
        targetType: code
      id: 1788331807537-source-1788331982688-target
      source: '1788331807537'
      sourceHandle: source
      target: '1788331982688'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: code
        targetType: code
      id: 1788331982688-source-1788332032668-target
      source: '1788331982688'
      sourceHandle: source
      target: '1788332032668'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: code
        targetType: code
      id: 1788330733325-source-1788335817786-target
      source: '1788330733325'
      sourceHandle: source
      target: '1788335817786'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: code
        targetType: code
      id: 1788332032668-source-1788335817786-target
      source: '1788332032668'
      sourceHandle: source
      target: '1788335817786'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: code
        targetType: iteration
      id: 1788335817786-source-1788337304285-target
      source: '1788335817786'
      sourceHandle: source
      target: '1788337304285'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: true
        isInLoop: false
        iteration_id: '1788337304285'
        sourceType: iteration-start
        targetType: code
      id: 1788337304285start-source-1788337339793-target
      source: 1788337304285start
      sourceHandle: source
      target: '1788337339793'
      targetHandle: target
      type: custom
      zIndex: 1001
    - data:
        isInIteration: true
        isInLoop: false
        iteration_id: '1788337304285'
        sourceType: code
        targetType: knowledge-retrieval
      id: 1788337339793-source-1788338544990-target
      source: '1788337339793'
      sourceHandle: source
      target: '1788338544990'
      targetHandle: target
      type: custom
      zIndex: 1001
    - data:
        isInIteration: true
        isInLoop: false
        iteration_id: '1788337304285'
        sourceType: knowledge-retrieval
        targetType: llm
      id: 1788338544990-source-1788338632376-target
      source: '1788338544990'
      sourceHandle: source
      target: '1788338632376'
      targetHandle: target
      type: custom
      zIndex: 1001
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: iteration
        targetType: llm
      id: 1788337304285-source-1788338943159-target
      source: '1788337304285'
      sourceHandle: source
      target: '1788338943159'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: code
        targetType: llm
      id: 1788335817786-source-1788338943159-target
      source: '1788335817786'
      sourceHandle: source
      target: '1788338943159'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: llm
        targetType: tool
      id: 1788338943159-source-1791377555308-target
      source: '1788338943159'
      sourceHandle: source
      target: '1791377555308'
      targetHandle: target
      type: custom
      zIndex: 0
    - data:
        isInIteration: false
        isInLoop: false
        sourceType: tool
        targetType: end
      id: 1791377555308-source-1788339385458-target
      source: '1791377555308'
      sourceHandle: source
      target: '1788339385458'
      targetHandle: target
      type: custom
      zIndex: 0
    nodes:
    - data:
        selected: false
        title: 用户输入
        type: start
        variables:
        - allowed_file_extensions: []
          allowed_file_types:
          - document
          allowed_file_upload_methods:
          - local_file
          - remote_url
          default: ''
          hide: false
          hint: ''
          label: device_logs
          options: []
          placeholder: ''
          required: true
          type: file
          variable: device_logs
        - allowed_file_extensions: []
          allowed_file_types:
          - document
          allowed_file_upload_methods:
          - local_file
          - remote_url
          default: ''
          hide: false
          hint: ''
          label: workorder
          options: []
          placeholder: ''
          required: false
          type: file
          variable: workorder
        - default: ''
          hint: ''
          label: workorder_text
          max_length: 256
          options: []
          placeholder: ''
          required: false
          type: text-input
          variable: workorder_text
      height: 161
      id: '1788329510283'
      position:
        x: 83
        y: 208
      positionAbsolute:
        x: 83
        y: 208
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        is_array_file: false
        selected: false
        title: 日志提取
        type: document-extractor
        variable_selector:
        - '1788329510283'
        - device_logs
      height: 105
      id: '1788330698134'
      position:
        x: 508
        y: 143
      positionAbsolute:
        x: 508
        y: 143
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        code: "import json\nfrom typing import Dict, List, Any\n\n\ndef main(text:\
          \ str) -> Dict[str, str]:\n    \"\"\"\n    Dify Code 节点入口函数。\n    解析 Markdown\
          \ 表格日志，过滤并分组输出 JSON。\n\n    Args:\n        text: Markdown 表格文本\n\n    Returns:\n\
          \        包含 \"device_error_list\" 键的字典，其值为 JSON 字符串\n    \"\"\"\n    if\
          \ not text or not text.strip():\n        return {\"device_error_list\":\
          \ \"{}\"}\n\n    lines = [line.strip() for line in text.splitlines() if\
          \ line.strip()]\n    if not lines:\n        return {\"device_error_list\"\
          : \"{}\"}\n\n    # 识别表头行、分隔行和数据行\n    header_line = None\n    data_lines\
          \ = []\n\n    for line in lines:\n        # 必须是有效的表格行（以 | 开头和结尾）\n     \
          \   if not (line.startswith('|') and line.endswith('|')):\n            continue\n\
          \n        # 分隔行特征：包含连续的 --- 或 :---:\n        if '---' in line:\n       \
          \     continue  # 跳过分隔行\n\n        if header_line is None:\n           \
          \ header_line = line\n        else:\n            data_lines.append(line)\n\
          \n    if header_line is None:\n        # 无法解析表头，返回空结果\n        return {\"\
          device_error_list\": \"{}\"}\n\n    # 解析表头列名\n    header_cells = [cell.strip()\
          \ for cell in header_line.split('|')[1:-1]]\n    # 确定关键列的索引（不区分大小写，模糊匹配）\n\
          \    idx_timestamp = idx_severity = idx_device = idx_message = None\n\n\
          \    for i, col in enumerate(header_cells):\n        col_lower = col.lower()\n\
          \        if 'timestamp' in col_lower or 'time' in col_lower:\n         \
          \   idx_timestamp = i\n        elif 'severity' in col_lower or 'level' in\
          \ col_lower:\n            idx_severity = i\n        elif 'device' in col_lower\
          \ or 'device_id' in col_lower or 'host' in col_lower:\n            idx_device\
          \ = i\n        elif 'message' in col_lower or 'msg' in col_lower:\n    \
          \        idx_message = i\n\n    # 若未找到，按默认顺序（0: timestamp, 1: severity,\
          \ 2: device, 3: message）\n    if idx_timestamp is None:\n        idx_timestamp\
          \ = 0\n    if idx_severity is None:\n        idx_severity = 1\n    if idx_device\
          \ is None:\n        idx_device = 2\n    if idx_message is None:\n      \
          \  idx_message = 3\n\n    max_needed_idx = max(idx_timestamp, idx_severity,\
          \ idx_device, idx_message)\n\n    # 解析数据行\n    records: List[Dict[str, Any]]\
          \ = []\n\n    for line in data_lines:\n        cells = [cell.strip() for\
          \ cell in line.split('|')[1:-1]]\n        # 补齐缺失的列（末尾空列可能被省略）\n        while\
          \ len(cells) <= max_needed_idx:\n            cells.append('')\n\n      \
          \  timestamp = cells[idx_timestamp] if idx_timestamp < len(cells) else ''\n\
          \        severity = cells[idx_severity].upper() if idx_severity < len(cells)\
          \ else ''\n        device = cells[idx_device] if idx_device < len(cells)\
          \ else ''\n        message = cells[idx_message] if idx_message < len(cells)\
          \ else ''\n\n        # 只保留 ERROR 和 CRITICAL（去掉 WARNING）\n        if severity\
          \ not in ('ERROR', 'CRITICAL'):\n            continue\n\n        # 移除 message\
          \ 开头的 \"设备名: \" 前缀\n        if device and message.startswith(device + ':\
          \ '):\n            message = message[len(device) + 2:]\n\n        records.append({\n\
          \            'timestamp': timestamp,\n            'severity': severity,\n\
          \            'message': message,\n            'device': device\n       \
          \ })\n\n    # 按设备分组\n    groups: Dict[str, List[Dict[str, str]]] = {}\n\
          \    for rec in records:\n        device = rec.pop('device')\n        groups.setdefault(device,\
          \ []).append(rec)\n\n    # 每组按时间排序（字符串排序，假设时间格式可比较）\n    for dev in groups:\n\
          \        groups[dev].sort(key=lambda x: x['timestamp'])\n\n    # 转为 JSON\
          \ 字符串，中文不转义\n    json_str = json.dumps(groups, ensure_ascii=False)\n\n \
          \   return {\"device_error_list\": json_str}"
        code_language: python3
        default_value:
        - key: device_error_list
          type: string
          value: 缺失字段
        error_strategy: default-value
        outputs:
          device_error_list:
            children: null
            type: string
        selected: false
        title: 日志处理
        type: code
        variables:
        - value_selector:
          - '1788330698134'
          - text
          value_type: string
          variable: text
      height: 88
      id: '1788330733325'
      position:
        x: 1458.3946364096894
        y: 143
      positionAbsolute:
        x: 1458.3946364096894
        y: 143
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        cases:
        - case_id: 'true'
          conditions:
          - comparison_operator: not empty
            id: c93e0817-2d82-4368-bab8-59ad3966c5f8
            value: ''
            varType: string
            variable_selector:
            - '1788329510283'
            - workorder_text
          id: 'true'
          logical_operator: and
        selected: false
        title: 工单来源匹配
        type: if-else
      height: 140
      id: '1788331739155'
      position:
        x: 491.9556194875337
        y: 388.25622964762124
      positionAbsolute:
        x: 491.9556194875337
        y: 388.25622964762124
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        is_array_file: false
        selected: false
        title: 工单提取
        type: document-extractor
        variable_selector:
        - '1788329510283'
        - workorder
      height: 105
      id: '1788331807537'
      position:
        x: 801
        y: 676.0334747713231
      positionAbsolute:
        x: 801
        y: 676.0334747713231
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        code: "def main(workorder_text: any) -> dict:\n    return {\"text\": str(workorder_text)}"
        code_language: python3
        outputs:
          text:
            children: null
            type: string
        selected: false
        title: 文本直传
        type: code
        variables:
        - value_selector:
          - '1788329510283'
          - workorder_text
          value_type: string
          variable: workorder_text
      height: 52
      id: '1788331843557'
      position:
        x: 801
        y: 428.1615087319258
      positionAbsolute:
        x: 801
        y: 428.1615087319258
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        code: "def main(text_from_string: str, text_from_file: str) -> dict:\n   \
          \ \"\"\"\n    Dify Code 节点入口函数\n    :param text_from_string: 来自字符串的输入\n\
          \    :param text_from_file: 来自文件的输入\n    :return: 包含 'merged_text' 键的字典，值为优先选择的非空字符串\n\
          \    \"\"\"\n    # 去除首尾空格，若为 None 则转换为空字符串\n    s = text_from_string.strip()\
          \ if text_from_string else \"\"\n    f = text_from_file.strip() if text_from_file\
          \ else \"\"\n\n    # 优先取非空的字符串参数，否则取文件参数（可能为空）\n    merged = s if s else\
          \ f\n\n    return {\"merged_text\": merged}"
        code_language: python3
        outputs:
          merged_text:
            children: null
            type: string
        selected: false
        title: 合并工单文本
        type: code
        variables:
        - value_selector:
          - '1788331843557'
          - text
          value_type: string
          variable: text_from_string
        - value_selector:
          - '1788331807537'
          - text
          value_type: string
          variable: text_from_file
      height: 52
      id: '1788331982688'
      position:
        x: 1142
        y: 554
      positionAbsolute:
        x: 1142
        y: 554
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        code: "import csv, json, io\nfrom datetime import datetime, timedelta\n\n\
          def parse_table(text):\n    if not isinstance(text, str):\n        text\
          \ = str(text or \"\")\n    text = text.strip()\n    if not text:\n     \
          \   return []\n    lines = [ln for ln in text.splitlines() if ln.strip()]\n\
          \    if \"|\" in lines[0]:\n        rows = []\n        header = None\n \
          \       for ln in lines:\n            cells = [c.strip() for c in ln.strip().strip(\"\
          |\").split(\"|\")]\n            if cells and all(c and set(c) <= set(\"\
          -: \") for c in cells):\n                continue\n            if header\
          \ is None:\n                header = cells\n                continue\n \
          \           row = {}\n            for i, h in enumerate(header):\n     \
          \           row[h] = cells[i] if i < len(cells) else \"\"\n            rows.append(row)\n\
          \        return rows\n    return list(csv.DictReader(io.StringIO(text)))\n\
          \ndef main(text):\n    rows = parse_table(text)\n    groups = {}\n    order_seq\
          \ = []\n    for r in rows:\n        ts = (r.get(\"timestamp\") or \"\").strip()\n\
          \        dev = (r.get(\"related_device\") or \"\").strip()\n        key\
          \ = (ts, dev)\n        if key not in groups:\n            groups[key] =\
          \ []\n            order_seq.append(key)\n        groups[key].append(r)\n\
          \    result = []\n    for key in order_seq:\n        items = groups[key]\n\
          \        ts, dev = key\n        order_ids = [i.get(\"order_id\", \"\").strip()\
          \ for i in items]\n        user_ids = [i.get(\"user_id\", \"\").strip()\
          \ for i in items]\n        t_start = t_end = \"\"\n        try:\n      \
          \      dt = datetime.strptime(ts, \"%Y-%m-%d %H:%M:%S\")\n            t_start\
          \ = (dt - timedelta(minutes=10)).strftime(\"%Y-%m-%d %H:%M:%S\")\n     \
          \       t_end = (dt + timedelta(minutes=10)).strftime(\"%Y-%m-%d %H:%M:%S\"\
          )\n        except Exception:\n            pass\n        first = items[0]\n\
          \        result.append({\n            \"merged_order_ids\": order_ids,\n\
          \            \"related_device\": dev,\n            \"user_ids\": user_ids,\n\
          \            \"timestamp\": ts,\n            \"time_start\": t_start,\n\
          \            \"time_end\": t_end,\n            \"complaint_type\": first.get(\"\
          complaint_type\", \"\").strip(),\n            \"description\": first.get(\"\
          description\", \"\").strip()\n        })\n    return {\"work_order_with_time\"\
          : json.dumps(result, ensure_ascii=False)}"
        code_language: python3
        outputs:
          work_order_with_time:
            children: null
            type: string
        selected: false
        title: 工单处理
        type: code
        variables:
        - value_selector:
          - '1788331982688'
          - merged_text
          value_type: string
          variable: text
      height: 52
      id: '1788332032668'
      position:
        x: 1464.197964355585
        y: 554
      positionAbsolute:
        x: 1464.197964355585
        y: 554
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        code: "from datetime import datetime\nimport json, re\n\ndef main(work_order_with_time,\
          \ device_error_list):\n    def parse_llm_json(x):\n        if isinstance(x,\
          \ (list, dict)):\n            return x\n        if not isinstance(x, str):\n\
          \            return None\n        s = x.strip()\n        m = re.search(r\"\
          ```(?:json)?\\s*(.*?)\\s*```\", s, re.S)\n        if m:\n            s =\
          \ m.group(1).strip()\n        try:\n            return json.loads(s)\n \
          \       except Exception:\n            return None\n\n    def parse_time(s):\n\
          \        if not isinstance(s, str):\n            return None\n        for\
          \ fmt in [\"%Y-%m-%d %H:%M:%S\", \"%Y/%m/%d %H:%M\", \"%Y/%m/%d %H:%M:%S\"\
          ]:\n            try:\n                return datetime.strptime(s.strip(),\
          \ fmt)\n            except Exception:\n                continue\n      \
          \  return None\n\n    wo_raw = parse_llm_json(work_order_with_time)\n  \
          \  orders = []\n    if isinstance(wo_raw, dict):\n        wo_raw = wo_raw.get(\"\
          work_order_with_time\", wo_raw)\n    if isinstance(wo_raw, list):\n    \
          \    orders = [o for o in wo_raw if isinstance(o, dict)]\n\n    log_raw\
          \ = parse_llm_json(device_error_list)\n    dev_logs = {}\n    if isinstance(log_raw,\
          \ dict):\n        if \"device_error_list\" in log_raw and isinstance(log_raw[\"\
          device_error_list\"], list):\n            for dd in log_raw[\"device_error_list\"\
          ]:\n                if isinstance(dd, dict) and dd.get(\"device_id\"):\n\
          \                    dev_logs[dd[\"device_id\"]] = dd.get(\"error_logs\"\
          , []) or []\n        else:\n            for dev_id, logs in log_raw.items():\n\
          \                if isinstance(logs, list):\n                    dev_logs[dev_id]\
          \ = logs\n    elif isinstance(log_raw, list):\n        for dd in log_raw:\n\
          \            if isinstance(dd, dict) and dd.get(\"device_id\"):\n      \
          \          dev_logs[dd[\"device_id\"]] = dd.get(\"error_logs\", []) or []\n\
          \n    report = \"\"\n    retrieve_list = []\n    for order in orders:\n\
          \        device = order.get(\"related_device\", \"\")\n        oid = order.get(\"\
          merged_order_ids\") or order.get(\"order_id\") or \"\"\n        if isinstance(oid,\
          \ list):\n            oid = \", \".join(str(x) for x in oid)\n        users\
          \ = order.get(\"user_ids\") or order.get(\"user_id\") or \"\"\n        if\
          \ isinstance(users, list):\n            users = \", \".join(str(x) for x\
          \ in users)\n        desc = order.get(\"description\", \"\")\n        t_start\
          \ = parse_time(order.get(\"time_start\"))\n        t_end = parse_time(order.get(\"\
          time_end\"))\n        device_type = device.split(\"_\")[0] if \"_\" in device\
          \ else device\n\n        logs = dev_logs.get(device, [])\n        matched\
          \ = []\n        for log in logs:\n            if not isinstance(log, dict):\n\
          \                continue\n            lt = parse_time(log.get(\"timestamp\"\
          ))\n            if t_start and t_end and lt and t_start <= lt <= t_end:\n\
          \                matched.append(log)\n\n        report += f\"\\n工单：{oid}\\\
          n设备：{device}\\n受影响用户：{users}\\n用户问题：{desc}\\n问题日志：\\n\"\n        for log\
          \ in matched:\n            msg = log.get(\"clean_message\") or log.get(\"\
          message\") or \"\"\n            sev = log.get(\"severity\", \"\")\n    \
          \        report += f\"- {msg}（级别：{sev}）\\n\"\n            retrieve_list.append({\"\
          device_type\": device_type, \"message\": msg})\n\n    seen = set()\n   \
          \ dedup_list = []\n    for r in retrieve_list:\n        key = (r[\"device_type\"\
          ], r[\"message\"])\n        if key in seen:\n            continue\n    \
          \    seen.add(key)\n        dedup_list.append(r)\n\n    return {\"retrieve_list\"\
          : dedup_list, \"work_order_report\": report.strip()}"
        code_language: python3
        outputs:
          retrieve_list:
            children: null
            type: array[object]
          work_order_report:
            children: null
            type: string
        selected: false
        title: 工单日志匹配
        type: code
        variables:
        - value_selector:
          - '1788330733325'
          - device_error_list
          value_type: string
          variable: device_error_list
        - value_selector:
          - '1788332032668'
          - work_order_with_time
          value_type: string
          variable: work_order_with_time
      height: 52
      id: '1788335817786'
      position:
        x: 1835.502423928929
        y: 316.9997077529053
      positionAbsolute:
        x: 1835.502423928929
        y: 316.9997077529053
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        error_handle_mode: terminated
        flatten_output: true
        height: 175.49640708269203
        is_parallel: true
        iterator_input_type: array[object]
        iterator_selector:
        - '1788335817786'
        - retrieve_list
        output_selector:
        - '1788338632376'
        - text
        output_type: array[string]
        parallel_nums: 10
        selected: false
        start_node_id: 1788337304285start
        title: 迭代
        type: iteration
        width: 983.74101770673
      height: 175
      id: '1788337304285'
      position:
        x: 2192.200327872236
        y: 510.3013178336039
      positionAbsolute:
        x: 2192.200327872236
        y: 510.3013178336039
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 984
      zIndex: 0
    - data:
        desc: ''
        isInIteration: true
        selected: false
        title: ''
        type: iteration-start
      draggable: false
      height: 48
      id: 1788337304285start
      parentId: '1788337304285'
      position:
        x: 24
        y: 68
      positionAbsolute:
        x: 2216.200327872236
        y: 578.3013178336039
      selectable: false
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom-iteration-start
      width: 44
      zIndex: 1001
    - data:
        code: "def main(item: dict) -> dict:\n    \"\"\"\n    Dify 代码节点函数\n    输入变量：item（字典类型，需包含\
          \ device_type 和 message 字段）\n    输出：{\"text\": \"device_type：值 message：值\"\
          }\n    \"\"\"\n    # 提取字段，若缺失则设为空字符串\n    device_type = item.get('device_type',\
          \ '')\n    message = item.get('message', '')\n\n    # 拼接结果（使用中文冒号，中间有空格）\n\
          \    result = f\"device_type：{device_type} message：{message}\"\n\n    #\
          \ 返回符合 Dify 输出格式的字典\n    return {\"text\": result}"
        code_language: python3
        isInIteration: true
        isInLoop: false
        iteration_id: '1788337304285'
        outputs:
          text:
            children: null
            type: string
        selected: false
        title: 转string
        type: code
        variables:
        - value_selector:
          - '1788337304285'
          - item
          value_type: object
          variable: item
      height: 52
      id: '1788337339793'
      parentId: '1788337304285'
      position:
        x: 121.74101770672996
        y: 65.49640708269203
      positionAbsolute:
        x: 2313.941345578966
        y: 575.7977249162959
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 1001
    - data:
        dataset_ids:
        - /GMEapRfyENjwHGNJV49yPtVRvDLhxX/L5quJxFjREqwyjbAEA10PDTmCSTH4NQb
        isInIteration: true
        isInLoop: false
        iteration_id: '1788337304285'
        multiple_retrieval_config:
          reranking_enable: true
          reranking_mode: reranking_model
          reranking_model:
            model: netease-youdao/bce-reranker-base_v1
            provider: langgenius/siliconflow/siliconflow
          top_k: 4
        query_attachment_selector: []
        query_variable_selector:
        - '1788337339793'
        - text
        retrieval_mode: multiple
        selected: false
        title: 知识检索
        type: knowledge-retrieval
      height: 90
      id: '1788338544990'
      parentId: '1788337304285'
      position:
        x: 423.74101770672996
        y: 65.49640708269203
      positionAbsolute:
        x: 2615.941345578966
        y: 575.7977249162959
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 1001
    - data:
        context:
          enabled: true
          variable_selector:
          - '1788338544990'
          - result
        isInIteration: true
        isInLoop: false
        iteration_id: '1788337304285'
        model:
          completion_params: {}
          mode: chat
          name: qwen3.6-plus
          provider: langgenius/tongyi/tongyi
        prompt_template:
        - id: b71b1ecb-8e71-42f3-bab6-153bb2dfa2c0
          role: system
          text: '你是专业通信网络运维工程师。参考本次知识检索到的故障维护方案{{#context#}}，输出完整的内容，格式如下：

            设备类型

            日志类型

            日志信息

            日志含义

            可能原因

            处理步骤'
        selected: false
        title: 日志智能检索
        type: llm
        vision:
          enabled: false
      height: 88
      id: '1788338632376'
      parentId: '1788337304285'
      position:
        x: 725.74101770673
        y: 65.49640708269203
      positionAbsolute:
        x: 2917.941345578966
        y: 575.7977249162959
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 1001
    - data:
        context:
          enabled: true
          variable_selector:
          - '1788337304285'
          - output
        model:
          completion_params: {}
          mode: chat
          name: qwen3.6-plus
          provider: langgenius/tongyi/tongyi
        prompt_template:
        - id: 4c4f152c-de63-4645-a3ee-352ae8cab798
          role: system
          text: '你是专业网络运维专家，结合下面的工单故障信息{{#1788335817786.work_order_report#}}和知识库维护方案{{#context#}}，生成标准的诊断报告。

            诊断报告中的日志含义、可能原因、处理步骤应优先来自知识库检索结果。

            不得完全脱离知识库自行编造维护结论。

            报告中不得输出知识库 metadata、dataset_id、segment_id、score 等调试信息。

            报告的格式：

            智能故障诊断处置单

            报告至少包含两部分：

            1. 处置优先级

            需以表格形式展示，字段包括：

            |优先级|工单编号|责任专业|处理时限|设备故障类型|影响对象|判断结论|当前动作|（markdown表格渲染）

            2. 分工单处置

            每张工单需单独输出，内容包括：

            •责任专业

            •处理时限

            •处置结论

            •关键证据

            •现场操作

            •恢复验证

            •升级条件

            •需补充信息'
        selected: false
        title: 智能诊断
        type: llm
        vision:
          enabled: false
      height: 88
      id: '1788338943159'
      position:
        x: 3180.9052033489556
        y: 39.82253318592847
      positionAbsolute:
        x: 3180.9052033489556
        y: 39.82253318592847
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        outputs:
        - value_selector:
          - '1788338943159'
          - text
          value_type: string
          variable: T2
        - value_selector:
          - '1791377555308'
          - files
          value_type: array[file]
          variable: F2
        selected: false
        title: 输出
        type: end
      height: 115
      id: '1788339385458'
      position:
        x: 4190.3344264672105
        y: -4.976932719416055
      positionAbsolute:
        x: 4190.3344264672105
        y: -4.976932719416055
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    - data:
        is_team_authorization: true
        paramSchemas:
        - auto_generate: null
          default: null
          form: llm
          human_description:
            en_US: Markdown text
            ja_JP: Markdown text
            pt_BR: Markdown text
            zh_Hans: Markdown格式文本
          input_schema: null
          label:
            en_US: Markdown text
            ja_JP: Markdown text
            pt_BR: Markdown text
            zh_Hans: Markdown格式文本
          llm_description: ''
          max: null
          min: null
          multiple: false
          name: md_text
          options: []
          placeholder: null
          precision: null
          required: true
          scope: null
          template: null
          type: string
        - auto_generate: null
          default: null
          form: llm
          human_description:
            en_US: Optional custom output file name, and the filename suffix is not
              required.
            ja_JP: Optional custom output file name, and the filename suffix is not
              required.
            pt_BR: Optional custom output file name, and the filename suffix is not
              required.
            zh_Hans: 可选的自定义输出文件名，后缀名无需指定
          input_schema: null
          label:
            en_US: Output Filename
            ja_JP: Output Filename
            pt_BR: Output Filename
            zh_Hans: 输出文件名
          llm_description: ''
          max: null
          min: null
          multiple: false
          name: output_filename
          options: []
          placeholder: null
          precision: null
          required: false
          scope: null
          template: null
          type: string
        params:
          md_text: ''
          output_filename: ''
        plugin_id: bowenliang123/md_exporter
        plugin_unique_identifier: bowenliang123/md_exporter:3.6.0@11b39de742c7f3d61db183ff8e938f08fc14b98549e4b5159551e82aa74f7b41
        provider_icon: /console/api/workspaces/current/plugin/icon?tenant_id=84d3b678-df20-415b-960a-ccbe897e3e9d&filename=aa1c633e6a6a95b5b758343827dcabf9d288f19d7995b0d39878fbf54e924475.png
        provider_id: bowenliang123/md_exporter/md_exporter
        provider_name: bowenliang123/md_exporter/md_exporter
        provider_show_name: Markdown 转换器
        provider_type: builtin
        selected: false
        title: Markdown ⮕ MD
        tool_configurations: {}
        tool_description: 将 Markdown 转换为 .md 文件的工具
        tool_label: Markdown ⮕ MD
        tool_name: md_to_md
        tool_node_version: '2'
        tool_parameters:
          md_text:
            type: mixed
            value: '{{#1788338943159.text#}}'
          output_filename:
            type: mixed
            value: 张三_告警工单.md
        type: tool
      height: 52
      id: '1791377555308'
      position:
        x: 3644.70029193049
        y: -25.29105974863568
      positionAbsolute:
        x: 3644.70029193049
        y: -25.29105974863568
      selected: false
      sourcePosition: right
      targetPosition: left
      type: custom
      width: 242
      zIndex: 0
    viewport:
      x: -1913.6709780834449
      y: 354.36230707755755
      zoom: 0.5357206724452673
  rag_pipeline_variables: []
