Here is two ways to do this:
One version uses reduce which you can use very often if you want to carry some kind of state (here: The index where you're currently at). The reduce would need a second fn call applied to it to have the result in your form.
;; Simply take second as a result:
(let [s "firstchunksecondthirdandlast"]
(reduce
(fn [[s xs] len]
[(subs s len)
(conj xs (subs s 0 len))])
[s []]
[10 6 12]))
The other version first builds up the indices of start-end and then uses destructing to get them out of the sequence:
(let [s "firstchunksecondthirdandlast"]
(mapv
(fn [[start end]]
(subs s start end))
;; Build up the start-end indices:
(partition 2 1 (reductions + (cons 0 [10 6 12])))))
Note that neither of these are robust and throw ugly errors if the string it too short. So you should be much more defensive and use some asserts.