I had thought about the issue of capping before I posted my previous answer. The capping is the most difficult part, and I thought that it would've been a waste to have spent time on it if if turned out that the whole tubeplot idea didn't meet your needs. I had considered plottools:-cylinder, but it is quite difficult (though not impossible) to use because it only generates cylinders with axes parallel to the z-axis. So they would have to be individually rotated at random. I also considered representing each cap as a parametric surface; it's a lot of analytic geometry to get the parameters right.
It turns out that the caps can be generated with tubeplot, if you're willing to accept caps that are not perfectly flat; rather, they are slightly conical, like cylinders of hard candy wrapped in paper which is twisted at the ends. The radius of the tube can vary (with the same parameter, t, that is used as the parameter of the tube's curve), and we simply need to make it go abruptly to 0 at both ends. I do this with a step function created with piecewise.
Gen:= (N,R)-> RandomTools:-Generate(list(float(range= 1..R), N)):
x,x1,y,y1,z,z1:= seq(Gen(Npts,20), k= 1..6):
R:= Gen(Npts,3): # random radius parameter
candy:= piecewise(t <= 0, 0, t < 1, 1, 0):
[x+(x1-x)*t, y+(y1-y)*t, z+(z1-z)*t, radius= R*candy]
plots:-tubeplot(P(x,x1,y,y1,z,z1,R), t= 0..1, tubepoints= 20)
plots:-display([seq](S(x[k],x1[k],y[k],y1[k],z[k],z1[k],R[k]), k= 1..Npts));