Merge branch 'tool_manage_new' into 'code_intepreter'

accept goal during run; move more logic from role to planner

See merge request agents/data_agents_opt!63
This commit is contained in:
林义章 2024-01-30 08:58:18 +00:00
commit 31a9410e6d
3 changed files with 50 additions and 45 deletions

View file

@ -44,6 +44,48 @@ class Planner(BaseModel):
def current_task_id(self):
return self.plan.current_task_id
async def update_plan(self, goal: str = "", max_tasks: int = 3, max_retries: int = 3):
if goal:
self.plan = Plan(goal=goal)
plan_confirmed = False
while not plan_confirmed:
context = self.get_useful_memories()
rsp = await WritePlan().run(context, max_tasks=max_tasks, use_tools=self.use_tools)
self.working_memory.add(Message(content=rsp, role="assistant", cause_by=WritePlan))
# precheck plan before asking reviews
is_plan_valid, error = precheck_update_plan_from_rsp(rsp, self.plan)
if not is_plan_valid and max_retries > 0:
error_msg = f"The generated plan is not valid with error: {error}, try regenerating, remember to generate either the whole plan or the single changed task only"
logger.warning(error_msg)
self.working_memory.add(Message(content=error_msg, role="assistant", cause_by=WritePlan))
max_retries -= 1
continue
_, plan_confirmed = await self.ask_review(trigger=ReviewConst.TASK_REVIEW_TRIGGER)
update_plan_from_rsp(rsp=rsp, current_plan=self.plan)
self.working_memory.clear()
async def process_task_result(self, task_result: TaskResult):
# ask for acceptance, users can other refuse and change tasks in the plan
review, task_result_confirmed = await self.ask_review(task_result)
if task_result_confirmed:
# tick off this task and record progress
await self.confirm_task(self.current_task, task_result, review)
elif "redo" in review:
# Ask the Role to redo this task with help of review feedback,
# useful when the code run is successful but the procedure or result is not what we want
pass # simply pass, not confirming the result
else:
# update plan according to user's feedback and to take on changed tasks
await self.update_plan()
async def ask_review(
self, task_result: TaskResult = None, auto_run: bool = None, trigger: str = ReviewConst.TASK_REVIEW_TRIGGER
):
@ -74,28 +116,6 @@ class Planner(BaseModel):
self.working_memory.add(Message(content=review, role="user", cause_by=AskReview))
await self.update_plan(review)
async def update_plan(self, max_tasks: int = 3, max_retries: int = 3):
plan_confirmed = False
while not plan_confirmed:
context = self.get_useful_memories()
rsp = await WritePlan().run(context, max_tasks=max_tasks, use_tools=self.use_tools)
self.working_memory.add(Message(content=rsp, role="assistant", cause_by=WritePlan))
# precheck plan before asking reviews
is_plan_valid, error = precheck_update_plan_from_rsp(rsp, self.plan)
if not is_plan_valid and max_retries > 0:
error_msg = f"The generated plan is not valid with error: {error}, try regenerating, remember to generate either the whole plan or the single changed task only"
logger.warning(error_msg)
self.working_memory.add(Message(content=error_msg, role="assistant", cause_by=WritePlan))
max_retries -= 1
continue
_, plan_confirmed = await self.ask_review(trigger=ReviewConst.TASK_REVIEW_TRIGGER)
update_plan_from_rsp(rsp=rsp, current_plan=self.plan)
self.working_memory.clear()
def get_useful_memories(self, task_exclude_field=None) -> list[Message]:
"""find useful memories only to reduce context length and improve performance"""
# TODO dataset description , code steps

View file

@ -452,10 +452,11 @@ class Role(SerializationMixin, is_polymorphic_base=True):
async def _plan_and_act(self) -> Message:
"""first plan, then execute an action sequence, i.e. _think (of a plan) -> _act -> _act -> ... Use llm to come up with the plan dynamically."""
### Common Procedure in both single- and multi-agent setting ###
# create initial plan and update until confirmation
await self.planner.update_plan()
# create initial plan and update it until confirmation
goal = self.rc.memory.get()[-1].content # retreive latest user requirement
await self.planner.update_plan(goal=goal)
# take on tasks until all finished
while self.planner.current_task:
task = self.planner.current_task
logger.info(f"ready to take on task {task}")
@ -463,25 +464,10 @@ class Role(SerializationMixin, is_polymorphic_base=True):
# take on current task
task_result = await self._act_on_task(task)
# ask for acceptance, users can other refuse and change tasks in the plan
review, task_result_confirmed = await self.planner.ask_review(task_result)
# process the result, such as reviewing, confirming, plan updating
await self.planner.process_task_result(task_result)
if task_result_confirmed:
# tick off this task and record progress
await self.planner.confirm_task(task, task_result, review)
elif "redo" in review:
# Ask the Role to redo this task with help of review feedback,
# useful when the code run is successful but the procedure or result is not what we want
continue
else:
# update plan according to user's feedback and to take on changed tasks
await self.planner.update_plan()
completed_plan_memory = self.planner.get_useful_memories() # completed plan as a outcome
rsp = completed_plan_memory[0]
rsp = self.planner.get_useful_memories()[0] # return the completed plan as a response
self.rc.memory.add(rsp) # add to persistent memory

View file

@ -23,10 +23,9 @@ async def run_code_interpreter(role_class, requirement, auto_run, use_tools, use
"""
if role_class == "ci":
role = CodeInterpreter(goal=requirement, auto_run=auto_run, use_tools=use_tools, tools=tools)
role = CodeInterpreter(auto_run=auto_run, use_tools=use_tools, tools=tools)
else:
role = MLEngineer(
goal=requirement,
auto_run=auto_run,
use_tools=use_tools,
use_code_steps=use_code_steps,