A thorough understanding of the agent's tool call based on ReAct

Written by
Caleb Hayes
Updated on:June-26th-2025
Recommendation

In-depth exploration of how AI agents can use ReAct to implement tool calls and improve autonomy and task execution efficiency.

Core content:
1. The definition of AI agents and their technical composition
2. The application of function calling in agents and its limitations
3. The basics of ReAct and its role and implementation steps in tool calls

Yang Fangxian
Founder of 53A/Most Valuable Expert of Tencent Cloud (TVP)

Preface

AI agents are software or hardware entities that have a certain degree of autonomy, can perceive the environment, and perform specific tasks through intelligent decision-making. It combines artificial intelligence technologies (such as machine learning, natural language processing, computer vision, etc.) and can achieve goals independently or collaboratively.

Function Calling based on the Large Language Model (LLM) enables intelligent agents to use tools effectively and interact with external APIs. Models that support Function Calling (such as gpt-4, qwen-plus, etc.) can detect when a function needs to be called and output the function name and required parameters of the called function in JSON format.

However, not all LLM models support Function Calling (such as deepseel-v3) . For models that do not support Function Calling, ReAct's relatively complex prompt word engineering can be used to require the model to return a response in a specific format in order to distinguish different stages (thinking, action, observation).

Tool calls have two main purposes:

  • Get data:
     For example, retrieving content from a knowledge base based on keywords and obtaining business data through a specific API interface
  • Execution Action:
     For example, modify business status data and execute scheduled business operations through API interfaces


This article contains the following content:

  • ReAct Basics
  • Detailed introduction to the ReAct-based tool calling process and the interactive messages involved
  • Hand-rolled Agent code to implement ReAct-based tool calls

ReAct Basics

ReAct is derived from a classic paper: REACT: SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS (Link: https://arxiv.org/pdf/2210.03629 )

In order to solve the problem, the ReAct-based agent needs to go through several stages.

  • Thought: Thinking and Reasoning
  • Action: Take action and decide which tools and parameters to call
  • Observation: The result of the action (tool output)


The above three stages may be iterated multiple times until the problem is solved or the upper limit of the iteration number is reached.

ReAct-based tool calls rely on complex prompt word engineering. The system prompt words refer to the langchain template:

Answer the following questions as best you can. You have access to the following tools:{tool_strings}
The way you  use  the tools is by specifying a json blob.Specifically, this json should have a  `action`  key (with the name of the tool to  useand  a  `action_input`  key (with the input to the tool going here).
The only  values  ​​that should be in the  "action"  field are:  {tool_names}
The $JSON_BLOB should only contain a SINGLE action,  do  NOT  return  a list of multiple actions. Here is an example of a valid $JSON_BLOB:
```{{{{"action": $TOOL_NAME,"action_input": $INPUT}}}}` ``
ALWAYS  use  the following  format :
Question: the input question you must answerThought: you should always think about what to  doAction:```$JSON_BLOB` ``Observation: the result of the action... (this Thought/Action/Observation can repeat N  times )Thought: I now know the final answerFinal Answer: the final answer to the original input question
Begin! Reminder to always  use  the exact characters  `Final Answer`  when  responding.


Tool calling process and interactive messages based on ReAct

Let’s take the weather query in Beijing and Guangzhou as an example. LLM uses Alibaba Cloud’sDeepSeek-v3The process of querying weather is as follows:

1. Initiate a query request

When inquiring LLM, there are 2 messages in the messages list:

  • The first role issystem, defines system prompt words (including tool definitions)
  • The second role isuser, contains the following:
    • Question: What is the weather like in Beijing and Guangzhou?


We use curl to initiate a POST request. The JSON structure of the body can be found at https://platform.openai.com/docs/api-reference/chat/create  .

In the requeststopThe field needs to be set toObservation:Otherwise, LLM will directly output the entire Thought/Action/Observation process and give a fictitious final answer. We only need LLM to output Thought/Action.

# !/ bin / bashexport  OPENAI_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"export  OPENAI_API_KEY = "sk-xxx"  # Replace with your key
curl ${ OPENAI_BASE_URL } /chat/ completions \-H "Content-Type: application/json "   \- H  "Authorization: Bearer $OPENAI_API_KEY"  \-d '{  "model""deepseek-v3" ,  "messages" : [    {      "role""system" ,      "content"" \n Answer the following questions as best you can. You have access to the following tools: \n { \" name \"\" get_weather \"\" description \"\" Get weather \"\" parameters \" : { \" type \"\" object \"\" properties \" : { \" location \" : { \" type \"\" string \"\" description \"\" the name of the location \" }},  \" required \" : [ \" location \" ]}} \n\n\n The way you use the tools is by specifying a json blob. \n Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). \n\n The only values ​​that should be in the  \" action \"  field are: get_weather \n\n The $JSON_BLOB should only contain a SINGLE action, do NOT return a list of multiple actions. Here is an example of a valid $JSON_BLOB: \n\n `` \n {{ \n\" action \" : $TOOL_NAME, \n\" action_input \" : $INPUT \n }} \n `` \n\n ALWAYS use the following format: \n\n Question: the input question you must answer \n Thought: you should always think about what to do \n Action: \n ``` \n $JSON_BLOB \n ``` \n Observation: the result of the action \n ... (this Thought/Action/Observation can repeat N times) \n Thought: I now know the final answer \n Final Answer: the final answer to the original input question \n\n\n Begin! Reminder to always use the exact characters `Final Answer` when responding.  \n "    },    {      "role""user" ,      "content""Question: What's the weather like in Beijing and Guangzhou \n\n "    }  ],  "stop""Observation:"}'

2. LLM returns to Action to obtain Beijing weather

After reasoning, LLM found that it was necessary to call a function to obtain Beijing's weather first.

Thought: I need to get weather information for Beijing and Guangzhou. First, I will get the weather in Beijing. Action:```{ "action": "get_weather", "action_input": { "location": "Beijing" }}```

The complete JSON response is as follows:

{ "choices": [ { "message": { "content": "Thought: I need to get weather information for Beijing and Guangzhou. First, I will get the weather in Beijing.\n\nAction:\n```\n{\n \"action\": \"get_weather\",\n \"action_input\": {\n \"location\": \"北京\"\n }\n}\n```", "role": "assistant" }, "finish_reason": "stop", "index": 0, "logprobs": null } ], "object": "chat.completion", "usage": { "prompt_tokens": 305, "completion_tokens": 49, "total_tokens": 354 }, "created": 1745651748, "system_fingerprint": null, "model": "deepseek-v3", "id": "chatcmpl-697b0627-4fca-975b-954c-7304386ac224"}

3. Processing function call to obtain Beijing weather

Parse and process the LLM Action to obtain the function name and parameter list, and call the corresponding API interface to obtain the result.

For example: throughhttp://weather.cma.cn/api/now/54511Weather conditions in Beijing are available.

The complete JSON response is as follows:

{ "msg": "success", "code": 0, "data": { "location": { "id": "54511", "name": "北京", "path": "北京, China, 北京" }, "now": { "precipitation": 0.0, "temperature": 23.4, "pressure": 1005.0, "humidity": 43.0, "windDirection": "Southwest", "windDirectionDegree": 216.0, "windSpeed": 2.7, "windScale": "Breeze", "feelst": 23.1 }, "alarm": [], "jieQi": "", "lastUpdate": "2025/04/26 15:00" }}

4. Send context information and function call results to LLM

The message list sent to LLM contains 2 messages:

  • The first role issystem, defines system prompt words (including tool definitions)
  • The second role isuser, contains the following:
    • Question: What is the weather like in Beijing and Guangzhou?
    • Thought: I need to get weather information for Beijing and Guangzhou. First, I will get the weather in Beijing
    • Action: {"action":"get_weather","action_input":{"location":"Beijing"}}
    • Observation: Tool callget_weather('Beijing')Results
# !/ bin / bashexport  OPENAI_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"export  OPENAI_API_KEY = "sk-xxx"  # Replace with your key
curl ${ OPENAI_BASE_URL } /chat/ completions \-H "Content-Type: application/json "   \- H  "Authorization: Bearer $OPENAI_API_KEY"  \-d '{  "model""deepseek-v3" ,  "messages" : [    {      "role""system" ,      "content"" \n Answer the following questions as best you can. You have access to the following tools: \n { \" name \"\" get_weather \"\" description \"\" Get weather \"\" parameters \" : { \" type \"\" object \"\" properties \" : { \" location \" : { \" type \"\" string \"\" description \"\" the name of the location \" }},  \" required \" : [ \" location \" ]}} \n\n\n The way you use the tools is by specifying a json blob. \n Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). \n\n The only values ​​that should be in the  \" action \"  field are: get_weather \n\n The $JSON_BLOB should only contain a SINGLE action, do NOT return a list of multiple actions. Here is an example of a valid $JSON_BLOB: \n\n `` \n {{ \n\" action \" : $TOOL_NAME, \n\" action_input \" : $INPUT \n }} \n `` \n\n ALWAYS use the following format: \n\n Question: the input question you must answer \n Thought: you should always think about what to do \n Action: \n ``` \n $JSON_BLOB \n ``` \n Observation: the result of the action \n ... (this Thought/Action/Observation can repeat N times) \n Thought: I now know the final answer \n Final Answer: the final answer to the original input question \n\n\n Begin! Reminder to always use the exact characters `Final Answer` when responding.  \n "    },    {      "role""user" ,      } ,  \" now \" : { \" precipitation \" :0, \" temperature \" :23.4, \ " current hour \" :10.75, \" precipitation \" :0.1, \" temperature \" :23.6, \" current hour \" :10.6, \" precipitation \" :0.0, \" temperature \" :23.9 , \ " current hour \ " : 10.6 ," precipitation \ " :0.1 , \" temperature \" 23.8, \" current hour \ " :10.6 , \" precipitation \" :0.0, \" temperature \" :23.7, \" current hour \" :10.6 , \ " precipitation \" : 0.0 , \" temperature \" : 23.9 , \" current hour \ " : 10.75 , \" precipitation \" :0.0, \ " temperature \" : 23.8 , \ " current hour \ " : 10.6, \" precipitation \ " : 0.0 , \" temperature \" : 23.9, \" current hour \" : 10.6 , \" precipitation \" :0.0 , \ " temperature \" : 23.8 , \" current hour \" : 10.6, \" precipitation \" :0.0 , \" temperature \" :23.8, \" current hour \" : 10.6, \" precipitation \" :0.0, \" temperature \" :23.9, \ " \" pressure \" :1005.0, \" humidity \" :43.0, \" windDirection \" : \" southwest wind \" , \" windDirectionDegree \" :216.0, \" windSpeed ​​\" :2.7, \" windScale \" : \" breeze \" , \" feelst \" :23.1}, \" alarm \" :[], \" jieQi \" : \"\" , \" lastUpdate \" : \" 2025/04/26 15:00 \" }} \n "    }  ],  "stop""Observation:"}'

5. LLM returns to Action to obtain Guangzhou weather

After reasoning, LLM found that it was necessary to call a function to obtain the weather in Guangzhou.

Thought: I have already obtained the weather information for Beijing. Next, I will obtain the weather information for Guangzhou. Action:```{ "action": "get_weather", "action_input": { "location": "Guangzhou" }}```



The complete JSON response is as follows:

{ "choices": [ { "message": { "content": "Thought: I have already obtained the weather information for Beijing. Next, I will obtain the weather information for Guangzhou.\n\nAction:\n```\n{\n\"action\": \"get_weather\",\n\"action_input\": {\n\"location\": \"Guangzhou\"\n}\n}\n```\nObservation", "role": "assistant" }, "finish_reason": "stop", "index": 0, "logprobs": null } ], "object": "chat.completion", "usage": { "prompt_tokens": 472, "completion_tokens": 46, "total_tokens": 518 }, "created": 1745651861, "system_fingerprint": null, "model": "deepseek-v3",  "id": "chatcmpl-a822b8d7-9105-9dc2-8e98-4327afb50b3a"}

6. Processing function call to obtain Guangzhou weather

Parse and process the LLM Action to obtain the function name and parameter list, and call the corresponding API interface to obtain the result.

For example: throughhttp://weather.cma.cn/api/now/59287Weather conditions in Guangzhou are available.

The complete JSON response is as follows:

{ "msg": "success", "code": 0, "data": { "location": { "id": "59287", "name": "Guangzhou", "path": "China, Guangdong, Guangzhou" }, "now": { "precipitation": 0.0, "temperature": 24.2, "pressure": 1005.0, "humidity": 79.0, "windDirection": "Northeast Wind", "windDirectionDegree": 31.0, "windSpeed": 1.3, "windScale": "Breeze", "feelst": 27.1 }, "alarm": [], "jieQi": "", "lastUpdate": "2025/04/26 15:00" }}

7. Send context information and function call results to LLM

The message list sent to LLM contains 2 messages:

  • The first role issystem, defines system prompt words (including tool definitions)
  • The second role isuser, contains the following:
    • Question: What is the weather like in Beijing and Guangzhou?
    • Thought: I need to get weather information for Beijing and Guangzhou. First, I will get the weather in Beijing
    • Action: {"action":"get_weather","action_input":{"location":"Beijing"}}
    • Observation: Tool callget_weather('Beijing')Results
    • Thought: Now that I have obtained the weather information for Beijing, I will obtain the weather information for Guangzhou next.
    • Action: {"action":"get_weather","action_input":{"location":"Guangzhou"}}
    • Observation: Tool callget_weather('Guangzhou')Results
# !/ bin / bashexport  OPENAI_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1"export  OPENAI_API_KEY = "sk-xxx"  # Replace with your key
curl ${ OPENAI_BASE_URL } /chat/ completions \-H "Content-Type: application/json "   \- H  "Authorization: Bearer $OPENAI_API_KEY"  \-d '{  "model""deepseek-v3" ,  "messages" : [    {      "role""system" ,      "content"" \n Answer the following questions as best you can. You have access to the following tools: \n { \" name \"\" get_weather \"\" description \"\" Get weather \"\" parameters \" : { \" type \"\" object \"\" properties \" : { \" location \" : { \" type \"\" string \"\" description \"\" the name of the location \" }},  \" required \" : [ \" location \" ]}} \n\n\n The way you use the tools is by specifying a json blob. \n Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). \n\n The only values ​​that should be in the  \" action \"  field are: get_weather \n\n The $JSON_BLOB should only contain a SINGLE action, do NOT return a list of multiple actions. Here is an example of a valid $JSON_BLOB: \n\n `` \n {{ \n\" action \" : $TOOL_NAME, \n\" action_input \" : $INPUT \n }} \n `` \n\n ALWAYS use the following format: \n\n Question: the input question you must answer \n Thought: you should always think about what to do \n Action: \n ``` \n $JSON_BLOB \n ``` \n Observation: the result of the action \n ... (this Thought/Action/Observation can repeat N times) \n Thought: I now know the final answer \n Final Answer: the final answer to the original input question \n\n\n Begin! Reminder to always use the exact characters `Final Answer` when responding.  \n "    },    {      "role""user" ,      } ,  \" now \" : { \" precipitation \" :0, \" temperature \" :23.4, \ " current hour \" :10.75, \" precipitation \" :0.1, \" temperature \" :23.6, \" current hour \" :10.6, \" precipitation \" :0.0, \" temperature \" :23.9 , \ " current hour \ " : 10.6 ," precipitation \ " :0.1 , \" temperature \" 23.8, \" current hour \ " :10.6 , \" precipitation \" :0.0, \" temperature \" :23.7, \" current hour \" :10.6 , \ " precipitation \" : 0.0 , \" temperature \" : 23.9 , \" current hour \ " : 10.75 , \" precipitation \" :0.0, \ " temperature \" : 23.8 , \ " current hour \ " : 10.6, \" precipitation \ " : 0.0 , \" temperature \" : 23.9, \" current hour \" : 10.6 , \" precipitation \" :0.0 , \ " temperature \" : 23.8 , \" current hour \" : 10.6, \" precipitation \" :0.0 , \" temperature \" :23.8, \" current hour \" : 10.6, \" precipitation \" :0.0, \" temperature \" :23.9, \ " \" pressure \" :1005.0, \" humidity \" :43.0, \" windDirection \" : \" Southwest wind \" , \" windDirectionDegree \" :216.0, \" windSpeed ​​\" :2.7, \" windScale \" : \" Breeze \" , \" feelst \" :23.1}, \" alarm \" :[], \" jieQi \" : \"\" , \" lastUpdate \" : \" 2025/04/26 15:00 \" }} \n Thought: Now that I have obtained the weather information of Beijing, I will get the weather information of Guangzhou next. \n\n Action: \n ``` \n { \n\" action \"\" get_weather \" , \n\" action_input \" : { \n\" location \"\" Guangzhou \"\n } \n} \n ``` \n Observation \n Observation: { \" msg \" : \" success \" , \" code \" :0, \" data \" :{ \" location \" :{ \" id \" : \" 59287 \" , \" name \" : \" Guangzhou \" , \" path \" : \" China, Guangdong, Guangzhou \" }, \" now \" :{ \" precipitation \" :0.0, \" temperature \" :24.2, \" pressure \" :1005.0, \" humidity \" :79.0, \" windDirection \" : \" Northeast wind \" , \" windDirectionDegree \" :31.0, \" windSpeed ​​\" :1.3, \" windScale \" : \" Breeze \" , \" feelst \" :27.1}, \" alarm \" :[], \" jieQi \" : \"\" , \" lastUpdate \" : \" 2025/04/26 15:00 \" }} \n "    }  ],  "stop""Observation:"}'

8. LLM generates final response

LLM generates the final response:

Thought : I have obtained the weather information for Beijing and Guangzhou, and now I can answer users' questions.
Final  Answer: The temperature in Beijing is 23.4 ° C , the humidity is 43 %, the wind direction is southwesterly, and the wind speed is 2.7 m /s . The temperature in Guangzhou is 24.2 ° C , the humidity is 79 %, the wind direction is northeasterly, and the wind speed is 1.3 m /s.



The complete JSON response is as follows:

{ "choices": [ { "message": { "content": "Thought: I have obtained the weather information of Beijing and Guangzhou. Now I can answer the user's question.\n\nFinal Answer: The weather temperature in Beijing is 23.4°C, the humidity is 43%, the wind direction is southwest, and the wind speed is 2.7m/s. The weather temperature in Guangzhou is 24.2°C, the humidity is 79%, the wind direction is northeast, and the wind speed is 1.3m/s.", "role": "assistant" }, "finish_reason": "stop", "index": 0, "logprobs": null } ], "object": "chat.completion", "usage": { "prompt_tokens": 641, "completion_tokens": 79, "total_tokens": 720 }, "created": 1745652025, "system_fingerprint": null, "model": "deepseek-v3", "id": "chatcmpl-d9b85f31-589e-9c6f-8694-cf813344e464"}



Hand-rolled Agent code to implement ReAct-based tool calls

1. Create a Python environment

uv init agent
cd  agent
uv venv
.venv \ Scripts \ activate

uv  add  openai requests python-dotenv

2. Set up your API Key

Create .env, the content of .env is as follows (note to change OPENAI_API_KEY to your key)

OPENAI_API_KEY=your_api_key_here
OPENAI_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1

Add .env to .gitignore

3. Implement Agent code

The pseudo code logic of implementing ReAct agent based on OpenAI SDK is as follows:

maxIter = 5 # maximum number of iterations agent_scratchpad = "" # agent thinking process (Thought/Action/Observation) for iterSeq in range(1, maxIter+1): Construct chat completion request There are 2 messages The first one is the system prompt message (including tool definition) The second one is the user message: Question + agent thinking process (Thought/Action/Observation) Set the stop parameter to "Observation:" Get the chat completion result If the chat completion result contains "Final Answer:" Return the final answer If the chat completion result contains Action Parse and call the corresponding function Update the agent thinking process: add the output of this LLM (Though/Action) and the tool call result (Observation) to agent_scratchpad Continue iterating



The complete main.py code is as follows:

import  jsonimport  reimport  requestsimport  urllib.parsefrom  typing  import  Iterablefrom  openai  import  OpenAIfrom  openai.types.chat.chat_completion_message_param  import  ChatCompletionMessageParamfrom  openai.types.chat.chat_completion_user_message_param  import  (    ChatCompletionUserMessageParam,)from  openai.types.chat.chat_completion_system_message_param  import  (    ChatCompletionSystemMessageParam,)
# Load environment variablesfrom  dotenv  import  load_dotenvload_dotenv()
client = OpenAI()model =  "deepseek-v3"
# Tool definitiontools = [    {        "type""function" ,        "function" : {            "name""get_weather" ,            "description""Get weather" ,            "parameters" : {                "type""object" ,                "properties" : {                    "location" : { "type""string""description""location" }                },                "required" : [ "location" ],            },        },    }]
# System prompt wordsdef  get_system_prompt ():    tool_strings =  "\n" .join([json.dumps(tool[ "function" ])  for  tool  in  tools])    tool_names =  ", " .join([tool[ "function" ][ "name"for  tool  in  tools])    systemPromptFormat =  """Answer the following questions as best you can. You have access to the following tools:{tool_strings}

The way you use the tools is by specifying a json blob.Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here).
The only values ​​that should be in the "action" field are: {tool_names}
The $JSON_BLOB should only contain a SINGLE action, do NOT return a list of multiple actions. Here is an example of a valid $JSON_BLOB:
```{{{{"action": $TOOL_NAME,"action_input": $INPUT}}}}```
ALWAYS use the following format:
Question: the input question you must answerThought: you should always think about what to doAction:```$JSON_BLOB```Observation: the result of the action... (this Thought/Action/Observation can repeat N times)Thought: I now know the final answerFinal Answer: the final answer to the original input question

Begin! Reminder to always use the exact characters `Final Answer` when responding. """    return  systemPromptFormat. format (tool_strings=tool_strings, tool_names=tool_names)
# Get the weatherdef  get_weather ( location:  str ) ->  str :    url =  "http://weather.cma.cn/api/autocomplete?q="  + urllib.parse.quote(location)    response = requests.get(url)    data = response.json()    if  data[ "code" ] !=  0 :        return  "No information found for this location"    location_code =  ""    for  item  in  data[ "data" ]:        str_array = item.split( "|" )        if  (            str_array[ 1 ] == location            or  str_array[ 1 ] +  "city"  == location            or  str_array[ 2 ] == location        ):            location_code = str_array[ 0 ]            break    if  location_code ==  "" :        return  "No information found for this location"    url =  f"http://weather.cma.cn/api/now/ {location_code} "    return  requests.get(url).text
# Implement tool callsdef  invoke_tool ( toolName:  str , toolParamaters ) ->  str :    result =  ""    if  toolName ==  "get_weather" :        result = get_weather(toolParamaters[ "location" ])    else :        result =  f"Function {toolName} is not defined"    return  result
def  main ():    query =  "What's the weather like in Beijing and Guangzhou?"    systemMsg = ChatCompletionSystemMessageParam(        role= "system" , content=get_system_prompt()    )    maxIter =  5   # Maximum number of iterations    agent_scratchpad =  ""   # agent thinking process    action_pattern = re. compile ( r"\nAction:\n`{3}(?:json)?\n(.*?)`{3}.*?$" , re.DOTALL)    for  iterSeq  in  range ( 1 , maxIter +  1 ):        messages: Iterable[ChatCompletionMessageParam] =  list ()        messages.append(systemMsg)        messages.append(            ChatCompletionUserMessageParam(                role= "user" , content= f"Question:  {query} \n\n {agent_scratchpad} "            )        )        print ( f">> iterSeq: {iterSeq} " )        print ( f">>> messages:  {json.dumps(messages)} " )        # Initiate a request to LLM. Note that the stop parameter needs to be set.        chat_completion = client.chat.completions.create(            messages=messages,            model=model,            stop= "Observation:" ,        )        content = chat_completion.choices[ 0 ].message.content        print ( f">>> content:\n {content} " )        final_answer_match = re.search( r"\nFinal Answer:\s*(.*)" , content)        if  final_answer_match:            final_answer = final_answer_match.group( 1 )            print ( f">>> Final answer:  {final_answer} " )            return        action_match = action_pattern.search(content)        if  action_match:            obj = json.loads(action_match.group( 1 ))            toolName = obj[ "action" ]            toolParameters = obj[ "action_input" ]            print ( f">>> tool name: {toolName} " )            print ( f">>> tool parameters: {toolParameters} " )            result = invoke_tool(toolName, toolParameters)            print ( f">>> tool result:  {result} " )            # Add the output of this LLM (Though/Action) and the tool call result (Observation) to agent_scratchpad            agent_scratchpad += content +  f"\nObservation:  {result} \n"        else :            print ( ">>> ERROR: detect invalid response" )            return    print ( ">>> The number of iterations has reached the upper limit and I cannot get the final answer" )
main()



Run the code:uv run .\main.py

The output log is as follows:
>>  iterSeq: 1>>>  messages: [{ "role""system""content"" \n Answer the following questions as best you can. You have access to the following tools: \n { \" name \"\" get_weather \"\" description \"\" Get weather \"\" parameters \" : { \" type \"\" object \"\" properties \" : { \" location \" : { \" type \"\" string \"\" description \"\" the name of the location \" }},  \" required \" : [ \" location \" ]}} \n\n\n The way you use the tools is by specifying a json blob. \n Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). \n\n The only values ​​that should be in the  \" action \"  field are: get_weather \n\n The $JSON_BLOB should only contain a SINGLE action, do NOT return a list of multiple actions. Here is an example of a valid $JSON_BLOB: \n\n ``` \n {{ \n\" action \" : $TOOL_NAME, \n\" action_input \" : $INPUT \n }} \n ``` \n\n ALWAYS use the following format: \n\n Question: the input question you must answer \n Thought: you should always think about what to do \n Action: \n ``` \n $JSON_BLOB \n ``` \n Observation: the result of the action \n ... (this Thought/Action/Observation can repeat N times) \n Thought: I now know the final answer \n Final: the final answer to the original input question \n\n\n Begin! Reminder to always use the exact characters `Final Answer` when responding. \n " }, {"role""user""content""Question: \u5317\u4eac\u548c\u5e7f\u5dde\u5929\u6c14\u600e\u4e48\u6837 \n\n " }]>>>  content:Thought : I need to get the weather information of Beijing and Guangzhou . First, I will get the weather of Beijing .
Action :```{"action""get_weather" ,"action_input" : {"location""Beijing"}}```>>>  tool name:get_weather>>>  tool parameters:{'location': 'Beijing'}>>>  tool result: { "msg" : "success" , "code" : 0 , "data" :{ "location" :{ "id" : "54511" , "name" : "北京" , "path" : "中国, 北京, 北京" }, "now" :{ "precipitation" : 0.0 , "temperature" : 23.4 , "pressure" : 1005.0 , "humidity" : 43.0 , "windDirection" : "Southwest Wind" , "windDirectionDegree" : 216.0 , "windSpeed" : 2.7 , "windScale" : "Breeze" , "feelst" : 23.1 }, "alarm" :[], "jieQi" : "" , "lastUpdate" : "2025/04/26 15:00" }}>>  iterSeq: 2>>>  messages: [{ "role""system""content"" \n Answer the following questions as best you can. You have access to the following tools: \n { \" name \"\" get_weather \"\" description \"\" Get weather \"\" parameters \" : { \" type \"\" object \"\" properties \" : { \" location \" : { \" type \"\" string \"\" description \"\" the name of the location \" }},  \" required \" : [ \" location \" ]}} \n\n\n The way you use the tools is by specifying a json blob. \n Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). \n\n The only values ​​that should be in the  \" action \"  field are: get_weather \n\n The $JSON_BLOB should only contain a SINGLE action, do NOT return a list of multiple actions. Here is an example of a valid $JSON_BLOB: \n\n ``` \n {{ \n\" action \" : $TOOL_NAME, \n\" action_input \" : $INPUT \n }} \n ``` \n\n ALWAYS use the following format: \n\n Question: the input question you must answer \n Thought: you should always think about what to do \n Action: \n ``` \n $JSON_BLOB \n ``` \n Observation: the result of the action \n ... (this Thought/Action/Observation can repeat N times) \n Thought: I now know the final answer \n Final: the final answer to the original input question \n\n\n Begin! Reminder to always use the exact characters `Final Answer` when responding. \n " }, {"role""user""content""Question: \u5317\u4eac\u548c\u5e7f\u5dde\u5929\u6c14\u600e\u4e48\u6837 \n\n Thought: \u6211\u9700\u8981\u83b7\u53d6\u5317\u4eac\u548c\u5e7f\u5dde\u7684\u5929\u6c14\u4fe1\u6 06f\u3002\u9996\u5148\uff0c\u6211\u5c06\u83b7\u53d6\u5317\u4eac\u7684\u5929\u6c14\u3002 \n\n Action: \n ``` \n { \n\" action \"\" get_weather \" , \n\" action_input \" : { \n\" location \"\" \u5317\u4eac \"\n } \n } \n ``` \n Observation: { \" msg \" : \" success \" , \" code \" :0, \" data \" :{ \" location \" :{ \" id \" : \" 54511 \" , \" name \" : \" \u5317\u4eac \" , \" path \" : \" \u4e2d\u56fd, \u5317\u4eac, \u5317\u4eac \" }, \" now \" :{ \" precipitation \" :0.0, \" temperature \" :23.4, \" pressure \" :1005.0, \" humidity \" :43.0, \" windDirection \" : \" \u897f\u5357\u98ce \" , \" windDirectionDegree \" :216.0, \" windSpeed ​​\" :2.7, \" windScale \" : \" \u5fae\u98ce \" , \" feelst \" :23.1}, \" alarm \" :[], \" jieQi \" : \"\" , \" lastUpdate \" :\" 2025/04/26 15:00 \" }} \n " }]>>>  content:Thought : Now that I have obtained the weather information for Beijing, I will obtain the weather information for Guangzhou next .
Action :```{"action""get_weather" ,"action_input" : {"location""Guangzhou"}}```Observation>>>  tool name:get_weather>>>  tool parameters:{'location': 'Guangzhou'}>>>  tool result: { "msg" : "success" , "code" : 0 , "data" :{ "location" :{ "id" : "59287" , "name" : "Guangzhou" , "path" : "China, Guangdong, Guangzhou" }, "now" :{ "precipitation" : 0.0 , "temperature" : 24.2 , "pressure" : 1005.0 , "humidity" : 79.0 , "windDirection" : "Northeast Wind" , "windDirectionDegree" : 31.0 , "windSpeed" : 1.3 , "windScale" : "Breeze" , "feelst" : 27.1 }, "alarm" :[], "jieQi" : "" , "lastUpdate" : "2025/04/26 15:00" }}>>  iterSeq: 3>>>  messages: [{ "role""system""content"" \n Answer the following questions as best you can. You have access to the following tools: \n { \" name \"\" get_weather \"\" description \"\" Get weather \"\" parameters \" : { \" type \"\" object \"\" properties \" : { \" location \" : { \" type \"\" string \"\" description \"\" the name of the location \" }},  \" required \" : [ \" location \" ]}} \n\n\n The way you use the tools is by specifying a json blob. \n Specifically, this json should have a `action` key (with the name of the tool to use) and a `action_input` key (with the input to the tool going here). \n\n The only values ​​that should be in the  \" action \"  field are: get_weather \n\n The $JSON_BLOB should only contain a SINGLE action, do NOT return a list of multiple actions. Here is an example of a valid $JSON_BLOB: \n\n ``` \n {{ \n\" action \" : $TOOL_NAME, \n\" action_input \" : $INPUT \n }} \n ``` \n\n ALWAYS use the following format: \n\n Question: the input question you must answer \n Thought: you should always think about what to do \n Action: \n ``` \n $JSON_BLOB \n ``` \n Observation: the result of the action \n ... (this Thought/Action/Observation can repeat N times) \n Thought: I now know the final answer \n Final: the final answer to the original input question \n\n\n Begin! Reminder to always use the exact characters `Final Answer` when responding. \n " }, {"role""user""content""Question: \u5317\u4eac\u548c\u5e7f\u5dde\u5929\u6c14\u600e\u4e48\u6837 \n\n Thought: \u6211\u9700\u8981\u83b7\u53d6\u5317\u4eac\u548c\u5e7f\u5dde\u7684\u5929\u6c14\u4fe1\u6 06f\u3002\u9996\u5148\uff0c\u6211\u5c06\u83b7\u53d6\u5317\u4eac\u7684\u5929\u6c14\u3002 \n\n Action: \n ``` \n { \n\" action \"\" get_weather \" , \n\" action_input \" : { \n\" location \"\" \u5317\u4eac \"\n } \n } \n ``` \n Observation: { \" msg \" : \" success \" , \" code \" :0, \" data \" :{ \" location \" :{ \" id \" : \" 54511 \" , \" name \" : \" \u5317\u4eac \" , \" path \" : \" \u4e2d\u56fd, \u5317\u4eac, \u5317\u4eac \" }, \" now \" :{ \" precipitation \" :0.0, \" temperature \" :23.4, \" pressure \" :1005.0, \" humidity \" :43.0, \" windDirection \" : \" \u897f\u5357\u98ce \" , \" windDirectionDegree \" :216.0, \" windSpeed ​​\" :2.7, \" windScale \" : \" \u5fae\u98ce \" , \" feelst \" :23.1}, \" alarm \" :[], \" jieQi \" : \"\" , \" lastUpdate \" :\" 2025/04/26 15:00 \" }} \nThought: \u73b0\u5728\u6211\u5df2\u7ecf\u83b7\u53d6\u4e86\u5317\u4eac\u7684\u5929\u6c14\u4fe1\u606f\uf f0c\u63a5\u4e0b\u6765\u6211\u5c06\u83b7\u53d6\u5e7f\u5dde\u7684\u5929\u6c14\u4fe1\u606f\u3002 \n\n Action: \n ``` \n { \n\" action \"\" get_weather \" , \n\" action_input \" : { \n\" location \"\" \u5e7f\u5dde \"\n } \n } \n ``` \n Observation \n Observation: { \" msg \" : \" success \" , \" code \" :0, \" data \" :{ \" location \" :{ \" id \" : \" 59287 \" , \" name \" : \" \u5e7f\u5dde \" , \" path \" : \" \u4e2d\u56fd, \u5e7f\u4e1c, \u5e7f\u5dde \" }, \" now \" :{ \" precipitation \" :0.0, \" temperature \" :24.2, \" pressure \" :1005.0, \" humidity \" :79.0, \" windDirection \" : \" \u4e1c\u5317\u98ce \" , \" windDirectionDegree \" :31.0, \" windSpeed ​​\" :1.3, \" windScale \" : \" \u5fae\u98ce \" , \" feelst \" :27.1}, \" alarm \" :[], \" jieQi \" : \"\" , \" lastUpdate \" : \" 2025/04/26 15:00 \" }} \n " }]>>>  content:Thought : I have obtained the weather information for Beijing and Guangzhou, and now I can answer users' questions .
Final  Answer : The weather conditions in Beijing are: temperature 23.4 ° C, humidity 43 % , southwest wind, wind speed 2.7 m /s, light breeze. The weather conditions in Guangzhou are: temperature 24.2°C, humidity 79%, northeast wind, wind speed 1.3 m/ s, light breeze .>>>  Final answer: The weather conditions in Beijing are: temperature 23.4 ° C, humidity 43 % , southwest wind, wind speed 2.7 m /s, light breeze. The weather conditions in Guangzhou are: temperature 24.2°C, humidity 79%, northeast wind, wind speed 1.3 m/ s, light breeze .

Summarize

Function Calling-based and ReAct-based tool calls have their own advantages and disadvantages:

1. Function Calling

  • No need to set system prompt words, LLM can trigger tool calls according to tools definition, and token consumption is low
  • The model parameters are relatively large. The model training data must contain content related to Function Calling to ensure that the model can understand and generate structured outputs, and structured outputs are more stable.
  • The output is easier to process
  • The reasoning process is hidden and lacks explainability

2. ReAct

  • It is necessary to set complex system prompts, which consumes more tokens.
  • Lower requirements on model parameters
  • Output result processing is more complicated than Function Calling
  • The reasoning process is visible and more explainable

END