We can define a helper function that will release any component of a held expression that matches a particular pattern:
releaseHeldMatches[patt_] := ReplaceAll[p:patt :> RuleCondition[p]]
We can then use it to release the ReplaceAll that appears in the expression from the question:
expr // releaseHeldMatches[_ReplaceAll]
(* HoldForm[a = 10 b] *)
The function releasePattern from the question can then be defined thus:
releasePattern = releaseHeldMatches[_ReplaceAll];
expr // releasePattern
(* HoldForm[a = 10 b] *)
Both of these work upon some part of the expression that matches a pattern. Perhaps we would like to release a part found at a particular index instead:
releaseAt[i__][expr_] := ReplacePart[expr, {i} -> expr[[i]]]
expr // releaseAt[1, 2]
(* HoldForm[a = 10 b] *)
Note: one might object to releaseHeldMatches operating upon level zero of the held expression, or lament that extracted subexpressions may be held in their own right. I purposely choose not to worry about either of these contingencies, but should one care:
releaseHeldMatchesPedantic[patt_, expr_] :=
Replace[expr, p: patt :> RuleCondition[ReleaseHold[p]], {1, Infinity}]
releaseHeldMatchesPedantic[patt_][expr_] :=
releaseHeldMatchesPedantic[patt, expr]