# AzureGroundednessMiddleware

> **Class** in `langchain_azure_ai`

📖 [View in docs](https://reference.langchain.com/python/langchain-azure-ai/agents/middleware/content_safety/_groundedness/AzureGroundednessMiddleware)

AgentMiddleware that evaluates groundedness of model outputs.

Groundedness detection analyses language model outputs to determine whether
they are factually aligned with user-provided information or contain
fictional/hallucinated content.

The middleware runs as an ``after_model`` hook — it evaluates every model
response immediately after generation.  The behaviour when ungrounded
content is detected depends on ``exit_behavior``:

* ``"error"`` (default) – raises :exc:`ContentSafetyViolationError`,
  halting the graph.  The exception carries the evaluation details.
* ``"continue"`` – annotates the state with a ``groundedness_evaluation``
  key containing the evaluation results and lets execution proceed.

In both modes the state is annotated with the evaluation result so callers
can inspect it.

**Grounding sources** are collected automatically from the chat history by
default:

* ``SystemMessage`` content – the system prompt often contains the
  authoritative context the model should stay grounded in.
* ``ToolMessage`` content – tool / function-call results such as RAG
  retrieval chunks, web-search snippets, or database lookups.
* ``AIMessage`` annotation titles – citation metadata attached to model
  responses (e.g. ``url_citation`` annotations from web-search grounding).

You can override the extraction logic by supplying a ``context_extractor``
callable.  It receives the current graph state and the LangGraph
:class:`~langchain.agents.middleware.Runtime` execution context, and must
return a :class:`GroundednessInput` (or ``None`` to skip evaluation
entirely) containing the answer to evaluate, the grounding sources, and
(for ``task="QnA"``) the question::

```python
from langchain_azure_ai.agents.middleware import (
    AzureGroundednessMiddleware,
    GroundednessInput,
)

def my_extractor(state, runtime):
    # ``runtime`` is the LangGraph Runtime object — use it to access
    # the user-defined context, memory store, stream writer, etc.
    return GroundednessInput(
        answer=state["custom_answer"],
        sources=state["retrieved_chunks"],
        question=state.get("user_question"),
    )

middleware = AzureGroundednessMiddleware(
    context_extractor=my_extractor,
    task="QnA",
)
```

After the model runs (in ``continue`` mode), the state will contain a
``groundedness_evaluation`` key with the evaluation results::

```json
{
    "is_grounded": True,
    "ungrounded_percentage": 0.0,
    "details": []
}
```

## Signature

```python
AzureGroundednessMiddleware(
    self,
    endpoint: Optional[str] = None,
    credential: Optional[Any] = None,
    *,
    project_endpoint: Optional[str] = None,
    domain: Literal['Generic', 'Medical'] = 'Generic',
    task: Literal['Summarization', 'QnA'] = 'Summarization',
    exit_behavior: Literal['error', 'continue'] = 'error',
    name: str = 'azure_groundedness',
    context_extractor: Optional[Callable[[AgentState[Any], Runtime[Any]], Optional[GroundednessInput]]] = None,
)
```

## Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `endpoint` | `Optional[str]` | No | Azure Content Safety resource endpoint URL.  Falls back to the ``AZURE_CONTENT_SAFETY_ENDPOINT`` environment variable. Mutually exclusive with ``project_endpoint``. (default: `None`) |
| `credential` | `Optional[Any]` | No | Azure credential.  Accepts a :class:`~azure.core.credentials.TokenCredential`, :class:`~azure.core.credentials.AzureKeyCredential`, or a plain API-key string.  Defaults to :class:`~azure.identity.DefaultAzureCredential` when ``None``. (default: `None`) |
| `project_endpoint` | `Optional[str]` | No | Azure AI Foundry project endpoint URL (e.g. ``https://<resource>.services.ai.azure.com/api/projects/<project>``). Falls back to the ``AZURE_AI_PROJECT_ENDPOINT`` environment variable. Mutually exclusive with ``endpoint``. (default: `None`) |
| `domain` | `Literal['Generic', 'Medical']` | No | The domain of the text for analysis.  ``"Generic"`` (default) or ``"Medical"``. (default: `'Generic'`) |
| `task` | `Literal['Summarization', 'QnA']` | No | The task type for the analysis.  ``"Summarization"`` (default) or ``"QnA"``. (default: `'Summarization'`) |
| `exit_behavior` | `Literal['error', 'continue']` | No | What to do when ungrounded content is detected.  One of ``"error"`` (default) or ``"continue"``. (default: `'error'`) |
| `name` | `str` | No | Node-name prefix used when wiring this middleware into a LangGraph.  Defaults to ``"azure_groundedness"``. (default: `'azure_groundedness'`) |
| `context_extractor` | `Optional[Callable[[AgentState[Any], Runtime[Any]], Optional[GroundednessInput]]]` | No | Optional callable with signature ``(state, runtime) -> Optional[GroundednessInput]`` that receives the current graph state and the LangGraph :class:`~langchain.agents.middleware.Runtime` execution context, and returns the answer, grounding sources, and optional question to evaluate, or ``None`` to skip evaluation entirely.  When ``None`` (default) the middleware uses its built-in extraction logic. (default: `None`) |

## Extends

- `_AzureContentSafetyBaseMiddleware`

## Constructors

```python
__init__(
    self,
    endpoint: Optional[str] = None,
    credential: Optional[Any] = None,
    *,
    project_endpoint: Optional[str] = None,
    domain: Literal['Generic', 'Medical'] = 'Generic',
    task: Literal['Summarization', 'QnA'] = 'Summarization',
    exit_behavior: Literal['error', 'continue'] = 'error',
    name: str = 'azure_groundedness',
    context_extractor: Optional[Callable[[AgentState[Any], Runtime[Any]], Optional[GroundednessInput]]] = None,
) -> None
```

| Name | Type |
|------|------|
| `endpoint` | `Optional[str]` |
| `credential` | `Optional[Any]` |
| `project_endpoint` | `Optional[str]` |
| `domain` | `Literal['Generic', 'Medical']` |
| `task` | `Literal['Summarization', 'QnA']` |
| `exit_behavior` | `Literal['error', 'continue']` |
| `name` | `str` |
| `context_extractor` | `Optional[Callable[[AgentState[Any], Runtime[Any]], Optional[GroundednessInput]]]` |


## Properties

- `state_schema`

## Methods

- [`get_annotation_from_evaluations()`](https://reference.langchain.com/python/langchain-azure-ai/agents/middleware/content_safety/_groundedness/AzureGroundednessMiddleware/get_annotation_from_evaluations)
- [`get_evaluation_response()`](https://reference.langchain.com/python/langchain-azure-ai/agents/middleware/content_safety/_groundedness/AzureGroundednessMiddleware/get_evaluation_response)
- [`after_model()`](https://reference.langchain.com/python/langchain-azure-ai/agents/middleware/content_safety/_groundedness/AzureGroundednessMiddleware/after_model)
- [`aafter_model()`](https://reference.langchain.com/python/langchain-azure-ai/agents/middleware/content_safety/_groundedness/AzureGroundednessMiddleware/aafter_model)

---

[View source on GitHub](https://github.com/langchain-ai/langchain-azure/blob/7a6a664d617264df8dcb12fcfb1bacc09f21d504/libs/azure-ai/langchain_azure_ai/agents/middleware/content_safety/_groundedness.py#L61)