Model comparisons · 2026-09-25
Tool calling and JSON Schema with Ember-1
The tool_choice options for tool calling on Ember-1, structured output with strict JSON Schema, the line between the call a model proposes and the action an application takes, and what changes when moving to moonshot/kimi-k3.
Short answer
Ember-1 supports tool calling: tool_choice works as auto, as required, and in the form that forces a specific tool by name. For structured output both json_object and strict json_schema are supported. Both work with reasoning on and off.
This row is available until 6 October 2026. Its successor, moonshot/kimi-k3, supports tool calling and json_object but does not list strict json_schema; in a flow that relies on a schema, validation moves to the application's side at that switch.
tool_choice options
tool_choice decides whether the model calls a tool and which one. Each of the three forms suits a different flow.
| Value | Behaviour | Flow it suits |
|---|---|---|
| auto | The model calls a tool when needed and answers in text otherwise | General-purpose assistant |
| required | The model always calls a tool | An agent loop that needs an action every turn |
| A tool named explicitly | The model calls only that tool | Single-step information extraction |
A tool call is a proposal
When the model calls a tool it does nothing itself; it states which function it wants called with which arguments. Making the call, validating the arguments and returning the result to the model in a role: tool message is the application's job. A finish_reason of tool_calls in the response marks this case. The tool result is sent back matched to the call's tool_call_id; if the model proposed more than one call in the same response, each result is added as a separate message with its own identifier.
That split is also the basis of safety. Which user may call which tool comes from an allowlist on the server, not from the prompt. For actions that are hard to reverse, such as payments, deletions or sending messages outside, the model's proposal passes through an approval step and carries a key that prevents the same action from running twice. The required option guarantees that a call is produced, not that the call is correct or authorised.
Writing tool definitions
Whether the model calls a tool at the right time with the right arguments depends largely on its definition. The tool's name and description are the text the model sees; a description that says clearly what the tool does and when to use it reduces confusion between two similar tools. Parameters are defined with a JSON schema; using an enum for a parameter with a limited set of values makes it harder for the model to produce an invalid one.
Tool definitions are sent as input tokens with every request. As long as they sit at the start of the prompt and do not change between requests, the automatic cache lets them be read at the discounted rate. Giving a flow only the tools it really needs reduces both cost and the chance of a wrong tool choice.
Structured output with strict JSON Schema
json_object mode makes the answer a valid JSON object but does not fix its fields. Strict json_schema makes the answer conform to the schema given: required fields are present, types match and no extra fields appear. Parsing errors disappear as a result.
A schema guarantees the shape, not the correctness of the values. A refund amount arrives as a number but can exceed the order total; an order number arrives as a string but can point to an order that does not exist. The example below takes schema-shaped output and compares the values with the application's own data.
Extraction with strict JSON Schema and a value check
import json, os
from openai import OpenAI
client = OpenAI(base_url=os.environ["LLMTR_BASE_URL"] + "/v1", api_key=os.environ["LLMTR_API_KEY"])
schema = {
"type": "object",
"properties": {
"order_id": {"type": "string"},
"refund_amount": {"type": "number"},
"reason": {"type": "string"},
},
"required": ["order_id", "refund_amount", "reason"],
"additionalProperties": False,
}
res = client.chat.completions.create(
model="fireworks/ember-1",
messages=[{"role": "user", "content": "Extract the refund request from this support message:\n" + ticket}],
response_format={"type": "json_schema",
"json_schema": {"name": "refund_request", "strict": True, "schema": schema}},
)
data = json.loads(res.choices[0].message.content)
# The schema guarantees the shape; the application checks the values.
order = orders.get(data["order_id"])
if order is None or not (0 < data["refund_amount"] <= order.total):
send_to_review(data)
else:
propose_refund(order, data["refund_amount"]) # approval and permission checks happen here
When moving to Kimi K3
moonshot/kimi-k3 supports tool calling, so tool definitions and the loop carry over as they are. For structured output, however, only json_object is available. Conformance to the schema is then checked by the application instead of the model: the returned object is validated against the same schema, and an answer that does not fit is requested again or sent to review.
Writing that validation while still on Ember-1 has one more benefit: on the day of the move only the model identifier and response_format change, and the code that relies on the schema stays the same. Describing the schema briefly in the prompt as well raises the chance that the model produces the right fields in json_object mode.
Unexpected cases
Under auto the model may answer in text instead of calling a tool; the flow should handle that without treating it as an error. As tool results are fed back, the conversation grows and every turn carries the tokens of the previous turns again. A turn limit on an agent loop keeps a case where the model calls the same tool over and over from inflating the cost.
With reasoning on, every turn also produces reasoning tokens, billed as output. For single-step work where it is clear which tool will be called, switching reasoning off cuts unnecessary tokens.
Frequently asked questions
Is required tool_choice safe on its own?
Not on its own. It guarantees that a tool call is produced; whether the call is correct and authorised is checked by the application with its own allowlist and rules.
Does strict JSON Schema guarantee that the values are correct?
No. It guarantees the shape: required fields and types. The correctness of amounts, numbers and dates is checked against the application's own data.
Can I use JSON Schema on Kimi K3?
moonshot/kimi-k3 does not list strict json_schema; json_object is used and the answer is validated against the same schema on the application side.
Does tool calling work with reasoning off?
Yes. auto, required and named tool_choice work with reasoning on and off. Switching reasoning off on single-step work reduces output tokens.
Do tool definitions add to the cost?
Yes, they count as input tokens on every request. Definitions that stay unchanged at the start of the prompt can be read from cache at $0.30 per million tokens.