google / google/adk-python

Add `response_json_schema` support to `RunConfig` for per-request structured output

Aperta
#3,866 5 commenti 0 reazioni 2 assegnatari Rivendicata da @wuliang229 Vedi su GitHub
a2a needs review
Lingua principale
Python
Stelle
21.5k
Fork
4k
Merge medio
1g 14h
PR unite (30g)
37

Descrizione

**Is your feature request related to a problem? Please describe.**

When building A2A (Agent-to-Agent) servers using ADK, the calling agent can request structured output by including a JSON schema in the message metadata, per the [A2A Structured Data Exchange
spec](https://google.github.io/A2A/#/documentation?id=structured-data-exchange):

```json
{
"message": {
"parts": [{
"text": "Show me a list of my open IT tickets",
"metadata": {
"mediaType": "application/json",
"schema": {
"type": "array",
"items": {
"type": "object",
"properties": {
"ticketNumber": { "type": "string" },
"description": { "type": "string" }
}
}
}
}
}]
}
}
```

The schema is per-request, not per-agent. Different requests to the same agent may request different output schemas (or no schema at all).

Currently, there's no direct way to pass a response schema through `Runner.run_async()`. The available options are:
1. `LlmAgent.output_schema` - Set at agent creation time, not per-request
2. `LlmAgent.generate_content_config` - Also set at agent creation time
3. `before_model_callback` / Plugin - Works, but requires storing the schema in session state and reading it back in a callback, which is indirect

**Describe the solution you'd like**

Add optional fields to `RunConfig`:

```python
class RunConfig(BaseModel):
# ...

response_json_schema: Optional[dict[str, Any]] = None
"""JSON Schema for structured output. When set, configures the LLM
to return responses conforming to this schema."""

response_mime_type: Optional[str] = None
"""MIME type for the response. Defaults to 'application/json' when
response_json_schema is set."""
```

Then in `BaseLlmFlow`, apply these to the `LlmRequest.config` before calling the LLM:

```python
if invocation_context.run_config and invocation_context.run_config.response_json_schema:
llm_request.config = llm_request.config or types.GenerateContentConfig()
llm_request.config.response_json_schema = invocation_context.run_config.response_json_schema
llm_request.config.response_mime_type = (
invocation_context.run_config.response_mime_type or "application/json"
)
```

Example Usage

```python
schema = {
"type": "object",
"properties": {
"answer": {"type": "string"},
"confidence": {"type": "number"}
}
}

async for event in runner.run_async(
user_id="user-123",
session_id="session-456",
new_message=content,
run_config=RunConfig(response_json_schema=schema),
):
# LLM responses will conform to the schema
...
```

**Describe alternatives you've considered**

Using a plugin/callback. This works but requires:
1. Storing the schema in session state before calling `run_async()`
2. Creating a plugin that reads from session state in `before_model_callback`
3. Setting it on `llm_request.config.response_json_schema`

This is indirect and couples the schema to session state rather than the request itself.

**Additional context**

This started with me trying to send A2A requests to [kagent](https://kagent.dev/) (which uses ADK under the hood) including as the documentation says. But the schema information is dropped by ADK.

Guida per i contributori

Apri la guida per i contributori

Valutazione

Questa issue non è ancora stata valutata.

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.