I see. So your units have to go through the path vertices closely or exactly.
Which is a problem, because at the vertex they can't dodge around obstacles.
To minimize the problem, you want to reduce the number of vertices.
But you're kinda doubtful about this idea.
Which is because you subconsciously know that making a problem happening less often does not solve the problem.
So you still have to work on that anyway, and thus the work on minimizing the problem might be a waste of time.
That's what you think, i guess.
Obviously you should solve to problem first, i conclude.
Part of the solution must be: A unit should be allowed to diverge from the path, and there should be no difference regarding vertices and edges. It should be allowed to have some distance from a vertex as well.
So i propose you store 'the current vertex (or edge if you prefer)’ per unit.
It does not matter how far this vertex is away. It only matters the Unit knows which it is.
Each time you update the unit, you check if the next vertex on the path is in reach, and make it the current it if so.
This ensures the unit has to travel the whole path, and it can not accidentally go backwards. It always tries to reach the current vertex, but if it comes close enough, it makes the next vertex the goal.
If an obstacle blocks the way to the current vertex, the problem is addressed using obstacle avoidance behavior.
Once this works, you can easily extend this to look forwards the path for the farthest unblocked vertex,
to get the path smoothing and looking smarter stuff discussed above.
So i guess this would work well, and only one costly ray is needed per step, for the potential next vertex. (Such ray is still much cheaper than computing a shortest path, ofc.)
However, there might be one new problem, depending on what you currently do:
I assume each Unit (or groups of units) store their path. So the path remains constant, and thus we can index vertices as proposed.
Only rarely there should be a reason to compute a new path. E.g. if units get another objective, or if the path gets blocked, etc.
So if there is a new path, you just set the unit to the first vertex, which at this time will be close.
Over the next few frames, the units will refine their target vertex to a furthest distance, for the path smoothing and smartness stuff.
So it should just work, and updating paths causes not problems.