Workshops ... Part 2: Start with a plain model call

Part 2: Start with a plain model call

Now the notebook has a working search(query) function over the course FAQ. Before adding the tool, ask the model the course question directly.

from openai import OpenAI

openai_client = OpenAI()

response = openai_client.responses.create(
    model="gpt-4o-mini",
    input=[
        {"role": "user", "content": "I just discovered the course. Can I join it?"}
    ],
)

response.output_text

The model can answer general questions from its training data, but it does not know which course we mean or what the FAQ says. That is the gap tool use fills.

Describe the tool

The Responses API needs a language-independent description of the function. Python knows what search means, but the model only sees the schema we send.

search_tool = {
    "type": "function",
    "name": "search",
    "description": "Search the FAQ database",
    "parameters": {
        "type": "object",
        "properties": {
            "query": {
                "type": "string",
                "description": "Search query text to look up in the course FAQ."
            }
        },
        "required": ["query"],
        "additionalProperties": False
    }
}

This schema is the contract between the model and your code. The model can decide to call search, but your Python process is still responsible for executing the function.

Let the model request a function call

Now create the conversation history and send the tool list with the request.

developer_prompt = """
You're a course teaching assistant.
You're given a question from a course student and your task is to answer it.
""".strip()

question = "I just discovered the course. Can I still join it?"

chat_messages = [
    {"role": "developer", "content": developer_prompt},
    {"role": "user", "content": question}
]

The developer message gives the assistant its job. The user message is the student question.

response = openai_client.responses.create(
    model="gpt-4o-mini",
    input=chat_messages,
    tools=[search_tool],
)

response.output

For this question, the response contains a function_call entry. In the live session the model chose a query like join course now. That is not the final answer yet. It is a request for your code to run the tool.

Execute the requested function

The function call contains JSON arguments. Parse them, call the Python function, and serialize the result so the model can read it on the next request.

import json

call = response.output[0]
args = json.loads(call.arguments)

results = search(**args)
result_json = json.dumps(results, indent=2)

The model also needs to see its own function-call request. Add the model output to the conversation history before adding the tool result.

chat_messages.extend(response.output)

chat_messages.append({
    "type": "function_call_output",
    "call_id": call.call_id,
    "output": result_json,
})

The call_id links the tool output to the specific function call the model requested.

Ask the model again

Call the Responses API a second time with the expanded history:

response = openai_client.responses.create(
    model="gpt-4o-mini",
    input=chat_messages,
    tools=[search_tool],
)

response.output_text

This time the model has the original question, its own decision to call search, and the FAQ results. It can now produce the course-specific answer.

LLMs are stateless between API calls. The memory is the list you send as input. If you leave out the previous messages, the model does not know what happened in the earlier call.

Questions & Answers (0)

Sign in to ask questions