Skip to main content
Use the format that matches how your application will consume the result: Native annotations are documented in annotation format. They are not automatically converted to JSON objects by the API. Function-call schemas are also separate from final-response constraints: function.strict is accepted but does not enforce argument validity. function.arguments is a string that can contain invalid JSON; parse it and validate it against your function schema before execution.

Request a JSON Schema response

Install perceptron>=0.4.0 and jsonschema, and set PERCEPTRON_API_KEY. This example constrains the answer and validates it locally before use:
Define required fields and allowed values explicitly. Use numeric bounds when a field represents a bounded quantity, and include an appropriate unknown or empty value when the image may not contain the requested information. A valid schema constrains the structure; it does not establish that the model’s interpretation is correct.

Define the response with Pydantic

Pydantic v2 can generate the JSON Schema and validate the response with the same Python model. Install it with pip install "pydantic>=2,<3", then run this after defining client and the image messages above:
All three fields are required, extra="forbid" rejects unexpected fields, and the literal types restrict allowed values. model_validate_json raises ValidationError for malformed JSON or values that do not match the model. Handle that failure before storing the result or using it in another workflow.

Use regex for a short answer

Run this after the client and image messages above. Pass regex directly to the SDK’s message API:
Use one response constraint per request. Keep regex patterns small and test them against the answer shapes you intend to allow.

Combine tools with a constrained final answer

A request cannot declare non-empty function tools together with a json_schema response format or regex. The SDK raises BadRequestError for this combination before sending the request. First complete the tool loop. Append every tool result to the conversation. Then request the final answer with your response constraint and omit tools, tool_choice, and parallel_tool_calls for that request. The completed tool history can remain in messages. Save the function-calling example as inventory.py. Its run() function returns the completed conversation, including the lookup results and assistant answer. Save the following as inventory_report.py in the same directory:
With PERCEPTRON_API_KEY set as in the function-calling guide, install the dependencies and run the report script:
The script runs the inventory lookup workflow, then makes one additional request for the report. With the example inventory, the report should contain:
Always validate function names and arguments in your application before dispatch. A constrained final answer does not retroactively validate a tool call or its result.

Validate completed streams

With stream=True, individual delta.content chunks can end inside a JSON string or annotation tag. Use stream.get_final_completion() to assemble the response, check response.complete and the finish reason, then parse and validate the final text. Treat finish_reason: "length", API errors, or a lost connection as incomplete output. The SDK requests usage by default for Perceptron streams. Usage can arrive in a final chunk with choices: []; the assembled completion includes it. If you process chunks directly, consume usage independently of choice deltas. The video tracking stream example demonstrates streaming; replace annotation parsing with JSON or regex validation for constrained responses.