Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Agents planning #31702

Merged
merged 12 commits into from
Jul 22, 2024
Merged

Agents planning #31702

merged 12 commits into from
Jul 22, 2024

Conversation

aymeric-roucher
Copy link
Contributor

@aymeric-roucher aymeric-roucher commented Jun 28, 2024

What does this PR do?

This adds an optional planning steps to agents, to let them insert steps of higher-level planning to their workflow.

It also:

  • improves several aspects in the Python code interpreter, particularly to handle pandas series.
  • removes an AgentType behavior where int and floats or other outputs would be converted to AgentType, which made them less accessible.

Fix infinite loops in python interpreter
@HuggingFaceDocBuilderDev

The docs for this PR live here. All of your documentation changes will be reflected on that endpoint. The docs are available until 30 days after the last update.

**BASE_PYTHON_TOOLS.copy(),
**self.toolbox.tools,
},
custom_tools=self.custom_tools,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change is made because I needed to separate two sets of tools:

  • user-defined tools that are static (at least they do not change within one call to run) but can be changed in-between run calls
  • agent-defined tools that will have to change within one run (thus the different handling in python interpreter)

@@ -365,7 +365,118 @@ def download_prompt(prompt_or_repo_id, agent_name, mode="run"):
6. Don't name any new variable with the same name as a tool: for instance don't name a variable 'final_answer'.
7. Never create any notional variables in our code, as having these in your logs might derail you from the true variables.
8. You can use imports in your code, but only from the following list of modules: <<authorized_imports>>
9. Don't give up! You're in charge of solving the task, not providing directions to solve it.
9. The state persists between code executions: so if in one step you've created variables or imported modules, these will all persist.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This precision helps e.g. with matplotlib plots that persist between code snippets.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nice prompt!

@@ -75,8 +85,8 @@ def get_iterable(obj):
raise InterpreterError("Object is not iterable")


def evaluate_unaryop(expression, state, tools):
operand = evaluate_ast(expression.operand, state, tools)
def evaluate_unaryop(expression, state, static_tools, custom_tools):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We add the distinction between static_tools and custom_tools everywhere: static_tools are the ones that the interpreter is not allowed to overwrite or create new ones (like base Python functions or user-defined tools), whereas custom_tools are the ones it can modify or extend.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, understood! Can you clarify that in the methods' docstrings?

ops = [type(op) for op in condition.ops]

result = True
current_left = left

for op, comparator in zip(ops, comparators):
if op == ast.Eq:
result = result and (current_left == comparator)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change allows to support pandas "==" statement between a Series and an int for instance

f"""
The code blob you used is invalid: due to the following error: {e}
This means that the regex pattern {pattern} was not respected: make sure to include code with the correct pattern, for instance:
Thoughts: Your thoughts
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We remind the correct pattern to guide the LLM towards correct formatting.

@@ -655,7 +687,7 @@ def provide_final_answer(self, task) -> str:
except Exception as e:
return f"Error in generating final llm output: {e}."

def run(self, task: str, stream: bool = False, **kwargs):
def run(self, task: str, stream: bool = False, reset: bool = True, **kwargs):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This reset option is provisory, it will be refined later to help multi-turn conversation with an user.

@@ -726,6 +764,91 @@ def direct_run(self, task: str, **kwargs):

return final_answer

def planning_step(self, task, is_first_step=False, iteration: int = None):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We tried to keep this planning step as simple as possible for now.

Copy link
Member

@LysandreJik LysandreJik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No problem for me to merge this!

As the agents framework grows, it would be nice to complete the docstrings to hve each method be understood better; for example the methods planning_step, provide_final_answer, direct_run, stream_run, etc, are they supposed to be run by the user or by the Agent?

Clarifying this via their docstring would help a lot regarding the accessibility of the framework

@@ -75,8 +85,8 @@ def get_iterable(obj):
raise InterpreterError("Object is not iterable")


def evaluate_unaryop(expression, state, tools):
operand = evaluate_ast(expression.operand, state, tools)
def evaluate_unaryop(expression, state, static_tools, custom_tools):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, understood! Can you clarify that in the methods' docstrings?

@@ -365,7 +365,118 @@ def download_prompt(prompt_or_repo_id, agent_name, mode="run"):
6. Don't name any new variable with the same name as a tool: for instance don't name a variable 'final_answer'.
7. Never create any notional variables in our code, as having these in your logs might derail you from the true variables.
8. You can use imports in your code, but only from the following list of modules: <<authorized_imports>>
9. Don't give up! You're in charge of solving the task, not providing directions to solve it.
9. The state persists between code executions: so if in one step you've created variables or imported modules, these will all persist.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nice prompt!

@aymeric-roucher aymeric-roucher merged commit b381880 into main Jul 22, 2024
20 checks passed
@aymeric-roucher aymeric-roucher deleted the agents-planning branch July 22, 2024 08:49
MHRDYN7 pushed a commit to MHRDYN7/transformers that referenced this pull request Jul 23, 2024
* Allow planning for agents
zucchini-nlp pushed a commit to zucchini-nlp/transformers that referenced this pull request Jul 24, 2024
* Allow planning for agents
itazap pushed a commit that referenced this pull request Jul 25, 2024
* Allow planning for agents
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants