ควบคุมข้อมูลมืดที่ไม่มีโครงสร้างด้วย Gemini และแคตตาล็อกความรู้

1. บทนำ

ข้อมูลขององค์กรกว่า 80% อยู่ในรูปแบบที่ไม่มีโครงสร้าง เช่น คู่มือวิศวกรรม PDF, ขั้นตอนการปฏิบัติงานมาตรฐาน (SOP), ใบรับรองการปฏิบัติตามข้อกำหนด และแผนผังอุปกรณ์ที่จัดเก็บไว้ใน Cloud Storage เนื่องจากแคตตาล็อกแบบเดิมจะจัดทำดัชนีเฉพาะสคีมาตารางเชิงสัมพันธ์ เอกสารเหล่านี้จึงยังคงเป็น "Dark Data" ซึ่งมองไม่เห็นในการค้นหาระดับองค์กร ไม่ได้เชื่อมต่อกับตารางสินค้าคงคลังที่มีโครงสร้าง และไม่ได้รับการยืนยันว่าสอดคล้องกับกฎระเบียบ

เมื่อผู้ตรวจสอบหรือ AI Agent ถามว่า "SKU ของฮาร์ดแวร์ใดบ้างที่ต้องมีการรับรองความปลอดภัย UL-153 และระดับอันตรายจากความร้อนของฮาร์ดแวร์เหล่านั้นคืออะไร" แคตตาล็อกที่จัดทำดัชนีเฉพาะตาราง SQL จะตอบคำถามไม่ได้ ข้อเท็จจริงจะอยู่ในไฟล์ PDF ที่ไม่มีโครงสร้างใน Cloud Storage

โซลูชันด้านสถาปัตยกรรม: ข้อมูลเมตาแบบหลายรูปแบบในรูปแบบโค้ด

ใน Codelab นี้ คุณจะได้สร้างไปป์ไลน์Metadata-as-Code แบบครบวงจรใน Google Cloud ซึ่งจะเปลี่ยนคู่มือ PDF ที่ไม่มีโครงสร้างใน Cloud Storage ให้เป็นชิ้นงาน Knowledge Catalog ที่บังคับใช้สคีมาโดยใช้ Gemini Enterprise Agent Platform (Google GenAI SDK, google-genai)

ขั้นตอนการกํากับดูแลข้อมูลมืดที่ไม่มีโครงสร้าง

  1. การลงทะเบียนชุดไฟล์ (EntryGroup และ Entry): จัดกลุ่ม PDF ที่ไม่มีโครงสร้างใน Cloud Storage เป็นรายการชุดไฟล์เชิงตรรกะที่มีการควบคุมใน Knowledge Catalog
  2. การแยกข้อมูลหลายรูปแบบของ Gemini (สคีมา Pydantic): เรียกใช้แพลตฟอร์ม Agent ของ Gemini Enterprise ในไบต์ PDF ดิบพร้อมการตรวจสอบที่กำหนดได้response_schema
  3. การเชื่อมโยงแง่มุมของ Control Plane: แนบเพย์โหลด JSON ด้านการปฏิบัติงานและการปฏิบัติตามข้อกำหนดที่ตรวจสอบแล้วเป็นอินสแตนซ์ Aspect ที่มีการพิมพ์อย่างเข้มงวดในรายการแคตตาล็อก
  4. การค้นพบแคตตาล็อกแบบรวม: ทำให้ชุดไฟล์ PDF ที่ไม่มีโครงสร้างและข้อมูลเมตาที่ดึงออกมาค้นพบได้ผ่าน SearchEntriesRequest

แนวคิดหลัก: Primitive ของ Control Plane ของ Knowledge Catalog

ลองนึกภาพว่าทีมของคุณจัดเก็บคู่มือผลิตภัณฑ์ในรูปแบบ PDF หลายร้อยรายการไว้ใน Cloud Storage หากต้องการให้ค้นหาและตรวจสอบไฟล์เหล่านั้นในแคตตาล็อกความรู้ได้ง่าย ให้คิดถึงองค์ประกอบที่ใช้สร้างสรรค์ทั้ง 5 อย่างเหมือนกับการจัดระเบียบคู่มือที่เป็นกระดาษในตู้เก็บเอกสารในสำนักงาน

  • EntryGroup (ตู้ล็อกสำหรับทีมเดียว): ตู้ที่มีล็อก เฉพาะเพื่อนร่วมทีมที่มีสิทธิ์ (roles/dataplex.entryCreator) เท่านั้นที่จะวางโฟลเดอร์ไว้ข้างในได้ คุณต้องนำทุกโฟลเดอร์ออกจากตู้ก่อนจึงจะนำตู้เองออกได้
  • EntryType (ป้ายกำกับหมวดหมู่โฟลเดอร์): ป้ายกำกับที่บอกให้ผู้ใช้ทราบว่าโฟลเดอร์แสดงถึงชิ้นงานประเภทใด เช่น "คอลเล็กชันคู่มือ PDF" แทนที่จะเป็น "ตารางฐานข้อมูล"
  • Entry (โฟลเดอร์ไฟล์ที่มีลิงก์พื้นที่เก็บข้อมูล): โฟลเดอร์แคตตาล็อกสำหรับคู่มือ PDF โฟลเดอร์จะเก็บการ์ดตำแหน่งที่ชี้ไปยังที่เก็บข้อมูล Cloud Storage (gs://...) ที่มีไฟล์ PDF จริงอยู่ แทนที่จะเก็บสำเนาที่เป็นกระดาษจำนวนมาก
  • AspectType (แบบฟอร์มรายการตรวจสอบเปล่า): แบบฟอร์มเปล่าที่นำกลับมาใช้ใหม่ได้พร้อมช่องที่พิมพ์ไว้ล่วงหน้า (เช่น "รายการตรวจสอบความปลอดภัย" ที่ขอ operational_hazard_level เป็นข้อความและ confidence_score เป็นตัวเลขจาก 0.0 ถึง 1.0) คุณสร้างแบบฟอร์มเปล่านี้เพียงครั้งเดียวและนำกลับมาใช้ใหม่ในโฟลเดอร์หลายพันโฟลเดอร์ได้
  • Aspect (รายการตรวจสอบที่กรอกข้อมูลครบถ้วนแล้วซึ่งแนบมากับโฟลเดอร์): หลังจากที่แพลตฟอร์ม Agent ของ Gemini Enterprise อ่านคู่มือ PDF และกรอกข้อมูลในช่องว่างแล้ว ระบบจะคลิปรายการตรวจสอบที่กรอกข้อมูลครบถ้วนแล้วนั้นไว้ในโฟลเดอร์ Entry เนื่องจากรายการตรวจสอบแต่ละรายการมีคีย์ของตัวเอง (aspect_keys) ทีมวิศวกรรมและทีมกฎหมายจึงสามารถแนบรายการตรวจสอบของตนเองลงในโฟลเดอร์เดียวกันได้โดยไม่ต้องเขียนทับงานของกันและกัน

แหล่งข้อมูลระดับภูมิภาคทั้ง 5 รายการจะอยู่ใน projects/{project}/locations/{location}/

เส้นทางแบบสัมบูรณ์และแบบสัมพัทธ์

บทบาทใน Knowledge Catalog

การลบและกฎ IAM

EntryGroup
.../entryGroups/{id}

คอนเทนเนอร์เชิงตรรกะที่จัดกลุ่มรายการและควบคุมการเข้าถึงของทีม (roles/dataplex.entryCreator)

ต้องไม่มีEntryทรัพยากรย่อยก่อนลบ

EntryType
.../entryTypes/{id}

คำจำกัดความหมวดหมู่สำหรับคลาสของชิ้นงาน (entry.entry_type เช่น ชุดไฟล์ PDF ที่ไม่มีโครงสร้าง)

ลบได้หลังจากนำรายการทั้งหมดที่ใช้ประเภทนี้ออกแล้วเท่านั้น

Entry (ชุดไฟล์)
.../entries/{entry_id}

ระเบียนแคตตาล็อกที่ลิงก์ URI ของ Cloud Storage จริง (entry_source.resource) กับชื่อเชิงตรรกะ (gcs:{bucket})

อยู่ใน EntryGroup และมีบันทึก Aspect ที่แนบมา

AspectType
.../aspectTypes/{id}

เทมเพลตสคีมาที่นำกลับมาใช้ใหม่ได้ซึ่งกำหนด record_fields ที่พิมพ์ (string, enum, double) และหมายเลขฟิลด์ที่อิงตาม 1 (index)

สร้างครั้งเดียวต่อภูมิภาคและแชร์ในรายการต่างๆ

Aspect
Entry.aspects[key]

ข้อมูลเมตา JSON ที่ผ่านการตรวจสอบซึ่งตรงกับ AspectType ที่แนบมากับ Entry ผ่าน UpdateEntryRequest

อัปเดตโดยใช้ update_mask และ aspect_keys เพื่อไม่ให้ไปเขียนทับไปป์ไลน์อื่น

สิ่งที่คุณจะสร้าง

การใช้สคริปต์เสริมใน codelabs/metadata-as-code-lab คุณจะเรียกใช้และตรวจสอบไปป์ไลน์ 7 ขั้นตอนได้

  1. schemas.py — สคีมา Pydantic BaseModel แบบคู่ (DarkDataExtractedMetadata และ DocumentGovernanceMetadata) ที่จับคู่แบบ 1:1 กับเทมเพลต Knowledge Catalog AspectType
  2. step2_provision.py — การจัดสรรแบบนิจพลของพิมพ์เขียว EntryGroup, EntryType และ AspectType
  3. step3_register_fileset.py — อัปโหลด LUM-LIG-DES-8G8J_manual.pdf ไปยัง Cloud Storage และลงทะเบียนเป็น Fileset ที่มีการควบคุม Entry
  4. step4_extract_metadata.py - การค้นหาโมเดล Gemini เรือธงแบบไดนามิกและการแยก PDF แบบมัลติโมดัลโดยใช้ google-genai
  5. step5_attach_aspects.py, step6_search_catalog.py และ step7_verify_assertions.py - การแนบแง่มุมการผ่าตัด การค้นหาแคตตาล็อกแบบ Exponential Backoff และการยืนยันระนาบควบคุมแบบครบวงจร

สิ่งที่ต้องดำเนินการก่อนและสิ่งที่คุณต้องมี

  • โปรเจ็กต์ Google Cloud ที่เปิดใช้การเรียกเก็บเงินและ Google Cloud Shell (ติดตั้ง gcloud, git, python3 และ pip ไว้ล่วงหน้า)
  • สิทธิ์ IAM ในการจัดการทรัพยากร Knowledge Catalog (roles/dataplex.admin) จัดสรร Bucket และออบเจ็กต์ Cloud Storage (roles/storage.admin) และเรียกใช้ Gemini Enterprise Agent Platform (roles/aiplatform.user)
  • เว็บเบราว์เซอร์ เช่น Google Chrome

2. การตั้งค่าและข้อกำหนด

โคลนที่เก็บคู่ใน Cloud Shell

เปิดคอนโซล Google Cloud เปิดใช้ Cloud Shell และทำการชำระเงินแบบ Sparse ของ codelabs/metadata-as-code-lab ซึ่งรวมถึงคู่มือวิศวกรรม PDF ตัวอย่าง (LUM-LIG-DES-8G8J_manual.pdf) และสคริปต์ Python ทั้งหมด

git clone --branch main --depth 1 --filter=blob:none --sparse \
  https://github.com/GoogleCloudPlatform/devrel-demos.git
cd devrel-demos
git sparse-checkout set codelabs/metadata-as-code-lab
cd codelabs/metadata-as-code-lab
ls -la

กำหนดค่าตัวแปรสภาพแวดล้อม

ตั้งค่ารหัสโปรเจ็กต์ ตำแหน่งของ Control Plane ระดับภูมิภาค และ Bucket Cloud Storage เป้าหมายใน Cloud Shell โดยทำดังนี้

export PROJECT_ID="${PROJECT_ID:-$(gcloud config get-value project)}"
gcloud config set project $PROJECT_ID

export REGION="us-central1"
export BUCKET_NAME="${PROJECT_ID}-dark-data-manuals"
export GEMINI_LOCATION="global"

echo "Configured Project ID        : $PROJECT_ID"
echo "Knowledge Catalog Region     : $REGION"
echo "Gemini Endpoint Location     : $GEMINI_LOCATION"
echo "Target Cloud Storage Bucket  : $BUCKET_NAME"

เปิดใช้ API และติดตั้งการขึ้นต่อกัน

เปิดใช้ API ของ Google Cloud ที่จำเป็นและติดตั้งการอ้างอิง Python (google-genai, google-cloud-dataplex, pydantic และ pandas) จาก requirements.txt

gcloud services enable \
  dataplex.googleapis.com \
  storage.googleapis.com \
  aiplatform.googleapis.com \
  --quiet
python3 -m pip install --upgrade --quiet --user --break-system-packages -r requirements.txt

3. กำหนดสคีมา Pydantic และเทมเพลตแง่มุม

schemas.py กำหนดสัญญาเสริม 2 ฉบับที่จับคู่การตรวจสอบ Pydantic ฝั่งไคลเอ็นต์กับเทมเพลตแคตตาล็อกความรู้ AspectTypeฝั่งเซิร์ฟเวอร์ ดังนี้

  1. DarkDataExtractedMetadata: แอตทริบิวต์การปฏิบัติงานที่ดึงมาจาก PDF (ชื่อเอกสาร ออนโทโลยีโดเมน ระดับอันตรายด้านความปลอดภัย แหล่งที่มาของการเขียน/เวอร์ชัน ข้อมูลสรุปสำหรับผู้บริหาร และคะแนนความเชื่อมั่นในการแยกข้อมูล)
  2. DocumentGovernanceMetadata: รหัสการปฏิบัติตามกฎระเบียบ (UL-153, FCC Part 15, CE-LVD, RoHS), เจ้าของความรับผิดชอบ, นโยบายการเก็บรักษา และสตริงตัวระบุตารางอ้างอิง (lakehouse_cross_ref_table) สำหรับการลิงก์คู่มือ PDF กับตารางสินค้าคงคลังดาวน์สตรีม

ตรวจสอบ schemas.py

ก่อนอื่น DarkDataExtractedMetadata ใช้ข้อจำกัดของ Pydantic Field (ge=0.0, le=1.0 ซึ่งหมายถึงมากกว่า/น้อยกว่าหรือเท่ากับใน confidence_score) เพื่อจำกัดเอาต์พุต JSON ของแพลตฟอร์ม Gemini Enterprise Agent ดังนี้

class DarkDataExtractedMetadata(BaseModel):
    document_title: str = Field(
        description="Official document title or product model name extracted from the PDF manual."
    )
    # ... domain_ontology, operational_hazard_level, author_provenance ...
    version_provenance: str = Field(
        description="Document version, revision code, or publication standard identifier."
    )
    # ... document_summary ...
    confidence_score: float = Field(
        ge=0.0,
        le=1.0,
        description="AI extraction confidence metric between 0.0 and 1.0.",
    )

ประการที่สอง extracted_aspect_template จะทำซ้ำชื่อฟิลด์ที่แน่นอนเหล่านั้นและแมปประเภท str และ float ของ Python กับ string และ double ของ Knowledge Catalog record_fields โปรดทราบว่าสัญญา Protobuf ของ AspectType.MetadataTemplate กำหนดให้ทุกฟิลด์ใน record_fields ต้องประกาศจำนวนเต็มฐาน 1 ที่ไม่ซ้ำกันและเป็นบวกอย่างเคร่งครัด index (1 ถึง 7) การละเว้นหรือทำซ้ำ index จะทำให้ create_aspect_type ล้มเหลวโดยมี 400 INVALID_ARGUMENT ดังนี้

extracted_aspect_template = {
    "name": "DarkDataExtractedMetadata",
    "type": "record",
    "record_fields": [
        {
            "name": "document_title",
            "type": "string",
            "index": 1,
            "annotations": {"description": "Official document title or product model name."},
        },
        # ... fields 2 through 6 (string) ...
        {
            "name": "confidence_score",
            "type": "double",
            "index": 7,
            # ... annotations ...
        },
    ],
}

ตรวจสอบโมดูลสคีมา

เรียกใช้ schemas.py เพื่อยืนยันการกำหนดค่าสภาพแวดล้อมและคอมไพล์ทั้ง 2 สคีมา

python3 schemas.py
Configured Project ID         : your-project-id
Knowledge Catalog Region      : us-central1
Gemini Endpoint Location      : global
Governed Fileset Storage URI  :
  gs://your-project-id-dark-data-manuals/sop-pdfs/LUM-LIG-DES-8G8J_manual.pdf
Target Fileset Entry ID       : sop-manuals-fileset-lum8g8j
✓ Defined DarkDataExtractedMetadata and DocumentGovernanceMetadata
  Pydantic schemas.
✓ Prepared Knowledge Catalog AspectType metadata templates.

4. จัดสรรเนมสเปซและประเภทแง่มุมที่กำหนดเอง

ก่อนลงทะเบียนรายการชุดไฟล์หรือแนบข้อมูลเมตา step2_provision.py จะจัดสรรทรัพยากรระนาบควบคุม 3 รายการในแคตตาล็อกความรู้ ดังนี้

  • EntryGroup: dark-data-fileset-group
  • EntryType: unstructured-pdf-fileset
  • AspectType Blueprint: dark-data-extracted-metadata และ document-governance-aspect

การจัดสรรที่ไม่มีผลข้างเคียงใน step2_provision.py

การเรียกใช้การสร้างแต่ละครั้งใน step2_provision.py จะห่อหุ้มการดำเนินการที่ใช้เวลานาน (op.result()) ไว้ในบล็อก try / except AlreadyExists เพื่อให้สคริปต์สามารถเรียกใช้ซ้ำได้อย่างปลอดภัยโดยไม่ล้มเหลวกับทรัพยากรที่มีอยู่

# Provision AspectType 1: dark-data-extracted-metadata
try:
    at1_op = catalog_client.create_aspect_type(
        parent=parent_location,
        aspect_type_id=EXTRACTED_ASPECT_TYPE_ID,
        aspect_type=AspectType(
            name=extracted_aspect_type_name,
            display_name="Dark Data Multimodal Extracted Metadata",
            # ... description ...
            metadata_template=extracted_aspect_template,
        ),
    )
    if hasattr(at1_op, "result"):
        at1_op.result()
    print(f"Created AspectType: {extracted_aspect_type_name}")
except AlreadyExists:
    print(f"AspectType already exists; retrieving live resource: {extracted_aspect_type_name}")

live_extracted_aspect_type = catalog_client.get_aspect_type(name=extracted_aspect_type_name)

เมื่อลงทะเบียน metadata_template=extracted_aspect_template แล้ว Knowledge Catalog จะบังคับใช้สคีมาที่ขอบเขต API โดยจะปฏิเสธการเรียกใช้ update_entry() ครั้งต่อๆ ไปที่ส่งสตริงไปยัง confidence_score (double)

เรียกใช้ step2_provision.py

เรียกใช้สคริปต์การจัดสรรและยืนยันว่าได้ลงทะเบียนประเภทแง่มุมที่กำหนดเองในภูมิภาคของคุณแล้ว

python3 step2_provision.py
gcloud dataplex aspect-types list --location=$REGION
Created EntryGroup:
  projects/your-project-id/locations/us-central1/entryGroups/
  dark-data-fileset-group
Created EntryType :
  projects/your-project-id/locations/us-central1/entryTypes/
  unstructured-pdf-fileset
Created AspectType:
  projects/your-project-id/locations/us-central1/aspectTypes/
  dark-data-extracted-metadata
Created AspectType:
  projects/your-project-id/locations/us-central1/aspectTypes/
  document-governance-aspect
✓ All Knowledge Catalog namespaces and AspectType blueprints are active.

5. ลงทะเบียนรายการไฟล์เซ็ตที่ไม่มีโครงสร้าง

แคตตาล็อกความรู้จะจัดกลุ่มเอกสารที่เกี่ยวข้องใน Cloud Storage (gs://YOUR_BUCKET/sop-pdfs/*.pdf) เป็นรายการชุดไฟล์เชิงตรรกะแทนที่จะทำให้แคตตาล็อกรกด้วยตัวชี้ไฟล์ที่แยกกันนับล้านรายการ ไม่ว่าจะผ่านการสแกนการค้นพบอัตโนมัติ (DataScanServiceClient) หรือการลงทะเบียนแบบเป็นโปรแกรมโดยตรง (CatalogServiceClient.create_entry)

วิธีที่ step3_register_fileset.py แมปพื้นที่เก็บข้อมูลกับแคตตาล็อก

step3_register_fileset.pyอัปโหลด LUM-LIG-DES-8G8J_manual.pdf ไปยัง gs://${BUCKET_NAME}/sop-pdfs/LUM-LIG-DES-8G8J_manual.pdf และลงทะเบียน Entry ที่มีการกำกับดูแล

fully_qualified_fileset_uri = f"gcs:{BUCKET_NAME}"
fileset_entry_spec = Entry(
    name=fileset_entry_name,
    entry_type=entry_type_resource_name,
    fully_qualified_name=fully_qualified_fileset_uri,
    entry_source=EntrySource(
        resource=VIRTUAL_STORAGE_URI,
        system="Cloud Storage",
        platform="Google Cloud",
        display_name="LUM-LIG-DES-8G8J Unstructured SOP & Technical Manual Fileset",
        # ... description ...
        location=REGION,
    ),
)

create_entry_op = catalog_client.create_entry(
    parent=entry_group_resource_name,
    entry_id=FILESET_ENTRY_ID,
    entry=fileset_entry_spec,
)

โปรดสังเกตบทบาทที่แตกต่างกันของฟิลด์ URI ทั้ง 2 รายการใน Entry

  • fully_qualified_name=fully_qualified_fileset_uri (f"gcs:{BUCKET_NAME}"): ใช้รูปแบบ gcs:{bucket_name} FQN ที่เป็น Canonical ซึ่ง Knowledge Catalog กำหนดให้ใช้เพื่อเชื่อมโยงรายการแคตตาล็อกเชิงตรรกะกับที่เก็บข้อมูล Cloud Storage ที่อยู่เบื้องหลัง
  • entry_source.resource=VIRTUAL_STORAGE_URI: จัดเก็บ URI ของออบเจ็กต์ gs:// จริงที่ผู้ปฏิบัติงานการแยกข้อมูลดาวน์สตรีมตรวจสอบ

เรียกใช้ step3_register_fileset.py

python3 step3_register_fileset.py
Created Cloud Storage bucket:
  gs://your-project-id-dark-data-manuals in us-central1
Uploaded unstructured PDF manual to:
  gs://your-project-id-dark-data-manuals/sop-pdfs/LUM-LIG-DES-8G8J_manual.pdf
Registered governed Fileset Entry:
  projects/your-project-id/locations/us-central1/entryGroups/
  dark-data-fileset-group/entries/sop-manuals-fileset-lum8g8j
  -> Fully Qualified Name : gcs:your-project-id-dark-data-manuals
  -> Physical Resource URI:
  gs://your-project-id-dark-data-manuals/sop-pdfs/LUM-LIG-DES-8G8J_manual.pdf
  -> Source System        : Cloud Storage

6. แยกข้อมูลเมตาของเอกสารด้วย Gemini

step4_extract_metadata.py จะอ่านไบต์ PDF ดิบและเรียกใช้แพลตฟอร์ม Agent ของ Gemini Enterprise (genai_client.models.generate_content) โดยใช้รูปแบบสำคัญ 2 รูปแบบ ได้แก่

1. การค้นหารุ่นเรือธงแบบไดนามิก

สคริปต์จะค้นหา genai_client.models.list() และจัดเรียงโมเดลที่ใช้งานอยู่ตาม (is_ga_channel, semantic_version_tuple) เพื่อเลือกโมเดล flash ที่พร้อมให้บริการแก่บุคคลทั่วไป (GA) รุ่นล่าสุดแทนที่จะเขียนสตริงเวอร์ชันของโมเดลที่เปราะบางลงในโค้ด

genai_client = genai.Client(
    vertexai=True,
    project=PROJECT_ID,
    location=GEMINI_LOCATION,
)

for model_obj in genai_client.models.list():
    raw_id = (model_obj.name or "").split("/")[-1]
    # Filter to flagship Gemini Flash models (version >= 3.0) and prioritize GA over preview
    ...
    discovered_candidates.append((is_ga_channel, ver_tuple, raw_id))

discovered_candidates.sort(key=lambda item: (item[0], item[1]), reverse=True)

2. การแยกข้อมูลมัลติโมดัลที่จำกัดด้วยสคีมา (Part.from_bytes + response_schema)

การส่ง response_mime_type="application/json" และ response_schema=DarkDataExtractedMetadata (ตามด้วย DocumentGovernanceMetadata) จะจำกัดการถอดรหัสโทเค็นโดยตรงไปยังสคีมา JSON ของ Pydantic ดังนี้

with open(LOCAL_PDF_PATH, "rb") as pdf_file:
    raw_pdf_bytes = pdf_file.read()

extraction_response = genai_client.models.generate_content(
    model=candidate_model,
    contents=[
        types.Part.from_bytes(data=raw_pdf_bytes, mime_type="application/pdf"),
        extraction_prompt,
    ],
    config=types.GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=DarkDataExtractedMetadata,
        temperature=0.1,
    ),
)

extracted_dark_data = json.loads(extraction_response.text)
validated_extraction = DarkDataExtractedMetadata(**extracted_dark_data)

เรียกใช้ step4_extract_metadata.py

python3 step4_extract_metadata.py
Dynamically discovered active GA model currency :
  gemini-3.8-flash (version (3, 8))
Loaded unstructured PDF manual at: LUM-LIG-DES-8G8J_manual.pdf
Read unstructured PDF document (1184 bytes).
  Executing multimodal extraction with gemini-3.8-flash...
✓ Multimodal extraction completed using model: gemini-3.8-flash
✓ Governance classification completed using model: gemini-3.8-flash

--- Extracted Multimodal Operational Metadata ---
Extracted Attribute    Multimodal Value
document_title    LUM-LIG-DES-8G8J Contemporary Linen Desk Lamp
domain_ontology    Electrical Hardware & Lighting Systems
operational_hazard_level    MEDIUM
author_provenance    Global Hardware Safety & Lighting Systems Engin
version_provenance    Rev 4.2
document_summary    This document outlines standard operating proce
confidence_score    0.99

--- Extracted Governance & Inventory Cross-Reference Metadata ---
Governance Attribute    Classification Value
compliance_classifications    UL-153 Portable Luminaires, FCC Part 15, CE-LVD
stewardship_owner    Global Hardware Safety & Lighting Systems Engin
retention_policy    10-Year Active Product Lifecycle Archival
lakehouse_cross_ref_table    lakehouse.your-project-id.retail_hardware
governance_status    VERIFIED_PRODUCTION

7. แนบแง่มุมที่ตรวจสอบแล้วกับข้อมูลแคตตาล็อก

step5_attach_aspects.py จะเชื่อมโยงเพย์โหลด JSON ที่ตรวจสอบแล้ว (extracted_metadata.json และ governance_metadata.json) กับรายการ sop-manuals-fileset-lum8g8j ผ่าน catalog_client.update_entry()

การเปลี่ยนแปลงลักษณะการผ่าตัดใน step5_attach_aspects.py

extracted_aspect_key = f"{PROJECT_ID}.{REGION}.{EXTRACTED_ASPECT_TYPE_ID}"
governance_aspect_key = f"{PROJECT_ID}.{REGION}.{GOVERNANCE_ASPECT_TYPE_ID}"

updated_entry_payload = Entry(
    name=fileset_entry_name,
    entry_type=entry_type_resource_name,
    fully_qualified_name=fully_qualified_fileset_uri,
    aspects={
        extracted_aspect_key: Aspect(
            aspect_type=extracted_aspect_type_name,
            data=extracted_data,
        ),
        governance_aspect_key: Aspect(
            aspect_type=governance_aspect_type_name,
            data=governance_data,
        ),
    },
)

update_op = catalog_client.update_entry(
    request=dataplex_v1.UpdateEntryRequest(
        entry=updated_entry_payload,
        update_mask={"paths": ["aspects"]},
        aspect_keys=[extracted_aspect_key, governance_aspect_key],
    )
)

การส่งทั้งขอบเขต update_mask={"paths": ["aspects"]} และ aspect_keys=[extracted_aspect_key, governance_aspect_key] จะจำกัดการเปลี่ยนแปลงอย่างเคร่งครัดไว้ที่คีย์ของ 2 ด้านนี้ โดยจะไม่แตะต้อง entry_source และแง่มุมใดๆ ที่เป็นของทีมอื่นๆ

เรียกใช้ step5_attach_aspects.py

python3 step5_attach_aspects.py
Successfully bound 2 Aspect(s) to Entry:
  projects/your-project-id/locations/us-central1/entryGroups/
  dark-data-fileset-group/entries/sop-manuals-fileset-lum8g8j

=== Live Attached Aspect: document-governance-aspect ===
Catalog Field    Authoritative Stored Value
compliance_classifications    UL-153 Portable Luminaires, FCC Part 15, CE-LVD
stewardship_owner    Global Hardware Safety & Lighting Systems Engin
retention_policy    10-Year Active Product Lifecycle Archival
lakehouse_cross_ref_table    lakehouse.your-project-id.retail_hardware
governance_status    VERIFIED_PRODUCTION

=== Live Attached Aspect: dark-data-extracted-metadata ===
Catalog Field    Authoritative Stored Value
document_title    LUM-LIG-DES-8G8J Contemporary Linen Desk Lamp
domain_ontology    Electrical Hardware & Lighting Systems
operational_hazard_level    MEDIUM
author_provenance    Global Hardware Safety & Lighting Systems Engin
version_provenance    Rev 4.2
document_summary    This document outlines standard operating proce
confidence_score    0.99

การยืนยันแบบ 2 เส้นทาง

  • แทร็ก 1 (การยืนยัน CLI): ตรวจสอบรายการที่มีแง่มุมทั้งหมดที่แนบมาผ่าน gcloud:
    gcloud dataplex entries describe sop-manuals-fileset-lum8g8j \
      --entry-group=dark-data-fileset-group \
      --location=$REGION \
      --view=ALL
    
  • แทร็กที่ 2 (การตรวจสอบ UI ของคอนโซล):
    1. เปิด Search Console ของแคตตาล็อกความรู้ ค้นหา LUM-LIG-DES-8G8J Unstructured SOP & Technical Manual Fileset (sop-manuals-fileset-lum8g8j) แล้วเลือกรายการที่ตรงกันจากผลการค้นหา
    2. ในส่วนแท็กและแง่มุมที่ไม่บังคับ ให้ตรวจสอบว่าทั้งข้อมูลเมตาที่แยกจากข้อมูลมืดแบบมัลติโมดัลและแง่มุมการกำกับดูแลเอกสารและการอ้างอิงโยงสินค้าคงคลังแสดงระดับอันตราย (MEDIUM), รหัสการปฏิบัติตามข้อกำหนด (UL-153, FCC Part 15, CE-LVD, RoHS) และสตริงตารางการอ้างอิงโยง (lakehouse_cross_ref_table)

8. ค้นหาข้อมูลมืดที่มีการควบคุมในแคตตาล็อก

เมื่อแนบแง่มุมที่กำหนดเองแล้ว คู่มือ PDF ที่ไม่มีโครงสร้างใน Cloud Storage จะค้นพบได้ผ่านการค้นหาในแคตตาล็อกความรู้ (catalog_client.search_entries())

การสำรวจ search_entries() ใน step6_search_catalog.py

step6_search_catalog.py polls search_entries() โดยใช้ Exponential Backoff และอ่านคีย์แง่มุมที่กำหนดหน้า Canonical ผ่าน .endswith():

search_query = f"entrygroup={entry_group_resource_name} name:{FILESET_ENTRY_ID}"

while elapsed_seconds < max_wait_seconds:
    catalog_search_results = list(
        catalog_client.search_entries(
            request=dataplex_v1.SearchEntriesRequest(
                name=parent_location,
                query=search_query,
            )
        )
    )
    if catalog_search_results:
        break
    backoff_seconds = min(5 * (2 ** attempt), 30)
    time.sleep(backoff_seconds)
    ...

for k, asp in detailed_entry.aspects.items():
    if k.endswith(f".{REGION}.{EXTRACTED_ASPECT_TYPE_ID}"):
        print(f"    Domain Ontology     : {asp.data.get('domain_ontology')}")
        print(f"    Hazard Level        : {asp.data.get('operational_hazard_level')}")
    elif k.endswith(f".{REGION}.{GOVERNANCE_ASPECT_TYPE_ID}"):
        print(f"    Compliance Codes    : {asp.data.get('compliance_classifications')}")
        print(f"    Lakehouse Join Table: {asp.data.get('lakehouse_cross_ref_table')}")

เรียกใช้ step6_search_catalog.py

python3 step6_search_catalog.py
Executing Knowledge Catalog search query:
  'entrygroup=projects/your-project-id/locations/us-central1/entryGroups/
  dark-data-fileset-group name:sop-manuals-fileset-lum8g8j'...

✓ Discovered 1 governed asset(s) in Knowledge Catalog:

[1] Entry Resource Name :
    projects/your-project-id/locations/us-central1/entryGroups/
    dark-data-fileset-group/entries/sop-manuals-fileset-lum8g8j
    Fully Qualified Name: gcs:your-project-id-dark-data-manuals
    Entry Type :
    projects/your-project-id/locations/us-central1/entryTypes/
    unstructured-pdf-fileset
    Physical Storage URI:
    gs://your-project-id-dark-data-manuals/sop-pdfs/LUM-LIG-DES-8G8J_manual.pdf
    Domain Ontology     : Electrical Hardware & Lighting Systems
    Hazard Level        : MEDIUM
    Compliance Codes    : UL-153 Portable Luminaires, FCC Part 15, CE-LVD, RoHS
    Lakehouse Join Table:
    lakehouse.your-project-id.retail_hardware.luminaire_sku_inventory_iceberg

การยืนยันแบบ 2 เส้นทาง

  • แทร็ก 1 (การค้นหา CLI): ค้นหาดัชนีการค้นหาโดยตรงผ่าน gcloud
    gcloud dataplex entries search "name:sop-manuals-fileset-lum8g8j" --project=$PROJECT_ID
    
  • แทร็กที่ 2 (การค้นหาด้วยภาษาธรรมชาติใน UI ของคอนโซล):
    1. เปิด Search Console ของแคตตาล็อกความรู้ แล้วค้นหา LUM-LIG-DES-8G8J หรือ UL-153
    2. ดูวิธีที่ Knowledge Catalog แสดงรายการชุดไฟล์ PDF ของ Cloud Storage ที่มีการควบคุมและลักษณะข้อมูลเมตาที่แนบมา

9. ยืนยันการยืนยันการกำกับดูแลแบบครบวงจร

step7_verify_assertions.py เรียกใช้การยืนยันที่กำหนดได้กับคำตอบของระนาบควบคุม แคตตาล็อกความรู้ แบบเรียลไทม์เพื่อยืนยันว่า EntryGroup, EntryType, ทั้งพิมพ์เขียวที่กำหนดเอง AspectType, เพย์โหลดของแง่มุมที่เชื่อมโยง EntryView.ALL (ขอบเขต confidence_score และสตริง lakehouse_cross_ref_table) และการค้นพบดัชนีการค้นหาทั้งหมดสำเร็จ:

verify_eg = catalog_client.get_entry_group(name=entry_group_resource_name)
assert verify_eg.name == entry_group_resource_name, "EntryGroup resource name mismatch."

verify_entry = catalog_client.get_entry(
    request=dataplex_v1.GetEntryRequest(
        name=fileset_entry_name,
        view=dataplex_v1.EntryView.ALL,
    )
)
bound_extracted = next(
    (
        asp for k, asp in verify_entry.aspects.items()
        if k.endswith(f".{REGION}.{EXTRACTED_ASPECT_TYPE_ID}")
    ),
    None,
)
bound_governance = next(
    (
        asp for k, asp in verify_entry.aspects.items()
        if k.endswith(f".{REGION}.{GOVERNANCE_ASPECT_TYPE_ID}")
    ),
    None,
)

assert bound_extracted is not None, f"Aspect '{EXTRACTED_ASPECT_TYPE_ID}' not found on live Entry."
assert bound_governance is not None, (
    f"Aspect '{GOVERNANCE_ASPECT_TYPE_ID}' not found on live Entry."
)
assert (
    bound_extracted.data.get("document_title") == expected_extraction["document_title"]
), "Extracted title mismatch."
assert (
    0.0 <= float(bound_extracted.data.get("confidence_score", -1.0)) <= 1.0
), "Invalid confidence score in catalog."
assert (
    "lakehouse" in str(bound_governance.data.get("lakehouse_cross_ref_table", "")).lower()
), "Missing Lakehouse cross-reference."
...
assert len(search_results) >= 1, "Expected at least 1 search result in Knowledge Catalog."

เรียกใช้ step7_verify_assertions.py

python3 step7_verify_assertions.py && echo "Verification exit code: $?"
Running substantive end-to-end verification assertions...
✓ All 5 substantive verification assertions passed
  against live Google Cloud control plane state!
Verification exit code: 0

10. ออกแบบไปป์ไลน์ที่ขับเคลื่อนด้วยเหตุการณ์

แม้ว่าการเรียกใช้สคริปต์ Python แบบอินเทอร์แอกทีฟใน Cloud Shell จะเหมาะสำหรับการสร้างและทดสอบสัญญาการกำกับดูแล แต่สภาพแวดล้อมขององค์กรจะได้รับคู่มือวิศวกรรม PDF ใหม่หรือที่แก้ไขแล้ว ใบรับรองการปฏิบัติตามข้อกำหนดของซัพพลายเออร์ และเอกสาร SOP หลายพันรายการทุกวันจาก ERP, Product Lifecycle Management (PLM) และพอร์ทัลของผู้ให้บริการ การเรียกใช้สคริปต์แบบกลุ่มด้วยตนเองจะสร้างจุดบอดด้านการกำกับดูแลระหว่างการอัปโหลดเอกสารและการจัดทำดัชนีแคตตาล็อกอย่างรวดเร็ว

ในสภาพแวดล้อมการใช้งานจริง ทีมแพลตฟอร์มจะดำเนินการกับโค้ดที่แน่นอนที่คุณรันในขั้นตอนที่ 4 และ 5 เป็นไปป์ไลน์แบบไม่ต้องดำเนินการใดๆ และขับเคลื่อนด้วยเหตุการณ์ ดังนี้

Data Pipeline สำหรับ Dark Data ที่ขับเคลื่อนด้วยเหตุการณ์

  1. การนำเข้าเอกสารอย่างต่อเนื่อง (Cloud Storage → Eventarc): เมื่อใดก็ตามที่มีการอัปโหลดคู่มือ PDF ใหม่หรือการแก้ไขใหม่เขียนทับออบเจ็กต์ที่มีอยู่ใน Cloud Storage Bucket จะปล่อย CloudEvent google.cloud.storage.object.v1.finalized ที่มีตัวระบุ Bucket, เส้นทางออบเจ็กต์ และหมายเลขออบเจ็กต์รุ่น
  2. การแยกข้อมูลหลายรูปแบบแบบไม่เก็บสถานะ (Eventarc → Cloud Run → Gemini Enterprise Agent Platform): Eventarc จะกำหนดเส้นทาง CloudEvent ไปยัง Worker Cloud Run แบบไร้เซิร์ฟเวอร์ที่แพ็กเกจ schemas.py, step4_extract_metadata.py และ step5_attach_aspects.py Worker จะสตรีมไบต์ PDF ไปยังแพลตฟอร์ม Agent ของ Gemini Enterprise โดยมีresponse_schemaบังคับใช้ ซึ่งรับประกันว่าแอตทริบิวต์ที่แยกออกมาทั้งหมดจะเป็นไปตาม DarkDataExtractedMetadata และ DocumentGovernanceMetadata
  3. การอัปเดตระนาบควบคุมการผ่าตัด (Cloud Run → Knowledge Catalog): Worker จะแก้ไข Fileset หลัก Entry และเรียกใช้ catalog_client.update_entry() ด้วย update_mask={"paths": ["aspects"]} และ aspect_keys ที่ชัดเจน แม้ว่าเอกสารหลายสิบฉบับจะประมวลผลเสร็จพร้อมกัน แต่การเปลี่ยนแปลงแต่ละครั้งจะอัปเดตเฉพาะคีย์แง่มุมที่กำหนดเท่านั้น
  4. การกักกันผู้ดูแลที่มีความน่าเชื่อถือ: หาก PDF เดิมที่สแกนแล้วให้ผลลัพธ์การแยกข้อมูล confidence_score ต่ำกว่าเกณฑ์การปฏิบัติงาน (เช่น < 0.85) ผู้ปฏิบัติงานจะตั้งค่า governance_status = "PENDING_STEWARD_REVIEW" ในแง่มุมที่แนบมาเพื่อให้ผู้ดูแลข้อมูลสามารถค้นหา Knowledge Catalog สำหรับชิ้นงานที่มีความน่าเชื่อถือต่ำซึ่งต้องมีการตรวจสอบจากเจ้าหน้าที่

วิธีที่องค์กรใช้รูปแบบนี้ในการใช้งานจริง

กรณีการใช้งานระดับองค์กร

วิธีการทำงานของข้อมูลเมตาเป็นโค้ดในทางปฏิบัติ

ผลกระทบทางธุรกิจและการปฏิบัติงาน

การตรวจสอบด้านกฎระเบียบอัตโนมัติและความพร้อมในการเรียกคืน
(การผลิต ฮาร์ดแวร์ และพลังงาน)

ระบบการปฏิบัติตามข้อกำหนดจะรวมด้านความปลอดภัยของ PDF ที่ไม่มีโครงสร้าง (compliance_classifications, operational_hazard_level) กับตารางสินค้าคงคลัง SKU ที่มีโครงสร้าง (lakehouse_cross_ref_table) ใน BigQuery และ Lakehouse สำหรับ Apache Iceberg

เมื่อมีการอัปเดตมาตรฐาน เช่น UL-153 หรือ CE-LVD ผู้ตรวจสอบจะระบุ SKU ของฮาร์ดแวร์และสถานที่ตั้งของคลังสินค้าที่ได้รับผลกระทบทั้งหมดได้ในไม่กี่วินาที แทนที่จะต้องเปิดโฟลเดอร์ PDF หลายพันโฟลเดอร์ด้วยตนเอง

เอเจนต์ AI ที่อิงตามข้อมูลจริงและการกรองล่วงหน้าของ RAG
(ผู้ช่วยความรู้สำหรับองค์กร)

ก่อนที่ Agent แบบ Retrieval Augmented Generation (RAG) ในแพลตฟอร์ม Agent ของ Gemini Enterprise จะตอบคำถามของวิศวกรภาคสนาม Agent จะกรองรายการแคตตาล็อกความรู้ตาม governance_status = "VERIFIED_PRODUCTION" และ version_provenance

ป้องกันไม่ให้ผู้ช่วย AI สร้างข้อมูลที่ไม่ถูกต้องหรืออ้างอิงร่างวิศวกรรมที่เลิกใช้งานแล้ว, SOP ที่หมดอายุ หรือคู่มือของบุคคลที่สามที่ยังไม่ได้รับการยืนยัน

การเพิ่มคุณค่าแบบพร้อมกันหลายทีม
(Data Mesh แบบกระจายอำนาจ)

ไปป์ไลน์อิสระหลายรายการจะเพิ่มคุณค่าให้กับชุดไฟล์เดียวกัน Entry: ผู้ปฏิบัติงานด้านวิศวกรรม AI จะอัปเดต dark-data-extracted-metadata ฝ่ายกฎหมายจะแนบนโยบายการเก็บรักษาผ่าน document-governance-aspect และฝ่ายรักษาความปลอดภัยจะแนบแง่มุมด้านความละเอียดอ่อนของ DLP

เนื่องจากUpdateEntryRequestมีการเปลี่ยนแปลงขอบเขตผ่าน aspect_keys ทีมโดเมนแต่ละทีมจึงติดตั้งใช้งานและอัปเดตไปป์ไลน์ข้อมูลเมตาของตนเองได้อย่างอิสระโดยไม่ต้องเขียนทับข้อมูลการกำกับดูแลของทีมอื่นๆ

การพัฒนาสคีมา CI/CD ผ่าน GitOps
(วิศวกรรมแพลตฟอร์มและข้อมูล)

ทีมแพลตฟอร์มจัดเก็บschemas.pyควบคู่ไปกับคำจำกัดความของ Terraform google_dataplex_aspect_type ใน Git คำขอ Pull จะตรวจสอบว่าฟิลด์ Pydantic ใหม่มีindexที่ตรงกันซึ่งอิงตาม 1 ในเทมเพลต AspectType ก่อนการติดตั้งใช้งาน

ขจัดความคลาดเคลื่อนของสคีมาระหว่างโค้ดการแยกข้อมูลแอปพลิเคชันกับระนาบควบคุมของแคตตาล็อกความรู้ในโปรเจ็กต์ dev, staging และ prod

11. การล้างข้อมูลในสภาพแวดล้อม

ในแคตตาล็อกความรู้ คุณจะลบคอนเทนเนอร์หลักและเทมเพลตสคีมาไม่ได้ในขณะที่รายการย่อยยังอ้างอิงถึงคอนเทนเนอร์หลักและเทมเพลตสคีมาเหล่านั้น cleanup.py จะลบทรัพยากรตามลำดับการอ้างอิงย้อนกลับที่เข้มงวด (Entry → EntryGroup → EntryType → AspectTypes → ออบเจ็กต์ใน Bucket ของ Cloud Storage → ไฟล์ JSON ชั่วคราว)

# 1. Delete Fileset Entry first
catalog_client.delete_entry(name=target_entry_path)

# 2. Delete EntryGroup container
del_eg_op = catalog_client.delete_entry_group(name=target_eg_path)
if hasattr(del_eg_op, "result"):
    del_eg_op.result()

# 3. Delete EntryType and Custom AspectTypes
del_et_op = catalog_client.delete_entry_type(name=target_et_path)
if hasattr(del_et_op, "result"):
    del_et_op.result()
for aspect_id_val in (EXTRACTED_ASPECT_TYPE_ID, GOVERNANCE_ASPECT_TYPE_ID):
    target_at_path = f"{active_parent}/aspectTypes/{aspect_id_val}"
    del_at_op = catalog_client.delete_aspect_type(name=target_at_path)
    if hasattr(del_at_op, "result"):
        del_at_op.result()

เรียกใช้ cleanup.py

python3 cleanup.py
Starting reverse-dependency resource cleanup in Knowledge Catalog...
Deleted Fileset Entry:
  projects/your-project-id/locations/us-central1/entryGroups/
  dark-data-fileset-group/entries/sop-manuals-fileset-lum8g8j
Deleted EntryGroup   :
  projects/your-project-id/locations/us-central1/entryGroups/
  dark-data-fileset-group
Deleted EntryType    :
  projects/your-project-id/locations/us-central1/entryTypes/
  unstructured-pdf-fileset
Deleted AspectType   :
  projects/your-project-id/locations/us-central1/aspectTypes/
  dark-data-extracted-metadata
Deleted AspectType   :
  projects/your-project-id/locations/us-central1/aspectTypes/
  document-governance-aspect
Deleted Cloud Storage object :
  gs://your-project-id-dark-data-manuals/sop-pdfs/LUM-LIG-DES-8G8J_manual.pdf
Deleted Cloud Storage bucket : gs://your-project-id-dark-data-manuals
Removed local temporary file : extracted_metadata.json
Removed local temporary file : governance_metadata.json
✓ Standalone teardown complete. Environment cleanly reset.

นำไดเรกทอรีที่เก็บที่โคลนออก

หลังจาก cleanup.py ลบทรัพยากรในระบบคลาวด์เสร็จแล้ว ให้กลับไปที่ไดเรกทอรีหน้าแรกและนำโฟลเดอร์ที่เก็บ devrel-demos ที่โคลนไว้ออกจาก Cloud Shell โดยใช้คำสั่งต่อไปนี้

cd ~
rm -rf ~/devrel-demos

12. ยินดีด้วย

คุณได้สร้างและยืนยันไปป์ไลน์การกํากับดูแลข้อมูลเมตาเป็นโค้ดแบบครบวงจรที่เปลี่ยน PDF ที่ไม่มีโครงสร้างใน Cloud Storage ให้เป็นชิ้นงานแคตตาล็อกความรู้ที่ค้นพบได้และบังคับใช้สคีมาโดยใช้ Gemini Enterprise Agent Platform

ต้องทำอะไรต่อ

  • ทำงานอัตโนมัติด้วย Terraform: จัดการทรัพยากร google_dataplex_aspect_type และ google_dataplex_entry_group แบบประกาศในไปป์ไลน์ CI/CD
  • ติดตั้งใช้งาน Eventarc + Worker ของ Cloud Run: สร้างคอนเทนเนอร์ให้กับ step4_extract_metadata.py และ step5_attach_aspects.py เป็นบริการ Cloud Run ที่ขับเคลื่อนด้วยเหตุการณ์
  • การรวมข้อมูลสินค้าคงคลังขั้นปลายใน BigQuery: ส่งออกข้อมูลเมตาด้านการกำกับดูแลที่แยกออกมา (lakehouse_cross_ref_table) เพื่อรวมแอตทริบิวต์การปฏิบัติตามข้อกำหนดของเอกสารที่ไม่มีโครงสร้างกับตารางสินค้าคงคลัง SKU ที่มีโครงสร้าง

เอกสารอ้างอิง