

0 / 2 embers
0 / 3000 xp
click for more info
Complete a lesson to start your streak
click for more info
Still calibrating
click for more info
Not enough gems
Cost: 6 gems
1: System Prompt
incomplete
2: Function Declaration
incomplete
3: More Declarations
incomplete
4: Calling Functions
incomplete
This lesson's interactive features are locked, please to keep using them
So we've written a bunch of functions that are LLM-friendly (text in, text out), but how does an LLM actually call a function?
Well, the answer is that... it doesn't. At least not directly. It works like this:
We're using the LLM as a decision-making engine, but we're still the ones running the code (thankfully).
Let's build the part of this system that tells the LLM which functions are available to it.
schema_get_files_info = {
"type": "function",
"function": {
"name": "get_files_info",
"description": "Lists files in a specified directory relative to the working directory, providing file size and directory status",
"parameters": {
"type": "object",
"properties": {
"directory": {
"type": "string",
"description": "Directory path to list files from, relative to the working directory (default is the working directory itself)",
},
},
},
},
}
I added this schema to my functions/get_files_info.py file. You can put it wherever you like, but you'll probably find it convenient to keep each declaration close to the corresponding function.
Notice that, in the declaration for the LLM, we don't even mention the working_directory parameter of the function! We'll be passing that argument "from the outside," without the LLM agent knowing about it or being able to affect it.
available_functions = [
schema_get_files_info,
]
I put the list of available functions in a new file, call_function.py. As always, you can organize your code in whatever way makes sense to you.
response = client.chat.completions.create(
model="openrouter/free",
messages=messages,
tools=available_functions,
)
system_prompt = """
You are a helpful AI coding agent.
When a user asks a question or makes a request, make a function call plan. You can perform the following operations:
- List files and directories
All paths you provide should be relative to the working directory. You do not need to specify the working directory in your function calls as it is automatically injected for security reasons.
"""
tool_call.function.name: the name of the function to call (a string)tool_call.function.arguments: the arguments, as a JSON string (use json.loads to turn it into a dict - remember to import json at the top of your file)Grab the message with message = response.choices[0].message. If message.tool_calls is set, iterate over it and print the name and arguments of each function call. If it's None (or empty), there were no function calls, so just print message.content as normal.
for tool_call in message.tool_calls:
function_args = json.loads(tool_call.function.arguments or "{}")
print(f"Calling function: {tool_call.function.name}({function_args})")
The idea is that each response from the LLM agent should consist of either text or one or more tool calls. The reason for this will become clear later. For now, if you find any tool calls, just print those; and if you don't find any, just print the response text.
get_files_info({'directory': '.'}) (the model may also omit directory and rely on the default, returning empty args)get_files_info({'directory': 'pkg'})We aren't actually calling functions yet – we're just making sure the LLM knows which functions are available and how to request that they be called.
Submit the CLI tests.