Uma diferença é que conjaceita qualquer número de argumentos para inserir em uma coleção, enquanto consleva apenas um:
(conj '(1 2 3) 4 5 6)
; => (6 5 4 1 2 3)
(cons 4 5 6 '(1 2 3))
; => IllegalArgumentException due to wrong arity
Outra diferença está na classe do valor de retorno:
(class (conj '(1 2 3) 4))
; => clojure.lang.PersistentList
(class (cons 4 '(1 2 3))
; => clojure.lang.Cons
Observe que eles não são realmente intercambiáveis; em particular, clojure.lang.Consnão implementa clojure.lang.Counted, então a counton ele não é mais uma operação de tempo constante (neste caso, provavelmente seria reduzido para 1 + 3 - o 1 vem do percurso linear sobre o primeiro elemento, o 3 vem de (next (cons 4 '(1 2 3))ser um PersistentListe portanto Counted).
A intenção por trás dos nomes é, creio eu, que conssignifica contr (construir a seq) 1 , ao passo que conjsignifica conj (inserir um item em uma coleção). A seqsendo construído por conscomeça com o elemento passado como primeiro argumento e tem como next/ restparte a coisa resultante da aplicação de seqpara o segundo argumento; como mostrado acima, tudo é de classe clojure.lang.Cons. Em contraste, conjsempre retorna uma coleção mais ou menos do mesmo tipo da coleção passada a ele. (Grosso modo, porque a PersistentArrayMapserá transformado em PersistentHashMapassim que crescer além de 9 entradas.)
1 Tradicionalmente, no mundo Lisp, conscons (constrói um par), então Clojure se afasta da tradição Lisp ao ter sua consfunção construir um seq que não possui um tradicional cdr. O uso generalizado de conspara significar "construir um registro de algum tipo ou outro para manter uma série de valores juntos" é atualmente onipresente no estudo de linguagens de programação e sua implementação; é isso que se quer dizer quando se menciona "evitar golpes".