Skip to content

Commit

Permalink
finalizing agent tracining, goes from 0.68 to 0.8 for hotpot qa answe…
Browse files Browse the repository at this point in the history
…ring which is quite high with gpt35
  • Loading branch information
liyin2015 committed Dec 29, 2024
1 parent daa8178 commit 3889f8a
Show file tree
Hide file tree
Showing 8 changed files with 106 additions and 104 deletions.
102 changes: 42 additions & 60 deletions adalflow/adalflow/components/agent/react.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
FunctionOutput,
FunctionExpression,
)
from adalflow.optim.grad_component import fun_to_grad_component
from adalflow.core.model_client import ModelClient
from adalflow.utils.logger import printc

Expand Down Expand Up @@ -159,7 +160,6 @@ def call(
step_output.function = func

step_output.observation = result.output

return step_output


Expand Down Expand Up @@ -302,13 +302,7 @@ def _init_tools(
model_client: ModelClient,
model_kwargs: Dict,
):
r"""Initialize the tools. Using copy or not can impact the status of tools depending on the tools' status."""
# try:
# tools = [deepcopy(tool) for tool in tools]
# except Exception:
# from copy import copy

# tools = [copy(tool) for tool in tools]
r"""Initialize the tools. Using reference or else(copy or deepcopy) we can not set the training/eval mode for each tool."""

tools = tools
_additional_llm_tool = (
Expand Down Expand Up @@ -344,32 +338,30 @@ def finish(answer: str, **kwargs) -> str:

def _execute_action(
self,
action_step: StepOutput,
step_output: StepOutput,
response: Union[Parameter, GeneratorOutput],
id: Optional[str] = None,
) -> Optional[StepOutput]:
"""Parse the action string to a function call and execute it. Update the action_step with the result."""
# extract the action from the response
"""Parse the action string to a function call and execute it. Update the step_output with the result."""

if isinstance(response, Parameter):
def handle_error(response: Parameter, e: str):

def handle_error(response: Parameter, e: str):
from adalflow.optim.grad_component import fun_to_grad_component
@fun_to_grad_component
def set_step_output_with_error(
step_output: StepOutput, error: str, response: Any
):
"""Set the step_output with error."""
step_output.observation = f"erro: {error} at {response.data}"
return step_output

print(f"action_step: {action_step}")
response.add_successor_map_fn(
successor=set_step_output_with_error, map_fn=lambda x: x.data
)
return set_step_output_with_error.forward(step_output, e, response)

@fun_to_grad_component
def set_step_output_with_error(
step_output: StepOutput, error: str, response: Any
):
"""Set the step_output with error."""
step_output.observation = f"erro: {error} at {response.data}"
return step_output
step = step_output.step

response.add_successor_map_fn(
successor=set_step_output_with_error, map_fn=lambda x: x.data
)
return set_step_output_with_error.forward(action_step, e, response)
if isinstance(response, Parameter):

try:
function_output_to_step_output = FunctionOutputToStepOutput()
Expand All @@ -379,15 +371,13 @@ def set_step_output_with_error(
expr_or_fun=response, step="parse", map_fn=lambda x: x.data.data
)
# add action to the step_output
action_step.action = response.data.data
step_output.action = response.data.data
# parse failed
if not isinstance(func, Parameter):
raise ValueError(
f"Expected Parameter, but got {type(func)}: {func}"
)
if isinstance(func, str):
# create dummy step output
from adalflow.optim.grad_component import fun_to_grad_component

@fun_to_grad_component
def set_step_output_with_error(
Expand All @@ -401,10 +391,10 @@ def set_step_output_with_error(
successor=set_step_output_with_error,
map_fn=lambda x: x.data.data,
)
action_step = set_step_output_with_error.forward(
action_step, response, error=func
step_output = set_step_output_with_error.forward(
step_output, response, error=func
)
return action_step
return step_output

except Exception as e:
e = f"{e} at parsing error at functionexpression: {response.data}"
Expand All @@ -426,7 +416,6 @@ def set_step_output_with_error(

if isinstance(result, str):
# create dummy step output
from adalflow.optim.grad_component import fun_to_grad_component

@fun_to_grad_component
def set_step_output_with_error(step_output: StepOutput, data: str):
Expand All @@ -439,11 +428,11 @@ def set_step_output_with_error(step_output: StepOutput, data: str):
successor=set_step_output_with_error,
map_fn=lambda x: x.data.data,
)
action_step = set_step_output_with_error.forward(
action_step, response
step_output = set_step_output_with_error.forward(
step_output, response
)

return action_step
return step_output

except Exception as e:
e = f"{e} Error executing function: {func}"
Expand All @@ -461,14 +450,14 @@ def set_step_output_with_error(step_output: StepOutput, data: str):
func.add_successor_map_fn(
successor=function_output_to_step_output, map_fn=lambda x: x.data
)
action_step = function_output_to_step_output.forward(
step_output = function_output_to_step_output.forward(
action_str=response,
step=action_step.step,
step=step,
result=result,
func=func,
)

return action_step
return step_output
except Exception as e:
e = f"{e} Error converting function output to step output: {result.data}"

Expand All @@ -478,8 +467,8 @@ def set_step_output_with_error(step_output: StepOutput, data: str):

return self._execute_action_eval_mode(
x=response,
step_output=action_step,
step=action_step.step,
step_output=step_output,
step=step,
id=id,
)

Expand Down Expand Up @@ -548,14 +537,14 @@ def _run_one_step(
step_history_value = (
step_history.data if isinstance(step_history, Parameter) else step_history
)
for step in step_history_value:
if not step:
for data in step_history_value:
if not data:
raise ValueError(
f"Expected StepOutput, but got {type(step)}, all steps: {step_history_value}"
f"Expected StepOutput, but got {type(data)}, all steps: {step_history_value}"
)
if not isinstance(step, StepOutput):
if not isinstance(data, StepOutput):
raise ValueError(
f"Expected StepOutput, but got {type(step)}, all steps: {step_history_value}"
f"Expected StepOutput, but got {type(data)}, all steps: {step_history_value}"
)

log.debug(
Expand All @@ -566,11 +555,6 @@ def _run_one_step(
response: Union[GeneratorOutput, Parameter] = self.planner(
prompt_kwargs=prompt_kwargs, model_kwargs=model_kwargs, id=id
)
# except Exception as e:
# error_msg = f"Error happened in planner response: {e}. Training mode: {self.planner.training}"
# raise ValueError(
# error_msg
# ) # raise the error for debugging as this should not happen in normal cases.

except Exception as e:
error_msg = f"Error happened in planner response at step {step}: {e}.\n"
Expand All @@ -580,7 +564,6 @@ def _run_one_step(
error_msg += f"Traceback:\n{traceback.format_exc()}"
raise RuntimeError(error_msg)

# create a new step output
step_output: StepOutput = StepOutput(step=step)

try:
Expand All @@ -591,9 +574,8 @@ def _run_one_step(
raise ValueError(
f"Expected GeneratorOutput, but got {type(response.data)}, value: {response.data}"
)

# Detect planner parsing errors to FunctionExpression so that the prompt can be trained to self-correct
if not isinstance(response.data.data, FunctionExpression):
from adalflow.optim.grad_component import fun_to_grad_component

@fun_to_grad_component
def set_step_output_with_error(
Expand All @@ -616,13 +598,14 @@ def set_step_output_with_error(
step_output: Parameter = self._execute_action(
step_output, response, id
)

# printc(f"step_output: {step_output}", color="red")
if self.debug:
printc(f"step_output: {step_output.data}", color="red")
if not isinstance(step_output, Parameter):
raise ValueError(
f"Ensure step_output to be Parameter at training mode. Got {type(step_output)}.\n\
Please check the observation for error details: {step_output}"
)
# combine the current step_output with the step_history
step_output.add_successor_map_fn(
successor=self.append_step_history, map_fn=lambda x: x.data
)
Expand All @@ -646,7 +629,7 @@ def set_step_output_with_error(
else:

step_output: StepOutput = self._execute_action(
action_step=step_output, response=response, id=id
step_output=step_output, response=response, id=id
)
if not step_output:
raise RuntimeError(
Expand Down Expand Up @@ -740,7 +723,6 @@ def bicall(
step_history = None

if self.training:

step_history = Parameter(
data=[],
param_type=ParameterType.INPUT,
Expand Down Expand Up @@ -826,7 +808,7 @@ def forward(
# print(OutputParameter.__mro__)

app = App()
app.train()
app.eval()
output = app("I want to multiply 3 and 4.", id="123")
print(output)
output.draw_graph()
# output.draw_graph()
4 changes: 3 additions & 1 deletion adalflow/adalflow/core/base_data_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -292,7 +292,9 @@ class TrecDataList(DataClass):
# {'data': [{'question': 'What is the capital of France?'}]}
"""
if not is_dataclass(self):
raise ValueError("to_dict() called on a class type, not an instance.")
raise ValueError(
f"to_dict() is not called on a dataclass instance: {self.__class__}. You might forget to use @dataclass decorator."
)
# convert all fields to its data if its parameter
fields = self.__dataclass_fields__
from adalflow.optim.parameter import Parameter
Expand Down
1 change: 0 additions & 1 deletion adalflow/adalflow/core/func_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,6 @@ def sync_function_1():
raise ValueError(
f"FunctionTool {self.definition.func_name} is in eval mode, but the output is Parameter"
)
print("output is Parameter")
output.data = FunctionOutput(
name=self.definition.func_name,
# raw_input={"args": args, "kwargs": kwargs},
Expand Down
19 changes: 8 additions & 11 deletions adalflow/adalflow/core/tool_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,12 @@ def bicall(
context: Dict[str, object] = {},
):
if isinstance(func, Parameter):
printc(f"context: {context}", color="yellow")
# printc(f"context: {context}", color="yellow")
func_data: Function = func.map_to_successor(self)
if not isinstance(func_data, Function):
raise ValueError(f"Error parsing function expression: {func}")
tool: FunctionTool = context[func_data.name]
print(f"tool training: {tool.training}")
# print(f"tool training: {tool.training}")
output = tool.forward(*func_data.args, **func_data.kwargs)

from adalflow.optim.grad_component import fun_to_grad_component
Expand Down Expand Up @@ -119,16 +119,16 @@ def call(self, expr: FunctionExpression, context: Dict[str, object]) -> Function

expr_str = expr.action
func_name, args, kwargs = parse_function_call_expr(expr_str, context)
printc(
f"func_name: {func_name}, args: {args}, kwargs: {kwargs}", color="yellow"
)
# printc(
# f"func_name: {func_name}, args: {args}, kwargs: {kwargs}", color="yellow"
# )
output = Function(
name=func_name,
args=args,
kwargs=kwargs,
thought=expr.thought,
)
printc(f"output: {output}", color="yellow")
# printc(f"output: {output}", color="yellow")
return output


Expand Down Expand Up @@ -231,9 +231,9 @@ def parse_func_expr(

func = FunctionExperssionToFunction()
expr.add_successor_map_fn(func, map_fn=map_fn)
print("FunctionExperssionToFunction")
# print("FunctionExperssionToFunction")
output = func.forward(expr, context=self.context)
print(f"output data: {output.data}")
# print(f"output data: {output.data}")
return output

except Exception as e:
Expand Down Expand Up @@ -301,7 +301,6 @@ def forward(
"Run a forward pass on the tool manager such as parsing function expression or executing function."
if isinstance(expr_or_fun, Parameter):
expr_or_fun_data = map_fn(expr_or_fun)
print(f"expr_or_fun_data: {expr_or_fun_data}")
if step == "execute":
if isinstance(expr_or_fun_data, Function):
return self.execute_func(expr_or_fun, map_fn=map_fn)
Expand All @@ -311,9 +310,7 @@ def forward(
)
else:
if isinstance(expr_or_fun_data, FunctionExpression):
print(f"start parsing: {expr_or_fun_data}")
output = self.parse_func_expr(expr_or_fun, map_fn=map_fn)
print(f"output 3: {output.data}")
return output
else:
raise NotImplementedError(
Expand Down
16 changes: 8 additions & 8 deletions adalflow/adalflow/optim/grad_component.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,6 @@ def backward(self, *, response: "Parameter", id: str = None, **kwargs):
Subclass should implement this method if you need additional backward logic.
"""
from adalflow.optim.parameter import GradientContext

log.info(f"GradComponent backward: {response.name}")
children_params = response.predecessors
Expand Down Expand Up @@ -197,13 +196,14 @@ def backward(self, *, response: "Parameter", id: str = None, **kwargs):
grad.is_default_copy = (
True # response and pred will keep the original gradient
)
grad.add_context(
GradientContext(
variable_desc=pred.role_desc,
response_desc=response.name,
input_output=f"""{response.component_trace.to_context_str()}""",
)
)
# NOTE: test of keep the initial gradient context
# grad.add_context(
# GradientContext(
# variable_desc=pred.role_desc,
# response_desc=response.name,
# input_output=f"""{response.component_trace.to_context_str()}""",
# )
# )

pred.add_gradient(grad)

Expand Down
Loading

0 comments on commit 3889f8a

Please sign in to comment.