Галоўная / Артыкулы

Пайплайн для перавода з Git у GCS для Spark: стварэнне і завантажэння праекту на Scala з вікорыстаннем SBT, гатовага для агента.

Дэтэрміністычны пайплайн на Python, які клонуе рэпозытарый Scala, створае вялікі JAR-файл на Java 11 за дапамою SBT і завантажае яго у GCS, створаны так, каб агент ADK могаў запускаць яго як інструмент.

Выдавец: REACTAPP.TOP6 хв чытання1464 слоў

Крыніцы: From Prompt Engineering to Agentic Workflow: Building Intelligent Systems on Dataproc Serverless Part 1

Кожны, хто працаваў над праектамі на платформе Spark з лэптопа ў прыметную срэду, ведае такі працэс. Пры гэтым трэба справляцца з командамі Git, працэсамі кампайлінгу SBT, завантажэнням дадзеных у хмарны сховішча і вікорыстанням калькуляваннях інфраструктурных API, пры чым кожны крок выпалюеся вручную. Існуе іншы спосаб: замест таго, каб прасіць ШЫ пра фрагменты коду (тэхніка стварэння запітаў), вы перадаеце агенту ШЫ весь цыкл жыцця праекта і дазволяеце яму самам выпалюваць усі крокі. За дапамогою набора для разработкі агентав Google (ADK), Gemini 2.5 Flash і Dataproc Serverless, большая мова модэля можа выступаць у ролі партнера для працы з DevOps і інжынерыяй дадзеных.

Шосты ўрадок павярнуўся да фундаменту гэтага налашчэння: дэтэрміністычны Python-пайплайн, які запоўняе рэпазітарый Scala/Spark з Git, стварае вялікі JAR-файл за дапамою SBT пад Java 11 і выкладае яго ў Google Cloud Storage. Пайплайн напісаны так, каб агент могаў выкорыстоўваць яго як інструмент. Сам шар агента, з функцыяльнымі інструментамі ADK, праблемай прыемкай падтверджэння, інтэрактыўнымі сесіямі Dataproc Serverless і фронтэндам чату Streamlit, будуецца на яго основе пазней.

Практычны рэзультат — 20-хвілінная, супяжызаная з багамі процедура стварэння і развертання ператвараецца на надзяйны каманды, якую агент можа запускаць на падставе простага англійскага запіту.

Боль внутранняга ціклу ў працы з Spark

Распрацоўшчыкі веб-сайтатов атрымоюць практычна мгновенную адзвеччу пры выкарыстоўванні функцыі гэтага перзагружання модуляў. Інжынеры, якія працуюць з вялікімі масавымі дадзеннямі, рэдка калі атрымоюць такія можлівасці. Цыкл рэдагавання, складання, размешчэння і тэставання, які часта называюць внутранім цыклам, часта зупініваецца на калькі пунктаў:

  1. Несувярэнныя асяроддзя. Версія Java на ноутбуке не сувярэнна з версіяй на кластэрэ Spark. Класычным прыкладам ёсць Java 17 на локальным апаратзе проты Java 11 у фармаце байткода на Dataproc.
  2. Дорогі працэс пакавання. Стварэнне вялікага JAR-файла з атрыбутамі sbt clean compile assembly можа зайняць калькі хвілін, выкарыстоўваючы значны рэсурс CPU і памяці.
  3. Ручныя дзеянні ў воблаку. Людзі пераходзяць у Google Cloud Console або вводзяць дугія команды CLI, якія лёгка можна спісаць некалькі.
  • Адмініструванне підключэння ноутбука. Падключэнне новага JAR-файла да сераўісу interactive notebook абяроцца пашукам у глыбокіх структурах атрыбутаў Dataproc.
  • Ідэя такая: што, якбы весь ланцоўка была кодам, адлагоджаным і паданым агенту, які прымае інструкцыі на звычной мове? Наступныя раздзелы опісваюць автаматызаваную лінію пабудовы Git-до-GCS на мовах Scala/SBT, створаную як выконвальны інструмент для агентаў LLM.

    Правілы дызайну інструментаў, безпечных для агентаў

    Каб AI-агент могаў безпечна запускаць сістэму пабудовы, інструмент павінен адпавядаць трох прынцыпам:

    1. Дэтэрміністычны выконанне. Скрыпт пераканаецца ў стані сераўісу, напрыклад, падтвердзіўшы наявнасць Java 11, прычым перад тым, як пачаць дорогі крок компіляцыі.
    2. Чыстая ізоляцыя. Пабудовы ведуцца ў тымчасовых каталогах, якія пазней адмаўляюцца, тады прастор на дыску не накапліваецца.
    3. Стандартны ўвод і выход. Кожны этап выдруквае логі, якія можна аналізаваць машынай, і вяртае чыстае становішча.

    Працэсы стварэння і заваносу залічваюцца окрэмымі, таму кожны з іх можна вызваць, працаваць з яму і практыкаваць занова незалежна.

    Адкалэнне, па кроках

    Фіксаванне стварэння на Java 11

    Рамкі працы Spark на Dataproc Serverless выкалекаваны так, каб была бінарная сумеснасць з Java 11. Камп’ютары распрацоўшчыкаў часта выкорыстоваюць Java 17 або 21, і гэта несувязанасць вызывае памылкі байткода, такія як UnsupportedClassVersionError: 61.0 vs 55.0.

    Клас ArtifactBuilder у файле artifact_builder.py запобегае гэтам, пераглядаючы установленыя JDK-ы пад час працы і прыязджаючы JAVA_HOME толькі да падпроцэса стварэння, таму сістэмныя настройкі залішаюцца некалечанымі:

    import os
    import subprocess
    import logging
    
    class ArtifactBuilder:
        """Builds Scala JAR artifacts from Git repositories using SBT."""
    
        def __init__(self, repo_url: str, branch: str = "main"):
            self.repo_url = repo_url
            self.branch = branch
    
        def clone_repo(self, dest_dir: str):
            """Clone the given Git repository to the destination directory."""
            logging.info(f"Cloning {self.repo_url} (branch={self.branch}) into {dest_dir}")
            subprocess.run(["git", "clone", "-b", self.branch, self.repo_url, dest_dir], check=True)
    
        def find_build_dir(self, root_dir: str) -> str:
            """Recursively search for SBT build file."""
            for dirpath, _, filenames in os.walk(root_dir):
                if "build.sbt" in filenames:
                    logging.info(f"Detected SBT build file in {dirpath}")
                    return dirpath
            raise FileNotFoundError(f"No build.sbt file found in {root_dir}")
    
        def check_java_installed(self):
            """Ensure Java 11 is available and active in environment."""
            env = os.environ.copy()
            env["JAVA_HOME"] = "/opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk/Contents/Home"
            env["PATH"] = f"/opt/homebrew/opt/openjdk@11/bin:{env.get('PATH', '')}"
    
            result = subprocess.run(
                ["java", "-version"],
                check=True,
                env=env,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True
            )
            output = result.stdout + result.stderr
            if "version" in output:
                version_str = output.split("version")[1].split()[0].strip('"')
                major_version = int(version_str.split(".")[0])
                if major_version != 11:
                    raise EnvironmentError(f"Java 11 required, but detected Java {major_version}")
            logging.info("Java 11 verified successfully.")
    
        def build_artifact(self, repo_dir: str) -> str:
            """Compile and assemble fat JAR."""
            build_dir = self.find_build_dir(repo_dir)
            self.check_java_installed()
    
            env = os.environ.copy()
            env["JAVA_HOME"] = "/opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk/Contents/Home"
            env["PATH"] = f"/opt/homebrew/opt/openjdk@11/bin:{env.get('PATH', '')}"
    
            logging.info("Running: sbt clean compile assembly...")
            subprocess.run(["sbt", "clean", "compile", "assembly"], cwd=build_dir, env=env, check=True)
    
            target_dir = os.path.join(build_dir, "target")
            return self._find_file(target_dir, ".jar")
    
        def _find_file(self, directory: str, extension: str) -> str:
            for root, _, files in os.walk(directory):
                for f in files:
                    if f.endswith(extension):
                        return os.path.join(root, f)
            raise FileNotFoundError(f"No {extension} file found in {directory}")
    

    Надзяйна публікацыя у хмарны ўтрымванне дадзеных

    Выклікі gsutil або gcloud на рэвэлі Shell можу мовчкі збыцца пад некалькама сітуацыямі аутантыкацыі. Таму модуль uploader.py вікорыстоўвае офіцыйную бібліятэку-кліента Python для Google Cloud Storage, якая стварае рэальныя асывенты, якія можа пазначыць і запісаць канвей:

    from google.cloud import storage
    import logging
    import os
    
    class ArtifactUploader:
        """Handles secure upload of artifacts to Google Cloud Storage."""
    
        def __init__(self):
            self.client = storage.Client()
    
        def upload_to_gcs(self, bucket_name: str, artifact_path: str, dest_path: str):
            if not os.path.exists(artifact_path):
                raise FileNotFoundError(f"Artifact not found: {artifact_path}")
    
            logging.info(f"Uploading {artifact_path} → gs://{bucket_name}/{dest_path}")
            bucket = self.client.bucket(bucket_name)
            blob = bucket.blob(dest_path)
            blob.upload_from_filename(artifact_path)
            logging.info("Upload to GCS completed successfully.")
    

    Аб’яднанне як будувальніка, так і завантажувача ў CLI

    У падсумку run_build_and_upload.py аб’яднвае будувальнік і завантажувач у адны ArtifactPipeline з дэтэрміністычным інтэрфейсам у командной лініі.

    Няхто не павінен запам’ятовваць чы ручнаўляць гэтыя команды. Распрацоўшчык выказвае сваю мету у фронтэне чату, напрыклад: «Збудаваць мой рэпазітарый у версіі main і завантажыць яго ў мой бакет GCS». Бэкенд агента выкарыстоўвае параметры з гэтага запісу і запускае відпаведную команду. Гэта тое, што ён выканае у фонавым рэжыме:

    # Executed autonomously in the background by the Agent's backend tool:
    python3 artifact_pipeline/run_build_and_upload.py \
      --repo "https://github.com/<username>/demo-pipeline.git" \
      --branch main \
      --bucket "demo-spark-sandbox-bucket" \
      --dest "spark-jobs/spark-serverless-job_test.jar" \
      --cleanup
    

    Лог тэрміналу адзюнктнага слоя з рэальнага запуску паказвае, як агент Google ADK работае з Gemini 2.5 Flash у Vertex AI. Ён чытае паведамленне карыстальніка і автаматычна вызывае artifact_pipeline/run_build_and_upload.py з правымі параметрамі.

    Следзіце за запускам пайплайна

    Пераканаленне ў Cloud Storage. Калі працэс загрузкі завершыцца, файл у фармаце JAR будзе знаходзіцца ў выбранай корзіне, гатовы для прыўязкі да Dataproc. У консолі скомпіляваны файл Spark JAR з’яўляецца па такам шляху, як gs://<bucket-name>/spark-jobs/spark-serverless-job_test.jar, з розмерам 186,8 MB.

    Кераванне з інтэрфейса чату. За дапамою інтэрфейса Streamlit, стварэнне і аплодзіць вядуцца выключна за дапамою нейтральнай мовы. Распрацоўшчык задае рэпазітарый Git, галузь, бакет і шлях падачы, а агент плануе і выконвае інструменты стварэння. Калі завершаецца стварэнне артыкла і аплодзіць у GCS, агент следуе за сваёй машынай станоў і просі падтверджэння перш чым запускаць серверлессны нотбук.

    Адпаведна дзеянне у разы невясковасці

    Пайплайн, прызначаны для практычнага вжытку, павінен адпавядаць у чытальны спосаб. Калі выйшае з ладу стварэнне або серавер, агент перэхопляе паказаныя кроці выключнення і дае практычныя настановы замест таго, каб програма зламалася.

    Проблемы з аутантыкацыяй у Git. Як толькі пайплайн пераключаецца на прыватны рэпазітары, выйшае брак у аутантыкацыі, і ўтвараецца блокаванне стандартнага выходу Git (на прыклад, Invalid username or token / Password authentication is not supported). Пасля чаго паказваеся, як настроіць SSH або токен.

    Памылкі пад час выканання і ў сяродовыце. Калі ў сяродовыце Python выйдзе якаясь нечаканая проблема, напрыклад, відсутная залежнасць або ModuleNotFoundError, агент ізолюе проблему, паказвае точны трабек-трэйс і пропануе способы вярнуць працу. Сесія чату застаецца актываючайся, з інтэракtywnымі запросамі на пракату, а не заканчваецца разам з бракам.

    Урокі, якія трэба запам’ятаваць

    1. Складнасць домэну трэба спроставаць. Калі працэс складаецца з чатырох разных крокаў, іх трэба аднаць у адны ідэмпатны каманду з чысткіма вхіднамі і выходнымі данымі.
  • Дыяграматыкі для вызоў з коду. Утрымваюце інтэрактыўныя запыты параду ў скрыптах будавання, і робіце кожны параметр доступным як аргумент чыта API-пакета.
  • Дайце агентам надзейную базу. Дэтэрміністычная падстава дазволяе LLM надзейна запускаць складныя працэсы будавання, замест таго каб генераваць халюцынацыі ў віглядзе команд шэлу.
  • Планаваце адказ на неудачы. Чыстая перэхопленне паказанняях дазволяе агенту дыягнаставаць проблемы аутантыкацыі, відсутныя файлы чыта зламаныя залежнасці, а пасля поясніць іх корыстніку.
  • Надзейныя агентскія сістэмы растуць знізу вверх. Замена ручных крокаў компіляцыі ізольаваным, сумэнным з Java 11 Python-двіжкам ператварае медленны, кранглы бутлнэк у надзейную будуючую елемент. Калі пайплайн Git-до-GCS будзе запакаваны як самастойны, ідэмпатэнтны інструмент, ён можа служыць рукамі чыта ногамі AI-агента.