forked from tangqiaoyu/ToolAlpaca
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
8143012
commit ab41a7d
Showing
29 changed files
with
111,851 additions
and
61,853 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
prefix = """Anser the user's question with the help of tools. The user cannot see the tool usage or use the tool themselves, you can use the tools. And the user cannot see the process of your tool use, so you must give all the infomation in Final Answer field to user. Your task is to answer the user's question, so DO NOT make up anything. If your required parameters are missing use tool "getDetails" to ask user provide them. | ||
You have access to the following tools:""" | ||
suffix = """Begin! | ||
Question: {input} | ||
Thought:{agent_scratchpad}""" | ||
|
||
format_instructions = """Use the following format: | ||
Question: the input question you must answer | ||
Thought: Answer the following three questions with one paragraph: 1) Check whether there are any general terms or pronouns that lack sufficient context or specific information. 2) Consider the question and potential approach to answer it. 3) Explain your reasoning and the steps needed to reach a solution. | ||
Action: the action to take, should be one of [{tool_names}]. | ||
Action Input: the input to the action, should be json format. All of the action input must be realistic and from the user. Never generate any action input by yourself or copy the input description. | ||
Observation: the result of the action and how it contributes to the solution | ||
... (this Thought/Action/Action Input/Observation can repeat N times) | ||
Thought: Summarize the information gathered and the reasoning behind your final answer. | ||
Final Answer: Provide a user-friendly and detailed answer to the original input question that summarizes all relevant information from the Thought/Action/Action Input/Observation sequences, without mentioning specific tool usage details or technical jargon. Ensure the answer is both informative and appropriate for the user.""" | ||
|
||
prefix_v2 = """Your task is to answer the user's question using available tools. The user cannot see or use the tools themselves, nor can they see the process of your tool usage. Provide all necessary information in the "Final Answer" field. Do not make up any information. If required parameters are missing, use the "getDetails" tool to ask the user for them. | ||
You have access to the following tools:""" | ||
|
||
format_instructions_v2 = """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 [{tool_names}]. | ||
Action Input: the input to the action, must be JSON format. All of the action input must be realistic and from the user. | ||
Observation: the result of the action | ||
... (this Thought/Action/Action Input/Observation can repeat N times) | ||
Thought: Summarize the information gathered and the reasoning behind your final answer. | ||
Final Answer: Provide a user-friendly and detailed answer to the original input question that summarizes all relevant information from the Thought/Action/Action Input/Observation sequences.""" | ||
|
||
train_prompt_v1 = { | ||
"prefix": prefix, | ||
"suffix": suffix, | ||
"format_instructions": format_instructions | ||
} | ||
|
||
train_prompt_v2 = { | ||
"prefix": prefix_v2, | ||
"suffix": suffix, | ||
"format_instructions": format_instructions_v2 | ||
} | ||
|
||
|
||
prefix_test = """A chat between a curious user and an artificial intelligence assistant. The assistant gives helpful, detailed, and polite answers to the user's questions with the help of some tools. | ||
You have access to the following tools:""" | ||
|
||
suffix_test = """Begin! | ||
USER: {input} | ||
ASSISTANT Thought:{agent_scratchpad}""" | ||
|
||
format_instructions_test = """The chat follows this format: | ||
USER: the user's question | ||
ASSISTANT Thought: the assistant's inner thought about what to do next | ||
ASSISTANT Action: the action to take, must be one of [{tool_names}]. | ||
ASSISTANT Action Input: the input for the action, in JSON format. | ||
ASSISTANT Observation: the result of the action | ||
... (this Thought/Action/Action Input/Observation can repeat N times) | ||
ASSISTANT Thought: summarize the information gathered | ||
ASSISTANT Response: the final response to the user | ||
USER: user's next question | ||
...""" | ||
test_prompt_v1 = { | ||
"prefix": prefix_test, | ||
"suffix": suffix_test, | ||
"format_instructions": format_instructions_test | ||
} | ||
|
||
prefix_test_v2 = """Answer the following questions as best you can. You have access to the following tools:""" | ||
|
||
suffix_test = """Begin! | ||
USER: {input} | ||
ASSISTANT Thought:{agent_scratchpad}""" | ||
|
||
format_instructions_test_v2 = """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 [{tool_names}] | ||
Action Input: the input to the action, in JSON format. | ||
Observation: the result of the action | ||
... (this Thought/Action/Action Input/Observation can repeat N times) | ||
Thought: I now know the final answer | ||
Final Answer: the final answer to the original input question""" | ||
test_prompt_v2 = { | ||
"prefix": prefix_test_v2, | ||
"suffix": suffix, | ||
"format_instructions": format_instructions_test_v2 | ||
} | ||
|
||
prompt_proj = { | ||
"train_v1": train_prompt_v1, | ||
"train_v2": train_prompt_v2, | ||
"test_v1": test_prompt_v1, | ||
"test_v2": test_prompt_v2 | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,127 @@ | ||
import logging | ||
import requests | ||
from datetime import datetime | ||
|
||
|
||
logger = logging.getLogger(__name__) | ||
|
||
|
||
def convert_type(ori_type): | ||
type_mapping = { | ||
"string": str, | ||
"integer": int, | ||
"number": float, | ||
"boolean": bool, | ||
"array": list, | ||
"object": dict | ||
} | ||
|
||
type_mapping.update({j: i for i, j in type_mapping.items()}) | ||
|
||
return type_mapping.get(ori_type) | ||
|
||
|
||
def type_check(param_name, param_schema, input_params): | ||
type_check_error = [] | ||
doc_type = convert_type(param_schema.get("type", "")) | ||
|
||
if doc_type and not isinstance(input_params[param_name], doc_type): | ||
type_error = True | ||
if (doc_type in [int, float, bool] and type(input_params[param_name]) == str) or \ | ||
(doc_type == float and type(input_params[param_name]) == int): | ||
try: | ||
input_params[param_name] = doc_type(input_params[param_name]) | ||
type_error = False | ||
except ValueError: | ||
pass | ||
if type_error: | ||
type_check_error.append(( | ||
param_name, | ||
convert_type(doc_type), | ||
convert_type(type(input_params[param_name])) | ||
)) | ||
if "enum" in param_schema and input_params[param_name] != "" and\ | ||
input_params[param_name] not in param_schema["enum"]: | ||
|
||
type_check_error.append(( | ||
param_name, | ||
f'one of {param_schema["enum"]}', | ||
f'"{input_params[param_name]}"' | ||
)) | ||
return type_check_error | ||
|
||
|
||
|
||
def call_api_function(input_params, openapi_spec, path, method, base_url=None): | ||
|
||
function_doc = openapi_spec["paths"][path][method] | ||
|
||
required_params = set() | ||
params = { | ||
"query": {}, | ||
"header": {}, | ||
"path": {}, | ||
"cookie": {} | ||
} | ||
|
||
type_check_error = [] | ||
for param_doc in function_doc.get("parameters", []): | ||
if param_doc.get("required"): | ||
required_params.add((param_doc["in"], param_doc["name"])) | ||
|
||
if param_doc["name"] in input_params: | ||
required_params.discard((param_doc["in"], param_doc["name"])) | ||
params[param_doc["in"]][param_doc["name"]] = input_params[param_doc["name"]] | ||
type_check_error.extend(type_check(param_doc["name"], param_doc, input_params)) | ||
|
||
body_data = None | ||
required_body_params = None | ||
if "requestBody" in function_doc: | ||
body_data = {} | ||
request_body_schema = function_doc["requestBody"].get("content", {}).get("application/json", {}).get("schema", {}) | ||
|
||
if "properties" in request_body_schema: | ||
required_body_params = set(request_body_schema.get("required", [])) | ||
for property_name, property_value in request_body_schema["properties"].items(): | ||
if property_name in input_params: | ||
body_data[property_name] = input_params[property_name] | ||
required_body_params.discard(property_name) | ||
type_check_error.extend(type_check(property_name, property_value, input_params)) | ||
|
||
if len(type_check_error) > 0: | ||
error_str = "\n".join([f"Parameter type error: \"{i[0]}\", expected {i[1]}, but got {i[2]}. You need to change the input and try again." for i in type_check_error]) | ||
raise ValueError(error_str) | ||
|
||
if required_params or required_body_params: | ||
missing_params = ", ".join([f'"{param[1]}"' for param in required_params]) | ||
missing_params += [f'"{param}"' for param in required_body_params] | ||
raise ValueError(f"Missing required parameters: {', '.join(required_body_params)}. You need to change the input and try again.") | ||
|
||
base_url = openapi_spec['servers'][0]['url'] if base_url is None else base_url | ||
url = f"{base_url.rstrip('/')}{path.format(**params['path'])}" | ||
headers = {"Content-Type": "application/json"} | ||
headers.update(params["header"]) | ||
|
||
logger.debug("request url: {url}") | ||
response = requests.request( | ||
method=method.upper(), | ||
url=url, | ||
params=params["query"], | ||
json=body_data, | ||
headers=headers, | ||
cookies=params["cookie"] | ||
) | ||
|
||
if "image" in response.headers.get("Content-Type", ""): | ||
image_extension = response.headers.get("Content-Type", "").split("/")[-1] | ||
timestamp = datetime.now().strftime("%m%d%H%M%S") | ||
image_path = f"./images/{timestamp}.{image_extension}" | ||
with open(image_path, 'wb') as f: | ||
f.write(response.content) | ||
response._content = bytes(f"Recieved an image, saved in '{image_path}'.", "utf-8") | ||
|
||
logger.debug("url: {response.request.url}") | ||
logger.debug("body: {response.request.body}") | ||
logger.debug("headers: {response.request.headers}") | ||
|
||
return response |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
from pydantic import Field | ||
from langchain.agents import ZeroShotAgent | ||
from langchain.agents.agent import AgentOutputParser | ||
|
||
|
||
from .custom_parser import CustomMRKLOutputParser2 | ||
|
||
|
||
class CustomZeroShotAgent(ZeroShotAgent): | ||
output_parser: AgentOutputParser = Field(default_factory=CustomMRKLOutputParser2) | ||
|
||
@classmethod | ||
def _get_default_output_parser(cls, **kwargs) -> AgentOutputParser: | ||
return CustomMRKLOutputParser2() | ||
|
||
@property | ||
def observation_prefix(self) -> str: | ||
"""Prefix to append the observation with.""" | ||
return "ASSISTANT Observation: " | ||
|
||
@property | ||
def llm_prefix(self) -> str: | ||
"""Prefix to append the llm call with.""" | ||
return "ASSISTANT Thought:" |
Oops, something went wrong.