Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 108 additions & 0 deletions docs/query-agent/_includes/code/structured_outputs.mts
Original file line number Diff line number Diff line change
@@ -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();
102 changes: 102 additions & 0 deletions docs/query-agent/_includes/code/structured_outputs.py
Original file line number Diff line number Diff line change
@@ -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
21 changes: 18 additions & 3 deletions docs/query-agent/guides/ask_mode.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,16 +66,17 @@ 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:<br/>• `"none"` (default): faster and cheaper; where the final answer is the last LLM call and no further analysis is completed.<br/>• `"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:<br/>• `"none"` (default): faster and cheaper; where the final answer is the last LLM call and no further analysis is completed.<br/>• `"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). |

</TabItem>
<TabItem value="ts_agents" label="JavaScript/TypeScript">
| Parameter | Type | Description |
| --- | --- | --- |
| `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:<br/>• `"none"`: faster and cheaper; default setting where the final answer is the last LLM call.<br/>• `"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:<br/>• `"none"`: faster and cheaper; default setting where the final answer is the last LLM call.<br/>• `"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). |
</TabItem>
</Tabs>

Expand All @@ -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` | `<given_type>` | 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)
</TabItem>

Expand All @@ -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` | `<given_type>` | The final response, conforming to the schema given in `outputFormat`. |

The type of `finalAnswerParsed` is `Record<string, unknown>` if a raw JSON Schema object was supplied to `outputFormat`, otherwise it will be the inferred type of the Zod schema given (`z.infer<typeof schema>`).

[See the client documentation for more detail.](https://weaviate.github.io/agents-typescript-client/types/AskModeResponse.html)
</TabItem>

Expand Down
2 changes: 1 addition & 1 deletion docs/query-agent/reference/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading