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

Agent Loop

So we've got some function-calling working, but it's not fair to call our program an "agent" yet for one simple reason:

It has no feedback loop.

A key part of an "agent," as defined by AI-influencer-hype-bros, is that it can continuously use its tools to iterate on its own results. So we're going to build two things:

  1. A loop that will call the LLM over and over
  2. A list of messages in the "conversation." It will look something like this:
    • User: "Please fix the bug in the calculator"
    • Assistant: "I want to call get_files_info..."
    • Tool: "Here's the result of get_files_info..."
    • Assistant: "I want to call get_file_content..."
    • Tool: "Here's the result of get_file_content..."
    • Assistant: "I want to call run_python_file..."
    • Tool: "Here's the result of run_python_file..."
    • Assistant: "I want to call write_file..."
    • Tool: "Here's the result of write_file..."
    • Assistant: "I fixed the bug and then ran the calculator to ensure it's working."

This is a big step; take your time. (But you're also really close to the finish line now!)

Assignment

    • If you moved the chat.completions.create request into a dedicated function, you'll be calling that function in the loop. If you're doing everything in main(), that's also fine – just take care that the loop is scoped correctly.
    • Make sure to limit the loop iterations! This will stop the agent from spinning its wheels forever and burning through tons of tokens. I recommend starting with a limit of 20 iterations. You can use a for loop for this:
      for _ in range(20):
          # call the model, handle responses, etc.
      
  1. message = response.choices[0].message
    messages.append(message)
    

    This is the "assistant" turn in the conversation. If the model requested any tool calls, they're attached to this message, so adding it to the history keeps the conversation in sync.

    • "role": "tool"
    • "tool_call_id" set to that tool call's .id (this is how the model matches a result to its request)
    • "content" set to the string your function returned
    messages.append(result_message)
    

    Order matters: first append the assistant's message, then append one tool message per tool call. The OpenAI-style API requires every tool call to be answered by a matching tool message before the next assistant turn.

  2. (aiagent) wagslane@MacBook-Pro-2 aiagent % uv run main.py "how does the calculator render results to the console?"
     - Calling function: get_files_info
     - Calling function: get_file_content
    Final response:
    The calculator evaluates the expression, formats the result (along with the
    original expression) into a JSON-like string, and then prints that string to
    the console.
    

You may or may not need to make adjustments to your system prompt to get the LLM to behave the way you want. You're a prompt engineer now, so act like one!

Submit the CLI tests.