<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Function Calling | Ziyang Lin</title><link>https://ziyanglin.netlify.app/en/tags/function-calling/</link><atom:link href="https://ziyanglin.netlify.app/en/tags/function-calling/index.xml" rel="self" type="application/rss+xml"/><description>Function Calling</description><generator>Source Themes Academic (https://sourcethemes.com/academic/)</generator><language>en-us</language><lastBuildDate>Mon, 30 Jun 2025 07:00:00 +0000</lastBuildDate><image><url>https://ziyanglin.netlify.app/img/icon-192.png</url><title>Function Calling</title><link>https://ziyanglin.netlify.app/en/tags/function-calling/</link></image><item><title>LLM Tool Calling: The Key Technology Breaking AI Capability Boundaries</title><link>https://ziyanglin.netlify.app/en/post/llm-tool-calling/</link><pubDate>Mon, 30 Jun 2025 07:00:00 +0000</pubDate><guid>https://ziyanglin.netlify.app/en/post/llm-tool-calling/</guid><description>&lt;h2 id="1-macro-overview-why-tool-calling-is-llms-super-plugin">1. Macro Overview: Why Tool Calling is LLM's &amp;ldquo;Super Plugin&amp;rdquo;&lt;/h2>
&lt;p>The emergence of Large Language Models (LLMs) has fundamentally changed how we interact with machines. However, LLMs have an inherent, unavoidable &amp;ldquo;ceiling&amp;rdquo;: they are essentially &amp;ldquo;probability prediction machines&amp;rdquo; trained on massive text data, with their knowledge frozen at the time their training data ends. This means an LLM cannot know &amp;ldquo;what's the weather like today?&amp;quot;, cannot access your company's internal database, and cannot book a flight ticket for you.&lt;/p>
&lt;p>The &lt;strong>LLM Tool Calling / Function Calling&lt;/strong> mechanism emerged precisely to break through this ceiling. It gives LLMs an unprecedented ability: &lt;strong>calling external tools (APIs, functions, databases, etc.) to obtain real-time information, perform specific tasks, or interact with the external world&lt;/strong> when needed.&lt;/p>
&lt;p>In simple terms, the tool calling mechanism upgrades LLMs from &amp;ldquo;knowledgeable conversationalists&amp;rdquo; to capable &amp;ldquo;intelligent agents.&amp;rdquo; It allows LLMs to:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Obtain real-time information&lt;/strong>: By calling weather APIs, news APIs, search engines, etc., to get the latest information beyond the model's training data.&lt;/li>
&lt;li>&lt;strong>Operate external systems&lt;/strong>: Connect to enterprise CRM/ERP systems to query data, or connect to IoT devices to control smart home appliances.&lt;/li>
&lt;li>&lt;strong>Execute complex tasks&lt;/strong>: Break down complex user instructions (like &amp;ldquo;help me find and book a cheap flight to Shanghai next week&amp;rdquo;) and complete them by calling multiple APIs in combination.&lt;/li>
&lt;li>&lt;strong>Provide more precise, verifiable answers&lt;/strong>: For queries requiring exact calculations or structured data, LLMs can call calculators or databases instead of relying on their potentially inaccurate internal knowledge.&lt;/li>
&lt;/ul>
&lt;p>Therefore, tool calling is not just a simple extension of LLM functionality, but a core foundation for building truly powerful AI applications that deeply integrate with both the physical and digital worlds.&lt;/p>
&lt;h2 id="2-core-concepts-and-workflow-how-do-llms-learn-to-use-tools">2. Core Concepts and Workflow: How Do LLMs &amp;ldquo;Learn&amp;rdquo; to Use Tools?&lt;/h2>
&lt;p>To understand the underlying logic of tool calling, we need to view it as an elegant process involving three core roles working together:&lt;/p>
&lt;ol>
&lt;li>&lt;strong>Large Language Model (LLM)&lt;/strong>: The brain and decision-maker.&lt;/li>
&lt;li>&lt;strong>Tool Definitions&lt;/strong>: A detailed &amp;ldquo;tool instruction manual.&amp;rdquo;&lt;/li>
&lt;li>&lt;strong>Developer/Client-side Code&lt;/strong>: The ultimate &amp;ldquo;executor.&amp;rdquo;&lt;/li>
&lt;/ol>
&lt;p>The LLM itself &lt;strong>never actually executes any code&lt;/strong>. Its only task, after understanding the user's intent and the &amp;ldquo;tool manual&amp;rdquo; it has, is to &lt;strong>generate a JSON data structure that precisely describes which tool should be called and with what parameters&lt;/strong>.&lt;/p>
&lt;p>Below is a visual explanation of this process:&lt;/p>
&lt;pre>&lt;code class="language-mermaid">sequenceDiagram
participant User
participant Client as Client/Application Layer
participant LLM as Large Language Model
participant Tools as External Tools/APIs
User-&amp;gt;&amp;gt;+Client: &amp;quot;What's the weather in Beijing today?&amp;quot;
Client-&amp;gt;&amp;gt;+LLM: Submit user request + Tool Definitions
Note over LLM: 1. Understand user intent&amp;lt;br/&amp;gt;2. Match most appropriate tool (get_weather)&amp;lt;br/&amp;gt;3. Extract required parameters (location: &amp;quot;Beijing&amp;quot;)
LLM--&amp;gt;&amp;gt;-Client: Return JSON: {&amp;quot;tool_calls&amp;quot;: [{&amp;quot;function&amp;quot;: {&amp;quot;name&amp;quot;: &amp;quot;get_weather&amp;quot;, &amp;quot;arguments&amp;quot;: &amp;quot;{\&amp;quot;location\&amp;quot;: \&amp;quot;Beijing\&amp;quot;}&amp;quot;}}]}
Client-&amp;gt;&amp;gt;+Tools: 2. Based on LLM's JSON, call the actual get_weather(&amp;quot;Beijing&amp;quot;) function
Tools--&amp;gt;&amp;gt;-Client: Return weather data (e.g.: {&amp;quot;temperature&amp;quot;: &amp;quot;25°C&amp;quot;, &amp;quot;condition&amp;quot;: &amp;quot;sunny&amp;quot;})
Client-&amp;gt;&amp;gt;+LLM: 3. Submit tool execution result back to LLM
Note over LLM: 4. Understand the data returned by the tool
LLM--&amp;gt;&amp;gt;-Client: 5. Generate user-friendly natural language response
Client-&amp;gt;&amp;gt;-User: &amp;quot;The weather in Beijing today is sunny with a temperature of 25 degrees Celsius.&amp;quot;
&lt;/code>&lt;/pre>
&lt;h3 id="process-breakdown">Process Breakdown:&lt;/h3>
&lt;ol>
&lt;li>
&lt;p>&lt;strong>Define &amp;amp; Describe&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>Developers first need to define available tools in a structured way (typically using JSON Schema). This &amp;ldquo;manual&amp;rdquo; is crucial to the entire process and must clearly tell the LLM:
&lt;ul>
&lt;li>&lt;strong>Tool name&lt;/strong> (&lt;code>name&lt;/code>): For example, &lt;code>get_weather&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Tool function description&lt;/strong> (&lt;code>description&lt;/code>): For example, &amp;ldquo;Get real-time weather information for a specified city.&amp;rdquo; This is the most important basis for the LLM to understand the tool's purpose.&lt;/li>
&lt;li>&lt;strong>Tool parameters&lt;/strong> (&lt;code>parameters&lt;/code>): Detailed definition of what inputs the tool needs, including each input's name, type (string, number, boolean, etc.), whether it's required, and parameter descriptions.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Intent Recognition &amp;amp; Parameter Extraction&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>When a user makes a request (e.g., &amp;ldquo;Check the weather in Beijing&amp;rdquo;), the developer's application sends the user's original request &lt;strong>along with all the tool definitions from step 1&lt;/strong> to the LLM.&lt;/li>
&lt;li>The LLM's core task is to do two things:
&lt;ul>
&lt;li>&lt;strong>Intent Recognition&lt;/strong>: Among all available tools, determine which tool's function description best matches the user's request. In this example, it would match &lt;code>get_weather&lt;/code>.&lt;/li>
&lt;li>&lt;strong>Parameter Extraction&lt;/strong>: From the user's request, identify and extract values that satisfy the tool's parameter requirements. Here, it would recognize that the &lt;code>location&lt;/code> parameter value is &amp;ldquo;Beijing&amp;rdquo;.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>After completing these two steps, the LLM generates one or more &lt;code>tool_calls&lt;/code> objects, essentially saying &amp;ldquo;I suggest you call the function named &lt;code>get_weather&lt;/code> and pass in the parameter &lt;code>{ &amp;quot;location&amp;quot;: &amp;quot;Beijing&amp;quot; }&lt;/code>&amp;rdquo;.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Execute &amp;amp; Observe&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>The developer's application code receives the JSON returned by the LLM and parses this &amp;ldquo;call suggestion.&amp;rdquo;&lt;/li>
&lt;li>The application code &lt;strong>actually executes&lt;/strong> the &lt;code>get_weather(&amp;quot;Beijing&amp;quot;)&lt;/code> function locally or on the server side.&lt;/li>
&lt;li>After execution, it gets a real return result, such as a JSON object containing weather information.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>
&lt;p>&lt;strong>Summarize &amp;amp; Respond&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>To complete the loop, the application layer needs to submit the actual execution result from the previous step back to the LLM.&lt;/li>
&lt;li>This time, the LLM's task is to understand this raw data returned by the tool (e.g., &lt;code>{&amp;quot;temperature&amp;quot;: &amp;quot;25°C&amp;quot;, &amp;quot;condition&amp;quot;: &amp;quot;sunny&amp;quot;}&lt;/code>) and convert it into a fluent, natural, user-friendly response.&lt;/li>
&lt;li>Finally, the user receives the reply &amp;ldquo;The weather in Beijing today is sunny with a temperature of 25 degrees Celsius,&amp;rdquo; and the entire process is complete.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ol>
&lt;p>This process elegantly combines the LLM's powerful natural language understanding ability with the external tool's powerful functional execution capability, achieving a 1+1&amp;gt;2 effect.&lt;/p>
&lt;h2 id="3-technical-deep-dive-analyzing-the-industry-standard-openai-tool-calling">3. Technical Deep Dive: Analyzing the Industry Standard (OpenAI Tool Calling)&lt;/h2>
&lt;p>OpenAI's API is currently the de facto standard in the field of LLM tool calling, and its design is widely emulated. Understanding its implementation details is crucial for any developer looking to integrate LLM tool calling into their applications.&lt;/p>
&lt;h3 id="31-core-api-parameters">3.1. Core API Parameters&lt;/h3>
&lt;p>When calling OpenAI's Chat Completions API, there are two main parameters related to tool calling: &lt;code>tools&lt;/code> and &lt;code>tool_choice&lt;/code>.&lt;/p>
&lt;h4 id="tools-parameter-your-toolbox">&lt;code>tools&lt;/code> Parameter: Your &amp;ldquo;Toolbox&amp;rdquo;&lt;/h4>
&lt;p>The &lt;code>tools&lt;/code> parameter is an array where you can define one or more tools. Each tool follows a fixed structure, with the core being a &lt;code>function&lt;/code> object defined based on the &lt;strong>JSON Schema&lt;/strong> specification.&lt;/p>
&lt;p>&lt;strong>Example: Defining a weather tool and a flight booking tool&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-json">[
{
&amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,
&amp;quot;function&amp;quot;: {
&amp;quot;name&amp;quot;: &amp;quot;get_current_weather&amp;quot;,
&amp;quot;description&amp;quot;: &amp;quot;Get real-time weather information for a specified location&amp;quot;,
&amp;quot;parameters&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,
&amp;quot;properties&amp;quot;: {
&amp;quot;location&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,
&amp;quot;description&amp;quot;: &amp;quot;City and state/province name, e.g., 'San Francisco, CA'&amp;quot;
},
&amp;quot;unit&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,
&amp;quot;enum&amp;quot;: [&amp;quot;celsius&amp;quot;, &amp;quot;fahrenheit&amp;quot;],
&amp;quot;description&amp;quot;: &amp;quot;Temperature unit&amp;quot;
}
},
&amp;quot;required&amp;quot;: [&amp;quot;location&amp;quot;]
}
}
},
{
&amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,
&amp;quot;function&amp;quot;: {
&amp;quot;name&amp;quot;: &amp;quot;book_flight&amp;quot;,
&amp;quot;description&amp;quot;: &amp;quot;Book a flight ticket for the user from departure to destination&amp;quot;,
&amp;quot;parameters&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,
&amp;quot;properties&amp;quot;: {
&amp;quot;departure&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,
&amp;quot;description&amp;quot;: &amp;quot;Departure airport or city&amp;quot;
},
&amp;quot;destination&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,
&amp;quot;description&amp;quot;: &amp;quot;Destination airport or city&amp;quot;
},
&amp;quot;date&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,
&amp;quot;description&amp;quot;: &amp;quot;Desired departure date in YYYY-MM-DD format&amp;quot;
}
},
&amp;quot;required&amp;quot;: [&amp;quot;departure&amp;quot;, &amp;quot;destination&amp;quot;, &amp;quot;date&amp;quot;]
}
}
}
]
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Key Points Analysis&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>type&lt;/code>&lt;/strong>: Currently fixed as &lt;code>&amp;quot;function&amp;quot;&lt;/code>.&lt;/li>
&lt;li>&lt;strong>&lt;code>function.name&lt;/code>&lt;/strong>: Function name. Must be a combination of letters, numbers, and underscores, not exceeding 64 characters. This is the key for your code to identify which function to call.&lt;/li>
&lt;li>&lt;strong>&lt;code>function.description&lt;/code>&lt;/strong>: &lt;strong>Critically important&lt;/strong>. This is the main basis for the LLM to decide whether to select this tool. The description should clearly, accurately, and unambiguously explain what the function does. A good description can greatly improve the LLM's call accuracy.&lt;/li>
&lt;li>&lt;strong>&lt;code>function.parameters&lt;/code>&lt;/strong>: A standard JSON Schema object.
&lt;ul>
&lt;li>&lt;strong>&lt;code>type&lt;/code>&lt;/strong>: Must be &lt;code>&amp;quot;object&amp;quot;&lt;/code>.&lt;/li>
&lt;li>&lt;strong>&lt;code>properties&lt;/code>&lt;/strong>: Defines each parameter's name, type (&lt;code>string&lt;/code>, &lt;code>number&lt;/code>, &lt;code>boolean&lt;/code>, &lt;code>array&lt;/code>, &lt;code>object&lt;/code>), and description. The parameter description is equally important as it helps the LLM understand what information to extract from user input to fill this parameter.&lt;/li>
&lt;li>&lt;strong>&lt;code>required&lt;/code>&lt;/strong>: An array of strings listing which parameters are mandatory. If the user request lacks necessary information, the LLM might ask follow-up questions or choose not to call the tool.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h4 id="toolchoice-parameter-controlling-the-llms-choice">&lt;code>tool_choice&lt;/code> Parameter: Controlling the LLM's Choice&lt;/h4>
&lt;p>By default, the LLM decides on its own whether to respond with text or call one or more tools based on the user's input. The &lt;code>tool_choice&lt;/code> parameter allows you to control this behavior more precisely.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>&amp;quot;none&amp;quot;&lt;/code>&lt;/strong>: Forces the LLM not to call any tools and directly return a text response.&lt;/li>
&lt;li>&lt;strong>&lt;code>&amp;quot;auto&amp;quot;&lt;/code>&lt;/strong> (default): The LLM can freely choose whether to respond with text or call tools.&lt;/li>
&lt;li>&lt;strong>&lt;code>{&amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;, &amp;quot;function&amp;quot;: {&amp;quot;name&amp;quot;: &amp;quot;my_function&amp;quot;}}&lt;/code>&lt;/strong>: Forces the LLM to call this specific tool named &lt;code>my_function&lt;/code>.&lt;/li>
&lt;/ul>
&lt;p>This parameter is very useful in scenarios where you need to enforce a specific process or limit the LLM's capabilities.&lt;/p>
&lt;h3 id="32-requestresponse-lifecycle">3.2. Request-Response Lifecycle&lt;/h3>
&lt;p>A complete tool calling interaction involves at least two API requests.&lt;/p>
&lt;p>&lt;strong>First Request: From User to LLM&lt;/strong>&lt;/p>
&lt;pre>&lt;code class="language-python"># request
response = client.chat.completions.create(
model=&amp;quot;gpt-4o&amp;quot;,
messages=[{&amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;Please book me a flight from New York to London tomorrow&amp;quot;}],
tools=my_tools, # The tool list defined above
tool_choice=&amp;quot;auto&amp;quot;
)
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>First Response: LLM's &amp;ldquo;Call Suggestion&amp;rdquo;&lt;/strong>&lt;/p>
&lt;p>If the LLM decides to call a tool, the API response's &lt;code>finish_reason&lt;/code> will be &lt;code>tool_calls&lt;/code>, and the &lt;code>message&lt;/code> object will contain a &lt;code>tool_calls&lt;/code> array.&lt;/p>
&lt;pre>&lt;code class="language-json">{
&amp;quot;choices&amp;quot;: [
{
&amp;quot;finish_reason&amp;quot;: &amp;quot;tool_calls&amp;quot;,
&amp;quot;message&amp;quot;: {
&amp;quot;role&amp;quot;: &amp;quot;assistant&amp;quot;,
&amp;quot;content&amp;quot;: null,
&amp;quot;tool_calls&amp;quot;: [
{
&amp;quot;id&amp;quot;: &amp;quot;call_abc123&amp;quot;,
&amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,
&amp;quot;function&amp;quot;: {
&amp;quot;name&amp;quot;: &amp;quot;book_flight&amp;quot;,
&amp;quot;arguments&amp;quot;: &amp;quot;{\&amp;quot;departure\&amp;quot;:\&amp;quot;New York\&amp;quot;,\&amp;quot;destination\&amp;quot;:\&amp;quot;London\&amp;quot;,\&amp;quot;date\&amp;quot;:\&amp;quot;2025-07-01\&amp;quot;}&amp;quot;
}
}
]
}
}
],
...
}
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Key Points Analysis&lt;/strong>:&lt;/p>
&lt;ul>
&lt;li>&lt;strong>&lt;code>finish_reason&lt;/code>&lt;/strong>: A value of &lt;code>&amp;quot;tool_calls&amp;quot;&lt;/code> indicates that the LLM wants you to execute a tool call, rather than ending the conversation.&lt;/li>
&lt;li>&lt;strong>&lt;code>message.role&lt;/code>&lt;/strong>: &lt;code>assistant&lt;/code>.&lt;/li>
&lt;li>&lt;strong>&lt;code>message.tool_calls&lt;/code>&lt;/strong>: This is an array, meaning the LLM can request multiple tool calls at once.
&lt;ul>
&lt;li>&lt;strong>&lt;code>id&lt;/code>&lt;/strong>: A unique call ID. In subsequent requests, you'll need to use this ID to associate the tool's execution results.&lt;/li>
&lt;li>&lt;strong>&lt;code>function.name&lt;/code>&lt;/strong>: The function name the LLM suggests calling.&lt;/li>
&lt;li>&lt;strong>&lt;code>function.arguments&lt;/code>&lt;/strong>: &lt;strong>A JSON object in string form&lt;/strong>. You need to parse this string to get the specific parameters needed to call the function.&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;p>&lt;strong>Second Request: Returning Tool Results to the LLM&lt;/strong>&lt;/p>
&lt;p>After executing the tool in your code, you need to send the results back to the LLM to complete the conversation. At this point, you need to construct a new &lt;code>messages&lt;/code> list that includes:&lt;/p>
&lt;ol>
&lt;li>The original user message.&lt;/li>
&lt;li>The &lt;code>assistant&lt;/code> message returned by the LLM in the previous step (containing &lt;code>tool_calls&lt;/code>).&lt;/li>
&lt;li>A new message with the &lt;code>tool&lt;/code> role, containing the tool's execution results.&lt;/li>
&lt;/ol>
&lt;pre>&lt;code class="language-python"># message history
messages = [
{&amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: &amp;quot;Please book me a flight from New York to London tomorrow&amp;quot;},
response.choices[0].message, # Assistant's 'tool_calls' message
{
&amp;quot;tool_call_id&amp;quot;: &amp;quot;call_abc123&amp;quot;, # Must match the ID from the previous step
&amp;quot;role&amp;quot;: &amp;quot;tool&amp;quot;,
&amp;quot;name&amp;quot;: &amp;quot;book_flight&amp;quot;,
&amp;quot;content&amp;quot;: &amp;quot;{\&amp;quot;status\&amp;quot;: \&amp;quot;success\&amp;quot;, \&amp;quot;ticket_id\&amp;quot;: \&amp;quot;TICKET-45678\&amp;quot;}&amp;quot; # Actual return value from the tool
}
]
# second request
second_response = client.chat.completions.create(
model=&amp;quot;gpt-4o&amp;quot;,
messages=messages
)
&lt;/code>&lt;/pre>
&lt;p>&lt;strong>Second Response: LLM's Final Reply&lt;/strong>&lt;/p>
&lt;p>This time, the LLM will generate a natural language response for the user based on the tool's returned results.&lt;/p>
&lt;pre>&lt;code class="language-json">{
&amp;quot;choices&amp;quot;: [
{
&amp;quot;finish_reason&amp;quot;: &amp;quot;stop&amp;quot;,
&amp;quot;message&amp;quot;: {
&amp;quot;role&amp;quot;: &amp;quot;assistant&amp;quot;,
&amp;quot;content&amp;quot;: &amp;quot;Great! I've booked your flight from New York to London for tomorrow. Your ticket ID is TICKET-45678.&amp;quot;
}
}
],
...
}
&lt;/code>&lt;/pre>
&lt;p>With this, a complete tool calling cycle is finished.&lt;/p>
&lt;h2 id="4-code-implementation-a-complete-python-example">4. Code Implementation: A Complete Python Example&lt;/h2>
&lt;p>Below is an end-to-end Python example using OpenAI's Python library to demonstrate how to implement a weather query feature.&lt;/p>
&lt;pre>&lt;code class="language-python">import os
import json
from openai import OpenAI
from dotenv import load_dotenv
# --- 1. Initial Setup ---
load_dotenv() # Load environment variables from .env file
client = OpenAI(api_key=os.getenv(&amp;quot;OPENAI_API_KEY&amp;quot;))
# --- 2. Define Our Local Tool Functions ---
# This is a mock function; in a real application, it would call an actual weather API
def get_current_weather(location, unit=&amp;quot;celsius&amp;quot;):
&amp;quot;&amp;quot;&amp;quot;Get real-time weather information for a specified location&amp;quot;&amp;quot;&amp;quot;
if &amp;quot;New York&amp;quot; in location:
return json.dumps({
&amp;quot;location&amp;quot;: &amp;quot;New York&amp;quot;,
&amp;quot;temperature&amp;quot;: &amp;quot;10&amp;quot;,
&amp;quot;unit&amp;quot;: unit,
&amp;quot;forecast&amp;quot;: [&amp;quot;sunny&amp;quot;, &amp;quot;light breeze&amp;quot;]
})
elif &amp;quot;London&amp;quot; in location:
return json.dumps({
&amp;quot;location&amp;quot;: &amp;quot;London&amp;quot;,
&amp;quot;temperature&amp;quot;: &amp;quot;15&amp;quot;,
&amp;quot;unit&amp;quot;: unit,
&amp;quot;forecast&amp;quot;: [&amp;quot;light rain&amp;quot;, &amp;quot;northeast wind&amp;quot;]
})
else:
return json.dumps({&amp;quot;location&amp;quot;: location, &amp;quot;temperature&amp;quot;: &amp;quot;unknown&amp;quot;})
# --- 3. Main Execution Flow ---
def run_conversation(user_prompt: str):
print(f&amp;quot;👤 User: {user_prompt}&amp;quot;)
# Step 1: Send the user's message and tool definitions to the LLM
messages = [{&amp;quot;role&amp;quot;: &amp;quot;user&amp;quot;, &amp;quot;content&amp;quot;: user_prompt}]
tools = [
{
&amp;quot;type&amp;quot;: &amp;quot;function&amp;quot;,
&amp;quot;function&amp;quot;: {
&amp;quot;name&amp;quot;: &amp;quot;get_current_weather&amp;quot;,
&amp;quot;description&amp;quot;: &amp;quot;Get real-time weather information for a specified city&amp;quot;,
&amp;quot;parameters&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;object&amp;quot;,
&amp;quot;properties&amp;quot;: {
&amp;quot;location&amp;quot;: {
&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;,
&amp;quot;description&amp;quot;: &amp;quot;City name, e.g., New York City&amp;quot;,
},
&amp;quot;unit&amp;quot;: {&amp;quot;type&amp;quot;: &amp;quot;string&amp;quot;, &amp;quot;enum&amp;quot;: [&amp;quot;celsius&amp;quot;, &amp;quot;fahrenheit&amp;quot;]},
},
&amp;quot;required&amp;quot;: [&amp;quot;location&amp;quot;],
},
},
}
]
response = client.chat.completions.create(
model=&amp;quot;gpt-4o&amp;quot;,
messages=messages,
tools=tools,
tool_choice=&amp;quot;auto&amp;quot;,
)
response_message = response.choices[0].message
tool_calls = response_message.tool_calls
# Step 2: Check if the LLM decided to call a tool
if tool_calls:
print(f&amp;quot;🤖 LLM decided to call tool: {tool_calls[0].function.name}&amp;quot;)
# Add the LLM's reply to the message history
messages.append(response_message)
# Step 3: Execute the tool call
# Note: This example only handles the first tool call
tool_call = tool_calls[0]
function_name = tool_call.function.name
function_to_call = globals().get(function_name) # Get the function from the global scope
if not function_to_call:
print(f&amp;quot;❌ Error: Function {function_name} is not defined&amp;quot;)
return
function_args = json.loads(tool_call.function.arguments)
# Call the function and get the result
function_response = function_to_call(
location=function_args.get(&amp;quot;location&amp;quot;),
unit=function_args.get(&amp;quot;unit&amp;quot;),
)
print(f&amp;quot;🛠️ Tool '{function_name}' returned: {function_response}&amp;quot;)
# Step 4: Return the tool's execution result to the LLM
messages.append(
{
&amp;quot;tool_call_id&amp;quot;: tool_call.id,
&amp;quot;role&amp;quot;: &amp;quot;tool&amp;quot;,
&amp;quot;name&amp;quot;: function_name,
&amp;quot;content&amp;quot;: function_response,
}
)
print(&amp;quot;🗣️ Submitting tool result back to LLM, generating final response...&amp;quot;)
second_response = client.chat.completions.create(
model=&amp;quot;gpt-4o&amp;quot;,
messages=messages,
)
final_response = second_response.choices[0].message.content
print(f&amp;quot;🤖 LLM final response: {final_response}&amp;quot;)
return final_response
else:
# If the LLM didn't call any tools, directly return its text content
final_response = response_message.content
print(f&amp;quot;🤖 LLM direct response: {final_response}&amp;quot;)
return final_response
# --- Run Examples ---
if __name__ == &amp;quot;__main__&amp;quot;:
run_conversation(&amp;quot;What's the weather like in London today?&amp;quot;)
print(&amp;quot;\n&amp;quot; + &amp;quot;=&amp;quot;*50 + &amp;quot;\n&amp;quot;)
run_conversation(&amp;quot;How are you?&amp;quot;)
&lt;/code>&lt;/pre>
&lt;p>This example clearly demonstrates the entire process from defining tools, sending requests, handling &lt;code>tool_calls&lt;/code>, executing local functions, to sending results back to the model to get the final answer.&lt;/p>
&lt;h2 id="5-advanced-topics-and-best-practices">5. Advanced Topics and Best Practices&lt;/h2>
&lt;p>After mastering the basic process, we need to understand some advanced usage and design principles to build more robust and reliable tool calling systems.&lt;/p>
&lt;h3 id="51-parallel-tool-calling">5.1. Parallel Tool Calling&lt;/h3>
&lt;p>Newer models (like &lt;code>gpt-4o&lt;/code>) support parallel tool calling. This means the model can request multiple different, independent tools to be called in a single response.&lt;/p>
&lt;p>&lt;strong>Scenario Example&lt;/strong>: User asks: &amp;ldquo;What's the weather like in New York and London today?&amp;rdquo;&lt;/p>
&lt;p>The model might return a response containing two &lt;code>tool_calls&lt;/code>:&lt;/p>
&lt;ol>
&lt;li>&lt;code>get_current_weather(location=&amp;quot;New York&amp;quot;)&lt;/code>&lt;/li>
&lt;li>&lt;code>get_current_weather(location=&amp;quot;London&amp;quot;)&lt;/code>&lt;/li>
&lt;/ol>
&lt;p>Your code needs to be able to iterate through each &lt;code>tool_call&lt;/code> object in the &lt;code>message.tool_calls&lt;/code> array, execute them separately, collect all results, and then submit these results together in a new request to the model.&lt;/p>
&lt;p>&lt;strong>Code Handling Logic&lt;/strong>:&lt;/p>
&lt;pre>&lt;code class="language-python"># ... (received response_message containing multiple tool_calls)
messages.append(response_message) # Add assistant's reply to messages
# Execute functions for each tool call and collect results
tool_outputs = []
for tool_call in tool_calls:
function_name = tool_call.function.name
function_to_call = available_functions[function_name]
function_args = json.loads(tool_call.function.arguments)
output = function_to_call(**function_args)
tool_outputs.append({
&amp;quot;tool_call_id&amp;quot;: tool_call.id,
&amp;quot;role&amp;quot;: &amp;quot;tool&amp;quot;,
&amp;quot;name&amp;quot;: function_name,
&amp;quot;content&amp;quot;: output,
})
# Add all tool outputs to the message history
messages.extend(tool_outputs)
# Call the model again
second_response = client.chat.completions.create(
model=&amp;quot;gpt-4o&amp;quot;,
messages=messages
)
&lt;/code>&lt;/pre>
&lt;h3 id="52-error-handling">5.2. Error Handling&lt;/h3>
&lt;p>Tool calls are not always successful. APIs might time out, databases might be unreachable, or the function execution itself might throw exceptions. Gracefully handling these errors is crucial.&lt;/p>
&lt;p>When a tool execution fails, you should catch the exception and return structured information describing the error as the result of the tool call to the LLM.&lt;/p>
&lt;p>&lt;strong>Example&lt;/strong>:&lt;/p>
&lt;pre>&lt;code class="language-python">try:
# Try to call the API
result = some_flaky_api()
content = json.dumps({&amp;quot;status&amp;quot;: &amp;quot;success&amp;quot;, &amp;quot;data&amp;quot;: result})
except Exception as e:
# If it fails, return error information
content = json.dumps({&amp;quot;status&amp;quot;: &amp;quot;error&amp;quot;, &amp;quot;message&amp;quot;: f&amp;quot;API call failed: {str(e)}&amp;quot;})
# Return the result (whether successful or failed) to the LLM
messages.append({
&amp;quot;tool_call_id&amp;quot;: tool_call.id,
&amp;quot;role&amp;quot;: &amp;quot;tool&amp;quot;,
&amp;quot;name&amp;quot;: function_name,
&amp;quot;content&amp;quot;: content,
})
&lt;/code>&lt;/pre>
&lt;p>When the LLM receives error information, it typically responds to the user with an apologetic answer that reflects the problem (e.g., &amp;ldquo;Sorry, I'm currently unable to retrieve weather information. Please try again later.&amp;quot;) rather than causing the entire application to crash.&lt;/p>
&lt;h3 id="53-designing-effective-tool-descriptions">5.3. Designing Effective Tool Descriptions&lt;/h3>
&lt;p>&lt;strong>The quality of the tool description (&lt;code>description&lt;/code>) directly determines the LLM's call accuracy.&lt;/strong>&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Clear and Specific&lt;/strong>: Avoid using vague terms.
&lt;ul>
&lt;li>&lt;strong>Bad&lt;/strong>: &amp;ldquo;Get data&amp;rdquo;&lt;/li>
&lt;li>&lt;strong>Good&lt;/strong>: &amp;ldquo;Query the user's order history from the company's CRM system based on user ID&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Include Key Information and Limitations&lt;/strong>: If the tool has specific limitations, be sure to mention them in the description.
&lt;ul>
&lt;li>&lt;strong>Example&lt;/strong>: &amp;ldquo;Query flight information. Note: This tool can only query flights within the next 30 days and cannot query historical flights.&amp;rdquo;&lt;/li>
&lt;/ul>
&lt;/li>
&lt;li>&lt;strong>Start with a Verb&lt;/strong>: Use a clear verb to describe the core functionality of the function.&lt;/li>
&lt;li>&lt;strong>Clear Parameter Descriptions&lt;/strong>: The &lt;code>description&lt;/code> of parameters is equally important; it guides the LLM on how to correctly extract information from user conversations.
&lt;ul>
&lt;li>&lt;strong>Bad&lt;/strong>: &lt;code>&amp;quot;date&amp;quot;: &amp;quot;A date&amp;quot;&lt;/code>&lt;/li>
&lt;li>&lt;strong>Good&lt;/strong>: &lt;code>&amp;quot;date&amp;quot;: &amp;quot;Booking date, must be a string in YYYY-MM-DD format&amp;quot;&lt;/code>&lt;/li>
&lt;/ul>
&lt;/li>
&lt;/ul>
&lt;h3 id="54-security-considerations">5.4. Security Considerations&lt;/h3>
&lt;p>Giving LLMs the ability to call code is a double-edged sword and must be handled with caution.&lt;/p>
&lt;ul>
&lt;li>&lt;strong>Never Execute Code Generated by LLMs&lt;/strong>: The LLM's output is a &amp;ldquo;call suggestion,&amp;rdquo; not executable code. Never use &lt;code>eval()&lt;/code> or similar methods to directly execute strings generated by LLMs. You should parse the suggested function name and parameters, then call your pre-defined, safe, and trusted local functions.&lt;/li>
&lt;li>&lt;strong>Confirmation and Authorization&lt;/strong>: For operations with serious consequences (like deleting data, sending emails, making payments), implement a confirmation mechanism before execution. This could be forcing user confirmation at the code level or having the LLM generate a confirmation message after generating the call suggestion.&lt;/li>
&lt;li>&lt;strong>Principle of Least Privilege&lt;/strong>: Only provide the LLM with the minimum tools necessary to complete its task. Don't expose your entire codebase or irrelevant APIs.&lt;/li>
&lt;/ul>
&lt;h2 id="6-conclusion-and-future-outlook">6. Conclusion and Future Outlook&lt;/h2>
&lt;p>LLM tool calling is one of the most breakthrough advances in artificial intelligence in recent years. It transforms LLMs from closed &amp;ldquo;language brains&amp;rdquo; into open, extensible &amp;ldquo;intelligent agent&amp;rdquo; cores capable of interacting with the world. By combining the powerful natural language understanding capabilities of LLMs with the unlimited functionality of external tools, we can build unprecedented intelligent applications.&lt;/p>
&lt;p>From querying weather and booking hotels to controlling smart homes, analyzing corporate financial reports, and automating software development processes, tool calling is unlocking countless possibilities. As model capabilities continue to strengthen, tool description understanding will become more precise, multi-tool coordination will become more complex and intelligent, and error handling and self-correction capabilities will become stronger.&lt;/p>
&lt;p>In the future, we may see more complex Agentic architectures where LLMs not only call tools but can dynamically create, combine, and even optimize tools. Mastering the principles and practices of LLM tool calling is not only an essential skill to keep up with the current AI technology wave but also a key to future intelligent application development.&lt;/p></description></item></channel></rss>