We're sorry but this app doesn't work properly without JavaScript enabled. Please enable it to continue.

This lesson's interactive features are locked, please to keep using them

Function Declaration

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:

  1. We tell the LLM which functions are available to it.
  2. We give it a prompt.
  3. The LLM describes which function it wants to call, and what arguments to pass to it.
  4. We call that function with the provided arguments.
  5. We return the result to the LLM.

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.

Assignment

  1. 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.

  2. 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.

  3. response = client.chat.completions.create(
        model="openrouter/free",
        messages=messages,
        tools=available_functions,
    )
    
  4. 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.

    • "what files are in the root?" -> for example get_files_info({'directory': '.'}) (the model may also omit directory and rely on the default, returning empty args)
    • "what files are in the pkg directory?" -> 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.