app:
  description: 生命保険の保険金不正請求予兆スコアを生成し、根拠コメントを付与してSIU部門の調査優先度判定を支援するワークフロー
  icon: 🛡️
  icon_background: '#FFEAD5'
  mode: workflow
  name: 保険金不正請求 予兆スコア判定
  use_icon_as_answer_icon: false
kind: app
version: 0.6.0
workflow:
  conversation_variables: []
  environment_variables: []
  features:
    file_upload:
      image:
        enabled: false
    opening_statement: ''
    suggested_questions: []
    suggested_questions_after_answer:
      enabled: false
    text_to_speech:
      enabled: false
  graph:
    edges:
    - data:
        sourceType: start
        targetType: parameter-extractor
      id: start-to-extractor1
      source: start
      target: extractor1
    - data:
        sourceType: start
        targetType: knowledge-retrieval
      id: start-to-kr1
      source: start
      target: kr1
    - data:
        sourceType: parameter-extractor
        targetType: code
      id: extractor1-to-code1
      source: extractor1
      target: code1
    - data:
        sourceType: knowledge-retrieval
        targetType: code
      id: kr1-to-code1
      source: kr1
      target: code1
    - data:
        sourceType: code
        targetType: end
      id: code1-to-end
      source: code1
      target: end
    nodes:
    - data:
        title: 開始
        type: start
        variables:
        - label: query
          max_length: 2048
          options: []
          required: true
          type: paragraph
          variable: query
      height: 90
      id: start
      position:
        x: 80
        y: 282
      type: custom
      width: 244
    - data:
        title: 情報抽出 (請求情報)
        type: parameter-extractor
        model:
          provider: openai
          name: gpt-5-mini
          mode: chat
        query:
        - start
        - query
        parameters:
        - name: policy_number
          type: string
          description: 保険契約番号または証券番号
          required: true
        - name: claim_amount
          type: number
          description: 請求金額（数値）
          required: true
        - name: claimant_name
          type: string
          description: 被保険者または申請者の氏名
          required: false
        - name: claim_date
          type: string
          description: 請求日（任意）
          required: false
        - name: suspicious_notes
          type: string
          description: 請求文書内で検知される不審な記載やメタ情報（任意）
          required: false
        reasoning_mode: prompt
        instruction: '以下の入力テキスト（請求書類のOCR結果や申請者メモ等）から、指定した項目を抽出してください。


          出力ルール:

          1) policy_number は必ず返すこと。見つからない場合は空文字で返す。

          2) claim_amount は数値で返すこと。通貨記号やカンマが含まれている場合は数値に変換して返す。

          3) claimant_name, claim_date, suspicious_notes は見つかれば返し、なければ空文字にする。

          4) suspicious_notes には「不審な箇所」を短い箇条書きで列挙すること（例: 同一住所で複数申請, 証憑の不整合 等）。

          '
      height: 90
      id: extractor1
      position:
        x: 380
        y: 282
      type: custom
      width: 244
    - data:
        title: ナレッジ検索 (契約履歴・過去請求パターン)
        type: knowledge-retrieval
        dataset_ids:
        - __KR_0__
        retrieval_mode: single
        query_variable_selector:
        - start
        - query
        single_retrieval_config:
          model:
            provider: openai
            name: gpt-5-mini
            mode: chat
            completion_params:
              temperature: 0.3
          score_threshold_enabled: false
          top_k: 5
      height: 90
      id: kr1
      position:
        x: 680
        y: 282
      type: custom
      width: 244
    - data:
        title: 予兆スコア計算
        type: code
        code_language: python3
        code: "def _safe_str(v):\n    \"\"\"Convert any value to string safely.\"\"\
          \"\n    if v is None:\n        return \"\"\n    if isinstance(v, list):\n\
          \        return \"\\n\".join(str(i) for i in v)\n    return str(v)\n\ndef\
          \ _safe_list(v):\n    \"\"\"Ensure value is a list.\"\"\"\n    if v is None:\n\
          \        return []\n    if isinstance(v, str):\n        return [v]\n   \
          \ if isinstance(v, list):\n        return v\n    return [v]\n\ndef main(**kwargs)\
          \ -> dict:\n    inputs = kwargs\n    # ローカル閾値・重み\n    high_amount_threshold\
          \ = 100000.0\n    weight_amount = 30\n    weight_history = 25\n    weight_explicit_fraud\
          \ = 35\n    weight_suspicious_notes = 20\n    max_score = 100\n\n    policy_number\
          \ = inputs.get(\"policy_number\", \"\") or \"\"\n    claimant_name = inputs.get(\"\
          claimant_name\", \"\") or \"\"\n    claim_amount_raw = inputs.get(\"claim_amount\"\
          , 0)\n    try:\n        claim_amount = float(str(claim_amount_raw))\n  \
          \  except Exception:\n        claim_amount = 0.0\n\n    evidence = inputs.get(\"\
          evidence\", \"\") or \"\"\n    suspicious_notes = inputs.get(\"suspicious_notes\"\
          , \"\") or \"\"\n\n    score = 10  # ベーススコア\n    reasons_list = []\n\n \
          \   if claim_amount >= high_amount_threshold:\n        score = score + weight_amount\n\
          \        reasons_list.append(\"請求金額が高額閾値を超えたため +{}\".format(weight_amount))\n\
          \    # 過去履歴由来のヒューリスティクス\n    ev_low = str(evidence).lower()\n    if \"multiple\
          \ claims\" in ev_low or \"previous claim\" in ev_low or \"frequent claims\"\
          \ in ev_low or \"複数の請求\" in ev_low or \"過去の請求\" in ev_low:\n        score\
          \ = score + weight_history\n        reasons_list.append(\"過去の請求履歴で複数または類似パターンを検出したため\
          \ +{}\".format(weight_history))\n    if \"fraud\" in ev_low or \"不正\" in\
          \ ev_low or \"疑い\" in ev_low:\n        score = score + weight_explicit_fraud\n\
          \        reasons_list.append(\"ナレッジ検索で不正関連の記載を検出したため +{}\".format(weight_explicit_fraud))\n\
          \    if suspicious_notes:\n        score = score + weight_suspicious_notes\n\
          \        reasons_list.append(\"請求文書から抽出された不審メモが存在するため +{}\".format(weight_suspicious_notes))\n\
          \n    # 上限下限を調整\n    if score > max_score:\n        score = max_score\n\
          \    if score < 0:\n        score = 0\n\n    # 簡易サマリと詳細\n    reasons = \"\
          ；\".join(reasons_list) if reasons_list else \"特段のリスク指標は検出されませんでした。\"\n \
          \   evidence_str = str(evidence)\n    snippet = evidence_str[0:100] + \"\
          ...\" if len(evidence_str) > 100 else evidence_str\n\n    details = \"policy_number:\
          \ \" + policy_number + \"; claimant_name: \" + claimant_name + \"; claim_amount:\
          \ \" + str(claim_amount) + \"; evidence_snippet: \" + snippet\n\n    report\
          \ = \"総合予兆スコア: \" + str(int(score)) + \" / 100\\n根拠: \" + reasons + \"\\\
          n詳細: \" + details\n\n    return dict(result=dict(score=int(score), reasons=reasons,\
          \ details=details, report=report))\n"
        variables:
        - value_selector:
          - extractor1
          - policy_number
          variable: policy_number
        - value_selector:
          - extractor1
          - claim_amount
          variable: claim_amount
        - value_selector:
          - extractor1
          - claimant_name
          variable: claimant_name
        - value_selector:
          - extractor1
          - suspicious_notes
          variable: suspicious_notes
        - value_selector:
          - kr1
          - result
          variable: evidence
        outputs:
          result:
            type: object
            children: null
      height: 90
      id: code1
      position:
        x: 980
        y: 282
      type: custom
      width: 244
    - data:
        title: 終了
        type: end
        outputs:
        - value_selector:
          - code1
          - result
          variable: result
      height: 90
      id: end
      position:
        x: 1280
        y: 282
      type: custom
      width: 244
  hash: null
