diff --git a/docs/query-agent/_includes/code/structured_outputs.mts b/docs/query-agent/_includes/code/structured_outputs.mts
new file mode 100644
index 00000000..40e96982
--- /dev/null
+++ b/docs/query-agent/_includes/code/structured_outputs.mts
@@ -0,0 +1,108 @@
+import 'dotenv/config'
+const { loadClientInternally } = await import('./util.mjs').catch(() => import('../docs/query-agent/_includes/code/util.mjs'));
+
+const client = await loadClientInternally();
+
+
+// START SOInstantiate
+import { QueryAgent } from 'weaviate-agents';
+
+const qa = new QueryAgent(client, { collections: ['FinancialContracts'] });
+// END SOInstantiate
+
+
+// START SOBasicExampleBaseModel
+import { z } from 'zod';
+
+const ContractSummary = z.object({
+ contract_id: z.string(),
+ contract_title: z.string(),
+ auto_renew: z.boolean(),
+ parties_involved: z.array(z.string()),
+ requires_action: z.boolean(),
+});
+
+const res = await qa.ask(
+ "Find the oldest contract and include if it automatically renews, who is involved, and if user action is needed",
+ { outputFormat: ContractSummary }
+);
+
+console.log(res.finalAnswerParsed);
+// END SOBasicExampleBaseModel
+
+
+// START SOBasicDictExample
+const res2 = await qa.ask(
+ "Find the oldest contract and include if it automatically renews, who is involved, and if user action is needed",
+ {
+ outputFormat: {
+ type: "object",
+ properties: {
+ contract_id: { title: "Contract Id", type: "string" },
+ contract_title: { title: "Contract Title", type: "string" },
+ auto_renew: { title: "Auto Renew", type: "boolean" },
+ parties_involved: { items: { type: "string" }, title: "Parties Involved", type: "array" },
+ requires_action: { title: "Requires Action", type: "boolean" },
+ },
+ required: ["contract_id", "contract_title", "auto_renew", "parties_involved", "requires_action"],
+ title: "ContractSummary",
+ additionalProperties: false,
+ },
+ }
+);
+
+console.log(res2.finalAnswerParsed);
+// END SOBasicDictExample
+
+
+// START SOReasoningExample
+const FinalAnswer = z.object({
+ reasoning: z.string(),
+ final_answer: z.string(),
+});
+
+const res3 = await qa.ask("What is the most recent contract about AI?", { outputFormat: FinalAnswer });
+
+console.log(res3.finalAnswerParsed);
+// END SOReasoningExample
+
+
+// START SONestedExampleBaseModel
+const ContractInfo = z.object({
+ names_mentioned: z.array(z.string()).describe("All names within the contract text"),
+ contract_type: z.enum(["sales", "purchase", "other"]).describe("Determine the type of contract"),
+ summary: z.string().describe("Provide a brief summary of the contract."),
+ contract_uuid: z.uuid(),
+});
+
+const ContractInfoResponse = z.object({
+ contract_infos: z.array(ContractInfo),
+ overall_summary: z.string(),
+});
+
+const res4 = await qa.ask("Find and return all contracts about AI in 2023", { outputFormat: ContractInfoResponse });
+
+console.log(res4.finalAnswerParsed);
+// END SONestedExampleBaseModel
+
+
+// START SOCitationExample
+const CitedText = z.object({
+ sentence: z.string().describe("A single sentence from your answer, to be combined with other sentences"),
+ sources: z.array(z.uuid()).describe("The UUIDs of the sources that support the sentence"),
+});
+
+const CitedAnswer = z.object({
+ reasoning: z.string(),
+ final_answer: z.array(CitedText).describe(
+ "A list of cited sentences, that will combine together in a paragraph to be a full answer"
+ ),
+});
+
+const res5 = await qa.ask("What is the most recent contract about AI?", { outputFormat: CitedAnswer });
+
+console.log(res5.finalAnswerParsed);
+// END SOCitationExample
+
+
+await client.close();
diff --git a/docs/query-agent/_includes/code/structured_outputs.py b/docs/query-agent/_includes/code/structured_outputs.py
new file mode 100644
index 00000000..80d7673f
--- /dev/null
+++ b/docs/query-agent/_includes/code/structured_outputs.py
@@ -0,0 +1,102 @@
+import sys
+sys.path.insert(0, "docs/query-agent/_includes/code")
+from util import load_client_internally
+
+client = load_client_internally()
+
+
+# START SOInstantiate
+from weaviate.agents.query import QueryAgent
+
+qa = QueryAgent(client=client, collections=["FinancialContracts"])
+# END SOInstantiate
+
+
+# START SOBasicExampleBaseModel
+from pydantic import BaseModel
+
+class ContractSummary(BaseModel):
+ contract_id: str
+ contract_title: str
+ auto_renew: bool
+ parties_involved: list[str]
+ requires_action: bool
+
+res = qa.ask(
+ "Find the oldest contract and include if it automatically renews, who is involved, and if user action is needed",
+ output_format=ContractSummary,
+)
+
+print(res.final_answer_parsed)
+# END SOBasicExampleBaseModel
+
+# START SOBasicDictExample
+res = qa.ask(
+ "Find the oldest contract and include if it automatically renews, who is involved, and if user action is needed",
+ output_format={
+ 'properties': {
+ 'contract_id': {'title': 'Contract Id', 'type': 'string'},
+ 'contract_title': {'title': 'Contract Title', 'type': 'string'},
+ 'auto_renew': {'title': 'Auto Renew', 'type': 'boolean'},
+ 'parties_involved': {'items': {'type': 'string'}, 'title': 'Parties Involved', 'type': 'array'},
+ 'requires_action': {'title': 'Requires Action', 'type': 'boolean'}
+ },
+ 'required': ['contract_id', 'contract_title', 'auto_renew', 'parties_involved', 'requires_action'],
+ 'title': 'ContractSummary',
+ 'type': 'object'
+ }
+)
+
+print(res.final_answer_parsed)
+# END SOBasicDictExample
+
+# START SOReasoningExample
+from pydantic import BaseModel
+
+class FinalAnswer(BaseModel):
+ reasoning: str
+ final_answer: str
+
+res = qa.ask("What is the most recent contract about AI?", output_format=FinalAnswer)
+
+print(res.final_answer_parsed)
+# END SOReasoningExample
+
+# START SONestedExampleBaseModel
+from pydantic import BaseModel, Field
+from uuid import UUID
+from typing import Literal
+
+class ContractInfo(BaseModel):
+ names_mentioned: list[str] = Field(description="All names within the contract text")
+ contract_type: Literal["sales", "purchase", "other"] = Field(description="Determine the type of contract")
+ summary: str = Field(description="Provide a brief summary of the contract.")
+ contract_uuid: UUID
+
+class ContractInfoResponse(BaseModel):
+ contract_infos: list[ContractInfo]
+ overall_summary: str
+
+res = qa.ask("Find and return all contracts about AI in 2023", output_format=ContractInfoResponse)
+
+print(res.final_answer_parsed)
+# END SONestedExampleBaseModel
+
+# START SOCitationExample
+from pydantic import BaseModel
+from uuid import UUID
+
+class CitedText(BaseModel):
+ sentence: str = Field(description="A single sentence from your answer, to be combined with other sentences")
+ sources: list[UUID] = Field(description="The UUIDs of the sources that support the sentence")
+
+class CitedAnswer(BaseModel):
+ reasoning: str
+ final_answer: list[CitedText] = Field(
+ description="A list of cited sentences, that will combine together in a paragraph to be a full answer"
+ )
+
+res = qa.ask("What is the most recent contract about AI?", output_format=CitedAnswer)
+
+print(res.final_answer_parsed)
+# END SOCitationExample
\ No newline at end of file
diff --git a/docs/query-agent/guides/ask_mode.md b/docs/query-agent/guides/ask_mode.md
index 9913257a..b16f6795 100644
--- a/docs/query-agent/guides/ask_mode.md
+++ b/docs/query-agent/guides/ask_mode.md
@@ -66,7 +66,8 @@ The `.ask()` method accepts several arguments:
| --- | --- | --- |
| `query` | `str \| list[ChatMessage]` | The user query you want the agent to answer. This can be a simple string (`"What is the highest-grossing product?"`) or a list of chat messages (for conversational context). [See the page on multi-turn conversations for more detail](../reference/multi_turn_conversations.md). |
| `collections` | `list[str \| QueryAgentCollectionConfig] \| None` | The name(s) of the collections to search. You can pass one or many collection names as a list of strings (e.g., `["ECommerce", "BookSales"]`), or provide collection configuration objects for more control. If specified in the `ask` method, it will overwrite those defined in the instantiation of `QueryAgent`. [See the page on collection configuration for more detail](../reference/advanced_collections.md). |
-| `result_evaluation` | `Literal["llm", "none"]` | Controls whether the agent will ask an LLM to "evaluate" (i.e., rewrite or rephrase) the result based on all retrieved context. Accepts either:
• `"none"` (default): faster and cheaper; where the final answer is the last LLM call and no further analysis is completed.
• `"llm"`: higher cost/latency - enables a final step where an LLM subsets the sources retrieved to only those used in the answer, as well as enabling the optional fields `is_partial_answer` and `missing_information`. See [the response class](#response) for more details. |
+| `result_evaluation` | `Literal["llm", "none"]` | Controls whether the agent will ask an LLM to "evaluate" the result based on all retrieved context. Accepts either:
• `"none"` (default): faster and cheaper; where the final answer is the last LLM call and no further analysis is completed.
• `"llm"`: higher cost/latency - enables a final step where an LLM subsets the sources retrieved to only those used in the answer, as well as enabling the optional fields `is_partial_answer` and `missing_information`. See [the response class](#response) for more details. |
+| `output_format` | `dict \| type[BaseModel] \| None` | Optional schema for structured output in the final response. Modifies the `final_answer` field of the [response class](#response). See [the page on structured output for more details](../reference/structured_outputs.md). |
@@ -74,8 +75,8 @@ The `.ask()` method accepts several arguments:
| --- | --- | --- |
| `query` | `string \| ChatMessage[]` | The user query you want the agent to answer. This can be a simple string (`"What is the highest-grossing product?"`) or a list of chat messages (for conversational context). [See the page on multi-turn conversations for more detail](../reference/multi_turn_conversations.md). |
| `collections` | `(string \| QueryAgentCollectionConfig)[]` | The name(s) of the collections to search. You can pass one or many collection names as a list of strings (e.g., `["ECommerce", "BookSales"]`), or provide collection configuration objects for more control. [See the page on collection configuration for more detail](../reference/advanced_collections.md). If specified in the `ask` method, it will overwrite those defined in the instantiation of `QueryAgent`. |
-| `resultEvaluation` | `"llm" \| "none"` | Controls whether the agent will ask an LLM to "evaluate" (i.e., rewrite or rephrase) the result based on all retrieved context. Accepts either:
• `"none"`: faster and cheaper; default setting where the final answer is the last LLM call.
• `"llm"`: higher cost/latency - enables a final step where an LLM subsets the sources retrieved to only those used in the answer, as well as enabling the optional fields `is_partial_answer` and `missing_information`. See [the response class](#response) for more details. |
-
+| `resultEvaluation` | `"llm" \| "none"` | Controls whether the agent will ask an LLM to "evaluate" the result based on all retrieved context. Accepts either:
• `"none"`: faster and cheaper; default setting where the final answer is the last LLM call.
• `"llm"`: higher cost/latency - enables a final step where an LLM subsets the sources retrieved to only those used in the answer, as well as enabling the optional fields `is_partial_answer` and `missing_information`. See [the response class](#response) for more details. |
+| `outputFormat` | `ZodType \| object` | Optional schema for structured output in the final response. Pass a [Zod](https://zod.dev/) schema (parsed and validated) or a raw [Draft 2020-12 JSON Schema](https://json-schema.org/draft/2020-12) object (parsed only). Modifies the `finalAnswer` field of the [response class](#response), exposing the typed result on `finalAnswerParsed`. See [the page on structured output for more details](../reference/structured_outputs.md). |
@@ -99,6 +100,13 @@ The `AskModeResponse` class has the following properties:
| `final_answer` | `str` | A string comprising the LLM's final answer to the user query. |
| `sources` | `list[Source] \| None` | A list of `Source` objects, which have an `object_id` property correlating to the UUID of the Weaviate object that was retrieved during the run. If `result_evaluation` is `"llm"`, these are subset to only those that are relevant to the `final_answer`. |
+Additionally, there is another field if the `output_format` parameter on the call to ask mode (`qa.ask(..., output_format=...)`) was not `None`:
+| Field | Type | Description |
+| --- | --- | --- |
+| `final_answer_parsed` | `` | The final response, conforming to the schema given in the `output_format`. |
+
+The type of `final_answer_parsed` is a `dict` if a dictionary was supplied to `output_format`, otherwise it will be the exact type of the `BaseModel` given.
+
[See the client documentation for more detail.](https://weaviate-python-client.readthedocs.io/en/latest/weaviate-agents-python-client/docs/weaviate_agents.classes.html#weaviate_agents.classes.AskModeResponse)
@@ -115,6 +123,13 @@ The `AskModeResponse` class has the following properties:
| `finalAnswer` | `string` | A string comprising the LLM's final answer to the user query. |
| `sources` | `Source[]` | A list of `Source` objects, which have an `objectId` property correlating to the UUID of the Weaviate object that was retrieved during the run. If `resultEvaluation` is `"llm"`, these are subset to only those that are relevant to the `finalAnswer`. |
+Additionally, there is another field if the `outputFormat` parameter on the call to ask mode (`qa.ask(..., { outputFormat: ... })`) was provided:
+| Field | Type | Description |
+| --- | --- | --- |
+| `finalAnswerParsed` | `` | The final response, conforming to the schema given in `outputFormat`. |
+
+The type of `finalAnswerParsed` is `Record` if a raw JSON Schema object was supplied to `outputFormat`, otherwise it will be the inferred type of the Zod schema given (`z.infer`).
+
[See the client documentation for more detail.](https://weaviate.github.io/agents-typescript-client/types/AskModeResponse.html)
diff --git a/docs/query-agent/reference/index.md b/docs/query-agent/reference/index.md
index f121d088..e05e2459 100644
--- a/docs/query-agent/reference/index.md
+++ b/docs/query-agent/reference/index.md
@@ -12,7 +12,7 @@ See the different configuration options for the Query Agent and how you can cust
* **[Multi-turn Conversations](./multi_turn_conversations.md)**: Learn how to include multiple turns of conversations in a message history instead of a single user query.
* **[Additional Filters](./additional_filters.md)**: Define persistent filters that get added to every search the Query Agent performs.
* **[Collection Configuration](./advanced_collections.md)**: Setup your collections with more advanced configurations, such as named vectors, multi-tenancy and additional filters.
-
+* **[Structured Outputs](./structured_outputs.md)**: Configure the format of the ask mode response to conform to a schema.
## Questions and feedback
diff --git a/docs/query-agent/reference/structured_outputs.md b/docs/query-agent/reference/structured_outputs.md
new file mode 100644
index 00000000..276ab249
--- /dev/null
+++ b/docs/query-agent/reference/structured_outputs.md
@@ -0,0 +1,442 @@
+---
+title: Structured Outputs
+description: "Conform the final response to a particular schema."
+image: og/docs/query-agent.png
+# tags: ['agents', 'query-agent', 'configuration']
+---
+
+import Tabs from '@theme/Tabs';
+import TabItem from '@theme/TabItem';
+import FilteredTextBlock from '@site/src/components/Documentation/FilteredTextBlock';
+import PyCode from '!!raw-loader!/docs/query-agent/_includes/code/structured_outputs.py';
+import TSCode from '!!raw-loader!/docs/query-agent/_includes/code/structured_outputs.mts';
+
+
+Structured outputs ensure that the model's final response will adhere to a given schema. This means you can easily access aspects of a response which is customised to your use-case.
+
+## Basic Usage
+
+
+
+ In Python, you can either provide a Pydantic `BaseModel` or a raw dictionary conforming to the [Draft 2020-12 JSON Schema](https://json-schema.org/draft/2020-12) specification.
+
+ In the below examples, we use structured outputs to generate a set of metadata associated with a single retrieved item.
+
+ The structured output can be accessed by a new field, `final_answer_parsed`, which appears only when the `output_format` argument is not `None`. The raw string from the model can still be accessed at `final_answer`.
+
+ **Pydantic BaseModel**
+
+
+
+ Example output
+ ```python
+ ContractSummary(
+ contract_id='46',
+ contract_title='Employment Contract',
+ auto_renew=False,
+ parties_involved=['Weaviate', 'Mark Robson'],
+ requires_action=True
+ )
+ ```
+
+
+
+ **Dictionary**
+
+
+
+ Example output
+ ```python
+ {
+ 'contract_id': '46',
+ 'contract_title': 'Employment Contract',
+ 'auto_renew': False,
+ 'parties_involved': ['Weaviate', 'Mark Robson'],
+ 'requires_action': True
+ }
+ ```
+
+
+
+
+ In JavaScript/TypeScript, you can either provide a [Zod](https://zod.dev/) schema or a raw object conforming to the [Draft 2020-12 JSON Schema](https://json-schema.org/draft/2020-12) specification.
+
+ In the below examples, we use structured outputs to generate a set of metadata associated with a single retrieved item.
+
+ The structured output can be accessed by a new field, `finalAnswerParsed`, which appears only when the `outputFormat` argument is not null. The raw string from the model can still be accessed at `finalAnswer`.
+
+ **Zod schema**
+
+
+ Example output
+ ```typescript
+ {
+ contract_id: '46',
+ contract_title: 'Employment Contract',
+ auto_renew: false,
+ parties_involved: [ 'Weaviate', 'Mark Robson' ],
+ requires_action: true
+ }
+ ```
+
+
+ **Object**
+
+
+ Example output
+ ```typescript
+ {
+ contract_id: '46.0',
+ contract_title: 'Employment Contract',
+ auto_renew: false,
+ parties_involved: [ 'Weaviate', 'Mark Robson' ],
+ requires_action: true
+ }
+ ```
+
+
+
+
+
+## Example: Reasoning
+
+As a basic example, consider adding an additional field `reasoning` to the response. Order is preserved in the specification, so if this is provided _before_ the answer field, the model will produce a reasoning string before writing its answer, which can provide explainability to a response.
+
+
+
+
+
+ Example output
+ ```python
+ FinalAnswer(
+ reasoning='The most recent contract mentioning AI is the sales agreement dated 2024-03-15, but it does not mention AI in the text. The most recent contract that is actually about AI is the partnership agreement dated 2023-11-15 between Weaviate and FictionalSoft, which explicitly states it is for artificial intelligence research and development. No later AI-related contract is present in the provided data.',
+ final_answer='The most recent contract about AI is the partnership agreement dated 2023-11-15 between Weaviate and FictionalSoft. It is specifically for collaboration on artificial intelligence research and development. No more recent AI-related contract appears in the provided data.'
+ )
+ ```
+
+
+
+
+
+ Example output
+ ```typescript
+ {
+ reasoning: 'The most recent contract related to AI is the partnership agreement dated 2024-03-15 at 10:30 UTC. It specifically mentions collaboration on artificial intelligence research and development.',
+ final_answer: 'The most recent AI-related contract is a **Partnership Agreement** dated **2024-03-15 10:30 UTC** between **Weaviate** and **FictionalSoft**. It says the parties wish to establish a partnership to collaborate on **artificial intelligence research and development**. It has a **2-year term** and includes financial contributions of **$244.46 from Weaviate** and **$151.01 from FictionalSoft**, with profits split **50/50**.\n' +
+ '\n' +
+ 'If you want, I can also summarize the next most recent AI-related contract.'
+ }
+ ```
+
+
+
+
+## Example: Nested Schemas
+
+Nested schemas are supported, for example, you can define two schemas and have one reference the other, allowing more complex structured outputs to be crafted.
+
+In the below example, the final response will generate a list of information for each object that was retrieved, either extracted or generated from the content of the data, as well as providing an overall answer.
+
+
+
+
+
+ Example output
+ ```python
+ ContractInfoResponse(
+ contract_infos=[
+ ContractInfo(
+ names_mentioned=['Hans Zimmer', 'Weaviate', 'Mark Robson'],
+ contract_type='other',
+ summary='Loan agreement between Weaviate and Mark Robson for $342.00, dated 2023-03-15.',
+ contract_uuid=UUID('b2c4ffdc-411c-423a-9040-b7cbf5439bd0')
+ ),
+ ContractInfo(
+ names_mentioned=['John Smith', 'Weaviate'],
+ contract_type='other',
+ summary='Non-disclosure agreement between Weaviate and John Smith, dated 2022-03-15.',
+ contract_uuid=UUID('c126e3d3-db85-4a77-b49c-2a87fe48cd52')
+ ),
+ ContractInfo(
+ names_mentioned=['Johnathan Smith', 'Weaviate', 'John Smith'],
+ contract_type='other',
+ summary='Lease agreement for office space between Weaviate and John Smith, dated 2024-03-15.',
+ contract_uuid=UUID('6bbca4b9-fea1-4275-889a-1f5d4591ecbb')
+ ),
+ ContractInfo(
+ names_mentioned=['Arthur Penndragon', 'Weaviate', 'Mark Robson'],
+ contract_type='other',
+ summary='Loan agreement between Weaviate and Mark Robson for $620.41, dated 2023-03-15.',
+ contract_uuid=UUID('93213fd4-4c55-4a7c-a190-2e4c9d808566')
+ ),
+ ContractInfo(
+ names_mentioned=['Alice Johnson', 'Weaviate', 'Danny Williams'],
+ contract_type='other',
+ summary='Service agreement for digital marketing services between Weaviate and Danny Williams, dated
+ 2023-03-15, with total compensation of $961.89.',
+ contract_uuid=UUID('eed7d7f9-b06a-4d7b-b19a-f0f3782e49fd')
+ ),
+ ContractInfo(
+ names_mentioned=['Weaviate', 'John Smith'],
+ contract_type='other',
+ summary='Loan agreement between Weaviate and John Smith for $403.65, dated 2022-03-15.',
+ contract_uuid=UUID('5f75ec7e-ca7f-415c-9f5d-7d3a1518fad8')
+ ),
+ ContractInfo(
+ names_mentioned=['Hans Zimmer', 'Weaviate', 'Mark Robson'],
+ contract_type='sales',
+ summary='Sales agreement between Weaviate and Mark Robson for software licenses and support services,
+ dated 2023-04-24, with a total purchase price of $420.03.',
+ contract_uuid=UUID('174b1a9a-e9b2-4f48-960d-283a0fbbe3ab')
+ ),
+ ContractInfo(
+ names_mentioned=['John Williams', 'Weaviate', 'Mark Robson'],
+ contract_type='other',
+ summary='Service agreement between Weaviate and Mark Robson for consultation, software development, and
+ project management services, dated 2023-04-15, with total compensation of $744.35.',
+ contract_uuid=UUID('65848d82-e38e-4bed-b0bb-0c2830af8b27')
+ ),
+ ContractInfo(
+ names_mentioned=['John Williams', 'Weaviate'],
+ contract_type='other',
+ summary='Invoice from Weaviate to John Williams for data analysis, API integration, system maintenance,
+ technical support, and consultation services, dated 2023-10-15, totaling $873.17.',
+ contract_uuid=UUID('5b5544f9-7092-45d0-830d-dd211b0f3a70')
+ ),
+ ContractInfo(
+ names_mentioned=['Kaladin Stormblessed', 'Weaviate', 'John Smith'],
+ contract_type='other',
+ summary='Lease agreement between Weaviate and John Smith for office space, dated 2023-07-15.',
+ contract_uuid=UUID('f3f3730b-f3c4-4b2f-aa7a-1bc07b5814d8')
+ ),
+ ContractInfo(
+ names_mentioned=['Johnathan Smith', 'Weaviate', 'Mark Robson'],
+ contract_type='other',
+ summary='Non-disclosure agreement between Weaviate and Mark Robson, dated 2023-09-15.',
+ contract_uuid=UUID('3d4d802d-1820-4a5f-b8fe-6c5e189de1e6')
+ ),
+ ContractInfo(
+ names_mentioned=['John Williams', 'Weaviate', 'Danny Williams'],
+ contract_type='sales',
+ summary='Sales agreement between Weaviate and Danny Williams for products A, B, and C, dated
+ 2023-11-15, with a total purchase price of $270.68.',
+ contract_uuid=UUID('e645324e-14a4-4ca4-aeae-da146d55a3bb')
+ ),
+ ContractInfo(
+ names_mentioned=['John Williams', 'Weaviate', 'Mark Robson'],
+ contract_type='other',
+ summary='Invoice from Weaviate to Mark Robson dated 2023-04-15 for consultation, software development,
+ and project management services, totaling $744.35.',
+ contract_uuid=UUID('48a58d82-e38e-4bed-b0bb-0c2830af8b27')
+ ),
+ ContractInfo(
+ names_mentioned=['John Williams', 'Weaviate', 'John Smith'],
+ contract_type='other',
+ summary='Invoice from Weaviate to John Smith dated 2023-10-15 for consultation, development, and
+ additional charges, totaling $296.36.',
+ contract_uuid=UUID('03c0f5bb-f999-4b8b-86f3-271405de0037')
+ ),
+ ContractInfo(
+ names_mentioned=['Johnathan Smith', 'Weaviate', 'Danny Williams'],
+ contract_type='other',
+ summary='Service agreement between Weaviate and Danny Williams for software development, technical
+ support, and consultation services, dated 2023-03-15, with compensation of $273.86.',
+ contract_uuid=UUID('d68e20a9-4bd4-42d0-8986-d16425c3444a')
+ )
+ ],
+ overall_summary='There are multiple 2023 contracts related to AI, including two partnership agreements about artificial intelligence research and development, plus other 2023 contracts mentioning AI-adjacent services. Some listed contracts are not directly about AI but were returned from the available matching set.'
+ )
+ ```
+
+ A `Field` can be used to provide additional metadata, such as a `description`, or even constraints on numeric objects. A `Literal` can be used to constrain a field to produce only one of a few different objects.
+
+
+
+ A `.describe()` call can be used to provide additional metadata, such as a description, or even constraints on numeric objects. A `z.enum()` can be used to constrain a field to produce only one of a few different objects.
+
+ Example output
+ ```typescript
+ {
+ contract_infos: [
+ {
+ names_mentioned: [Array],
+ contract_type: 'other',
+ summary: 'Partnership agreement to collaborate on artificial intelligence research and development, including shared contributions, responsibilities, and profit or revenue sharing. Date: 2023-03-15.',
+ contract_uuid: '583a63f9-f71b-4926-8075-2ade04a689c3'
+ },
+ {
+ names_mentioned: [Array],
+ contract_type: 'other',
+ summary: 'Partnership agreement to collaborate on artificial intelligence projects and develop innovative AI solutions, with financial contributions, roles, and termination terms. Date: 2022-03-15.',
+ contract_uuid: '301d007b-53b4-4ce5-9913-a4b3f28fae2f'
+ },
+ {
+ names_mentioned: [Array],
+ contract_type: 'other',
+ summary: 'Partnership agreement focused on artificial intelligence and machine learning collaboration, including resource contributions, revenue sharing, confidentiality, and termination terms. Date: 2023-03-15.',
+ contract_uuid: 'c2d4620b-db64-4b20-ac10-dd805d9b135d'
+ },
+ {
+ names_mentioned: [Array],
+ contract_type: 'other',
+ summary: 'Partnership agreement to advance artificial intelligence technologies through combined resources and expertise, with defined contributions, responsibilities, and termination provisions. Date: 2023-03-15.',
+ contract_uuid: 'bbfd975d-85e8-47f1-acae-8d46ff028272'
+ },
+ {
+ names_mentioned: [Array],
+ contract_type: 'other',
+ summary: 'Partnership agreement to collaborate on artificial intelligence projects, with project management, technical development, funding contributions, and termination terms. Date: 2023-03-15.',
+ contract_uuid: '6e2f283c-0e29-4daa-979f-800dffe476fb'
+ },
+ {
+ names_mentioned: [Array],
+ contract_type: 'other',
+ summary: 'Service agreement for data analysis, cloud computing, software development, technical support, and consultation services. It includes compensation, confidentiality, and termination terms. Date: 2023-03-15 to 2023-09-15 depending on the agreement.',
+ contract_uuid: '8cab56ce-512e-47ef-9a38-5d5fa829444e'
+ },
+ {
+ names_mentioned: [Array],
+ contract_type: 'other',
+ summary: 'Service agreement providing consulting on artificial intelligence and data management systems, including implementation, training, and technical support. Date: 2023-03-15.',
+ contract_uuid: '24541d4f-d84c-4cbe-b935-60cbc64c170e'
+ }
+ ],
+ overall_summary: 'The AI-related contracts available are partnership and service agreements from 2022–2023, with one purchase order and several invoices that mention AI or related services.'
+ }
+ ```
+
+
+
+
+## Example: Citations
+
+For a custom implementation of citing text (for example, if you want citations in-line), you could create a schema that iteratively builds a response from objects consisting of pairs of text and source IDs.
+
+:::note Supported Citations
+The Query Agent natively supports subsetting and evaluating the quality of the response via the `result_evaluation` parameter in ask mode. [See here for more details](../guides/ask_mode.md#parameters)
+:::
+
+
+
+
+
+ Example output
+ ```python
+ CitedAnswer(
+ reasoning='The most recent contract mentioning AI is the partnership agreement dated 2024-03-15, which explicitly refers to AI-related work only in the contract text by implication? However, among the provided contracts, the latest one that clearly concerns AI is the partnership agreement from 2023-11-15, and another earlier partnership agreement from 2023-10-15 also mentions AI solutions. The 2024-03-15 sales agreement does not mention AI, so it is not relevant. The latest clearly AI-related contract in the data is the 2023-11-15 partnership agreement between Weaviate and FictionalSoft.',
+ final_answer=[
+ CitedText(
+ sentence='The most recent contract about AI is the partnership agreement dated 2023-11-15 between Weaviate and FictionalSoft.',
+ sources=[UUID('4601c407-7905-4bd5-a1b9-4234bf18e9b6')]
+ ),
+ CitedText(
+ sentence='It says the parties will collaborate on projects including artificial intelligence research and development, with a three-year term and 50/50 profit sharing.',
+ sources=[UUID('4601c407-7905-4bd5-a1b9-4234bf18e9b6')]
+ )
+ ]
+ )
+ ```
+
+
+
+
+
+ Example output
+ ```typescript
+ {
+ reasoning: 'The most recent contract that explicitly concerns AI is the partnership agreement dated 2023-11-15 between Weaviate and FictionalSoft, which states that the parties wish to collaborate on artificial intelligence research and development. Among the provided contracts, no later agreement mentions AI, and later-dated documents are sales or lease agreements without AI-related terms.',
+ final_answer: [
+ {
+ sentence: 'The most recent AI-related contract is the partnership agreement dated November 15, 2023, between Weaviate and FictionalSoft, which is for collaboration on artificial intelligence research and development.',
+ sources: [Array]
+ },
+ {
+ sentence: 'No later contract in the provided set mentions AI; the newer 2024 documents are a sales agreement and lease agreements that do not reference artificial intelligence.',
+ sources: [Array]
+ }
+ ]
+ }
+ ```
+
+
+
+
+## What is supported?
+
+
+| Feature | Supported? | Notes |
+|---------|:----------:|-------|
+| Min / max number of items in an array | ✅ | |
+| Min / max value of a number property | ✅ | E.g. constrain a value to be within a certain range. |
+| String formats: `uuid`, `date-time`, `time`, `date`, `duration`, `email`, `hostname`, `ipv4`, `ipv6` | ✅ | Validated as a string with the given format. |
+| Regular expression (pattern) on a string | ✅ | |
+| Recursive schemas (a schema referencing itself) | ✅ | |
+| Default values (e.g. `x: int = 1`) | ❌ | The field is always populated by the model, so the default is never used. Consider using nullable entries and transforming them afterwards. |
+| Schemas with 5000+ properties | ❌ | |
+| 1000 or more enum values across all properties | ❌ | |
+| More than 10 levels of nesting in a single property | ❌ | |
+
+
+## Streaming
+
+Structured outputs are supported with [streaming ask mode](../guides/ask_mode.md#streaming).
+
+When streaming, the structured output is delivered incrementally as raw string fragments through `StreamedTokens` instances. No special parsing is applied during the stream — each token is simply a piece of the final output. To use the partial result, accumulate the streamed tokens into a single string, then partially validate the string against your schema.
+
+To use the final result after completion, you do not need to use the streamed tokens. Simply access the `final_answer_parsed` attribute (`finalAnswerParsed` in TypeScript) of the [`AskModeResponse` final state output](../guides/ask_mode.md#responses).
+
+## Questions and feedback
+
+import DocsFeedback from '/\_includes/docs-feedback.mdx';
+
+
diff --git a/sidebars.js b/sidebars.js
index b328f000..2e07fe83 100644
--- a/sidebars.js
+++ b/sidebars.js
@@ -1371,6 +1371,11 @@ const sidebars = {
id: "query-agent/reference/advanced_collections",
className: "sidebar-item",
},
+ {
+ type: "doc",
+ id: "query-agent/reference/structured_outputs",
+ className: "sidebar-item",
+ },
],
},
{