|
from copy import deepcopy |
|
from typing import List, Tuple |
|
|
|
from mmengine.registry import Registry |
|
|
|
REGISTRY = Registry('helper') |
|
|
|
|
|
class LagentAgent: |
|
"""Agent wrapper for Lagent. |
|
|
|
https://github.com/InternLM/lagent. |
|
""" |
|
is_api = True |
|
|
|
def __init__(self, agent_type, llm, actions=None, protocol=None, **kwargs): |
|
llm = REGISTRY.build(llm) |
|
agent_cfg = {'type': agent_type, 'llm': llm, **kwargs} |
|
|
|
if actions is not None: |
|
from lagent.actions import ActionExecutor |
|
executor = ActionExecutor([]) |
|
for action in actions: |
|
action = REGISTRY.build(action) |
|
if 'agentlego' in type(action).__module__: |
|
action = action.to_lagent() |
|
executor.add_action(action) |
|
agent_cfg['action_executor'] = executor |
|
if protocol is not None: |
|
protocol = REGISTRY.build(protocol) |
|
agent_cfg['protocol'] = protocol |
|
|
|
from lagent import BaseAgent |
|
self.agent: BaseAgent = REGISTRY.build(agent_cfg) |
|
|
|
def reset(self): |
|
self.agent._session_history = [] |
|
for action in self.agent._action_executor.actions: |
|
if hasattr(action, 'reset'): |
|
action.reset() |
|
|
|
def set_history(self, history): |
|
self.agent._session_history = deepcopy(history) |
|
|
|
def gt_response(self, prompt): |
|
if 'CIReAct' in str(self.agent.__class__): |
|
gold = prompt |
|
prompt = f"""{self.agent._protocol.action['begin']} IPythonInterpreter |
|
{self.agent._protocol.action_input['begin']} ```python\n{gold}\n```\n""" |
|
action_input = dict( |
|
command=f"""```python\n{gold}\n```\n""", |
|
timeout=120, |
|
) |
|
response = self.agent._action_executor('IPythonInterpreter', |
|
action_input) |
|
gt_response = dict(role='assistant', content=prompt) |
|
system_response = dict( |
|
role='system', |
|
content=self.agent._protocol.format_response(response)) |
|
return [gt_response, system_response] |
|
else: |
|
gt_response = dict(role='assistant', content=prompt) |
|
return [gt_response] |
|
|
|
@property |
|
def template_parser(self): |
|
return self.agent._llm.template_parser |
|
|
|
@template_parser.setter |
|
def template_parser(self, value): |
|
self.agent._llm.template_parser = value |
|
|
|
def chat(self, |
|
user_input: str, |
|
history: List[dict] = None) -> Tuple[str, List[dict], List[dict]]: |
|
"""Chat with agent.""" |
|
if history: |
|
self.agent._session_history = history |
|
|
|
from lagent.schema import ActionReturn, AgentReturn |
|
generation: AgentReturn = self.agent.chat(user_input) |
|
|
|
inner_steps = generation.inner_steps |
|
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, inner_steps |
|
|
|
|
|
FORCE_STOP_PROMPT_EN = ( |
|
"""You should directly give results based on history information.""" |
|
) |
|
|
|
FEWSHOT_INSTRUCTION = """\ |
|
You are a assistant who can utilize external tools. |
|
{tool_description} |
|
To use a tool, please response with 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 tool that you want to use. |
|
``` |
|
The tool will give you response after your response using the following format: |
|
``` |
|
{response} the results after call the tool. |
|
``` |
|
Therefore DO NOT generate tool response by yourself. |
|
|
|
Also please follow the guidelines: |
|
1. Always use code interpreter to solve the problem. |
|
2. The generated codes should always in a markdown code block format. |
|
3. The generated codes will be executed in an ipython manner and the results will be cached. |
|
4. Your responded code should always be simple and only solves the problem in current step. |
|
|
|
Begin! |
|
""" |
|
|
|
PYTHON_INTERPRETER_DESCRIPTION = """\ |
|
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 |
|
final_answer = func(mid_variable) |
|
return final_answer |
|
```""" |
|
|
|
|
|
class CodeAgent(LagentAgent): |
|
"""Code Agent wrapper for Lagent.""" |
|
|
|
def __init__(self, llm, **kwargs): |
|
from lagent import PythonInterpreter, ReAct |
|
from lagent.agents.react import ReActProtocol |
|
|
|
agent_type = kwargs.pop('agent_type', ReAct) |
|
max_turn = kwargs.pop('max_turn', 3) |
|
actions = kwargs.pop( |
|
'actions', |
|
[ |
|
dict(type=PythonInterpreter, |
|
description=PYTHON_INTERPRETER_DESCRIPTION), |
|
], |
|
) |
|
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'), |
|
), |
|
) |
|
super().__init__(agent_type=agent_type, |
|
llm=llm, |
|
actions=actions, |
|
protocol=protocol, |
|
max_turn=max_turn, |
|
**kwargs) |
|
|