I would trust a CRM integration more after seeing how it handles an unknown budget than after seeing it call five tools. The useful question is whether the software preserves uncertainty before it turns a sentence into an action.
My rule is shape before action. First define the fields and their meaning. Then decide which validated result is allowed to trigger which operation. An agent loop should make that chain easier to inspect.
Start with a data contract
Suppose the fictional Cedar Metrics application extracts an account name, a budget status and a next step from meeting notes. Define those fields before writing the integration. Budget status might be confirmed, unconfirmed or unknown, with a separate note preserving the source evidence.
The distinction matters because downstream software may behave differently for each state. A missing budget statement should not be converted into confirmed simply because the schema requires a value. Include an honest representation of uncertainty in the contract.
I would ask the business owner to review the field definitions alongside the developer. A technically valid object can still encode the wrong sales process. Naming the states clearly prevents that disagreement from hiding inside a prompt.
TipInclude unknown or null where the source may legitimately lack a fact.
Use structured output for software consumers
The Responses API supports structured output, and the Python SDK provides a parsing helper that can use a Pydantic model as text_format. The downloadable example defines a small account-summary schema and requests that shape from a compatible model.
Read the parsed result only after checking whether the response completed and produced a parsed object. Refusals, incomplete responses and request errors need explicit handling. A schema-aware request does not guarantee that every invocation returns the business object you hoped for.
The example is an educational extraction request, not a production CRM connector. It uses fictional text and has no write tool. We checked its syntax and documented SDK usage without making a paid live request. Your project still needs a compatible, available model and a current SDK.
"""Educational structured extraction; running it makes a billable API request.
Install: python3 -m pip install openai pydantic
Configure OPENAI_API_KEY securely and OPENAI_MODEL to a compatible model.
Docs: https://developers.openai.com/api/docs/guides/structured-outputs
No CRM connection or write action is included.
"""
import os
from typing import Literal
from openai import OpenAI
from pydantic import BaseModel
class AccountSummary(BaseModel):
account: str
budget_status: Literal["confirmed", "unconfirmed", "unknown"]
budget_evidence: str | None
next_step: str | None
unknowns: list[str]
def main():
client = OpenAI()
response = client.responses.parse(
model=os.environ["OPENAI_MODEL"],
input=[
{"role": "system", "content": (
"Extract only supported facts from the fictional note. "
"Use unknown or null for absent evidence. Budget confirmation "
"requires an explicit statement; meeting attendance is not approval."
)},
{"role": "user", "content": (
"Fictional training note: Cedar Metrics needs consistent campaign "
"reporting. Budget is unconfirmed. Finance will attend the next "
"meeting; its date has not been set."
)},
],
text_format=AccountSummary,
max_output_tokens=2048,
)
if response.status != "completed" or response.output_parsed is None:
raise RuntimeError("No completed parsed result; inspect refusal or incomplete status.")
summary = response.output_parsed
# Known-answer check for this fixture only, not a general truth validator.
if summary.account != "Cedar Metrics" or summary.budget_status != "unconfirmed":
raise ValueError("The fictional fixture's expected facts were not preserved.")
print(summary.model_dump_json(indent=2))
if __name__ == "__main__":
main()
TipKeep schema definitions in the codebase so changes can be reviewed with their consumers.
Validate meaning after validating shape
A schema can require budget_status to be one of three strings. It cannot establish that the chosen string is supported by the meeting note. That requires a semantic check, source evidence or a review process appropriate to the workflow.
For Cedar Metrics, the phrase “budget is unconfirmed” should remain unconfirmed, while “finance will attend next week” should not become approval. Keep examples like these in an evaluation set and rerun them when changing the prompt, model or schema.
Use ordinary code for deterministic rules, such as a required identifier format or an allowed status transition. Let the model extract and interpret language within a defined scope, then apply the application’s business rules before any consequential action.
TipTest whether the output preserves uncertainty, not merely whether it parses.
Understand the function-calling handoff
With custom function calling, your request describes available functions and their argument schemas. The model may return a function-call item naming the operation and arguments. Your application receives that request, validates it and decides whether to execute the corresponding code.
After execution, the application supplies the result using a function_call_output item tied to the call_id, preserving the relevant response context. The model can then use that result in its next response. The official function-calling guide shows the complete request and response pattern.
This distinction is fundamental: describing a CRM update function does not authorize every requested update or execute it by magic. Your application owns the function implementation, account access and business authorization. The model’s requested arguments are input to inspect, not a permission slip.
TipUse an allowlist of implemented tool names rather than dynamically executing arbitrary returned names.
Make the first tool read-only
A useful first tool could retrieve an approved account record by a validated identifier. Its result might include the account name, owner and dated opportunity fields. The assistant can combine that evidence with a supplied note to prepare a draft summary.
Validate that the current application user may access the requested account. Do not rely on the model to enforce tenant isolation or decide whether an identifier belongs to the signed-in user. Those checks belong in the service code before returning data.
For a write tool, add stricter controls: allowed fields, valid transitions, intended recipient or record, and duplicate prevention. Keep a review step where the business workflow requires one. A correct read-only demo does not establish readiness for external updates.
TipReturn only the fields the task needs, with source identity and useful freshness information.
Give an agent loop a stopping rule
An agent is a workflow in which model decisions can lead to tool use, observations and another decision. That can be useful for tasks whose next step depends on what the previous step found. It also creates more opportunities for repetition and partial failure.
Define completion in business terms. For an account brief, the task may end when the required sources have been checked and a draft with unresolved questions exists. It should not keep searching indefinitely because one optional detail remains unavailable.
Set limits on turns, duration, tool use and cost appropriate to the application. Decide what happens when the task reaches a limit: return a partial draft with missing evidence, request human input or fail with a clear reason. The stopping rule is part of the product experience.
TipA useful partial result names what was checked and what remains unknown.
Observe the workflow without leaking its inputs
Keep enough operational information to understand failures: request or run identifiers, completion state, tool names, durations and relevant error categories. Avoid dumping credentials or unnecessary sensitive source text into logs that have a wider audience than the application itself.
For a tool failure, distinguish unavailable service, denied access, invalid arguments and a business rule rejection. These conditions need different responses. Retrying a denied action repeatedly is not useful recovery; blindly retrying a partially completed write may create duplicates.
I would review a small trace from a fictional test before connecting real data. It should explain the sequence well enough to debug without exposing more content than needed. Good observability serves the operator who has to repair Tuesday’s run.
TipUse stable run identifiers so logs and outputs can be matched without copying all source text.
Where agent designs become harder than necessary
The common mistake is adding a loop where one structured request would do. Another is assuming a schema makes the extracted facts true or that a tool call is automatically authorized. These shortcuts make a demo simpler while moving uncertainty into production.
Start with the smallest complete workflow: a defined input, structured extraction, validation and a reviewed draft. Add retrieval when context is missing. Add an action only when the workflow needs it and the application can enforce its boundary. Use an agent loop when observations genuinely determine the next step.
Download structured_summary.py to inspect the extraction stage. Pair it with a test set before designing a write tool. Which decision in your workflow actually needs model judgment, and which can ordinary code enforce?
How to set it up
Define the contract
Specify fields, allowed values and honest unknown states for the account-summary task.
Run structured extraction
Configure the official SDK, API key and a compatible model, then inspect the linked sample before running it.
Validate the result
Check completion, parsed shape and business meaning using fictional notes with known expected outcomes.
Add one tool if needed
Begin with read-only retrieval, enforce authorization in code and define the loop’s completion and failure conditions.
Frequently asked questions
Does structured output guarantee factual accuracy?
No. It constrains the response shape; evidence and business correctness still need validation.
How should missing information appear?
Define explicit unknown or nullable values rather than forcing the model to guess.
Does the model execute my custom function?
Your application receives the requested call and owns validation and execution of the custom function.
What links a tool result to its request?
The function_call_output item uses the corresponding call_id in the documented Responses API flow.
Should the model enforce tenant access?
No. Enforce identity and authorization in application code before returning or changing records.
When do I need an agent loop?
When observations from tools genuinely determine subsequent steps. A single structured request may be enough for extraction.
What should happen at the run limit?
Return an explicit partial or failure state according to the application contract, with missing evidence identified.
Was the downloadable sample live-tested?
No paid API request was made. Syntax and the documented SDK pattern were checked; run it in your configured project before adopting it.
Sources & further reading
ChatGPT and Codex change quickly. This page was last reviewed September 22, 2026; verify time-sensitive details against the official docs above before relying on them.