From 5502eab28ae4111e71cb16e07a87783d502a13d6 Mon Sep 17 00:00:00 2001 From: dannyjameswilliams Date: Mon, 22 Jun 2026 15:57:20 +0100 Subject: [PATCH 1/2] docs: add new structured output section --- .../_includes/code/structured_outputs.mts | 108 +++++ .../_includes/code/structured_outputs.py | 102 ++++ docs/query-agent/guides/ask_mode.md | 21 +- docs/query-agent/reference/index.md | 2 +- .../reference/structured_outputs.md | 440 ++++++++++++++++++ sidebars.js | 5 + 6 files changed, 674 insertions(+), 4 deletions(-) create mode 100644 docs/query-agent/_includes/code/structured_outputs.mts create mode 100644 docs/query-agent/_includes/code/structured_outputs.py create mode 100644 docs/query-agent/reference/structured_outputs.md 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..9e0ec058 --- /dev/null +++ b/docs/query-agent/reference/structured_outputs.md @@ -0,0 +1,440 @@ +--- +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 result, accumulate the streamed tokens into a single string, then validate the completed string against your schema. You can also attempt partial validation as the string grows if you want to react to the output before the stream finishes. + +## 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", + }, ], }, { From c51d7476292ac6968a12b6b1163fe2d6406e3b4e Mon Sep 17 00:00:00 2001 From: dannyjameswilliams Date: Wed, 24 Jun 2026 16:15:55 +0100 Subject: [PATCH 2/2] streaming correction, python/TS titles in basic usage --- docs/query-agent/reference/structured_outputs.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/docs/query-agent/reference/structured_outputs.md b/docs/query-agent/reference/structured_outputs.md index 9e0ec058..276ab249 100644 --- a/docs/query-agent/reference/structured_outputs.md +++ b/docs/query-agent/reference/structured_outputs.md @@ -24,7 +24,7 @@ Structured outputs ensure that the model's final response will adhere to a given 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 + **Pydantic BaseModel** - ### Dictionary + **Dictionary** - ### Object + **Object**