You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Isekai-Qwen/examples/function_call_finetune_exam...

234 lines
7.2 KiB
Python

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

#
# # Fine-tuning Script:
# Please start by reading the Fine-tuning section of README.md.
#
# # Fine-tuning Data Preparation:
# Then, if you would like to see some examples of how to prepare training samples for function calling,
# which is actually ReAct prompting under the hood, please read this file.
# # Inference Script:
# If you are interested in implementing function calling via ReAct prompting for inference,
# please refer to openai_api.py in our repository.
#
# If you have any questions, please raise an issue.
#
import json
def format_train_sample(messages):
#
# You do not need the `function` role, as Qwen's function calling is actually implemented via ReAct,
# not by adding a `function` role or `function_call` message. See openai_api.py for details.
#
# If you need the `system` role, you might need to modify `finetune.py` accordingly.
#
assert set(m["role"] for m in messages) == {"user", "assistant"}
sample = {
"conversations": [
{
"from": m["role"],
"value": m["content"],
}
for m in messages
]
}
return sample
TOOL_DESC = """{name_for_model}: Call this tool to interact with the {name_for_human} API. What is the {name_for_human} API useful for? {description_for_model} Parameters: {parameters}"""
REACT_INSTRUCTION = """Answer the following questions as best you can. You have access to the following APIs:
{tools_text}
Use the following format:
Question: the input question you must answer
Thought: you should always think about what to do
Action: the action to take, should be one of [{tools_name_text}]
Action Input: the input to the action
Observation: the result of the action
... (this Thought/Action/Action Input/Observation can be repeated zero or more times)
Thought: I now know the final answer
Final Answer: the final answer to the original input question
Begin!"""
def build_react_instruction(functions):
tools_text = []
tools_name_text = []
for func_info in functions:
name = func_info.get("name", "")
name_m = func_info.get("name_for_model", name)
name_h = func_info.get("name_for_human", name)
desc = func_info.get("description", "")
desc_m = func_info.get("description_for_model", desc)
tool = TOOL_DESC.format(
name_for_model=name_m,
name_for_human=name_h,
description_for_model=desc_m,
parameters=json.dumps(func_info["parameters"], ensure_ascii=False),
)
tools_text.append(tool)
tools_name_text.append(name_m)
tools_text = "\n\n".join(tools_text)
tools_name_text = ", ".join(tools_name_text)
instruction = REACT_INSTRUCTION.format(
tools_text=tools_text,
tools_name_text=tools_name_text,
)
return instruction
def main():
example_train_samples = []
example_functions = [
{
"name_for_human": "在线搜索",
"name_for_model": "search",
"description_for_model": "使用此工具可以搜索群内成员的信息或者在互联网上搜索信息。Format the arguments as a JSON object.", # If you expect `Action Input` to be a JSON.
"parameters": [
{
"name": "keywords",
"description": "需要搜索的关键词。",
"required": True,
"schema": {"type": "string"},
},
],
},
{
"name_for_human": "天气信息",
"name_for_model": "get_weather",
"description_for_model": "查询某个地点的天气信息。Format the arguments as a JSON object.",
"parameters": [
{
"name": "position",
"description": "需要查询天气的地点。",
"required": True,
"schema": {"type": "string"},
},
],
},
{
"name_for_human": "封禁用户",
"name_for_model": "ban_user",
"description_for_model": "在用户多次触犯道德规范时,使用此工具可以封禁用户。",
"parameters": [],
}
]
example_instruction = build_react_instruction(example_functions)
# This example has multiple actions in one single response.
example_train_samples.append(
[
{
"role": "user",
"content": f"{example_instruction}\n\nQuestion: Who is jay chou? And who is his wife?",
},
{
"role": "assistant",
"content": """
Thought: I need to google Jay Chou.
Action: google_search
Action Input: {"search_query": "Jay Chou"}
Observation: Jay Chou is ...
Thought: I need to google Jay's wife.
Action: google_search
Action Input: {"search_query": "Jay Chou's wife"}
Observation: Jay Chou's wife is ...
Thought: I now know the final answer
Final Answer: Jay Chou is ... His wife is ...
""".strip(),
},
]
)
# This example involves multiple rounds of conversation.
example_train_samples.append(
[
# Round #1
{
"role": "user",
"content": f"{example_instruction}\n\nQuestion: 123+456=?",
},
{
"role": "assistant",
"content": """
Thought: I need to compute the result using Code Interpreter.
Action: code_interpreter
Action Input:
```py
123 + 456
```
Observation: 579
Thought: I now know the final answer
Final Answer: 579
""".strip(),
},
# Round #2
{
"role": "user",
"content": "Multiply the result by 2.",
},
{
"role": "assistant",
"content": """
Thought: Code Interpreter is helpful for answering this question.
Action: code_interpreter
Action Input:
```py
579 * 2
```
Observation: 1158
Thought: I now know the final answer
Final Answer: 1158
""".strip(),
},
# Round #3
{
"role": "user",
"content": "You are so smart, Qwen.", # No action is needed for this question.
},
{
"role": "assistant",
"content": """
Thought: I now know the final answer
Final Answer: Thank you.
""".strip(),
},
# Round #4
{
"role": "user",
"content": "Please re-execute the code for computing my first question again.",
},
{
"role": "assistant",
"content": """
Thought: I need to re-compute the result.
Action: code_interpreter
Action Input:
```py
123 + 456
```
Observation: 579
Thought: I now know the final answer
Final Answer: 579
""".strip(),
},
]
)
example_train_samples = [format_train_sample(x) for x in example_train_samples]
with open(
"example_func_call_train_samples.json", "w"
) as fout: # data for fine-tuning
fout.write(json.dumps(example_train_samples, indent=2, ensure_ascii=False))
if __name__ == "__main__":
main()