WillHbx commited on
Commit
68e4a01
·
1 Parent(s): 3ffea9c

fix(llm): when using action (such as look around), remove the thinking

Browse files

block and increased token limit (from 512 to 1024) to make sure the full
asnwer won't be truncated anymore.

Files changed (2) hide show
  1. visualnovel/llm.py +27 -7
  2. visualnovel/orchestrator.py +1 -1
visualnovel/llm.py CHANGED
@@ -123,8 +123,23 @@ class TransformersLLM:
123
  print(f"[llm] {config.LLM_REPO} ready")
124
  self.torch = torch
125
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
126
  def complete(self, messages: list[dict[str, str]], **kw: Any) -> str:
127
- text = self.tok.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
128
  ids = self.tok(text, return_tensors="pt").to(self.model.device)
129
  out = self.model.generate(**ids, max_new_tokens=kw.get("max_tokens", 512))
130
  return self.tok.decode(out[0][ids.input_ids.shape[1] :], skip_special_tokens=True)
@@ -163,14 +178,19 @@ class TransformersLLM:
163
  {**m, "content": m["content"] + hint} if m["role"] == "system" else m for m in messages
164
  ]
165
  for attempt in range(3):
166
- raw = self.complete(augmented, **kw)
167
- # Strip Qwen3 <think>...</think> reasoning blocks before JSON extraction
168
- text = re.sub(r"<think>.*?</think>", "", raw, flags=re.DOTALL)
169
- text = re.sub(r"```(?:json)?\s*", "", text).strip()
170
- start, end = text.find("{"), text.rfind("}") + 1
 
 
 
 
 
171
  if start != -1 and end > start:
172
  try:
173
- return json.loads(text[start:end])
174
  except json.JSONDecodeError as exc:
175
  print(f"[llm] JSON parse error (attempt {attempt + 1}/3): {exc}")
176
  print("[llm] WARNING: all 3 retries failed, using empty schema fallback")
 
123
  print(f"[llm] {config.LLM_REPO} ready")
124
  self.torch = torch
125
 
126
+ def _apply_template(self, messages: list[dict[str, str]], enable_thinking: bool = True) -> str:
127
+ """Apply chat template, disabling Qwen3 thinking mode when asked."""
128
+ try:
129
+ return self.tok.apply_chat_template(
130
+ messages,
131
+ tokenize=False,
132
+ add_generation_prompt=True,
133
+ enable_thinking=enable_thinking,
134
+ )
135
+ except TypeError:
136
+ # Tokenizer doesn't support enable_thinking (non-Qwen3 models)
137
+ return self.tok.apply_chat_template(
138
+ messages, tokenize=False, add_generation_prompt=True
139
+ )
140
+
141
  def complete(self, messages: list[dict[str, str]], **kw: Any) -> str:
142
+ text = self._apply_template(messages)
143
  ids = self.tok(text, return_tensors="pt").to(self.model.device)
144
  out = self.model.generate(**ids, max_new_tokens=kw.get("max_tokens", 512))
145
  return self.tok.decode(out[0][ids.input_ids.shape[1] :], skip_special_tokens=True)
 
178
  {**m, "content": m["content"] + hint} if m["role"] == "system" else m for m in messages
179
  ]
180
  for attempt in range(3):
181
+ # Disable Qwen3 thinking mode: <think> blocks waste tokens and can truncate the JSON
182
+ text = self._apply_template(augmented, enable_thinking=False)
183
+ ids = self.tok(text, return_tensors="pt").to(self.model.device)
184
+ max_new = kw.get("max_tokens", 512)
185
+ out = self.model.generate(**ids, max_new_tokens=max_new)
186
+ raw = self.tok.decode(out[0][ids.input_ids.shape[1] :], skip_special_tokens=True)
187
+ # Still strip any residual think tags (safety net)
188
+ raw = re.sub(r"<think>.*?</think>", "", raw, flags=re.DOTALL)
189
+ raw = re.sub(r"```(?:json)?\s*", "", raw).strip()
190
+ start, end = raw.find("{"), raw.rfind("}") + 1
191
  if start != -1 and end > start:
192
  try:
193
+ return json.loads(raw[start:end])
194
  except json.JSONDecodeError as exc:
195
  print(f"[llm] JSON parse error (attempt {attempt + 1}/3): {exc}")
196
  print("[llm] WARNING: all 3 retries failed, using empty schema fallback")
visualnovel/orchestrator.py CHANGED
@@ -126,7 +126,7 @@ def direct_turn(
126
  schema=prompts.directive_schema(),
127
  temperature=0.7,
128
  top_p=0.9,
129
- max_tokens=512,
130
  )
131
  out = DirectorOutput.model_validate(raw)
132
  return _repair(state, out)
 
126
  schema=prompts.directive_schema(),
127
  temperature=0.7,
128
  top_p=0.9,
129
+ max_tokens=1024,
130
  )
131
  out = DirectorOutput.model_validate(raw)
132
  return _repair(state, out)