2023-09-22 15:28:22 +08:00
from typing import List , Tuple
from mmengine . registry import Registry
2023-10-25 23:05:15 +08:00
from opencompass . lagent . agents . react import ReAct
from opencompass . utils import get_logger
2023-09-22 15:28:22 +08:00
REGISTRY = Registry ( ' helper ' )
class LagentAgent :
""" Agent wrapper for Lagent.
https : / / github . com / InternLM / lagent .
"""
2023-11-07 19:11:44 +08:00
def __init__ ( self ,
agent_type ,
llm ,
actions = None ,
protocol = None ,
mutli_rounds = False ,
* * kwargs ) :
2023-09-22 15:28:22 +08:00
llm = REGISTRY . build ( llm )
agent_cfg = { ' type ' : agent_type , ' llm ' : llm , * * kwargs }
if actions is not None :
from lagent . actions import ActionExecutor
2023-11-07 19:11:44 +08:00
2023-09-22 15:28:22 +08:00
executor = ActionExecutor (
[ REGISTRY . build ( action ) for action in actions ] )
agent_cfg [ ' action_executor ' ] = executor
if protocol is not None :
protocol = REGISTRY . build ( protocol )
agent_cfg [ ' protocol ' ] = protocol
self . agent = REGISTRY . build ( agent_cfg )
2023-11-07 19:11:44 +08:00
self . mutli_rounds = mutli_rounds
2023-09-22 15:28:22 +08:00
2023-10-25 23:05:15 +08:00
def add_example ( self , example ) :
# format example in protocol if needed
call_protocol = self . agent . _protocol . call_protocol
if ' {example} ' in call_protocol :
self . agent . _protocol . call_protocol = call_protocol . format (
example = example )
else :
get_logger ( ) . warning ( ' Protocal template does not have example '
' placeholder, please check your template. ' )
2023-11-07 19:11:44 +08:00
def one_round_chat ( self , user_input , ice = None ) - > Tuple [ str , List [ dict ] ] :
""" One round chat with agent. """
2023-09-22 15:28:22 +08:00
from lagent . schema import ActionReturn , AgentReturn
2023-11-07 19:11:44 +08:00
2023-09-22 15:28:22 +08:00
generation : AgentReturn = self . agent . chat ( user_input )
answer = generation . response
steps = [ ]
for step in generation . actions :
step : ActionReturn
steps . append (
dict (
type = step . type ,
args = step . args ,
result = step . result ,
thought = step . thought ,
state = int ( step . state ) ,
errmsg = step . errmsg ,
valid = int ( step . valid ) ,
) )
return answer , steps
2023-10-25 23:05:15 +08:00
2023-11-07 19:11:44 +08:00
def chat ( self , user_input , ice = None ) - > Tuple [ str , List [ dict ] ] :
""" Chat with agent. """
if self . mutli_rounds :
steps = [ ]
for single_input in user_input :
answer , one_round_steps = self . one_round_chat ( single_input )
steps . append ( one_round_steps )
else :
answer , steps = self . one_round_chat ( user_input )
2023-10-25 23:05:15 +08:00
2023-11-07 19:11:44 +08:00
self . agent . reset ( ) # clear agent history
return answer , steps
FORCE_STOP_PROMPT_EN = (
""" You should directly give results based on history information. """ # noqa
)
2023-10-25 23:05:15 +08:00
FEWSHOT_INSTRUCTION = """ \
2023-11-07 19:11:44 +08:00
You are an assistant who can utilize external tools .
2023-10-25 23:05:15 +08:00
{ { tool_description } }
To use a tool , please use the following format :
` ` `
{ { thought } } Think what you need to solve , do you need to use tools ?
{ { action } } the tool name , should be one of [ { { action_names } } ]
{ { action_input } } the input to the action
` ` `
I will give you response after utilizing tools should using the following format :
` ` `
{ { response } } the results after call the tool .
` `
If you already know the answer , or you do not need to use tools ,
please using the following format to reply :
` ` `
{ { thought } } the thought process to get the final answer
{ { finish } } final answer
` ` `
{ example }
Begin !
2023-11-07 19:11:44 +08:00
""" # noqa
2023-10-25 23:05:15 +08:00
2023-11-07 19:11:44 +08:00
PYTHON_INTERPRETER_DESCRIPTION = """ \
2023-10-25 23:05:15 +08:00
It can run a Python code . The code must be a valid code that contains only python method , and the method ' name must be ' solution ' and returns a dict, which key is variable name. The libraries I recommend are sympy and scipy. the format is:
` ` ` python
# import packages
import xxx
def solution ( ) :
# initialize some variables
variable_names_with_real_meaning = xxx
# middle steps
mid_variable = func ( mid_variable )
# final answer
2023-11-07 19:11:44 +08:00
final_answer = func ( mid_variable )
2023-10-25 23:05:15 +08:00
return final_answer
2023-11-07 19:11:44 +08:00
` ` ` """ # noqa
2023-10-25 23:05:15 +08:00
class CodeAgent :
2023-11-07 19:11:44 +08:00
""" Code Agent wrapper for Lagent. """
2023-10-25 23:05:15 +08:00
def __new__ ( self , llm , * * kwargs ) :
from lagent . agents . react import ReActProtocol
2023-11-07 19:11:44 +08:00
from opencompass . lagent . actions . python_interpreter import \
PythonInterpreter
mutli_rounds = kwargs . pop ( ' mutli_rounds ' , False )
2023-10-25 23:05:15 +08:00
agent_type = kwargs . pop ( ' agent_type ' , ReAct )
max_turn = kwargs . pop ( ' max_turn ' , 3 )
2023-11-07 19:11:44 +08:00
actions = kwargs . pop (
' actions ' ,
[
dict ( type = PythonInterpreter ,
description = PYTHON_INTERPRETER_DESCRIPTION ) ,
] ,
)
2023-10-25 23:05:15 +08:00
protocol = kwargs . pop (
' protocol ' ,
dict (
type = ReActProtocol ,
call_protocol = FEWSHOT_INSTRUCTION ,
force_stop = FORCE_STOP_PROMPT_EN ,
finish = dict ( role = ' FINISH ' , begin = ' Final Answer: ' , end = ' \n ' ) ,
2023-11-07 19:11:44 +08:00
) ,
)
2023-10-25 23:05:15 +08:00
return LagentAgent ( agent_type = agent_type ,
llm = llm ,
max_turn = max_turn ,
actions = actions ,
protocol = protocol ,
2023-11-07 19:11:44 +08:00
mutli_rounds = mutli_rounds ,
2023-10-25 23:05:15 +08:00
* * kwargs )