|
| 1 | +import re |
| 2 | +from loguru import logger |
| 3 | +from agentscope.message import Msg |
| 4 | +from agentscope.agent import ReActAgent |
| 5 | +from agentscope.formatter import OpenAIChatFormatter |
| 6 | +from agentscope.model import OpenAIChatModel |
| 7 | +from agentscope.memory import InMemoryMemory |
| 8 | +from agentscope.tool import Toolkit, execute_python_code |
| 9 | +from ajet import AjetTuner, Workflow, WorkflowOutput, WorkflowTask |
| 10 | + |
| 11 | + |
| 12 | +def extract_final_answer(result) -> str: |
| 13 | + """Extract the final answer from the agent's response.""" |
| 14 | + try: |
| 15 | + if ( |
| 16 | + hasattr(result, "metadata") |
| 17 | + and isinstance(result.metadata, dict) |
| 18 | + and "result" in result.metadata |
| 19 | + ): |
| 20 | + return result.metadata["result"] |
| 21 | + if hasattr(result, "content"): |
| 22 | + if isinstance(result.content, dict) and "result" in result.content: |
| 23 | + return result.content["result"] |
| 24 | + return str(result.content) |
| 25 | + return str(result) |
| 26 | + except Exception as e: |
| 27 | + logger.warning(f"Extract final answer error: {e}. Raw: {result}") |
| 28 | + return str(result) |
| 29 | + |
| 30 | + |
| 31 | +system_prompt = """ |
| 32 | +You are an agent specialized in solving math problems with tools. |
| 33 | +Please solve the math problem given to you. |
| 34 | +You can write and execute Python code to perform calculation or verify your answer. |
| 35 | +You should return your final answer within \\boxed{{}}. |
| 36 | +""" |
| 37 | + |
| 38 | + |
| 39 | +class MathToolWorkflow(Workflow): # ✨✨ inherit `Workflow` class |
| 40 | + name: str = "math_agent_workflow" |
| 41 | + |
| 42 | + async def execute(self, workflow_task: WorkflowTask, tuner: AjetTuner) -> WorkflowOutput: |
| 43 | + # run agentscope |
| 44 | + query = workflow_task.task.main_query |
| 45 | + self.toolkit = Toolkit() |
| 46 | + self.toolkit.register_tool_function(execute_python_code) |
| 47 | + |
| 48 | + url_and_apikey = tuner.as_oai_baseurl_apikey() |
| 49 | + base_url = url_and_apikey.base_url |
| 50 | + api_key = url_and_apikey.api_key # the api key contain information, do not discard it |
| 51 | + model = OpenAIChatModel( |
| 52 | + model_name="whatever", |
| 53 | + client_args={"base_url": base_url}, |
| 54 | + api_key=api_key, |
| 55 | + stream=False, |
| 56 | + ) |
| 57 | + self.agent = ReActAgent( |
| 58 | + name="math_react_agent", sys_prompt=system_prompt, |
| 59 | + model=model, # ✨✨ compared with a normal agentscope agent, here is the difference! |
| 60 | + formatter=OpenAIChatFormatter(), |
| 61 | + toolkit=self.toolkit, |
| 62 | + memory=InMemoryMemory(), max_iters=2, |
| 63 | + ) |
| 64 | + self.agent.set_console_output_enabled(False) |
| 65 | + msg = Msg("user", query, role="user") |
| 66 | + result = await self.agent.reply(msg) |
| 67 | + final_answer = extract_final_answer(result) |
| 68 | + |
| 69 | + # compute reward |
| 70 | + reference_answer = workflow_task.task.metadata["answer"].split("####")[-1].strip() |
| 71 | + match = re.search(r"\\boxed\{([^}]*)\}", final_answer) |
| 72 | + if match: is_success = (match.group(1) == reference_answer) |
| 73 | + else: is_success = False |
| 74 | + return WorkflowOutput(reward=(1.0 if is_success else 0.0), metadata={"final_answer": final_answer}) |
0 commit comments