สร้าง Agent สรุปข่าวเทคโนโลยีรายวันด้วย Agent ที่ได้รับการจัดการใน Gemini API

1. ภาพรวม

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

Agent ที่ได้รับการจัดการใน Gemini API จะเปลี่ยนสมการ คุณเขียนไฟล์การกำหนดค่า Markdown 2 ไฟล์และสคริปต์ตัวแสดงผลที่สร้างไว้ล่วงหน้า ทำการเรียก API 1 ครั้ง และแซนด์บ็อกซ์ Ubuntu จริงจะบูต เรียกดูเว็บ เขียนข้อมูลสรุป และสร้าง PDF ไม่มีคอนเทนเนอร์ ไม่มีการทำให้ใช้งานได้ ไม่ต้องใช้โค้ดการจัดการเป็นกลุ่ม

ใน Codelab นี้ คุณจะได้สร้าง Agent ดังกล่าวตั้งแต่ฟังก์ชันว่างเปล่าไปจนถึงสรุปประจำวันที่ใช้งานได้จริง โดยจะทีละแนวคิด

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

  • สร้างและเรียกใช้เอเจนต์ที่มีการจัดการตัวแรกในแซนด์บ็อกซ์ Linux จริง
  • ปรับแต่ง Agent ด้วยสไตล์การบรรณาธิการ แหล่งข้อมูลบนเว็บ และทักษะ PDF
  • เพิ่มฮุกความปลอดภัยเพื่อบล็อกคำสั่งที่เป็นอันตรายก่อนที่จะเรียกใช้
  • ดาวน์โหลด PDF ที่ตัวแทนสร้างขึ้น
  • ปรับแต่งเนื้อหาโดยรวมในการสนทนาไปมาโดยไม่ต้องดึงข้อมูลเว็บอีกครั้ง
  • บันทึกการกำหนดค่าเอเจนต์และเรียกใช้ตามรหัสในการเรียกใช้ในอนาคต
  • ส่งข้อมูลสรุปไปยังกล่องจดหมายผ่าน Gmail API
  • ตั้งเวลาให้ Agent ทำงานและส่งโดยอัตโนมัติทุกวัน

สิ่งที่คุณต้องมี

  • Python 3.10 ขึ้นไป
  • คีย์ Gemini API: aistudio.google.com/api-keys (รวมระดับฟรีแล้ว ขอแนะนำให้ใช้การเรียกเก็บเงินเพื่อให้รันได้อย่างต่อเนื่อง)

2. Agent ที่ได้รับการจัดการใน Gemini API คืออะไร

ระบบ AI 3 ระดับ

ก่อนที่จะเจาะลึกเรื่องโค้ด มาดูตำแหน่งของ Agent ที่ได้รับการจัดการ เมื่อเทียบกับทางเลือกอีก 2 ทางกัน

ระดับ

คืออะไร

ใครเป็นผู้จัดการโครงสร้างพื้นฐาน

LLM มาตรฐาน

คุณป้อนพรอมต์ แล้ว Gemini จะตอบกลับด้วยข้อความ ไม่มีมือ ไม่มีหน่วยความจำ ไม่มีอินเทอร์เน็ต

ไม่มี: ไม่สามารถทำอะไรได้ด้วยตัวเอง

เอเจนต์ที่โฮสต์ด้วยตนเอง

คุณเชื่อมต่อ ADK/LangChain/AutoGen + Docker + เครื่องมือ + หน่วยความจำ

คุณ: ทั้งหมด (หรือแพลตฟอร์มที่มีการจัดการ เช่น Agent Engine)

Agent ที่ได้รับการจัดการ

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

Google: ทั้งหมด

Codelab นี้เกี่ยวกับแถวที่ 3 คุณจัดเตรียมไฟล์งานและการกำหนดค่า Google จะจัดการส่วนที่เหลือให้

สิ่งที่คุณจะสร้างด้วย ADK + Cloud Run

หากต้องการสร้างเอเจนต์สรุปข่าวที่เรียกดูเว็บ เรียกใช้ Python และสร้าง PDF คุณจะต้องมีสิ่งต่อไปนี้ด้วย ADK + Cloud Run

# agent.py: define tools and wire up the agent
from google.adk.agents import LlmAgent
from google.adk.tools import google_search, built_in_code_execution

agent = LlmAgent(
    name="digest-agent",
    model=MODEL,
    instruction=AGENTS_MD,          # your editorial voice and rules
    tools=[google_search, built_in_code_execution],
)
# app.py: serve the agent over HTTP
from google.adk.runners import FastApiRunner
runner = FastApiRunner(agent=agent)
app = runner.app
# pdf_tool.py: custom tool, install reportlab, render PDF
# scraper.py: custom tool, fetch each news source
# streaming.py: wire agent events to your SSE endpoint
# Dockerfile: package everything
FROM python:3.12
COPY . /app
RUN pip install google-adk reportlab requests
CMD ["uvicorn", "app:app", "--host", "0.0.0.0"]
# Deploy to Cloud Run
gcloud run deploy digest-agent \
  --image gcr.io/your-project/digest-agent \
  --set-secrets GEMINI_API_KEY=gemini-key:latest \
  --memory 2Gi

ซึ่งเป็นช่วงก่อนที่ Agent จะทำงาน คุณยังคงเป็นเจ้าของการแยกแซนด์บ็อกซ์ (ดังนั้นเอเจนต์จึงไม่สามารถทำให้เซิร์ฟเวอร์เสียหายได้) การติดตั้งแพ็กเกจ การจัดการสถานะระหว่างการเรียกใช้เครื่องมือ และโครงสร้างพื้นฐานการสตรีมเพื่อรับเหตุการณ์ไปยังไคลเอ็นต์

สิ่งที่ Agent ที่ได้รับการจัดการจะแทนที่

from google import genai
client = genai.Client()

stream = client.interactions.create(
    agent="antigravity-preview-05-2026",
    input="Generate the digest.",
    stream=True,
    environment={
        "type": "remote",
        "sources": [          # your config files, mounted at startup
            {
                "type": "inline",
                "target": ".agents/AGENTS.md",
                "content": AGENTS_MD,
            },
            {
                "type": "inline",
                "target": ".agents/skills/digest-pdf/SKILL.md",
                "content": SKILL_MD,
            },
            {
                "type": "inline",
                "target": ".agents/skills/digest-pdf/scripts/generate_pdf.py",
                "content": GENERATE_PDF_PY,
            },
        ],
    },
)

สิ่งที่ ADK + Cloud Run ต้องการ

สิ่งที่ Agent ที่ได้รับการจัดการจะจัดการให้คุณ

อิมเมจคอนเทนเนอร์ + Dockerfile + CI/CD

แซนด์บ็อกซ์ Ubuntu ที่มีการจัดการเต็มรูปแบบ (Python 3.12, Node 22, 4 CPU / 16 GB RAM)

การติดตั้งใช้งานและการปรับขนาด Cloud Run

จัดสรรต่อการโต้ตอบ 1 ครั้ง และจะหมดอายุโดยอัตโนมัติหลังจากไม่มีการใช้งานเป็นเวลา 7 วัน

การแยกแซนด์บ็อกซ์

แยกตามการโต้ตอบ

เครื่องมือ PDF ที่กำหนดเอง + pip install

Agent ติดตั้งแพ็กเกจภายในแซนด์บ็อกซ์

โครงสร้างพื้นฐานการสตรีม SSE

stream=True จะแสดงผลการทำซ้ำของเหตุการณ์

คำจำกัดความของเครื่องมือใน Python

เครื่องมือที่มีในตัว: การท่องเว็บ การเรียกใช้โค้ด ระบบไฟล์

การจัดการสถานะระหว่างการเรียกใช้เครื่องมือ

รวมไว้ในลูปการให้เหตุผลของ Agent

คุณเขียนไฟล์การกำหนดค่า (AGENTS.md, SKILL.md, สคริปต์ที่สร้างไว้ล่วงหน้า) และทำการเรียก API 1 ครั้ง Google จะจัดการส่วนที่เหลือให้

วิธีการทำงานของแซนด์บ็อกซ์

interactions.create() call
        │
        ▼
Google provisions Ubuntu sandbox (Python 3.12, Node 22, 4 CPU / 16 GB RAM)
        │
        ▼
Agent reasoning loop:
  plan → fetch URLs → run Python → write files → reason → repeat
        │
        ▼
Events stream back in real time: tool calls, text chunks, completion
        │
        ▼
interaction.completed → environment_id + interaction_id

Sandbox จะยังคงอยู่เป็นเวลา 7 วันหากไม่มีการใช้งาน คุณสามารถกลับมาทำงานต่อด้วย environment_id เพื่อปรับแต่งเอาต์พุต เรียกใช้งานติดตาม หรือฟอร์กเป็นเอเจนต์ที่มีชื่อที่บันทึกไว้

3. ตั้งค่า

คลิกปุ่มด้านล่างเพื่อเปิด Codelab นี้ใน Google Cloud Shell ระบบจะติดตั้งการขึ้นต่อกันทั้งหมดไว้ล่วงหน้า

เปิดใน Cloud Shell

ตัวเลือก ข: การตั้งค่าในพื้นที่

git clone https://github.com/Saoussen-CH/tech-digest-managed-agent.git
cd tech-digest-managed-agent

ติดตั้ง uv หากจำเป็น

curl -LsSf https://astral.sh/uv/install.sh | sh

กำหนดค่าคีย์ API

cp .env.example .env
cloudshell edit .env

ตั้งค่าคีย์ดังนี้

GEMINI_API_KEY=your-key-here

ติดตั้งการอ้างอิง

uv sync

4. โทรหา Agent ครั้งแรก

เปิดไฟล์เริ่มต้น

cloudshell edit run_digest.py

run_digest() มี TODO 1 รายการที่ต้องกรอกตอนนี้ และอีก 3 รายการสำหรับขั้นตอนถัดไป ระบบจะกรอกข้อมูลผู้ช่วย 2 คนไว้ให้แล้วที่ด้านบน

  • load_source(path): อ่านไฟล์จาก .agents/ ที่สัมพันธ์กับสคริปต์ คุณจะใช้ข้อมูลนี้ในแบบฝึกหัดถัดไปเพื่อต่อเชื่อมสไตล์การบรรณาธิการ เพลย์บุ๊ก PDF และโปรแกรมแสดงผลลงในแซนด์บ็อกซ์
  • run_stream(stream): ประมวลผลสตรีมเหตุการณ์และแสดงผล (environment_id, interaction_id) คุณไม่จำเป็นต้องเขียน Event Loop ด้วยตนเอง

สิ่งที่ต้องเพิ่ม

TODO 1: แทนที่ pass ด้วย (ข้าม TODO 3, 4 ไปก่อน เนื่องจากเป็นขั้นตอนถัดไป)

    from google import genai
    client = genai.Client()

    stream = client.interactions.create(
        agent=BASE_AGENT,
        agent_config={"type": "antigravity", "model": "gemini-3.7-flash"},
        input="Fetch the Hacker News front page and list the top 5 stories.",
        stream=True,
        environment="remote",
    )

    environment_id, interaction_id = run_stream(stream)
    print(f"\nDone. environment_id={environment_id}")

หน้าที่ของแต่ละส่วน

genai.Client()อ่านGEMINI_API_KEYจากสภาพแวดล้อม ส่วนอื่นๆ ทั้งหมดจะผ่านไคลเอ็นต์นี้

interactions.create() คือการเรียกหลัก โดยมีพารามิเตอร์ 4 รายการที่ทำให้การทำงานเป็นไปได้ ดังนี้

  • agent=BASE_AGENT: เลือก Agent ของ Antigravity (antigravity-preview-05-2026) ซึ่งเป็น Agent ที่ได้รับการจัดการแบบอเนกประสงค์ที่ขับเคลื่อนโดย Gemini 3.7 Flash โดยค่าเริ่มต้น คุณสามารถกำหนดค่าโมเดลพื้นฐานได้โดยใช้ agent_config (ตัวเลือก: gemini-3.7-flash, gemini-3.6-flash, gemini-3.5-flash, gemini-3.5-flash-lite) ซึ่งมาพร้อมกับเครื่องมือในตัว 3 อย่างที่เปิดใช้โดยค่าเริ่มต้น ได้แก่ code_execution (เรียกใช้ Bash, Python, Node.js), google_search และ url_context (ดึงและอ่านหน้าเว็บ) ระบบจะเปิดใช้เครื่องมือระบบไฟล์ (read_file, write_file, list_files) โดยอัตโนมัติเมื่อคุณส่งพารามิเตอร์ environment การเรียกใช้ครั้งเดียวจะจัดสรรสภาพแวดล้อม Ubuntu ที่มีการจัดการเต็มรูปแบบพร้อม Python 3.12, Node.js 22, git, pip และ curl ที่ติดตั้งไว้ล่วงหน้า ไม่ต้องสร้างคอนเทนเนอร์ ไม่ต้องทำให้ใช้งานได้
  • input: งานสำหรับการเรียกใช้ครั้งนี้ เอเจนต์จะเรียกดู Hacker News และให้เหตุผลเกี่ยวกับผลลัพธ์
  • environment="remote": จัดสรรแซนด์บ็อกซ์ระบบคลาวด์ใหม่สำหรับการโต้ตอบนี้
  • stream=True: แสดงผลตัววนซ้ำของเหตุการณ์แทนการบล็อก หากไม่มีพารามิเตอร์นี้ ระบบจะรอ 30-90 วินาทีและแสดงผลลัพธ์ทั้งหมดพร้อมกันเป็น interaction.output_text การสตรีมช่วยให้คุณเห็นเหตุผลของ Agent และดำเนินการได้ทันที การสตรีมไม่ใช่ฟีเจอร์ขั้นสูงในที่นี้ แต่เป็นค่าเริ่มต้นที่เหมาะสม เนื่องจากกล่องดำ 90 วินาทีไม่ได้ให้สัญญาณใดๆ เกี่ยวกับว่าตัวแทนกำลังทำงานหรือติดขัด

environment_id คือแฮนเดิลของแซนด์บ็อกซ์ที่เพิ่งเรียกใช้ หลังจาก interaction.completed แซนด์บ็อกซ์จะไม่ปิดตัวลง แต่จะยังคงใช้งานได้นานสูงสุด 7 วัน environment_id คือวิธีกลับไปที่หน้าดังกล่าว ส่งไปยังการโทร interactions.create() ครั้งที่ 2 แล้วตัวแทนจะกลับมาทำงานต่อในระบบไฟล์เดิม โดยมีไฟล์และแพ็กเกจที่ติดตั้งไว้เหมือนเดิมราวกับว่าไม่เคยหยุดทำงาน ขั้นตอนถัดไปจะใช้ข้อมูลนี้เพื่อดาวน์โหลด PDF โดยไม่ต้องเรียกใช้ตัวแทนอีกครั้ง และขั้นตอนหลังจากนั้นจะใช้ข้อมูลนี้เพื่อสนทนาต่อ

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

ยืนยัน

uv run python run_digest.py

คุณควรเห็นเอาต์พุตแบบเรียลไทม์ขณะที่เอเจนต์ทำงาน

[agent started]
  [tool] run_code
Here are the top 5 stories currently on the Hacker News front page, retrieved via the official Hacker News API:

1. **Qwen 3.6 27B is the sweet spot for local development** (471 points)
2. **.self: A new top-level domain designed to support self-hosting** (116 points)
...
Done. environment_id=e3de58774073f75a6ef42924c6ce2e88

API จะแสดงผล environment_id จริงแม้จะมี environment="remote" แซนด์บ็อกซ์ทำงานแล้ว สิ่งที่ขาดหายไปคือการกำหนดค่า ซึ่งไม่มีเสียง ไม่มีทักษะ และไม่มีเครื่องมือสร้าง PDF เอเจนต์เพียงแค่พิมพ์เรื่องราวเป็นข้อความแล้วก็หยุด ขั้นตอนถัดไปคือการเพิ่มข้อมูลเหล่านั้น

เอาต์พุตแต่ละบรรทัดจะแมปกับเหตุการณ์จาก run_stream() ดังนี้

step.type

คำอธิบาย

สิ่งที่ run_stream() พิมพ์

"url_context_call"

ตัวแทนดึงข้อมูล URL

[tool] url_context (https://...)

"code_execution_call"

Agent ที่รันโค้ดในแซนด์บ็อกซ์

[tool] run_code

"google_search_call"

เอเจนต์ค้นหาในเว็บ

[tool] google_search

"function_call"

เครื่องมือไฟล์และอื่นๆ

[tool] read_file (/workspace/...)

step.delta เมื่อ delta.type == "text"

ตัวแทนเขียนข้อความ

สตรีมไปยัง stdout โดยตรง

5. ปรับแต่ง Agent

ตัวแทนไม่มีคำสั่ง ไม่ว่าจะเป็นเสียง ทักษะ หรือเครื่องมือสร้าง PDF ในขั้นตอนนี้ คุณจะโหลดไฟล์การกำหนดค่าจาก .agents/ และติดตั้งไฟล์เหล่านั้นลงในแซนด์บ็อกซ์

สิ่งที่ต้องเปลี่ยน

ทำการเปลี่ยนแปลง 4 อย่างใน run_digest.py ดังนี้

TODO 2: ใต้ load_source() ให้เพิ่มค่าคงที่ระดับโมดูล 3 รายการ (ค่าคงที่เหล่านี้อยู่นอก run_digest() ที่ด้านบนของไฟล์)

AGENTS_MD       = load_source(".agents/AGENTS.md")
SKILL_MD        = load_source(".agents/skills/digest-pdf/SKILL.md")
GENERATE_PDF_PY = load_source(".agents/skills/digest-pdf/scripts/generate_pdf.py")

เปิดแต่ละไฟล์เพื่อดูสิ่งที่คุณกำลังโหลด AGENTS.md กำหนดสไตล์การบรรณาธิการและกฎเวิร์กโฟลว์ SKILL.md คือเพลย์บุ๊ก PDF แบบทีละขั้นตอน generate_pdf.py คือโปรแกรมแสดงผลที่สร้างไว้ล่วงหน้าซึ่งตัวแทนจะเรียกใช้

ตอนนี้ให้ทำการเปลี่ยนแปลงอีก 2 รายการภายใน run_digest() ดังนี้

TODO 3: เปลี่ยน environment จาก "remote" เป็นพจนานุกรมแหล่งที่มา และตั้งค่า input เป็น "Generate the digest.":

        environment={
            "type": "remote",
            "sources": [
                {
                    "type": "inline",
                    "target": ".agents/AGENTS.md",
                    "content": AGENTS_MD,
                },
                {
                    "type": "inline",
                    "target": ".agents/skills/digest-pdf/SKILL.md",
                    "content": SKILL_MD,
                },
                {
                    "type": "inline",
                    "target": ".agents/skills/digest-pdf/scripts/generate_pdf.py",
                    "content": GENERATE_PDF_PY,
                },
            ],
        },

สิ่งที่ต้องทำ 4: เพิ่มบรรทัดนี้หลัง print(f"\nDone. environment_id={environment_id}") ทันที

    save_env(ENVIRONMENT_ID=environment_id, INTERACTION_ID=interaction_id)

มีการกำหนด save_env ไว้ใน run_digest.py แล้ว โดยจะเขียนทั้ง 2 รหัสไปยัง .env เพื่อให้ขั้นตอนถัดไปดาวน์โหลด PDF ได้โดยไม่ต้องเรียกใช้ตัวแทนอีกครั้ง

การทำงานของแต่ละแหล่งที่มา

แต่ละแหล่งที่มาคือไฟล์ที่ติดตั้งในระบบไฟล์แซนด์บ็อกซ์เมื่อเริ่มต้นระบบก่อนที่เอเจนต์จะทำงาน target เส้นทางจะตรงกับตำแหน่งที่สายรัด Antigravity คาดว่าจะพบไฟล์

.agents/
├── AGENTS.md                              ← auto-loaded as global instructions
└── skills/
    └── digest-pdf/
        ├── SKILL.md                       ← auto-discovered and registered as a skill
        └── scripts/
            └── generate_pdf.py            ← pre-built renderer the agent can run

target เส้นทาง

ตัวแปร

สิ่งที่สายรัดทำกับอุปกรณ์

.agents/AGENTS.md

AGENTS_MD

โหลดอัตโนมัติเป็นคำสั่งถาวร: สไตล์การบรรณาธิการ เวิร์กโฟลว์ กฎการดำเนินการ

.agents/skills/digest-pdf/SKILL.md

SKILL_MD

ค้นพบและลงทะเบียนโดยอัตโนมัติเป็นทักษะที่มีชื่อ โดยเอเจนต์จะเรียกใช้ตามชื่อ

.agents/skills/digest-pdf/scripts/generate_pdf.py

GENERATE_PDF_PY

ตัวแสดงผล PDF ที่สร้างไว้ล่วงหน้า โดยเอเจนต์จะเขียน summaries.json แล้วเรียกใช้สคริปต์นี้

ยืนยัน

uv run python run_digest.py

การเรียกใช้จะใช้เวลา 1-3 นาที คุณควรเห็นเอเจนต์อ่านไฟล์การกำหนดค่า เขียนข้อมูลสรุป และบันทึก PDF ดังนี้

[agent started]
  [tool] read_file (/.agents/skills/digest-pdf/SKILL.md)
  [tool] list_files (/.agents/skills/digest-pdf/scripts)
  [tool] read_file (/.agents/skills/digest-pdf/scripts/generate_pdf.py)
  [tool] run_code
  [tool] write_file (/workspace/summaries.json)
  [tool] run_code
  [tool] delete_file (/tmp/test_scrape.py)
I have successfully generated today's tech news digest and saved the formatted document to /workspace/digest.pdf.
Done. environment_id=4129ffd75574e308748e9425d7ec828f

environment_id ตอนนี้เป็นค่าจริงแล้ว Sandbox ทำงานกับไฟล์การกำหนดค่าของคุณ และ Agent สร้าง digest.pdf ขั้นตอนถัดไปจะเพิ่มการตรวจสอบความปลอดภัยก่อนดาวน์โหลด

6. เพิ่ม Safety Hook

Hook ช่วยให้คุณเรียกใช้สคริปต์ภายในแซนด์บ็อกซ์ก่อนหรือหลังการเรียกใช้เครื่องมือแต่ละครั้ง เอเจนต์สรุปใช้ code_execution เพื่อเรียกใช้สคริปต์ Python ดังนั้นฮุก pre_tool_execution จึงสามารถสกัดกั้นการเรียกเหล่านั้นและบล็อกคำสั่งเชลล์ที่เป็นอันตรายก่อนที่จะดำเนินการได้

โดยรันไทม์จะอ่าน .agents/hooks.json จากแซนด์บ็อกซ์ ก่อนการเรียกใช้เครื่องมือจับคู่แต่ละครั้ง ระบบจะส่งรายละเอียดการโทรไปยังสคริปต์เกตบน stdin สคริปต์จะพิมพ์ {"decision": "allow"} หรือ {"decision": "deny", "reason": "..."} ไปยัง stdout การปฏิเสธจะยกเลิกการเรียกใช้เครื่องมือ และตัวแทนจะเห็นเหตุผลของคุณและแก้ไขตัวเอง

สิ่งที่ต้องเพิ่ม

TODO 5: ใน run_digest.py ให้เพิ่มค่าคงที่ 2 รายการนี้ไว้ใกล้ด้านบนหลังจากเรียกใช้ load_source ที่มีอยู่

import json

HOOKS_JSON = json.dumps({
    "safety-gate": {
        "pre_tool_execution": [
            {
                "matcher": "code_execution",
                "hooks": [
                    {
                        "type": "command",
                        "command": "python3 /.agents/hooks-scripts/gate.py",
                        "timeout": 10,
                    }
                ],
            }
        ]
    }
}, indent=2)

GATE_PY = """\
#!/usr/bin/env python3
import sys, json
data = json.load(sys.stdin)
cmd = str(data.get("tool_call", {}).get("args", {}))
if "rm -rf" in cmd:
    print(json.dumps({"decision": "deny", "reason": "Destructive command blocked by safety gate."}))
else:
    print(json.dumps({"decision": "allow"}))
"""

สิ่งที่ต้องทำ 6: เพิ่มรายการอีก 2 รายการลงในรายการ sources ภายใน interactions.create() ดังนี้

{"type": "inline", "target": ".agents/hooks.json",            "content": HOOKS_JSON},
{"type": "inline", "target": ".agents/hooks-scripts/gate.py", "content": GATE_PY},

วิธีที่ฮุกทำงานในการเรียกใช้ข้อมูลสรุป

ทุกครั้งที่เอเจนต์เรียกใช้ code_execution เพื่อเรียกใช้สคริปต์ Python หรือคำสั่งเชลล์ รันไทม์จะส่งรายละเอียดการโทรไปยัง gate.py ก่อน หากคำสั่งมี rm -rf ฮุกจะแสดง deny และ Agent จะได้รับเหตุผลการปฏิเสธและลองอีกครั้งด้วยตัวเลือกที่ปลอดภัย ส่วนการเรียกใช้โค้ดอื่นๆ ทั้งหมดจะผ่านไปโดยไม่มีการเปลี่ยนแปลง

ยืนยัน

uv run python run_digest.py

เอาต์พุตจะเหมือนเดิมทุกประการ โดยเกตเวย์ความปลอดภัยจะอนุญาตคำสั่งการสร้าง PDF ปกติทั้งหมด หากต้องการยืนยันว่าฮุกทำงาน ให้เปลี่ยนอินพุตของเอเจนต์ชั่วคราวเพื่อขอให้เรียกใช้ rm -rf /tmp/test คุณจะเห็นรายงานของเอเจนต์ที่ระบุว่าระบบบล็อกคำสั่งและเลือกคำสั่งอื่น

7. ดาวน์โหลด PDF

ตัวแทนเขียน digest.pdf ถึง /workspace/digest.pdf ภายในแซนด์บ็อกซ์ ภาพรวมสภาพแวดล้อมพร้อมใช้งานเป็นไฟล์เก็บถาวร tar ผ่าน Gemini Files API

ติดตั้ง requests หากจำเป็น

uv pip install requests

สิ่งที่ต้องกรอก

เปิด download_pdf.py โดยมีสิ่งที่ต้องทำ 2 รายการ

สิ่งที่ต้องทำ 1: กรอกข้อมูลในrequests.get() call:

    r = requests.get(
        f"https://generativelanguage.googleapis.com/v1beta/files/environment-{environment_id}:download",
        params={"alt": "media"},
        headers={"x-goog-api-key": api_key},
        allow_redirects=True,
    )
    r.raise_for_status()

URL จะระบุภาพรวมของแซนด์บ็อกซ์ params={"alt": "media"} จะแสดงผลไบต์ดิบแทนข้อมูลเมตา GEMINI_API_KEYที่มีอยู่จะตรวจสอบสิทธิ์ Files API ด้วย

TODO 2: ค้นหาและแยกไฟล์ PDF จากที่เก็บถาวร tar

            member = next(m for m in tar.getmembers() if m.name.endswith("workspace/digest.pdf"))
            tar.extract(member, path=tmp, filter="data")

คำนำหน้าเส้นทาง tar จะแตกต่างกันไปในแต่ละการเรียกใช้ ดังนั้นให้ค้นหาตามคำต่อท้ายแทนที่จะเขียนโค้ดเส้นทางที่แน่นอน filter="data" จะไม่แสดงคำเตือนการเลิกใช้งาน Python 3.13 เกี่ยวกับการแยกไฟล์ tar ที่ไม่ปลอดภัย

ยืนยัน

uv run python download_pdf.py
Saved digest.pdf (48,231 bytes)

เปิด digest.pdf ในไดเรกทอรีเดียวกัน ซึ่งมีข้อมูลสรุปที่จัดรูปแบบแล้วซึ่งตัวแทนสร้างจากหน้าเว็บที่ใช้งานจริง

8. สานต่อการสนทนา

คุณมี digest.pdf อยู่แล้ว หากต้องการเพียงแค่ไฟล์ ก็ถือว่าเสร็จสิ้น ขั้นตอนนี้เกี่ยวข้องกับเรื่องอื่น นั่นคือการขอให้ตัวแทนเปลี่ยนข้อมูลสรุปโดยไม่ต้องดึงข้อมูลเว็บอีกครั้ง

Sandbox ยังคงใช้งานได้ Agent ยังคงมี/workspace/digest.pdfและจดจำทุกเรื่องราวที่สรุป การเรียกใช้interactions.create()ครั้งที่ 2 จะส่งข้อความติดตามผลไปยังแซนด์บ็อกซ์เดียวกัน ในที่นี้ คุณขอให้เพิ่มหมายเหตุ "เหตุผลที่เรื่องนี้สำคัญ" ใต้แต่ละเรื่อง และอัปเดต PDF ในตำแหน่งเดิมโดยไม่ต้องดึงข้อมูลหรือสรุปใหม่

สิ่งที่ต้องกรอก

เปิด refine_digest.py มีสิ่งที่ต้องทำ 3 รายการ

สิ่งที่ต้องทำ 1 และ 2: กรอกพารามิเตอร์การสนทนาไปมา 2 รายการภายใน interactions.create()

    environment=environment_id,
    previous_interaction_id=interaction_id,

environment=environment_id จะกลับมาใช้แซนด์บ็อกซ์เดิมพร้อมกับไฟล์และแพ็กเกจ previous_interaction_id=interaction_id ให้ประวัติการสนทนาแก่ Agent รายละเอียดส่วนอื่นๆ ยังคงเดิมจากครั้งแรก

TODO 3: คงค่า interaction_id ใหม่กลับไปที่ .env หลังจากวนรอบเหตุการณ์

save_env(INTERACTION_ID=interaction_id)

interactions.create() ทุกครั้งที่โทรออกจะสร้าง interaction_id ใหม่ การเขียนกลับหมายความว่าการเรียกใช้ครั้งถัดไปจะส่งการปรับแต่งนี้เป็น previous_interaction_id และการเชื่อมโยงจะทำงานอย่างถูกต้อง รหัสแซนด์บ็อกซ์จะไม่เปลี่ยนแปลง ENVIRONMENT_ID จึงไม่ต้องอัปเดต

พารามิเตอร์ 2 รายการที่ทำให้การสนทนาไปมาทำงานได้

รหัส

สิ่งที่ยังคงอยู่

การเปรียบเทียบ

environment=environment_id

ไฟล์ แพ็กเกจที่ติดตั้ง สถานะระบบ: ทุกอย่างในระบบไฟล์ Linux

การใช้โต๊ะทำงานเดียวกันระหว่างการประชุม

previous_interaction_id=interaction_id

ประวัติการสนทนา: สิ่งที่ Agent พูดและทำในรอบก่อนหน้า

จดจำเนื้อหาที่พูดคุยกันในการประชุมครั้งล่าสุด

คุณจะส่งบัตรประจำตัวอย่างใดอย่างหนึ่งแยกกันได้

  • environment_id เท่านั้น: ใช้ไฟล์และแพ็กเกจซ้ำ แต่เริ่มการสนทนาใหม่ มีประโยชน์สำหรับงานใหม่ในพื้นที่ทำงานเดียวกัน
  • previous_interaction_id เท่านั้น: ดำเนินบริบทการสนทนาต่อ แต่ในแซนด์บ็อกซ์ใหม่ (ไฟล์จะหายไป)
  • ทั้ง 2 อย่าง: ความต่อเนื่องเต็มรูปแบบ ซึ่งเป็นสิ่งที่ขั้นตอนนี้ใช้

ไม่มี environment_id: แซนด์บ็อกซ์เปล่า ไม่มี PDF หากไม่มี previous_interaction_id: ไม่มีบริบท ตัวแทนจะปรับแต่งส่วนที่เฉพาะเจาะจงไม่ได้

ยืนยัน

uv run python refine_digest.py

สตรีมควรจะรวดเร็ว เนื่องจาก Agent ไม่ได้ดึงข้อมูลใดๆ อีก หลังจากดำเนินการเสร็จแล้ว ให้ทำดังนี้

Refinement done.
Saved digest_v2.pdf (52,418 bytes)

เปิด digest_v2.pdf แล้วเปรียบเทียบกับ digest.pdf ตอนนี้แต่ละเรื่องควรมีบรรทัด "เหตุผลที่เรื่องนี้สำคัญ" เพิ่มเข้ามาแล้ว

9. คงการกำหนดค่า Agent ที่มีการจัดการ

การโทรทุกครั้งที่ผ่านมาผ่าน AGENTS.md, SKILL.md และ generate_pdf.py ในบรรทัด วิธีนี้ใช้ได้ แต่โค้ดที่เรียกใช้จะนำเนื้อหาไฟล์ทั้งหมดไปในการเรียกใช้ทุกครั้ง agents.create() จะฝังการกำหนดค่าลงในเอเจนต์ที่มีชื่อที่บันทึกไว้ในฝั่งของ Google การเรียกใช้ครั้งถัดไปจะส่งเฉพาะรหัสตัวแทน

Inline calls:   send sources on every call
Named agent:    bake once → invoke by ID, no sources

สิ่งที่ต้องกรอก

เปิด save_agent.py มีรายการสิ่งที่ต้องทำ 1 รายการ (สิ่งที่ต้องทำ 1)

โปรดทราบว่าค่าคงที่จะนำเข้าจาก run_digest.py โดยตรง (ไม่มีการทำซ้ำ)

from run_digest import BASE_AGENT, AGENTS_MD, SKILL_MD, GENERATE_PDF_PY

สิ่งที่ต้องทำ 1: กรอกข้อมูลในagents.create() call:

agent = client.agents.create(
    id="my-digest",
    base_agent=BASE_AGENT,
    agent_config={
        "type": "antigravity",
        "model": "gemini-3.7-flash",
    },
    description="Daily tech digest with editorial voice and PDF generation.",
    base_environment={
        "type": "remote",
        "sources": [
            {
                "type": "inline",
                "target": ".agents/AGENTS.md",
                "content": AGENTS_MD,
            },
            {
                "type": "inline",
                "target": ".agents/skills/digest-pdf/SKILL.md",
                "content": SKILL_MD,
            },
            {
                "type": "inline",
                "target": ".agents/skills/digest-pdf/scripts/generate_pdf.py",
                "content": GENERATE_PDF_PY,
            },
        ],
    },
)

agent_config จะตั้งค่าโมเดลพื้นฐาน gemini-3.7-flash เป็นค่าเริ่มต้นและเป็นตัวเลือกที่ดีที่สุดสำหรับเวิร์กโฟลว์นี้ ส่วน gemini-3.6-flash, gemini-3.5-flash และ gemini-3.5-flash-lite จะพร้อมใช้งานหากคุณต้องการรันที่มีน้ำหนักเบาหรือต้นทุนต่ำกว่า

base_environment (ไม่ใช่ environment) คือความแตกต่างที่สำคัญจากการเรียกใช้แบบอินไลน์ในขั้นตอนก่อนหน้า โดยแหล่งข้อมูลจะจัดเก็บไว้ที่ฝั่งของ Google และจะติดตั้งโดยอัตโนมัติในการเรียกใช้ครั้งต่อๆ ไป เรียกใช้เพียงครั้งเดียว ไม่ใช่ทุกครั้งที่เรียกใช้ข้อมูลสรุป

ยืนยัน: บันทึก Agent

uv run python save_agent.py
Saved: my-digest
my-digest: Daily tech digest with editorial voice and PDF generation.

เรียกใช้ Agent ที่บันทึกไว้

เปิด invoke_agent.py โดยจะเรียกใช้เอเจนต์ที่บันทึกไว้ตามรหัสโดยไม่มีแหล่งที่มา

stream = client.interactions.create(
    agent="my-digest",
    input="Generate the digest.",
    stream=True,
    environment="remote",
)

เปรียบเทียบกับคำสั่งเรียกใช้แบบอินไลน์: agent=BASE_AGENT จะแทนที่ด้วย "my-digest" และบล็อก environment แบบเต็มที่มีแหล่งที่มาแบบอินไลน์ 3 รายการจะแทนที่ด้วย environment="remote" การกำหนดค่าจะฝังไว้ในฝั่งของ Google อยู่แล้ว

ยืนยัน: เรียกใช้เอเจนต์ที่บันทึกไว้

uv run python invoke_agent.py

คุณควรเห็นไลฟ์สดเดียวกันกับการเรียกใช้แบบอินไลน์ แต่การเรียกใช้จะไม่มีไฟล์ต้นฉบับ หลังจากเรียกใช้แล้ว ระบบจะอัปเดต ENVIRONMENT_ID และ INTERACTION_ID ใน .env เพื่อให้คุณใช้ refine_digest.py ต่อไปได้เหมือนเดิม

[agent started]
  [tool] read_file
  [tool] write_file
  [tool] run_code
I have successfully created today's tech news digest.
Done. environment_id=9a1c3e02-...

10. ส่งผ่าน Gmail

เอเจนต์ได้สร้างข้อมูลสรุปและบันทึกไว้ใน /workspace/digest.pdf แล้ว ตอนนี้คุณได้ดาวน์โหลดไฟล์นี้ไว้ในเครื่องแล้ว ขั้นตอนนี้จะส่งอีเมลไปยังกล่องจดหมายของคุณโดยตรงด้วยการให้ตัวแทนเรียก Gmail REST API จากภายในแซนด์บ็อกซ์

แนวทางคือคุณจะได้รับโทเค็นเพื่อการเข้าถึง OAuth 2.0 ในเครื่องและส่งไปยังเอเจนต์ในพรอมต์ input Agent ใช้ code_execution เพื่อสร้างอีเมล MIME ที่มีไฟล์ PDF แนบมาและ POST ไปยัง Gmail API ไม่มีเครื่องมือที่กำหนดเอง ไม่มีการลงทะเบียนเซิร์ฟเวอร์ MCP

ข้อกำหนดเบื้องต้น

เปิดใช้ Gmail API ในโปรเจ็กต์ GCP และสร้างรหัสไคลเอ็นต์ OAuth 2.0 โดยทำดังนี้

  1. ไปที่ console.cloud.google.com/apis/library/gmail.googleapis.com แล้วเปิดใช้ Gmail API
  2. ไปที่ API และบริการ > ข้อมูลเข้าสู่ระบบ > สร้างข้อมูลเข้าสู่ระบบ > รหัสไคลเอ็นต์ OAuth 2.0
  3. ประเภทแอปพลิเคชัน: แอปเดสก์ท็อป ดาวน์โหลด JSON และบันทึกเป็น credentials.json ในรูทของโปรเจ็กต์

เพิ่มอีเมลผู้รับใน .env ดังนี้

RECIPIENT_EMAIL=you@gmail.com

ติดตั้งไลบรารีการตรวจสอบสิทธิ์หากจำเป็น

uv sync

สิ่งที่ต้องกรอก

เปิด send_digest.py โดยมีสิ่งที่ต้องทำ 2 รายการ

TODO 1: โหลดหรือรีเฟรชโทเค็นเพื่อการเข้าถึง OAuth 2.0

creds = None
if TOKEN_FILE.exists():
    creds = Credentials.from_authorized_user_file(TOKEN_FILE, SCOPES)
if not creds or not creds.valid:
    if creds and creds.expired and creds.refresh_token:
        creds.refresh(Request())
        TOKEN_FILE.write_text(creds.to_json())
    else:
        flow = InstalledAppFlow.from_client_secrets_file("credentials.json", SCOPES)
        creds = flow.run_local_server(port=8080, open_browser=False)
        TOKEN_FILE.write_text(creds.to_json())

นำบรรทัด raise NotImplementedError ออกหลังจากเพิ่มแล้ว เมื่อเรียกใช้เป็นครั้งแรก ระบบจะเปิดเบราว์เซอร์สำหรับหน้าจอขอความยินยอม OAuth ระบบจะแคชโทเค็นใน .gmail_token.json เพื่อการเรียกใช้ในอนาคต

TODO 2: แทนที่ input="" ด้วยวิธีการทางอีเมล โทเค็นอยู่ในขอบเขตอยู่แล้วในฐานะ creds.token

    input=(
        "Use the Gmail REST API to send an email:\n"
        f"  To: {recipient}\n"
        "  Subject: Tech Digest - <today's date in YYYY-MM-DD format>\n"
        "  Attachment: /workspace/digest.pdf attached as digest.pdf\n\n"
        "For the body, read /workspace/summaries.json and format it as a "
        "human-readable newsletter, NOT raw JSON. Use this structure:\n"
        "  Tech Digest - <date>\n\n"
        "  === <source name> ===\n"
        "  1. <title>\n"
        "     <summary>\n\n"
        "Steps:\n"
        "1. Parse /workspace/summaries.json and build the formatted body text above.\n"
        "2. Read /workspace/digest.pdf as bytes.\n"
        "3. Build a MIME multipart message using Python's email library.\n"
        "4. Base64url-encode the raw message.\n"
        "5. POST to https://gmail.googleapis.com/gmail/v1/users/me/messages/send "
        "with Authorization header using this token: "
        f"{creds.token}"
    ),

หน้าที่ของแต่ละส่วน

การโต้ตอบจะกลับมาทำงานต่อในแซนด์บ็อกซ์เดียวกันกับที่ Agent สร้าง digest.pdf และ summaries.json ไว้แล้ว previous_interaction_id ให้ประวัติการสนทนากับเอเจนต์

ระบบจะส่งโทเค็นเพื่อการเข้าถึงในสตริง input Agent จะอ่านจากพรอมต์และใช้ในส่วนหัว Authorization: Bearer เมื่อเรียกใช้ Gmail API โดยจะไม่แตะต้องเครื่องหรือระบบไฟล์ในเครื่องของคุณ

เอเจนต์ใช้ code_execution เพื่อเขียนและเรียกใช้สคริปต์ Python ภายในแซนด์บ็อกซ์ โดยจะอ่าน summaries.json จัดรูปแบบเป็นจดหมายข่าว อ่าน digest.pdf สร้างข้อความ MIME แบบหลายส่วน เข้ารหัส base64url และ POST ไปยัง https://gmail.googleapis.com/gmail/v1/users/me/messages/send

ยืนยัน

uv run python send_digest.py
Sending digest...
[agent started]
  [tool] read_file (/workspace/summaries.json)
  [tool] run_code
  [tool] run_code
Email sent successfully.
Email sent. Check your inbox.

โปรดตรวจสอบกล่องจดหมาย คุณจะได้รับอีเมลที่มีเนื้อหาในรูปแบบจดหมายข่าวและไฟล์ digest.pdf แนบมา

11. กำหนดเวลาการเรียกใช้รายวัน

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

Manual:     python run_digest.py     → runs once, now
Trigger:    client.triggers.create() → runs every morning, automatically

สิ่งที่ต้องกรอก

เปิด create_trigger.py มีสิ่งที่ต้องทำ 1 รายการ

สิ่งที่ต้องทำ 1: กรอกข้อมูลในtriggers.create()โทร ทริกเกอร์จะเรียกใช้เวิร์กโฟลว์ทั้งหมดในแต่ละวัน ได้แก่ สร้างสรุปและส่งไปยังกล่องจดหมาย เนื่องจากโทเค็นเพื่อการเข้าถึงจะหมดอายุใน 1 ชั่วโมง จึงจะแทรกโทเค็นการรีเฟรชจาก .gmail_token.json เป็นแหล่งที่มาแบบอินไลน์เพื่อให้ตัวแทนสามารถแลกเปลี่ยนเป็นโทเค็นใหม่ได้ในแต่ละครั้งที่เรียกใช้

trigger = client.triggers.create(
    schedule="0 9 * * *",
    time_zone="UTC",
    display_name="daily-tech-digest",
    max_consecutive_failures=3,
    execution_timeout_seconds=600,
    interaction={
        "agent": "my-digest",
        "input": (
            f"Generate the daily tech digest following AGENTS.md instructions. "
            f"Then send an email to {recipient}:\n"
            "- Subject: Tech Digest - <today's date in YYYY-MM-DD format>\n"
            "- Body: the content of /workspace/summaries.json formatted as a readable "
            "newsletter (NOT raw JSON).\n"
            "- Attachment: /workspace/digest.pdf\n\n"
            "For Gmail auth: read /workspace/.gmail_creds.json, POST to "
            "https://oauth2.googleapis.com/token with grant_type=refresh_token "
            "and the client_id, client_secret, refresh_token from the file to get an "
            "access_token. Then POST to "
            "https://gmail.googleapis.com/gmail/v1/users/me/messages/send "
            "with Authorization: Bearer <access_token>."
        ),
        "environment": {
            "type": "remote",
            "sources": [
                {
                    "type": "inline",
                    "target": "/workspace/.gmail_creds.json",
                    "content": gmail_creds,
                }
            ],
        },
    },
)

execution_timeout_seconds=600 คือระยะหมดเวลาเริ่มต้น max_consecutive_failures=3 จะหยุดทริกเกอร์ชั่วคราวโดยอัตโนมัติหลังจากเรียกใช้ไม่สำเร็จ 3 ครั้งติดต่อกัน (ค่าเริ่มต้นของ API คือ 5 แต่ 3 จะระมัดระวังมากกว่าสำหรับเวิร์กช็อป)

sources จะแทรก .gmail_creds.json ลงในแซนด์บ็อกซ์ที่ /workspace/.gmail_creds.json Agent จะอ่านโทเค็นการรีเฟรช แลกเปลี่ยนเป็นโทเค็นเพื่อการเข้าถึงใหม่ และเรียกใช้ Gmail API โทเค็นเพื่อการรีเฟรชจะไม่มีวันหมดอายุ ดังนั้นจึงใช้ได้กับการเรียกใช้ที่กำหนดเวลาไว้ทุกครั้งโดยไม่ต้องรีเฟรชโทเค็นด้วยตนเอง

นำบรรทัด raise NotImplementedError ออกหลังจากเพิ่มการโทร

ยืนยัน

uv run python create_trigger.py
Trigger created: trig_abc123
Next run:        2026-07-23T09:00:00Z

create_trigger.py จะบันทึกรหัสทริกเกอร์ไปยัง .env โดยอัตโนมัติ

วิธีตรวจสอบประวัติการดำเนินการหลังการเรียกใช้

uv run python check_trigger.py

หากต้องการทริกเกอร์ทันทีโดยไม่ต้องรอเวลาที่กำหนดไว้ครั้งถัดไป ให้ทำดังนี้

uv run python fire_trigger.py

วิธีหยุดชั่วคราวหรือลบทริกเกอร์

uv run python pause_trigger.py

12. ล้าง

Sandbox จะหมดอายุโดยอัตโนมัติหลังจากไม่มีการใช้งานเป็นเวลา 7 วัน ไม่มีเซิร์ฟเวอร์ที่จะหยุด ไม่มีคอนเทนเนอร์ที่จะลบ

หากบันทึกการกำหนดค่าเอเจนต์ไว้ ให้ลบออกโดยทำดังนี้

uv run python delete_agent.py

13. สรุป

คุณสร้าง Agent ที่มีการจัดการตั้งแต่เริ่มต้นทีละแนวคิด แบบฝึกหัดแต่ละแบบสอนอะไรบ้าง

การออกกำลังกาย

แนวคิด

คีย์ API

โทรครั้งแรก

จัดสรรแซนด์บ็อกซ์ Linux จริงและสตรีมเหตุการณ์แบบสด

interactions.create(agent, input, environment, stream=True), event.event_type

ปรับแต่ง Agent

ต่อเชื่อมไฟล์การกำหนดค่าและคงรหัสไว้ใน .env ในการเรียกใช้เดียวกัน

environment.sources, save_env

เพิ่มฮุกความปลอดภัย

ดักการเรียกใช้เครื่องมือก่อนที่จะดำเนินการ ปฏิเสธคำสั่งที่เป็นอันตราย

hooks.json, pre_tool_execution, gate.py

ดาวน์โหลด PDF

ดาวน์โหลด PDF โดยไม่ต้องเรียกใช้ Agent อีกครั้ง

Gemini Files API :download ใน download_pdf.py

สนทนาต่อ

สานต่อการสนทนาโดยไม่ต้องดึงข้อมูลเว็บอีกครั้ง

environment=environment_id, previous_interaction_id=interaction_id

คงการกำหนดค่า Agent

คงการกำหนดค่าเอเจนต์ เรียกใช้ตามรหัส ไม่ต้องใช้แหล่งที่มา

agents.create(), agents.list()

ส่งผ่าน Gmail

รับโทเค็น OAuth ในเครื่อง แล้วส่งไปยังตัวแทน ซึ่งจะเรียกใช้ Gmail REST API ผ่าน code_execution

OAuth 2.0, client.interactions.create(input=...)

ตั้งเวลาเรียกใช้ทุกวัน

เรียกใช้ Agent โดยอัตโนมัติตามกำหนดเวลา Cron

client.triggers.create(schedule, time_zone, interaction)

รูปแบบสำคัญ

  1. การเรียกใช้ครั้งเดียว แซนด์บ็อกซ์เดียว: interactions.create() จัดการโครงสร้างพื้นฐานทั้งหมด (ไม่ต้องติดตั้งใช้งานคอนเทนเนอร์ ไม่ต้องติดตั้งแพ็กเกจในเครื่อง)
  2. การสตรีมแบบโพรเกรสซีฟ: stream=True เปลี่ยนกล่องดำ 90 วินาทีให้เป็นฟีดสดของการเรียกใช้เครื่องมือและข้อความ
  3. แหล่งข้อมูลในบรรทัด: ติดตั้ง AGENTS.md, SKILL.md และสคริปต์ที่สร้างไว้ล่วงหน้าลงในแซนด์บ็อกซ์โดยไม่ต้องอัปโหลดหรือขั้นตอนการติดตั้งใช้งาน
  4. ใช้ประโยชน์จากการค้นหาอัตโนมัติ: ระบบจะเลือกไฟล์ที่วางไว้ใน .agents/ โดยอัตโนมัติ (ไม่ต้องกำหนดค่า SDK)
  5. สถานะ 2 มิติ: environment_id ติดตามไฟล์และแพ็กเกจ previous_interaction_id ติดตามบริบทการสนทนา โดยสามารถส่งได้แยกกัน
  6. การดาวน์โหลดสแนปชอต: สภาพแวดล้อมคือไฟล์ tar ของระบบไฟล์แบบเต็ม ซึ่งเข้าถึงได้ผ่าน Gemini Files API
  7. ตัวแทนที่ระบุชื่อ: agents.create() จะฝังการกำหนดค่าอย่างถาวร การเรียกในอนาคตจะส่งเฉพาะรหัสตัวแทนและ environment="remote" โดยไม่มีแหล่งที่มา
  8. Hook: hooks.json + สคริปต์เกตจะสกัดกั้นการเรียกใช้เครื่องมือก่อนที่จะดำเนินการ deny การตอบกลับจะยกเลิกการโทรและเจ้าหน้าที่จะแก้ไขด้วยตนเอง
  9. การเรียก API ภายนอก: ส่งข้อมูลเข้าสู่ระบบในพรอมต์ input เอเจนต์จะเขียนและเรียกใช้โค้ดการผสานรวมภายในแซนด์บ็อกซ์ผ่าน code_execution
  10. ทริกเกอร์: กำหนดเวลา Agent ในนิพจน์ Cron ด้วย client.triggers.create() สภาพแวดล้อมจะยังคงอยู่ในการดำเนินการต่างๆ

ADK + Cloud Run เทียบกับ Agent ที่ได้รับการจัดการ: ความแตกต่างโดยย่อ

ความสามารถ

ADK + Cloud Run

Agent ที่ได้รับการจัดการใน Gemini API

จัดสรรแซนด์บ็อกซ์

docker build + gcloud run deploy

interactions.create()

กำหนดเครื่องมือ

ฟังก์ชัน Python ที่ลงทะเบียนกับเอเจนต์

ในตัว: การท่องเว็บ การเรียกใช้โค้ด ระบบไฟล์

ติดตั้งแพ็กเกจ

pip install ใน Dockerfile

Agent ทำงาน pip install ภายในแซนด์บ็อกซ์

สตรีมกิจกรรม

โครงสร้างพื้นฐาน SSE ที่กำหนดเอง

stream=True

ดำเนินการต่อในเซสชัน

ฐานข้อมูลเซสชัน + การแทรกบริบท

environment_id + previous_interaction_id

ไฟล์การกำหนดค่า

ฝังไว้ใน Agent หรือแทรกเมื่อเริ่มต้น

ติดตั้งผ่าน environment.sources

โครงสร้างพื้นฐานที่จะจัดการ

คอนเทนเนอร์, Cloud Run, IAM, ข้อมูลลับ

ไม่มี

ขั้นตอนถัดไป