# RubricMiddleware

> **Class** in `deepagents`

📖 [View in docs](https://reference.langchain.com/python/deepagents/middleware/rubric/RubricMiddleware)

Middleware that drives self-evaluated iteration against a rubric.

The middleware activates only when a caller passes a `rubric` on
invocation state. With no rubric, both `before_agent` and `after_agent`
return without modifying state, so the middleware is safe to include
unconditionally in a `create_deep_agent` stack.

!!! note "Observing non-satisfied terminations"
    When grading ends with `failed`, `max_iterations_reached`, or
    `grader_error`, the middleware does **not** mutate the response
    messages. The last `AIMessage` in the agent's output is whatever
    the model produced just before the grader gave up. Callers who
    need to branch on non-satisfied termination must inspect one of:

    - `_rubric_status` on the returned state (or `agent.get_state(...)`
      on a checkpointed thread),
    - the `on_evaluation` callback,
    - the `rubric_evaluation_end` stream event.

    A `logger.warning` is also emitted when `max_iterations_reached`
    fires.

## Signature

```python
RubricMiddleware(
    self,
    *,
    model: str | BaseChatModel,
    system_prompt: str | None = None,
    tools: Sequence[BaseTool] | None = None,
    max_iterations: int = 3,
    on_evaluation: Callable[[RubricEvaluation], None] | None = None,
)
```

## Parameters

| Name | Type | Required | Description |
|------|------|----------|-------------|
| `model` | `str \| BaseChatModel` | Yes | Model used by the grader sub-agent. Accepts either a model string like `"provider:model-id"` or a `BaseChatModel` instance. |
| `system_prompt` | `str \| None` | No | Custom grading instructions; falls back to the built-in grader prompt when not set. (default: `None`) |
| `tools` | `Sequence[BaseTool] \| None` | No | Tools the grader may call before producing its `GraderResponse`. With none, the grader reasons from the transcript alone. (default: `None`) |
| `max_iterations` | `int` | No | Hard cap on grader iterations per rubric attempt; hard-capped at 20. When the cap is reached without a `satisfied` verdict, the agent terminates with status `'max_iterations_reached'` (see the note above on how to observe this). (default: `3`) |
| `on_evaluation` | `Callable[[RubricEvaluation], None] \| None` | No | Optional callback one can invoke with each `RubricEvaluation` after grading. Exceptions raised by the callback are logged at error level and suppressed; do not use this callback to enforce control flow. (default: `None`) |

## Extends

- `AgentMiddleware[RubricState, ContextT, ResponseT]`

## Constructors

```python
__init__(
    self,
    *,
    model: str | BaseChatModel,
    system_prompt: str | None = None,
    tools: Sequence[BaseTool] | None = None,
    max_iterations: int = 3,
    on_evaluation: Callable[[RubricEvaluation], None] | None = None,
) -> None
```

| Name | Type |
|------|------|
| `model` | `str \| BaseChatModel` |
| `system_prompt` | `str \| None` |
| `tools` | `Sequence[BaseTool] \| None` |
| `max_iterations` | `int` |
| `on_evaluation` | `Callable[[RubricEvaluation], None] \| None` |


## Properties

- `state_schema`
- `max_iterations`

## Methods

- [`before_agent()`](https://reference.langchain.com/python/deepagents/middleware/rubric/RubricMiddleware/before_agent)
- [`abefore_agent()`](https://reference.langchain.com/python/deepagents/middleware/rubric/RubricMiddleware/abefore_agent)
- [`after_agent()`](https://reference.langchain.com/python/deepagents/middleware/rubric/RubricMiddleware/after_agent)
- [`aafter_agent()`](https://reference.langchain.com/python/deepagents/middleware/rubric/RubricMiddleware/aafter_agent)

---

[View source on GitHub](https://github.com/langchain-ai/deepagents/blob/d1c6946218b4f0f86ab7b02b6bb6af1e4b75cede/libs/deepagents/deepagents/middleware/rubric.py#L296)