LocalLLaMA, Qwen 3.5 chat template bug가 prefix-cache reuse를 조용히 무너뜨린다고 지적

실전 감각이 강한 r/LocalLLaMA debugging post가 주목받는 이유는 local agent workflow를 느리게 만드는 원인이 model weights도 inference engine도 아니라 chat template일 수 있다는 점을 보여주기 때문이다. 작성자는 M5 Max에서 Qwen 3.5와 oMLX.ai, OpenCode.ai, Pi.dev 조합을 최적화하는 동안 cache miss를 추적했고, 비슷한 현상을 llama.cpp 등 다른 backend에서도 재현했다고 말했다.

패턴은 꽤 구체적이다. tool call이 이어진 긴 turn 뒤에 간단한 follow-up question을 던지면, prefix cache를 재사용하지 않고 예전 context의 큰 덩어리를 다시 처리한다는 것이다. 글에 따르면 원인은 shipped Qwen 3.5 chat template가 historical assistant turn에 대해 reasoning_content가 비어 있어도 empty <think>...</think> block를 넣을 수 있다는 점이다. 그러면 의미상 같은 conversation history라도 serialized prompt가 달라지고, 결국 cache prefix matching이 깨져 불필요한 recomputation이 발생한다.

제안된 fix는 Jinja template의 one-line guard다. reasoning text가 실제로 있을 때만 historical wrapper를 출력하라는 것이다. Reddit post는 upstream discussion link도 함께 걸어 두었는데, 문제는 이미 Reddit 바깥에서도 확인된다. Hugging Face discussion의 제목은 “fix empty historical <think> blocks in chat_template.jinja”이고, GitHub issue #1826 역시 thinking을 끈 상태에서 같은 계열의 KV-cache breakage를 설명한다. thread의 commenters도 LM Studio와 다른 stack에서 비슷한 repeated prefill을 봤다고 했고, early tester 중 적어도 한 명은 patch 뒤 follow-up turn이 훨씬 빨라졌다고 적었다.

왜 이 글이 반응을 얻었나

이 post가 먹힌 이유는 agent performance가 이제 tool use 주변의 serialization detail에 얼마나 민감한지를 정확히 보여줬기 때문이다. 긴 local coding session에서는 prefix caching을 깨뜨리는 template bug 하나만으로 turn마다 수만 token이 낭비되고, 충분히 강한 model도 실제 체감상 망가진 것처럼 보일 수 있다. practitioners가 원하는 정보는 바로 이런 것이다. context window가 더 크고 quantized inference가 더 빨라져도, format bug 하나가 그 이점을 모두 지울 수 있다. 이 thread의 교훈은 단순하다. tool-heavy exchange 이후 Qwen 3.5가 옛 context를 계속 다시 읽는다면, cache layer를 탓하기 전에 chat template부터 확인해야 한다.