mirror of
https://github.com/ollama/ollama
synced 2026-04-23 08:45:14 +00:00
model/parsers: close think block if tool block starts in Qwen3.5 (#15022)
This commit is contained in:
parent
aec2fef95d
commit
1cefa749aa
|
|
@ -21,6 +21,7 @@ const (
|
|||
const (
|
||||
qwen35ThinkingOpenTag = "<think>"
|
||||
qwen35ThinkingCloseTag = "</think>"
|
||||
qwen35ToolCallOpenTag = "<tool_call>"
|
||||
)
|
||||
|
||||
// Qwen35Parser handles qwen3.5 reasoning extraction and delegates post-thinking
|
||||
|
|
@ -202,6 +203,14 @@ func (p *Qwen35Parser) eat() ([]qwen35Event, bool) {
|
|||
events = append(events, qwen35EventThinkingContent{content: unambiguous})
|
||||
}
|
||||
return events, false
|
||||
} else if strings.Contains(acc, qwen35ToolCallOpenTag) {
|
||||
// qwen3.5:9b model forgets sometimes to use </think> tag before the <tool_call> block starts
|
||||
// this condition ends the Think block and continues with the <tool_call> when the tag
|
||||
// is found
|
||||
thinking, tooling := p.splitAtTag(qwen35ToolCallOpenTag, true)
|
||||
p.buffer.Reset()
|
||||
p.buffer.WriteString(thinking + qwen35ThinkingCloseTag + qwen35ToolCallOpenTag + tooling)
|
||||
return events, true
|
||||
}
|
||||
|
||||
whitespaceLen := trailingWhitespaceLen(acc)
|
||||
|
|
|
|||
|
|
@ -108,7 +108,7 @@ func TestQwen35ParserAssistantPrefillStartsInContent(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestQwen35ParserToolCallEmittedInThinkingIsNotParsed(t *testing.T) {
|
||||
func TestQwen35ParserToolCallEmittedInThinkingIsParsed(t *testing.T) {
|
||||
parser := ParserForName("qwen3.5")
|
||||
if parser == nil {
|
||||
t.Fatal("expected qwen3.5 parser")
|
||||
|
|
@ -141,14 +141,20 @@ SF
|
|||
if content != "" {
|
||||
t.Fatalf("expected empty content, got %q", content)
|
||||
}
|
||||
expectedThinking := `Need weather lookup<tool_call><function=get_weather><parameter=location>
|
||||
SF
|
||||
</parameter></function></tool_call>`
|
||||
if thinking != expectedThinking {
|
||||
t.Fatalf("expected thinking %q, got %q", expectedThinking, thinking)
|
||||
if thinking != "Need weather lookup" {
|
||||
t.Fatalf("expected thinking %q, got %q", "Need weather lookup", thinking)
|
||||
}
|
||||
if len(calls) != 0 {
|
||||
t.Fatalf("expected no tool calls before </think>, got %d", len(calls))
|
||||
if len(calls) != 1 {
|
||||
t.Fatalf("expected 1 tool call, got %d", len(calls))
|
||||
}
|
||||
|
||||
if calls[0].Function.Name != "get_weather" {
|
||||
t.Fatalf("expected tool name %q, got %q", "get_weather", calls[0].Function.Name)
|
||||
}
|
||||
|
||||
location, ok := calls[0].Function.Arguments.Get("location")
|
||||
if !ok || location != "SF" {
|
||||
t.Fatalf("expected location %q, got %v", "SF", location)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue