As Hyukjin Kwon pointed out, the Observation API (Scala, Java, PySpark) could return a Map / Dict. It currently returns Row simply because the metrics are (internal to Observation) retrieved from the listener as rows. Since that is hidden from the user by the Observation API, there is no need to return Row.
If there is some value in the original Row, both could be provided via getAsRow and getAsMap.
The Observation API has been added to Spark in unreleased 3.3.0, so it should not be a blocker to remove the Row return type in 3.3.0 again.