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", + }, ], }, {