From 09d3849539f8d022c6ac58d64f187c33241408ee Mon Sep 17 00:00:00 2001 From: Sebastian Husch Lee <10526848+sjrl@users.noreply.github.com> Date: Mon, 5 Oct 2026 12:31:14 +0200 Subject: [PATCH] docs: add TypeSafe integration documentation pages (#13030) --- .../docs/pipeline-components/classifiers.mdx | 1 + .../typesafedocumentclassifier.mdx | 202 ++++++++++++++++++ .../docs/pipeline-components/routers.mdx | 3 +- .../routers/typesafetextrouter.mdx | 146 +++++++++++++ docs-website/sidebars.js | 2 + .../pipeline-components/classifiers.mdx | 1 + .../typesafedocumentclassifier.mdx | 202 ++++++++++++++++++ .../pipeline-components/routers.mdx | 3 +- .../routers/typesafetextrouter.mdx | 146 +++++++++++++ .../version-3.3-sidebars.json | 6 +- 10 files changed, 708 insertions(+), 4 deletions(-) create mode 100644 docs-website/docs/pipeline-components/classifiers/typesafedocumentclassifier.mdx create mode 100644 docs-website/docs/pipeline-components/routers/typesafetextrouter.mdx create mode 100644 docs-website/versioned_docs/version-3.3/pipeline-components/classifiers/typesafedocumentclassifier.mdx create mode 100644 docs-website/versioned_docs/version-3.3/pipeline-components/routers/typesafetextrouter.mdx diff --git a/docs-website/docs/pipeline-components/classifiers.mdx b/docs-website/docs/pipeline-components/classifiers.mdx index fc4a76d637..0f534161f1 100644 --- a/docs-website/docs/pipeline-components/classifiers.mdx +++ b/docs-website/docs/pipeline-components/classifiers.mdx @@ -13,3 +13,4 @@ Use Classifiers to classify your documents by specific traits and update the met | --- | --- | | [DocumentLanguageClassifier](classifiers/documentlanguageclassifier.mdx) | Classify documents by language. | | [TransformersZeroShotDocumentClassifier](classifiers/transformerszeroshotdocumentclassifier.mdx) | Classify the documents based on the provided labels. | +| [TypeSafeDocumentClassifier](classifiers/typesafedocumentclassifier.mdx) | Answer typed questions about documents with a TypeSafe System One model and store the answers in their metadata. | diff --git a/docs-website/docs/pipeline-components/classifiers/typesafedocumentclassifier.mdx b/docs-website/docs/pipeline-components/classifiers/typesafedocumentclassifier.mdx new file mode 100644 index 0000000000..ade1ff4081 --- /dev/null +++ b/docs-website/docs/pipeline-components/classifiers/typesafedocumentclassifier.mdx @@ -0,0 +1,202 @@ +--- +title: "TypeSafeDocumentClassifier" +id: typesafedocumentclassifier +slug: "/typesafedocumentclassifier" +description: "Answers typed questions about each document with a TypeSafe System One model, such as Jev, and stores the answers in its metadata." +--- + +# TypeSafeDocumentClassifier + +Answers typed questions about each document with a TypeSafe System One model, such as Jev, and stores the answers in its metadata. + +
+ +| | | +| --- | --- | +| **Most common position in a pipeline** | Before a [MetadataRouter](../routers/metadatarouter.mdx) | +| **Mandatory init variables** | `questions`: The questions to answer for every document, keyed by question ID

`api_key`: The TypeSafe API key. Can be set with the `TYPESAFE_API_KEY` env var. | +| **Mandatory run variables** | `documents`: A list of documents to classify | +| **Output variables** | `documents`: The classified documents, with the answers in their metadata

`failed_documents`: The documents that couldn't be classified | +| **API reference** | [TypeSafe](/reference/integrations-typesafe) | +| **GitHub link** | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/typesafe | +| **Package name** | `typesafe-haystack` | + +
+ +## Overview + +`TypeSafeDocumentClassifier` sends each document to a [TypeSafe](https://typesafe.ai) System One model and stores the answers in the document's metadata. System One models such as Jev don't generate text. They answer every question about a document in one request and return calibrated probabilities. + +Each question has one of three types: + +- `choice`: picks one label from `criteria`, a dict of label to description (or `None`). +- `score`: rates the text on the ordered levels in `criteria`, a list of level descriptions. +- `noul`: returns the probability that the yes/no question in `instructions` is true. + +You can write questions as dicts or use the `Choice`, `Score`, and `Noul` objects from the `typesafe-sdk` package. See the [TypeSafe documentation](https://docs.typesafe.ai/primitives) for the full question and answer format. + +The answers are stored under `meta["typesafe"]`, keyed by question ID. You can change the field name with `metadata_field`. The component classifies the document's `content` by default. To classify a metadata field instead, set `classification_field`. + +Documents without text to classify are returned in `failed_documents` with the reason in `meta["classification_error"]`. So are documents whose request failed, unless you set `raise_on_failure=True`, in which case the first failed request raises its error. + +Each document is sent as its own request. `max_workers` sets how many requests run at once, in both `run` and `run_async`. + +### Authentication + +The component reads the API key from the `TYPESAFE_API_KEY` environment variable by default. You can also pass it at initialization with `api_key`: + +```python +from haystack.utils import Secret +from haystack_integrations.components.classifiers.typesafe import ( + TypeSafeDocumentClassifier, +) + +classifier = TypeSafeDocumentClassifier( + questions={ + "refund": { + "type": "noul", + "instructions": "Is the customer asking for a refund?", + } + }, + api_key=Secret.from_token(""), +) +``` + +### Running models locally with Ollaya + +The component works with any server that implements the TypeSafe API, such as [Ollaya](https://ollaya.dev), which runs open decision models on your own machine. Set `api_base_url` to the server and `model` to one of its models. Ollaya accepts any non-empty API key unless it is configured with one. + +```shell +docker run -d --name ollaya -p 11435:11435 -v ollaya:/home/ollaya/.ollaya ghcr.io/ollaya-dev/ollaya +docker exec ollaya ollaya pull laya:en +``` + +```python +from haystack.utils import Secret +from haystack_integrations.components.classifiers.typesafe import ( + TypeSafeDocumentClassifier, +) + +classifier = TypeSafeDocumentClassifier( + questions={ + "refund": { + "type": "noul", + "instructions": "Is the customer asking for a refund?", + } + }, + model="laya:en", + api_key=Secret.from_token("local"), + api_base_url="http://localhost:11435", +) +``` + +## Usage + +Install the `typesafe-haystack` package to use the `TypeSafeDocumentClassifier`: + +```shell +pip install typesafe-haystack +``` + +### On its own + +```python +from haystack import Document +from haystack_integrations.components.classifiers.typesafe import ( + TypeSafeDocumentClassifier, +) + +classifier = TypeSafeDocumentClassifier( + questions={ + "department": { + "type": "choice", + "instructions": "Which department should handle this ticket?", + "criteria": {"billing": None, "technical": None, "sales": None}, + }, + "urgency": { + "type": "score", + "instructions": "How urgent is this ticket?", + "criteria": ["can wait", "this week", "today"], + }, + "refund": { + "type": "noul", + "instructions": "Is the customer asking for a refund?", + }, + }, +) + +result = classifier.run( + documents=[Document(content="I was charged twice, please refund me today.")] +) +print(result["documents"][0].meta["typesafe"]) +# {'department': {'type': 'choice', 'choice': 'billing', 'confidence': 0.9516, +# 'probabilities': {'billing': 0.9677, 'technical': 0.0221, 'sales': 0.0102}}, +# 'urgency': {'type': 'score', 'score': 1.948, 'confidence': 0.9389, +# 'legend': {'0': 'can wait', '1': 'this week', '2': 'today'}, +# 'probabilities': {'0': 0.0113, '1': 0.0295, '2': 0.9593}}, +# 'refund': {'type': 'noul', 'noul': 0.9498}} +``` + +### In a pipeline + +The following pipeline classifies support tickets by department and sends each one to a different output of a `MetadataRouter`, which matches on the nested answer field: + +```python +from haystack import Document, Pipeline +from haystack.components.routers import MetadataRouter +from haystack_integrations.components.classifiers.typesafe import ( + TypeSafeDocumentClassifier, +) + +labels = ["billing", "technical"] + +pipeline = Pipeline() +pipeline.add_component( + "classifier", + TypeSafeDocumentClassifier( + questions={ + "department": { + "type": "choice", + "instructions": "Which department should handle this ticket?", + "criteria": dict.fromkeys(labels), + } + }, + ), +) +pipeline.add_component( + "router", + MetadataRouter( + rules={ + label: { + "field": "meta.typesafe.department.choice", + "operator": "==", + "value": label, + } + for label in labels + } + ), +) +pipeline.connect("classifier.documents", "router.documents") + +result = pipeline.run( + { + "classifier": { + "documents": [ + Document(content="I was charged twice for my subscription."), + Document( + content="The app crashes every time I open the settings page." + ), + ] + } + } +) +print( + { + output: [document.content for document in documents] + for output, documents in result["router"].items() + } +) +# {'billing': ['I was charged twice for my subscription.'], +# 'technical': ['The app crashes every time I open the settings page.'], +# 'unmatched': []} +``` diff --git a/docs-website/docs/pipeline-components/routers.mdx b/docs-website/docs/pipeline-components/routers.mdx index 3a7459869c..4d4c16b185 100644 --- a/docs-website/docs/pipeline-components/routers.mdx +++ b/docs-website/docs/pipeline-components/routers.mdx @@ -19,4 +19,5 @@ Routers is a group of components that route queries or documents to other compon | [MetadataRouter](routers/metadatarouter.mdx) | Routes documents based on their metadata field values. | | [TextLanguageRouter](routers/textlanguagerouter.mdx) | Routes queries based on their language. | | [TransformersTextRouter](routers/transformerstextrouter.mdx) | Routes text input to various output connections based on a model-defined categorization label. | -| [TransformersZeroShotTextRouter](routers/transformerszeroshottextrouter.mdx) | Routes text input to various output connections based on user-defined categorization label. | \ No newline at end of file +| [TransformersZeroShotTextRouter](routers/transformerszeroshottextrouter.mdx) | Routes text input to various output connections based on user-defined categorization label. | +| [TypeSafeTextRouter](routers/typesafetextrouter.mdx) | Routes text input to the output of the label a TypeSafe System One model picks for it. | diff --git a/docs-website/docs/pipeline-components/routers/typesafetextrouter.mdx b/docs-website/docs/pipeline-components/routers/typesafetextrouter.mdx new file mode 100644 index 0000000000..0dc236c60a --- /dev/null +++ b/docs-website/docs/pipeline-components/routers/typesafetextrouter.mdx @@ -0,0 +1,146 @@ +--- +title: "TypeSafeTextRouter" +id: typesafetextrouter +slug: "/typesafetextrouter" +description: "Routes a text to the output of the label a TypeSafe System One model, such as Jev, picks for it." +--- + +# TypeSafeTextRouter + +Routes a text to the output of the label a TypeSafe System One model, such as Jev, picks for it. + +
+ +| | | +| --- | --- | +| **Most common position in a pipeline** | Flexible | +| **Mandatory init variables** | `labels`: The labels to route between

`api_key`: The TypeSafe API key. Can be set with the `TYPESAFE_API_KEY` env var. | +| **Mandatory run variables** | `text`: The text to route | +| **Output variables** | `
+ +## Overview + +`TypeSafeTextRouter` asks a [TypeSafe](https://typesafe.ai) System One model a single `choice` question over `labels` and sends the text to the output of the label it picks. System One models such as Jev don't generate text. They answer in one request and return calibrated probabilities. + +Pass `labels` as a list of label names, or as a dict of label to description to tell the model what each label means. `instructions` sets the question the model answers, for example "Which team should handle this support request?". + +When you set `min_confidence`, the component gets an extra `low_confidence` output. Texts whose answer has a `confidence` below the threshold go there instead, so you can send uncertain texts to a fallback such as an LLM or a human. Good thresholds depend on the model and the labels, so pick one based on your own data. See TypeSafe's guide to [confidence-gated routing](https://docs.typesafe.ai/patterns/confidence-routing). + +### Authentication + +The component reads the API key from the `TYPESAFE_API_KEY` environment variable by default. You can also pass it at initialization with `api_key`: + +```python +from haystack.utils import Secret +from haystack_integrations.components.routers.typesafe import TypeSafeTextRouter + +router = TypeSafeTextRouter( + labels=["billing", "technical"], api_key=Secret.from_token("") +) +``` + +### Running models locally with Ollaya + +The component works with any server that implements the TypeSafe API, such as [Ollaya](https://ollaya.dev), which runs open decision models on your own machine. Set `api_base_url` to the server and `model` to one of its models. Ollaya accepts any non-empty API key unless it is configured with one. + +```shell +docker run -d --name ollaya -p 11435:11435 -v ollaya:/home/ollaya/.ollaya ghcr.io/ollaya-dev/ollaya +docker exec ollaya ollaya pull laya:en +``` + +```python +from haystack.utils import Secret +from haystack_integrations.components.routers.typesafe import TypeSafeTextRouter + +router = TypeSafeTextRouter( + labels=["billing", "technical"], + model="laya:en", + api_key=Secret.from_token("local"), + api_base_url="http://localhost:11435", +) +``` + +## Usage + +Install the `typesafe-haystack` package to use the `TypeSafeTextRouter`: + +```shell +pip install typesafe-haystack +``` + +### On its own + +```python +from haystack_integrations.components.routers.typesafe import TypeSafeTextRouter + +router = TypeSafeTextRouter( + labels={ + "billing": "Payments, invoices, refunds and charges", + "technical": "Bugs, crashes and errors in the product", + }, + instructions="Which team should handle this support request?", + min_confidence=0.6, +) + +print(router.run(text="I was charged twice for my subscription.")) +# {'billing': 'I was charged twice for my subscription.'} +``` + +### In a pipeline + +The following pipeline routes a support question to the help articles of the team that handles it. Each label's output goes to its own retriever: + +```python +from haystack import Document, Pipeline +from haystack.components.retrievers.in_memory import InMemoryBM25Retriever +from haystack.document_stores.in_memory import InMemoryDocumentStore +from haystack_integrations.components.routers.typesafe import TypeSafeTextRouter + +billing_store = InMemoryDocumentStore() +billing_store.write_documents( + [ + Document( + content="If you were charged twice, contact support and we refund the duplicate charge within 5 business days." + ) + ] +) +technical_store = InMemoryDocumentStore() +technical_store.write_documents( + [ + Document( + content="If the app crashes on startup, update to the latest version and clear the app cache." + ) + ] +) + +pipeline = Pipeline() +pipeline.add_component( + "router", + TypeSafeTextRouter( + labels={ + "billing": "Payments, invoices, refunds and charges", + "technical": "Bugs, crashes and errors in the product", + }, + instructions="Which team should handle this support request?", + ), +) +pipeline.add_component( + "billing_retriever", InMemoryBM25Retriever(document_store=billing_store) +) +pipeline.add_component( + "technical_retriever", InMemoryBM25Retriever(document_store=technical_store) +) +pipeline.connect("router.billing", "billing_retriever.query") +pipeline.connect("router.technical", "technical_retriever.query") + +result = pipeline.run( + {"router": {"text": "I was charged twice, how do I get my money back?"}} +) +print(result["billing_retriever"]["documents"][0].content) +# If you were charged twice, contact support and we refund the duplicate charge within 5 business days. +``` diff --git a/docs-website/sidebars.js b/docs-website/sidebars.js index 7776cc885f..fae56d2f42 100644 --- a/docs-website/sidebars.js +++ b/docs-website/sidebars.js @@ -246,6 +246,7 @@ export default { items: [ 'pipeline-components/classifiers/documentlanguageclassifier', 'pipeline-components/classifiers/transformerszeroshotdocumentclassifier', + 'pipeline-components/classifiers/typesafedocumentclassifier', ], }, { @@ -685,6 +686,7 @@ export default { 'pipeline-components/routers/textlanguagerouter', 'pipeline-components/routers/transformerstextrouter', 'pipeline-components/routers/transformerszeroshottextrouter', + 'pipeline-components/routers/typesafetextrouter', ], }, { diff --git a/docs-website/versioned_docs/version-3.3/pipeline-components/classifiers.mdx b/docs-website/versioned_docs/version-3.3/pipeline-components/classifiers.mdx index fc4a76d637..0f534161f1 100644 --- a/docs-website/versioned_docs/version-3.3/pipeline-components/classifiers.mdx +++ b/docs-website/versioned_docs/version-3.3/pipeline-components/classifiers.mdx @@ -13,3 +13,4 @@ Use Classifiers to classify your documents by specific traits and update the met | --- | --- | | [DocumentLanguageClassifier](classifiers/documentlanguageclassifier.mdx) | Classify documents by language. | | [TransformersZeroShotDocumentClassifier](classifiers/transformerszeroshotdocumentclassifier.mdx) | Classify the documents based on the provided labels. | +| [TypeSafeDocumentClassifier](classifiers/typesafedocumentclassifier.mdx) | Answer typed questions about documents with a TypeSafe System One model and store the answers in their metadata. | diff --git a/docs-website/versioned_docs/version-3.3/pipeline-components/classifiers/typesafedocumentclassifier.mdx b/docs-website/versioned_docs/version-3.3/pipeline-components/classifiers/typesafedocumentclassifier.mdx new file mode 100644 index 0000000000..ade1ff4081 --- /dev/null +++ b/docs-website/versioned_docs/version-3.3/pipeline-components/classifiers/typesafedocumentclassifier.mdx @@ -0,0 +1,202 @@ +--- +title: "TypeSafeDocumentClassifier" +id: typesafedocumentclassifier +slug: "/typesafedocumentclassifier" +description: "Answers typed questions about each document with a TypeSafe System One model, such as Jev, and stores the answers in its metadata." +--- + +# TypeSafeDocumentClassifier + +Answers typed questions about each document with a TypeSafe System One model, such as Jev, and stores the answers in its metadata. + +
+ +| | | +| --- | --- | +| **Most common position in a pipeline** | Before a [MetadataRouter](../routers/metadatarouter.mdx) | +| **Mandatory init variables** | `questions`: The questions to answer for every document, keyed by question ID

`api_key`: The TypeSafe API key. Can be set with the `TYPESAFE_API_KEY` env var. | +| **Mandatory run variables** | `documents`: A list of documents to classify | +| **Output variables** | `documents`: The classified documents, with the answers in their metadata

`failed_documents`: The documents that couldn't be classified | +| **API reference** | [TypeSafe](/reference/integrations-typesafe) | +| **GitHub link** | https://github.com/deepset-ai/haystack-core-integrations/tree/main/integrations/typesafe | +| **Package name** | `typesafe-haystack` | + +
+ +## Overview + +`TypeSafeDocumentClassifier` sends each document to a [TypeSafe](https://typesafe.ai) System One model and stores the answers in the document's metadata. System One models such as Jev don't generate text. They answer every question about a document in one request and return calibrated probabilities. + +Each question has one of three types: + +- `choice`: picks one label from `criteria`, a dict of label to description (or `None`). +- `score`: rates the text on the ordered levels in `criteria`, a list of level descriptions. +- `noul`: returns the probability that the yes/no question in `instructions` is true. + +You can write questions as dicts or use the `Choice`, `Score`, and `Noul` objects from the `typesafe-sdk` package. See the [TypeSafe documentation](https://docs.typesafe.ai/primitives) for the full question and answer format. + +The answers are stored under `meta["typesafe"]`, keyed by question ID. You can change the field name with `metadata_field`. The component classifies the document's `content` by default. To classify a metadata field instead, set `classification_field`. + +Documents without text to classify are returned in `failed_documents` with the reason in `meta["classification_error"]`. So are documents whose request failed, unless you set `raise_on_failure=True`, in which case the first failed request raises its error. + +Each document is sent as its own request. `max_workers` sets how many requests run at once, in both `run` and `run_async`. + +### Authentication + +The component reads the API key from the `TYPESAFE_API_KEY` environment variable by default. You can also pass it at initialization with `api_key`: + +```python +from haystack.utils import Secret +from haystack_integrations.components.classifiers.typesafe import ( + TypeSafeDocumentClassifier, +) + +classifier = TypeSafeDocumentClassifier( + questions={ + "refund": { + "type": "noul", + "instructions": "Is the customer asking for a refund?", + } + }, + api_key=Secret.from_token(""), +) +``` + +### Running models locally with Ollaya + +The component works with any server that implements the TypeSafe API, such as [Ollaya](https://ollaya.dev), which runs open decision models on your own machine. Set `api_base_url` to the server and `model` to one of its models. Ollaya accepts any non-empty API key unless it is configured with one. + +```shell +docker run -d --name ollaya -p 11435:11435 -v ollaya:/home/ollaya/.ollaya ghcr.io/ollaya-dev/ollaya +docker exec ollaya ollaya pull laya:en +``` + +```python +from haystack.utils import Secret +from haystack_integrations.components.classifiers.typesafe import ( + TypeSafeDocumentClassifier, +) + +classifier = TypeSafeDocumentClassifier( + questions={ + "refund": { + "type": "noul", + "instructions": "Is the customer asking for a refund?", + } + }, + model="laya:en", + api_key=Secret.from_token("local"), + api_base_url="http://localhost:11435", +) +``` + +## Usage + +Install the `typesafe-haystack` package to use the `TypeSafeDocumentClassifier`: + +```shell +pip install typesafe-haystack +``` + +### On its own + +```python +from haystack import Document +from haystack_integrations.components.classifiers.typesafe import ( + TypeSafeDocumentClassifier, +) + +classifier = TypeSafeDocumentClassifier( + questions={ + "department": { + "type": "choice", + "instructions": "Which department should handle this ticket?", + "criteria": {"billing": None, "technical": None, "sales": None}, + }, + "urgency": { + "type": "score", + "instructions": "How urgent is this ticket?", + "criteria": ["can wait", "this week", "today"], + }, + "refund": { + "type": "noul", + "instructions": "Is the customer asking for a refund?", + }, + }, +) + +result = classifier.run( + documents=[Document(content="I was charged twice, please refund me today.")] +) +print(result["documents"][0].meta["typesafe"]) +# {'department': {'type': 'choice', 'choice': 'billing', 'confidence': 0.9516, +# 'probabilities': {'billing': 0.9677, 'technical': 0.0221, 'sales': 0.0102}}, +# 'urgency': {'type': 'score', 'score': 1.948, 'confidence': 0.9389, +# 'legend': {'0': 'can wait', '1': 'this week', '2': 'today'}, +# 'probabilities': {'0': 0.0113, '1': 0.0295, '2': 0.9593}}, +# 'refund': {'type': 'noul', 'noul': 0.9498}} +``` + +### In a pipeline + +The following pipeline classifies support tickets by department and sends each one to a different output of a `MetadataRouter`, which matches on the nested answer field: + +```python +from haystack import Document, Pipeline +from haystack.components.routers import MetadataRouter +from haystack_integrations.components.classifiers.typesafe import ( + TypeSafeDocumentClassifier, +) + +labels = ["billing", "technical"] + +pipeline = Pipeline() +pipeline.add_component( + "classifier", + TypeSafeDocumentClassifier( + questions={ + "department": { + "type": "choice", + "instructions": "Which department should handle this ticket?", + "criteria": dict.fromkeys(labels), + } + }, + ), +) +pipeline.add_component( + "router", + MetadataRouter( + rules={ + label: { + "field": "meta.typesafe.department.choice", + "operator": "==", + "value": label, + } + for label in labels + } + ), +) +pipeline.connect("classifier.documents", "router.documents") + +result = pipeline.run( + { + "classifier": { + "documents": [ + Document(content="I was charged twice for my subscription."), + Document( + content="The app crashes every time I open the settings page." + ), + ] + } + } +) +print( + { + output: [document.content for document in documents] + for output, documents in result["router"].items() + } +) +# {'billing': ['I was charged twice for my subscription.'], +# 'technical': ['The app crashes every time I open the settings page.'], +# 'unmatched': []} +``` diff --git a/docs-website/versioned_docs/version-3.3/pipeline-components/routers.mdx b/docs-website/versioned_docs/version-3.3/pipeline-components/routers.mdx index 3a7459869c..4d4c16b185 100644 --- a/docs-website/versioned_docs/version-3.3/pipeline-components/routers.mdx +++ b/docs-website/versioned_docs/version-3.3/pipeline-components/routers.mdx @@ -19,4 +19,5 @@ Routers is a group of components that route queries or documents to other compon | [MetadataRouter](routers/metadatarouter.mdx) | Routes documents based on their metadata field values. | | [TextLanguageRouter](routers/textlanguagerouter.mdx) | Routes queries based on their language. | | [TransformersTextRouter](routers/transformerstextrouter.mdx) | Routes text input to various output connections based on a model-defined categorization label. | -| [TransformersZeroShotTextRouter](routers/transformerszeroshottextrouter.mdx) | Routes text input to various output connections based on user-defined categorization label. | \ No newline at end of file +| [TransformersZeroShotTextRouter](routers/transformerszeroshottextrouter.mdx) | Routes text input to various output connections based on user-defined categorization label. | +| [TypeSafeTextRouter](routers/typesafetextrouter.mdx) | Routes text input to the output of the label a TypeSafe System One model picks for it. | diff --git a/docs-website/versioned_docs/version-3.3/pipeline-components/routers/typesafetextrouter.mdx b/docs-website/versioned_docs/version-3.3/pipeline-components/routers/typesafetextrouter.mdx new file mode 100644 index 0000000000..0dc236c60a --- /dev/null +++ b/docs-website/versioned_docs/version-3.3/pipeline-components/routers/typesafetextrouter.mdx @@ -0,0 +1,146 @@ +--- +title: "TypeSafeTextRouter" +id: typesafetextrouter +slug: "/typesafetextrouter" +description: "Routes a text to the output of the label a TypeSafe System One model, such as Jev, picks for it." +--- + +# TypeSafeTextRouter + +Routes a text to the output of the label a TypeSafe System One model, such as Jev, picks for it. + +
+ +| | | +| --- | --- | +| **Most common position in a pipeline** | Flexible | +| **Mandatory init variables** | `labels`: The labels to route between

`api_key`: The TypeSafe API key. Can be set with the `TYPESAFE_API_KEY` env var. | +| **Mandatory run variables** | `text`: The text to route | +| **Output variables** | `
+ +## Overview + +`TypeSafeTextRouter` asks a [TypeSafe](https://typesafe.ai) System One model a single `choice` question over `labels` and sends the text to the output of the label it picks. System One models such as Jev don't generate text. They answer in one request and return calibrated probabilities. + +Pass `labels` as a list of label names, or as a dict of label to description to tell the model what each label means. `instructions` sets the question the model answers, for example "Which team should handle this support request?". + +When you set `min_confidence`, the component gets an extra `low_confidence` output. Texts whose answer has a `confidence` below the threshold go there instead, so you can send uncertain texts to a fallback such as an LLM or a human. Good thresholds depend on the model and the labels, so pick one based on your own data. See TypeSafe's guide to [confidence-gated routing](https://docs.typesafe.ai/patterns/confidence-routing). + +### Authentication + +The component reads the API key from the `TYPESAFE_API_KEY` environment variable by default. You can also pass it at initialization with `api_key`: + +```python +from haystack.utils import Secret +from haystack_integrations.components.routers.typesafe import TypeSafeTextRouter + +router = TypeSafeTextRouter( + labels=["billing", "technical"], api_key=Secret.from_token("") +) +``` + +### Running models locally with Ollaya + +The component works with any server that implements the TypeSafe API, such as [Ollaya](https://ollaya.dev), which runs open decision models on your own machine. Set `api_base_url` to the server and `model` to one of its models. Ollaya accepts any non-empty API key unless it is configured with one. + +```shell +docker run -d --name ollaya -p 11435:11435 -v ollaya:/home/ollaya/.ollaya ghcr.io/ollaya-dev/ollaya +docker exec ollaya ollaya pull laya:en +``` + +```python +from haystack.utils import Secret +from haystack_integrations.components.routers.typesafe import TypeSafeTextRouter + +router = TypeSafeTextRouter( + labels=["billing", "technical"], + model="laya:en", + api_key=Secret.from_token("local"), + api_base_url="http://localhost:11435", +) +``` + +## Usage + +Install the `typesafe-haystack` package to use the `TypeSafeTextRouter`: + +```shell +pip install typesafe-haystack +``` + +### On its own + +```python +from haystack_integrations.components.routers.typesafe import TypeSafeTextRouter + +router = TypeSafeTextRouter( + labels={ + "billing": "Payments, invoices, refunds and charges", + "technical": "Bugs, crashes and errors in the product", + }, + instructions="Which team should handle this support request?", + min_confidence=0.6, +) + +print(router.run(text="I was charged twice for my subscription.")) +# {'billing': 'I was charged twice for my subscription.'} +``` + +### In a pipeline + +The following pipeline routes a support question to the help articles of the team that handles it. Each label's output goes to its own retriever: + +```python +from haystack import Document, Pipeline +from haystack.components.retrievers.in_memory import InMemoryBM25Retriever +from haystack.document_stores.in_memory import InMemoryDocumentStore +from haystack_integrations.components.routers.typesafe import TypeSafeTextRouter + +billing_store = InMemoryDocumentStore() +billing_store.write_documents( + [ + Document( + content="If you were charged twice, contact support and we refund the duplicate charge within 5 business days." + ) + ] +) +technical_store = InMemoryDocumentStore() +technical_store.write_documents( + [ + Document( + content="If the app crashes on startup, update to the latest version and clear the app cache." + ) + ] +) + +pipeline = Pipeline() +pipeline.add_component( + "router", + TypeSafeTextRouter( + labels={ + "billing": "Payments, invoices, refunds and charges", + "technical": "Bugs, crashes and errors in the product", + }, + instructions="Which team should handle this support request?", + ), +) +pipeline.add_component( + "billing_retriever", InMemoryBM25Retriever(document_store=billing_store) +) +pipeline.add_component( + "technical_retriever", InMemoryBM25Retriever(document_store=technical_store) +) +pipeline.connect("router.billing", "billing_retriever.query") +pipeline.connect("router.technical", "technical_retriever.query") + +result = pipeline.run( + {"router": {"text": "I was charged twice, how do I get my money back?"}} +) +print(result["billing_retriever"]["documents"][0].content) +# If you were charged twice, contact support and we refund the duplicate charge within 5 business days. +``` diff --git a/docs-website/versioned_sidebars/version-3.3-sidebars.json b/docs-website/versioned_sidebars/version-3.3-sidebars.json index 7b4c9e6635..41979fc0ac 100644 --- a/docs-website/versioned_sidebars/version-3.3-sidebars.json +++ b/docs-website/versioned_sidebars/version-3.3-sidebars.json @@ -241,7 +241,8 @@ }, "items": [ "pipeline-components/classifiers/documentlanguageclassifier", - "pipeline-components/classifiers/transformerszeroshotdocumentclassifier" + "pipeline-components/classifiers/transformerszeroshotdocumentclassifier", + "pipeline-components/classifiers/typesafedocumentclassifier" ] }, { @@ -680,7 +681,8 @@ "pipeline-components/routers/metadatarouter", "pipeline-components/routers/textlanguagerouter", "pipeline-components/routers/transformerstextrouter", - "pipeline-components/routers/transformerszeroshottextrouter" + "pipeline-components/routers/transformerszeroshottextrouter", + "pipeline-components/routers/typesafetextrouter" ] }, {