Skip to content

ADK Agent Container Image - #6894

Open
george-kalisse-sada wants to merge 1 commit into
GoogleCloudPlatform:masterfrom
george-kalisse-sada:SADA_1b_adk_agent_container
Open

ADK Agent Container Image#6894
george-kalisse-sada wants to merge 1 commit into
GoogleCloudPlatform:masterfrom
george-kalisse-sada:SADA_1b_adk_agent_container

Conversation

@george-kalisse-sada

Copy link
Copy Markdown
Collaborator

Files: ~13 new files (no Python benchmark logic)

  • perfkitbenchmarker/data/docker/agentic/adk-agent/README.md
  • perfkitbenchmarker/data/docker/agentic/adk-agent/Dockerfile
  • perfkitbenchmarker/data/docker/agentic/adk-agent/__init__.py
  • perfkitbenchmarker/data/docker/agentic/adk-agent/.dockerignore
  • perfkitbenchmarker/data/docker/agentic/adk-agent/.gcloudignore
  • perfkitbenchmarker/data/docker/agentic/adk-agent/cloudbuild-arm64.yaml
  • perfkitbenchmarker/data/docker/agentic/adk-agent/requirements.txt
  • perfkitbenchmarker/data/docker/agentic/adk-agent/main.py
  • perfkitbenchmarker/data/docker/agentic/adk-agent/gke_performance_agent/__init__.py
  • perfkitbenchmarker/data/docker/agentic/adk-agent/gke_performance_agent/agent.py
  • perfkitbenchmarker/data/docker/agentic/adk-agent/sandboxed_apps/python_test_app/benchmark_density.py
  • perfkitbenchmarker/data/docker/agentic/adk-agent/sandboxed_apps/python_test_app/benchmark_payload.py
  • perfkitbenchmarker/data/docker/agentic/adk-agent/sandboxed_apps/python_test_app/benchmark_qps.py

Description: Adds the ADK Agent container image — a FastAPI service deployed inside the GKE cluster that the PKB benchmark modules interact with via HTTP. Includes:

  • FastAPI endpoints for density, payload, QPS, and Chromium benchmarks
  • Mock LLM agent definition using Google ADK with BenchmarkGkeCodeExecutor
  • 3 benchmark scripts that execute inside gVisor sandboxes (density, payload, QPS)
  • Dockerfile, requirements, and Cloud Build config for ARM64 cross-compilation

Nothing in PKB imports these files — they are copied into a container image at build time.

@@ -0,0 +1,56 @@
# ADK Agent Container

FastAPI service deployed inside the GKE cluster that serves as the

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Replace "GKE" with "Kubernetes"

sandbox-side metrics.
"""
async with _benchmark_lock:
os.environ["BENCHMARK_MODE"] = "density"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not urgent, but maybe for a followup PR:

Using os env to pass configs is not very intuitive, and also has the risk of race conditions. Consider using the prompt to pass the configs

POST /benchmark/python/density
 | 
 v
FastAPI service 
 |
 | (prompt: {mode: "density", sample_count: 100...})
 v
ADK agent 
 |
 | (prompt: {mode: "density", sample_count: 100...})
 v
MockLLM
 |
 | (script instruction based on the prompt)
 v
ADK agent (execution)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@roycaihw Using os.environ is a design choice to keep the Python benchmark scripts static. If we passed parameters via the prompt, our MockLlm would have to perform string-replacement on the Python script's source code to inject the variables (e.g., changing SAMPLE_COUNT = 20 to 100) before sending it to the sandbox. With os.environ, the Python script remains static, and we cleanly inject the variables into the sandbox via standard Linux environment variables (/bin/sh -c 'SAMPLE_COUNT=100 python3 script.py').

Regarding race conditions: we explicitly use an asyncio.Lock() (_benchmark_lock) around the endpoint handlers to serialize benchmark requests, ensuring concurrent POSTs cannot clobber the shared environment variables.

req.concurrent_sessions,
)

prompt = "Please start the GKE performance benchmark workflow."

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The prompt is not used, correct? Can we drop it?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct that the content of the prompt is ignored by our MockLlm. However, the ADK Runner.run_async() method requires a non-empty string to initiate the conversation loop and trigger the first LLM generation. I can simplify the string to just "start" to make it clear that it is simply a trigger, but we cannot drop the variable entirely.

)


class ChromiumBenchmarkRequest(BaseModel):

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right now the main.py combines all the endpoints and their Request class. For better readability, can you split each endpoint and its Request class into a separate file?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll refactor into a "modular" FastAPI structure with an api/routes/ directory, moving each endpoint and its models into separate files.

_benchmark_lock = asyncio.Lock()


def _percentile_stats(sorted_values: list, prefix: str) -> dict:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you turn this function into a util for reuse? You have two methods (_percentile_stats and _percentile). Make them consistent.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll consolidate the percentile logic into a shared api/utils.py file, sure.

logging.exception("Error shutting down ThreadPoolExecutor")


app = FastAPI(title="GKE Benchmark Agent", version="0.2.0", lifespan=lifespan)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's replace GKE with Kubernetes

POST /benchmark/chromium/density → run the Chromium density benchmark
POST /run → raw ADK agent interaction

POST /benchmark/python/density — Request:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The documentation seems incomplete as it only has the request and response for POST /benchmark/python/density. I'd recommend putting the API endpoint documentation in a separate doc file.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll move the API doc out of main.py and into a new API_DOCS.md file.

elapsed_ms = (time.perf_counter() - t0) * 1000

print(json.dumps({
"sandbox_status": "ok",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's make this a "success" v.s. "fail" based on whether result matches the expectation (49,995,000-- the sum of all integers from 0 up to 9,999)

print(json.dumps({
"sandbox_status": "ok",
"sandbox_qps_exec_ms": round(elapsed_ms, 3),
"sandbox_compute_result": result,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's drop the "sandbox_compute_result" since it's just confusing to people unless they read the actual source of what the sandbox does.


print(json.dumps({
"sandbox_status": "ok",
"sandbox_qps_exec_ms": round(elapsed_ms, 3),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's drop "qps" from the metrics name since this metrics measures how long a simple python sandbox execution takes-- nothing related to qps here.

@hubatish

Copy link
Copy Markdown
Collaborator

Thanks for the review Roy. Give me a ping when Roy's lgtm'ed & I'll add the lgtm + tag which will start the merging process

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants