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

#
# # 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()