As discussed in comments you actually just want the URL. Here’s your code modified to be a get_avatar_url hook instead:
add_filter('get_avatar_url', 'lb_acf_profile_avatar_url', 10, 5);
function lb_acf_profile_avatar_url($url, $id_or_email, $args) {
$user="";
// Get user by id or email
if (is_numeric($id_or_email)) {
$id = (int) $id_or_email;
$user = get_user_by('id', $id);
} elseif (is_object($id_or_email)) {
if (!empty($id_or_email->user_id)) {
$id = (int) $id_or_email->user_id;
$user = get_user_by('id', $id);
}
} else {
$user = get_user_by('email', $id_or_email);
}
if (!$user) {
return $url;
}
$avatar_url = $user->get('user_url');
if ($avatar_url == '') {
return $url;
}
return $avatar_url;
}
Untested, sorry. It uses the same logic as the existing code to resolve the $id_or_email parameter into a user object: there’s probably some room for improvement here e.g. since the $id_or_email might already be the user object, and I’m a little nervous about the empty string checks but that’s what the existing (presumably working) code does.
You can then call WordPress’s get_avatar_url with a user ID and it should return user_url where available. I’d expect get_avatar to still work too with just this filter.