fix(tools): correctly render tools response in templates (#1932)

* fix(tools): allow to correctly display both Functions and Tools

* models(hermes-2-pro): correctly display function results
This commit is contained in:
Ettore Di Giacinto 2024-03-30 19:02:07 +01:00 committed by GitHub
parent 61e5e6bc36
commit 957f428fd5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 64 additions and 54 deletions

View File

@ -3,18 +3,15 @@ mmap: true
parameters: parameters:
model: huggingface://NousResearch/Hermes-2-Pro-Mistral-7B-GGUF/Hermes-2-Pro-Mistral-7B.Q6_K.gguf model: huggingface://NousResearch/Hermes-2-Pro-Mistral-7B-GGUF/Hermes-2-Pro-Mistral-7B.Q6_K.gguf
roles:
assistant_function_call: assistant
function: tool
template: template:
chat_message: | chat_message: |
<|im_start|>{{if eq .RoleName "assistant"}}assistant{{else if eq .RoleName "system"}}system{{else if eq .RoleName "function"}}{{.Role}}{{else if eq .RoleName "user"}}user{{end}} <|im_start|>{{if eq .RoleName "assistant"}}assistant{{else if eq .RoleName "system"}}system{{else if eq .RoleName "tool"}}tool{{else if eq .RoleName "user"}}user{{end}}
{{ if eq .RoleName "assistant_function_call" }}<tool_call>{{end}} {{ if .FunctionCall }}<tool_call>{{end}}
{{ if eq .RoleName "function" }}<tool_result>{{end}} {{ if eq .RoleName "tool" }}<tool_result>{{end}}
{{if .Content}}{{.Content}}{{end}} {{if .Content}}{{.Content}}{{end}}
{{if .FunctionCall}}{{toJson .FunctionCall}}{{end}} {{if .FunctionCall}}{{toJson .FunctionCall}}{{end}}
{{ if eq .RoleName "assistant_function_call" }}</tool_call>{{end}} {{ if .FunctionCall }}</tool_call>{{end}}
{{ if eq .RoleName "function" }}</tool_result>{{end}} {{ if eq .RoleName "tool" }}</tool_result>{{end}}
<|im_end|> <|im_end|>
# https://huggingface.co/NousResearch/Hermes-2-Pro-Mistral-7B-GGUF#prompt-format-for-function-calling # https://huggingface.co/NousResearch/Hermes-2-Pro-Mistral-7B-GGUF#prompt-format-for-function-calling
function: | function: |

View File

@ -4,18 +4,15 @@ f16: false
parameters: parameters:
model: huggingface://NousResearch/Hermes-2-Pro-Mistral-7B-GGUF/Hermes-2-Pro-Mistral-7B.Q6_K.gguf model: huggingface://NousResearch/Hermes-2-Pro-Mistral-7B-GGUF/Hermes-2-Pro-Mistral-7B.Q6_K.gguf
roles:
assistant_function_call: assistant
function: tool
template: template:
chat_message: | chat_message: |
<|im_start|>{{if eq .RoleName "assistant"}}assistant{{else if eq .RoleName "system"}}system{{else if eq .RoleName "function"}}{{.Role}}{{else if eq .RoleName "user"}}user{{end}} <|im_start|>{{if eq .RoleName "assistant"}}assistant{{else if eq .RoleName "system"}}system{{else if eq .RoleName "tool"}}tool{{else if eq .RoleName "user"}}user{{end}}
{{ if eq .RoleName "assistant_function_call" }}<tool_call>{{end}} {{ if .FunctionCall }}<tool_call>{{end}}
{{ if eq .RoleName "function" }}<tool_result>{{end}} {{ if eq .RoleName "tool" }}<tool_result>{{end}}
{{if .Content}}{{.Content}}{{end}} {{if .Content}}{{.Content}}{{end}}
{{if .FunctionCall}}{{toJson .FunctionCall}}{{end}} {{if .FunctionCall}}{{toJson .FunctionCall}}{{end}}
{{ if eq .RoleName "assistant_function_call" }}</tool_call>{{end}} {{ if .FunctionCall }}</tool_call>{{end}}
{{ if eq .RoleName "function" }}</tool_result>{{end}} {{ if eq .RoleName "tool" }}</tool_result>{{end}}
<|im_end|> <|im_end|>
# https://huggingface.co/NousResearch/Hermes-2-Pro-Mistral-7B-GGUF#prompt-format-for-function-calling # https://huggingface.co/NousResearch/Hermes-2-Pro-Mistral-7B-GGUF#prompt-format-for-function-calling
function: | function: |

View File

@ -236,7 +236,7 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, startup
// if function call, we might want to customize the role so we can display better that the "assistant called a json action" // if function call, we might want to customize the role so we can display better that the "assistant called a json action"
// if an "assistant_function_call" role is defined, we use it, otherwise we use the role that is passed by in the request // if an "assistant_function_call" role is defined, we use it, otherwise we use the role that is passed by in the request
if i.FunctionCall != nil && i.Role == "assistant" { if (i.FunctionCall != nil || i.ToolCalls != nil) && i.Role == "assistant" {
roleFn := "assistant_function_call" roleFn := "assistant_function_call"
r := config.Roles[roleFn] r := config.Roles[roleFn]
if r != "" { if r != "" {
@ -246,6 +246,11 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, startup
r := config.Roles[role] r := config.Roles[role]
contentExists := i.Content != nil && i.StringContent != "" contentExists := i.Content != nil && i.StringContent != ""
fcall := i.FunctionCall
if len(i.ToolCalls) > 0 {
fcall = i.ToolCalls
}
// First attempt to populate content via a chat message specific template // First attempt to populate content via a chat message specific template
if config.TemplateConfig.ChatMessage != "" { if config.TemplateConfig.ChatMessage != "" {
chatMessageData := model.ChatMessageTemplateData{ chatMessageData := model.ChatMessageTemplateData{
@ -253,7 +258,7 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, startup
Role: r, Role: r,
RoleName: role, RoleName: role,
Content: i.StringContent, Content: i.StringContent,
FunctionCall: i.FunctionCall, FunctionCall: fcall,
FunctionName: i.Name, FunctionName: i.Name,
LastMessage: messageIndex == (len(input.Messages) - 1), LastMessage: messageIndex == (len(input.Messages) - 1),
Function: config.Grammar != "" && (messageIndex == (len(input.Messages) - 1)), Function: config.Grammar != "" && (messageIndex == (len(input.Messages) - 1)),
@ -271,35 +276,49 @@ func ChatEndpoint(cl *config.BackendConfigLoader, ml *model.ModelLoader, startup
content = templatedChatMessage content = templatedChatMessage
} }
} }
marshalAnyRole := func(f any) {
j, err := json.Marshal(f)
if err == nil {
if contentExists {
content += "\n" + fmt.Sprint(r, " ", string(j))
} else {
content = fmt.Sprint(r, " ", string(j))
}
}
}
marshalAny := func(f any) {
j, err := json.Marshal(f)
if err == nil {
if contentExists {
content += "\n" + string(j)
} else {
content = string(j)
}
}
}
// If this model doesn't have such a template, or if that template fails to return a value, template at the message level. // If this model doesn't have such a template, or if that template fails to return a value, template at the message level.
if content == "" { if content == "" {
if r != "" { if r != "" {
if contentExists { if contentExists {
content = fmt.Sprint(r, i.StringContent) content = fmt.Sprint(r, i.StringContent)
} }
if i.FunctionCall != nil { if i.FunctionCall != nil {
j, err := json.Marshal(i.FunctionCall) marshalAnyRole(i.FunctionCall)
if err == nil { }
if contentExists { if i.ToolCalls != nil {
content += "\n" + fmt.Sprint(r, " ", string(j)) marshalAnyRole(i.ToolCalls)
} else {
content = fmt.Sprint(r, " ", string(j))
}
}
} }
} else { } else {
if contentExists { if contentExists {
content = fmt.Sprint(i.StringContent) content = fmt.Sprint(i.StringContent)
} }
if i.FunctionCall != nil { if i.FunctionCall != nil {
j, err := json.Marshal(i.FunctionCall) marshalAny(i.FunctionCall)
if err == nil { }
if contentExists { if i.ToolCalls != nil {
content += "\n" + string(j) marshalAny(i.ToolCalls)
} else {
content = string(j)
}
}
} }
} }
// Special Handling: System. We care if it was printed at all, not the r branch, so check seperately // Special Handling: System. We care if it was printed at all, not the r branch, so check seperately

View File

@ -3,18 +3,15 @@ mmap: true
parameters: parameters:
model: huggingface://NousResearch/Hermes-2-Pro-Mistral-7B-GGUF/Hermes-2-Pro-Mistral-7B.Q6_K.gguf model: huggingface://NousResearch/Hermes-2-Pro-Mistral-7B-GGUF/Hermes-2-Pro-Mistral-7B.Q6_K.gguf
roles:
assistant_function_call: assistant
function: tool
template: template:
chat_message: | chat_message: |
<|im_start|>{{if eq .RoleName "assistant"}}assistant{{else if eq .RoleName "system"}}system{{else if eq .RoleName "function"}}{{.Role}}{{else if eq .RoleName "user"}}user{{end}} <|im_start|>{{if eq .RoleName "assistant"}}assistant{{else if eq .RoleName "system"}}system{{else if eq .RoleName "tool"}}tool{{else if eq .RoleName "user"}}user{{end}}
{{ if eq .RoleName "assistant_function_call" }}<tool_call>{{end}} {{ if .FunctionCall }}<tool_call>{{end}}
{{ if eq .RoleName "function" }}<tool_result>{{end}} {{ if eq .RoleName "tool" }}<tool_result>{{end}}
{{if .Content}}{{.Content}}{{end}} {{if .Content}}{{.Content}}{{end}}
{{if .FunctionCall}}{{toJson .FunctionCall}}{{end}} {{if .FunctionCall}}{{toJson .FunctionCall}}{{end}}
{{ if eq .RoleName "assistant_function_call" }}</tool_call>{{end}} {{ if .FunctionCall }}</tool_call>{{end}}
{{ if eq .RoleName "function" }}</tool_result>{{end}} {{ if eq .RoleName "tool" }}</tool_result>{{end}}
<|im_end|> <|im_end|>
# https://huggingface.co/NousResearch/Hermes-2-Pro-Mistral-7B-GGUF#prompt-format-for-function-calling # https://huggingface.co/NousResearch/Hermes-2-Pro-Mistral-7B-GGUF#prompt-format-for-function-calling
function: | function: |