Qwen 3.5·3.6용 단일 Jinja 템플릿 호환성 및 안정성 개선
대화형 에이전트 프롬프트 렌더링과 툴 호출 포맷 정합성 보장 및 멀티턴 KV 캐시 동기화apache-2.0
Qwen 3.5/3.6용 단일 chat_template.jinja 파일로 Jinja 렌더링 오류와 KV 캐시 무효화, 에이전트 루프 정체, C++ 런타임 호환성 문제를 해결한다.
TL;DR
이 리포지토리는 Qwen 3.5 및 3.6 계열을 대상으로 한 단일 Jinja 템플릿으로서 다양한 추론 엔진에서 발생하던 렌더링 오류, KV 캐시 무효화, 토큰 낭비, 에이전트 루프 정체 문제를 해결하도록 설계되었다. 핵심 기법은 `<think>` 블록의 연대기적 보존과 경계 공백 정규화를 통해 로컬 KV 캐시와의 완전한 동기화를 달성하는 것, AST 평탄화와 minijinja 안전성 수정으로 C++ 런타임 파싱 병목을 제거하는 것, 그리고 연속 실패 카운터 기반의 두 단계 오류 에스컬레이션과 구조적 오류 검출로 무한 재시도 루프를 차단하는 것이다. 추가로 대용량 툴 페이로드를 제어하는 트렁케이션 설정과 JSON 오버라이드 옵션을 제공하되 JSON 모드에서는 트렁케이션을 자동 비활성화해 구조적 손상을 방지한다. 결과적으로 템플릿은 여러 엔진에서의 실무 호환성을 크게 개선하지만 JSON 모드 전환과 엔진별 구현 차이로 인해 일부 옵션은 환경별 테스트가 필요하다.
핵심 역량
- 이 템플릿은 단일 파일로 Qwen 3.5/3.6 대화 프롬프트를 렌더링하여 LM Studio, llama.cpp, vLLM, MLX 등 다양한 추론 엔진에서 동일한 출력 포맷을 생성한다. 렌더링 과정에서 엔진별 안전한 Jinja 대체구문과 순서 규칙을 적용해 파서 충돌 가능성을 줄인다. 또한 툴 콜을 XML 기본 포맷으로 유지하되 필요 시 JSON으로 오버라이드할 수 있는 옵션을 제공한다.
- 다중 턴 에이전트 루프에서 `<think>` 블록을 기본적으로 보존하여 연속 대화 중 'amnesia stall' 현상을 제거하고 로컬 KV 캐시의 적중률을 극대화한다. 이 보존 동작은 렌더된 이력의 연대기적 정렬과 경계 공백(normalization)을 통해 KV 캐시와 정확히 동기화된다. 제한된 하드웨어에서 토큰 낭비를 줄이려면 `preserve_thinking`을 false로 설정해 생각 블록을 제거할 수 있다.
- 툴 호출 실패 상황에서 연속 실패 카운터를 추적해 1차 오류 시에는 재시도 유도용 톤 변화와 다른 토큰 위치로의 프롬프트 시딩을 적용하고, 2차 이상 연속 오류 시에는 think 블록을 건너뛰고 즉시 교정 액션을 강제하는 아웃오브밴드 지시를 삽입한다. 이 메커니즘은 동일 실패 반복과 무한 재시도 루프를 차단한다. 길이 게이트와 구조적 검사 규칙을 결합해 정상 응답을 오류로 오인하는 확률을 줄인다.
강점
- 템플릿은 다양한 추론 엔진 환경에서 호환성을 맞추는 실용적 접근을 취해 LM Studio, llama.cpp, vLLM, MLX 등에서 동작하도록 설계되었다. 문법적 호환성 확보와 minijinja 안전성 보장을 통해 C++ 런타임에서 발생하던 크래시를 방지한다. Apache-2.0 라이선스로 상업적 사용과 수정이 자유로운 점도 실무 적용 관점에서 장점이다.
- 연대기적 이력 보존과 경계 공백 정규화를 통해 로컬 KV 캐시와의 완전한 동기화를 목표로 삼아 다중 턴 에이전트 루프에서 'amnesia stall' 문제를 제거했다는 점을 핵심 강점으로 내세운다. 이 접근은 모델의 토큰 재처리 비용을 줄이고 추론 효율을 높이는 데 직접적인 영향을 미친다. 다만 해당 수치는 README에 기반한 구현 단위의 주장으로 실환경 결과는 엔진·버전별 차이가 있을 수 있다.
알아두면 좋은 것
- 이 리포지토리는 chat_template.jinja 한 파일로 Qwen 3.5와 3.6 변형을 모두 지원하는 단일 템플릿을 제공하며 템플릿 내부의 Python 전용 Jinja 기능을 minijinja 호환형으로 전환했다. 그 결과 C++ 기반 추론 엔진에서 발생하던 필터·루프·대체 함수 충돌을 회피하도록 설계되었다. 템플릿은 기본적으로 XML 툴 콜을 유지하되 특정 환경에서 JSON 출력을 선택적으로 활성화할 수 있다.
- 템플릿의 주요 안정성 조치는 빈 `<think>` 삽입 제거, 연대기적 이력 보존을 통한 100% KV Cache 적중률 복원, AST 평탄화를 통한 C++ 파싱 병목 제거, 그리고 에러 감지를 구조적으로 제한하는 방식으로 요약된다. 특정 문제를 해결하기 위해 `preserve_thinking`, `max_tool_arg_chars`, `max_tool_response_chars` 같은 설정을 제공한다. JSON 모드로 전환할 때는 트렁케이션 기능이 자동으로 비활성화되어 JSON 구조 손상을 방지한다.
- 설치 및 사용법은 LM Studio의 프롬프트 템플릿 교체, llama.cpp의 `--jinja --chat-template-file` 옵션 사용, vLLM의 tokenizer_config.json에 템플릿 삽입과 `--tool-call-parser qwen3_coder` 플래그 사용 등으로 명시되어 있다. 리포지토리는 다양한 엔진별 런타임 지침을 포함해 즉시 적용 가능한 단계별 절차를 제공한다. 또한 `python3 scripts/test_v21.py`로 회귀 테스트를 실행할 수 있다.
- 라이선스는 Apache-2.0이며 업데이트 히스토리에 상세한 버전별 변경점이 기록되어 있다. 최근 v21 계열에서 JSON 툴 포맷 옵션과 합동 안정성 패치가 추가되었고 핵심 호환성 픽스가 여러 차례 반영되었다. 저자 표기는 원저자(Alibaba Cloud Qwen 팀)와 템플릿 수정자(froggeric), C++ 최적화 기여자(spiritbuun)로 분리되어 있다.
기술적 특징
- 사고 보존 전략은 기본적으로 `<think>` 블록을 연대기적으로 유지하도록 설계되어 KV 캐시와 렌더링된 이력을 완전히 동기화한다. 이 동기화는 생성 경계에서 단일 개행 정규화를 적용해 자동회귀 토큰 경계가 렌더된 프롬프트와 정확히 일치하도록 만든다. 그 결과로 README에서는 멀티턴 루프에서 100% KV Cache 적중률을 달성했다고 명시되어 있다. 이 설정은 필요에 따라 `preserve_thinking`을 false로 전환해 토큰 절약을 선택할 수 있다.
- AST 평탄화와 minijinja 호환성 리팩토링은 C++ 기반 엔진에서 Jinja 네스팅이 야기하던 파싱 병목을 제거하기 위한 구현 전략이다. 기존의 깊은 루프와 매크로 구조를 단순화해 `ns_state` 추적과 히스토리 렌더링 루프의 평가 비용을 줄였고, README에서는 `llama.cpp`에서 최대 80%의 스루풋 손실을 회복했다고 기술하고 있다. 또한 Python 전용 필터와 연산을 안전한 대체 구현으로 교체하여 minijinja에서의 무응답·크래시 가능성을 차단했다. 이 변경은 템플릿 렌더링 단계에서 발생하던 심각한 성능 저하를 완화한다.
- 툴 호출 오류 처리에서는 연속 실패 카운터(`consecutive_failures`) 기반의 두 단계 에스컬레이션을 도입해 반복되는 잘못된 툴 호출 패턴을 해소한다. 첫 번째 실패 시 프롬프트 접두어를 변경해 다른 토큰 위치에서 재시도를 유도하고 캐시된 '잘못된 attractor state'를 깨트린다. 두 번째 연속 실패 시에는 think 블록을 우회하고 즉시 수정 지시를 주입해 빠른 교정 행동을 강제한다. 이 로직은 무한 반복과 동일 실패 반복이라는 전형적 에이전트 고장을 직접적으로 차단한다.
- 오탐 검출 방지는 단순한 부분문자열 매칭 대신 구조적 패턴과 길이 게이트를 결합해 구현되었다. `Exception:`, `"error":`, `Traceback` 같은 시그니처와 응답 길이, 셸 프롬프트(`$ `) 제외 규칙을 사용해 정상 반환을 오류로 오인하는 케이스를 줄인다. 또한 대용량 반환 페이로드에 대해 `max_tool_arg_chars`와 `max_tool_response_chars`를 도입해 컨텍스트 폭주를 방지하며 JSON 모드 전환 시에는 트렁케이션을 자동 비활성화해 직렬화 파손을 피한다. 이 조합은 오류 재시도 루프와 컨텍스트 윈도우 초과를 동시에 완화한다.
차별점
- 단일 chat_template.jinja 파일로 Qwen 3.5와 3.6 변형을 모두 처리하는 통합 접근을 취해 사용자가 엔진별로 별도의 템플릿을 유지할 필요를 없앴다. 이 통합은 템플릿 내부의 분기와 호환 레이어를 통해 각 엔진의 파싱 제약을 런타임 옵션으로 캡슐화한다. 그 결과 배포 복잡도가 낮아지고 유지보수 포인트가 단일화된다.
- minijinja 안전성 확보를 위해 Jinja 구문의 Python 전용 필터와 호출을 C++ 친화적 대체로 전면 개편했다는 점에서 C++ 추론 환경과의 실사용 호환성이 강조된다. 구체적으로 `replace` 기반 대체를 `split|join` 방식으로 바꾸고 `loop.previtem` 같은 비호환 API를 명시적 인덱싱으로 대체했다. 이 차별화는 llama.cpp와 같은 엔진에서의 크래시·무응답 문제를 예방한다.
- 툴 콜 처리 흐름에서 구조적 검증과 두 단계 오류 에스컬레이션을 결합해 단순 재시도만으로는 해결되지 않는 에이전트 루프 병목을 직접 표적으로 설정했다는 점이 특징이다. 길이 기반 필터와 구조적 매칭은 오탐을 줄이면서 실패 시의 행동 변화를 정밀하게 제어한다. 이 방식은 기존의 broad substring 매칭에서 발생하던 반복 실패 루프를 근본적으로 축소한다.
959
Likes
0
Downloads
0 / 0
조회수
관련 토론
아직 관련 토론이 없습니다.
댓글
댓글을 작성하려면 로그인이 필요합니다.