Look into using Dynamic LINQ. It allows you to use string expressions instead of Lambda expressions.
It would end up looking something like this:
var results = Messages
.GroupBy(m => new { m.Year, m.Month })
.Select("new (Key.Year as Year, Sum(Metric1) as Metric)");
You'd just have to generate the select expression string outside of the query however you want to do that.
There is a version if Dynamic LINQ on Nuget here: https://www.nuget.org/packages/System.Linq.Dynamic.Library/