Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit f178636

Browse files
fix: Functionary bug fixes (abetlen#1385)
* fix completion tokens tracking, prompt forming * fix 'function_call' and 'tool_calls' depending on 'functions' and 'tools', incompatibility with python 3.8 * Updated README * fix for openai server compatibility --------- Co-authored-by: Andrei <[email protected]>
1 parent e6bbfb8 commit f178636

File tree

2 files changed

+57
-41
lines changed

2 files changed

+57
-41
lines changed

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -484,6 +484,8 @@ Due to discrepancies between llama.cpp and HuggingFace's tokenizers, it is requi
484484
tokenizer=LlamaHFTokenizer.from_pretrained("meetkai/functionary-small-v2.2-GGUF")
485485
)
486486
```
487+
488+
**NOTE**: There is no need to provide the default system messages used in Functionary as they are added automatically in the Functionary chat handler. Thus, the messages should contain just the chat messages and/or system messages that provide additional context for the model (e.g.: datetime, etc.).
487489
</details>
488490

489491
### Multi-modal Models

llama_cpp/llama_chat_format.py

Lines changed: 55 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1828,27 +1828,35 @@ def prepare_messages_for_inference(
18281828
version: Literal["v1", "v2"],
18291829
functions: Optional[List[llama_types.ChatCompletionFunctions]] = None,
18301830
tools: Optional[List[llama_types.ChatCompletionTool]] = None,
1831+
tool_choice: Union[Dict, str] = "auto",
18311832
):
18321833
all_messages: List[llama_types.ChatCompletionRequestMessage] = []
1833-
if functions is not None:
1834+
if tool_choice == "none":
18341835
all_messages.append(
18351836
llama_types.ChatCompletionRequestSystemMessage(
1836-
role="system", content=generate_schema_from_functions(functions)
1837+
role="system", content=generate_schema_from_functions([])
18371838
)
18381839
)
1839-
elif tools is not None:
1840-
all_messages.append(
1841-
llama_types.ChatCompletionRequestSystemMessage(
1842-
role="system",
1843-
content=generate_schema_from_functions(
1844-
[
1845-
tool["function"]
1846-
for tool in tools
1847-
if tool["type"] == "function"
1848-
]
1849-
),
1840+
else:
1841+
if functions is not None:
1842+
all_messages.append(
1843+
llama_types.ChatCompletionRequestSystemMessage(
1844+
role="system", content=generate_schema_from_functions(functions)
1845+
)
1846+
)
1847+
elif tools is not None and tool_choice != "none":
1848+
all_messages.append(
1849+
llama_types.ChatCompletionRequestSystemMessage(
1850+
role="system",
1851+
content=generate_schema_from_functions(
1852+
[
1853+
tool["function"]
1854+
for tool in tools
1855+
if tool["type"] == "function"
1856+
]
1857+
),
1858+
)
18501859
)
1851-
)
18521860

18531861
all_messages.append(
18541862
llama_types.ChatCompletionRequestSystemMessage(
@@ -1888,7 +1896,7 @@ def prepare_messages_for_inference(
18881896
function_call = "auto"
18891897

18901898
prompt = prepare_messages_for_inference(
1891-
messages, tokenizer, version, functions, tools
1899+
messages, tokenizer, version, functions, tools, function_call
18921900
)
18931901

18941902
# If no tools/functions are provided
@@ -1985,17 +1993,12 @@ def create_completion(stop):
19851993

19861994
content = ""
19871995
function_calls, function_bodies = [], []
1996+
completion_tokens = 0
19881997

19891998
if version == "v1":
19901999
# If no or "auto" tool_choice/function_call
19912000
if isinstance(function_call, str) and function_call == "auto":
19922001
stops = ["\n", END_ASSISTANT_TOKEN]
1993-
# If tool_choice/function_call is "none"
1994-
elif isinstance(function_call, str) and function_call == "none":
1995-
prompt = prepare_messages_for_inference(
1996-
messages, tokenizer, version, [], []
1997-
)
1998-
stops = END_ASSISTANT_TOKEN
19992002
# If tool_choice/function_call is provided
20002003
elif isinstance(function_call, dict):
20012004
prompt += f"{START_FUNCTION_CALL_TOKEN}{function_call['name']}:\n"
@@ -2009,12 +2012,15 @@ def create_completion(stop):
20092012

20102013
completion = create_completion(stop=stops)
20112014
completion_text = completion["choices"][0]["text"]
2015+
completion_tokens += completion["usage"]["completion_tokens"]
2016+
20122017

20132018
# If the generation does not involve a function call
20142019
if (
20152020
START_FUNCTION_CALL_TOKEN not in prompt
20162021
and START_FUNCTION_CALL_TOKEN not in completion_text
20172022
):
2023+
completion["usage"]["completion_tokens"] = completion_tokens
20182024
return _convert_completion_to_chat(completion, stream=stream) # type: ignore
20192025
# If the generation involves a function call in completion, generate the parameters
20202026
elif (
@@ -2032,30 +2038,22 @@ def create_completion(stop):
20322038
)
20332039
grammar = get_grammar(function_calls[-1])
20342040
completion = create_completion(stop=END_FUNCTION_CALL_TOKEN)
2041+
completion_tokens += completion["usage"]["completion_tokens"]
20352042
function_bodies.append(completion["choices"][0]["text"].strip())
20362043
# If the prompt involves a function call, just append generated parameters to function_bodies
20372044
else:
20382045
function_bodies.append(completion_text.strip())
20392046
else:
2040-
# If tool_choice/function_call is "none"
2041-
if isinstance(function_call, str) and function_call == "none":
2042-
prompt = (
2043-
prepare_messages_for_inference(messages, tokenizer, version, [], [])
2044-
+ "all\n<|content|>"
2045-
)
2046-
stops = [STOP_TOKEN, FROM_TOKEN]
2047-
completion = create_completion(stop=stops)
2048-
completion["choices"][0]["text"] = completion["choices"][0]["text"].strip()
2049-
return _convert_completion_to_chat(completion, stream=stream) # type: ignore
20502047
# If tool_choice/function_call is provided
2051-
elif isinstance(function_call, dict):
2048+
if isinstance(function_call, dict):
20522049
prompt += f"{function_call['name']}\n{CONTENT_TOKEN}"
20532050
function_call = function_call["name"]
20542051
function_calls.append(function_call)
20552052
grammar = get_grammar(function_call)
20562053
stops = [STOP_TOKEN, FROM_TOKEN]
20572054
completion = create_completion(stop=stops)
20582055
completion_text = completion["choices"][0]["text"]
2056+
completion_tokens += completion["usage"]["completion_tokens"]
20592057
function_bodies.append(completion_text.strip())
20602058
# If "auto" or no tool_choice/function_call
20612059
elif isinstance(function_call, str) and function_call == "auto":
@@ -2065,6 +2063,7 @@ def create_completion(stop):
20652063
stops = CONTENT_TOKEN
20662064
completion = create_completion(stop=stops)
20672065
completion_text = completion["choices"][0]["text"]
2066+
completion_tokens += completion["usage"]["completion_tokens"]
20682067
function_name = completion_text.strip()
20692068
if function_name == "all":
20702069
prompt += "all\n<|content|>"
@@ -2077,12 +2076,23 @@ def create_completion(stop):
20772076
stops = [RECIPIENT_TOKEN, STOP_TOKEN]
20782077
completion = create_completion(stop=stops)
20792078
completion_text = completion["choices"][0]["text"]
2079+
completion_tokens += completion["usage"]["completion_tokens"]
20802080
if function_name == "all":
2081-
content += completion_text.removesuffix("\n<|from|>assistant\n").removesuffix("\n<|from|> assistant\n")
2081+
if completion_text.endswith("\n<|from|>assistant\n"):
2082+
content += completion_text[:-len("\n<|from|>assistant\n")]
2083+
if completion_text.endswith("\n<|from|> assistant\n"):
2084+
content += completion_text[-len("\n<|from|> assistant\n")]
2085+
else:
2086+
content += completion_text
20822087
content = content.lstrip()
20832088
# Check whether the model wants to generate another turn
20842089
if "<|from|> assistant" in completion_text or "<|from|>assistant" in completion_text:
2085-
cleaned_completion_text = completion_text.removesuffix("\n<|from|>assistant\n").removesuffix("\n<|from|> assistant\n").strip()
2090+
if completion_text.endswith("\n<|from|>assistant\n"):
2091+
cleaned_completion_text = completion_text[:-len("\n<|from|>assistant\n")].strip()
2092+
elif completion_text.endswith("\n<|from|> assistant\n"):
2093+
cleaned_completion_text = completion_text[-len("\n<|from|> assistant\n")].strip()
2094+
else:
2095+
cleaned_completion_text = completion_text.strip()
20862096
prompt += f"{cleaned_completion_text}\n<|from|>assistant\n<|recipient|>"
20872097
else:
20882098
break
@@ -2092,6 +2102,7 @@ def create_completion(stop):
20922102
prompt += completion_text.strip()
20932103
grammar = None
20942104
completion = create_completion(stop=stops)
2105+
completion_tokens += completion["usage"]["completion_tokens"]
20952106
if "<|from|> assistant" in completion["choices"][0]["text"] or "<|from|>assistant" in completion["choices"][0]["text"]:
20962107
prompt += "\n<|from|>assistant\n<|recipient|>"
20972108
else:
@@ -2120,12 +2131,16 @@ def create_completion(stop):
21202131
)
21212132

21222133
# TODO: support stream mode
2123-
function_call_dict: Union[Dict[str, str], Dict[Literal["function_call"], llama_types.ChatCompletionRequestAssistantMessageFunctionCall]] = {
2124-
"function_call": {
2125-
"name": tool_calls[0]["function"]["name"],
2126-
"arguments": tool_calls[0]["function"]["arguments"],
2127-
}
2128-
} if len(tool_calls) == 1 else {}
2134+
function_call_dict: Union[Dict[str, str], Dict[Literal["function_call"], llama_types.ChatCompletionRequestAssistantMessageFunctionCall]] = {}
2135+
if len(tool_calls) > 0:
2136+
if tools is not None:
2137+
function_call_dict["tool_calls"] = tool_calls
2138+
else:
2139+
function_call_dict["function_call"] = {
2140+
"name": tool_calls[0]["function"]["name"],
2141+
"arguments": tool_calls[0]["function"]["arguments"],
2142+
}
2143+
completion["usage"]["completion_tokens"] = completion_tokens
21292144
return llama_types.CreateChatCompletionResponse(
21302145
id="chat" + completion["id"],
21312146
object="chat.completion",
@@ -2138,7 +2153,6 @@ def create_completion(stop):
21382153
"message": {
21392154
"role": "assistant",
21402155
"content": None if content == "" else content,
2141-
"tool_calls": tool_calls,
21422156
**function_call_dict,
21432157
},
21442158
"finish_reason": "tool_calls" if len(tool_calls) > 0 else "stop",

0 commit comments

Comments
 (0)