Skip to content
Open
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
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ Intrinsics are specialized LoRA adapters that add task-specific capabilities (RA
| `rag` | `rewrite_question(question, context, backend)` | Rewrite question into a retrieval query |
| `rag` | `clarify_query(question, documents, context, backend)` | Generate clarification or return "CLEAR" |
| `rag` | `find_citations(response, documents, context, backend)` | Document sentences supporting the response |
| `rag` | `check_context_relevance(question, document, context, backend)` | Whether a document is relevant (0–1); only supported for granite-4.0, not granite-4.1 |
| `rag` | `check_context_relevance(question, document, context, backend)` | Whether a document is relevant; returns a string label (e.g. `'relevant'`, `'partially relevant'`, `'irrelevant'`) |
| `rag` | `flag_hallucinated_content(response, documents, context, backend)` | Flag potentially hallucinated sentences |

```python
Expand Down
29 changes: 19 additions & 10 deletions docs/docs/advanced/intrinsics.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ Set up the backend once and reuse it across intrinsic calls:
# Returns: LocalHFBackend
from mellea.backends.huggingface import LocalHFBackend

backend = LocalHFBackend(model_id="ibm-granite/granite-4.0-micro")
backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")
```

Or, with a Granite Switch model via the OpenAI backend:
Expand Down Expand Up @@ -61,7 +61,7 @@ from mellea.stdlib.components import Document, Message
from mellea.stdlib.components.intrinsic import rag
from mellea.stdlib.context import ChatContext

backend = LocalHFBackend(model_id="ibm-granite/granite-4.0-micro")
backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")
context = ChatContext().add(Message("assistant", "Hello! How can I help you?"))
question = "What is the square root of 4?"

Expand All @@ -78,13 +78,13 @@ Assess whether a document is relevant to a question:

```python
# Requires: mellea[hf]
# Returns: float
# Returns: str
from mellea.backends.huggingface import LocalHFBackend
from mellea.stdlib.components import Document
from mellea.stdlib.components.intrinsic import rag
from mellea.stdlib.context import ChatContext

backend = LocalHFBackend(model_id="ibm-granite/granite-4.0-micro")
backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")
context = ChatContext()
question = "Who is the CEO of Microsoft?"
document = Document(
Expand All @@ -93,7 +93,7 @@ document = Document(
)

result = rag.check_context_relevance(question, document, context, backend)
print(result) # False — the document does not mention the CEO
print(result) # 'partially relevant' — doc is about Microsoft but not its CEO
```

## Hallucination detection
Expand All @@ -108,7 +108,7 @@ from mellea.stdlib.components import Document, Message
from mellea.stdlib.components.intrinsic import rag
from mellea.stdlib.context import ChatContext

backend = LocalHFBackend(model_id="ibm-granite/granite-4.0-micro")
backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")
context = (
ChatContext()
.add(Message("assistant", "Hello! How can I help you?"))
Expand Down Expand Up @@ -137,7 +137,7 @@ from mellea.stdlib.components import Document, Message
from mellea.stdlib.components.intrinsic import rag
from mellea.stdlib.context import ChatContext

backend = LocalHFBackend(model_id="ibm-granite/granite-4.0-micro")
backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")
context = ChatContext().add(Message("user", "Who attended the meeting?"))
documents = [
Document("Meeting attendees: Alice, Bob, Carol."),
Expand All @@ -162,7 +162,7 @@ from mellea.stdlib.components import Message
from mellea.stdlib.components.intrinsic import rag
from mellea.stdlib.context import ChatContext

backend = LocalHFBackend(model_id="ibm-granite/granite-4.0-micro")
backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")
context = (
ChatContext()
.add(Message("assistant", "Welcome to pet questions!"))
Expand All @@ -189,7 +189,7 @@ from mellea.stdlib.components import Document, Message
from mellea.stdlib.components.intrinsic import rag
from mellea.stdlib.context import ChatContext

backend = LocalHFBackend(model_id="ibm-granite/granite-4.0-micro")
backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")
context = ChatContext().add(
Message("user", "How did Murdoch expand in Australia versus New Zealand?")
)
Expand Down Expand Up @@ -222,7 +222,7 @@ from mellea.backends.huggingface import LocalHFBackend
from mellea.stdlib.components import Intrinsic, Message
from mellea.stdlib.context import ChatContext

backend = LocalHFBackend(model_id="ibm-granite/granite-4.0-micro")
backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")

# Register an adapter by task name
req_adapter = CustomIntrinsicAdapter(
Expand Down Expand Up @@ -250,3 +250,12 @@ The `Intrinsic` component loads aLoRA adapters (falling back to LoRA) by task na
For OpenAI backends with Granite Switch, adapters are loaded from the model's
HuggingFace repository configuration instead of the intrinsic catalog.
Output format is task-specific — `requirement-check` returns a likelihood score.

---

## Guardian Intrinsics

Safety and factuality checks use a separate set of Guardian-specific intrinsics:
`guardian_check()`, `policy_guardrails()`, `factuality_detection()`, and
`factuality_correction()`. These are documented in the
[Safety Guardrails](../how-to/safety-guardrails) how-to guide.
9 changes: 8 additions & 1 deletion docs/docs/advanced/security-and-taint-tracking.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
---
title: "Security and Taint Tracking"
description: "Use GuardianCheck with IBM Granite Guardian to validate LLM outputs for safety risks."
description: "[Deprecated] GuardianCheck API for LLM output safety validation. Use Guardian Intrinsics instead."
# diataxis: how-to
---

> **Deprecated API.** The `GuardianCheck` class documented here is deprecated as
> of Mellea v0.4 and will emit `DeprecationWarning` on use. For new code, use the
> [Guardian Intrinsics](../how-to/safety-guardrails) — `guardian_check()`,
> `policy_guardrails()`, `factuality_detection()`, and `factuality_correction()` —
> which are faster, use a single Granite model instead of a separate Guardian model, and produce consistent
> structured output.

**Prerequisites:** [Instruct, Validate, Repair](../concepts/instruct-validate-repair)
complete, `pip install mellea`, Ollama running locally with a Granite Guardian model
pulled.
Expand Down
6 changes: 3 additions & 3 deletions docs/docs/concepts/architecture-vs-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,8 +135,8 @@ orchestrator:
with [`ChatContext`](../reference/glossary#chatcontext) and the `@tool` decorator. See
[Tools and Agents](../how-to/tools-and-agents).
- **Guarded agents** — combine the ReACT pattern with `requirements` and
`GuardianCheck` to enforce safety constraints at every step. See
[Security and Taint Tracking](../advanced/security-and-taint-tracking).
[Guardian Intrinsics](../how-to/safety-guardrails) to enforce safety constraints
at every step.
- **Structured outputs** — use `@generative` with Pydantic models or `Literal` types
to enforce type-safe structured output at each step. See
[Generative Functions](../how-to/generative-functions).
Expand Down Expand Up @@ -212,4 +212,4 @@ tools or steps.
---

**See also:** [Tools and Agents](../how-to/tools-and-agents) |
[Security and Taint Tracking](../advanced/security-and-taint-tracking)
[Safety Guardrails](../how-to/safety-guardrails)
2 changes: 1 addition & 1 deletion docs/docs/concepts/plugins.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -1003,4 +1003,4 @@ from mellea.plugins import (

---

**See also:** [Glossary](../reference/glossary), [Tools and Agents](../how-to/tools-and-agents), [Security and Taint Tracking](../advanced/security-and-taint-tracking), [OpenTelemetry Tracing](../observability/tracing)
**See also:** [Glossary](../reference/glossary), [Tools and Agents](../how-to/tools-and-agents), [Safety Guardrails](../how-to/safety-guardrails), [OpenTelemetry Tracing](../observability/tracing)
5 changes: 1 addition & 4 deletions docs/docs/docs.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
"how-to/configure-model-options",
"how-to/use-images-and-vision",
"how-to/build-a-rag-pipeline",
"how-to/safety-guardrails",
"how-to/refactor-prompts-with-cli",
"how-to/unit-test-generative-code",
"how-to/handling-exceptions"
Expand Down Expand Up @@ -483,10 +484,6 @@
"source": "/integrations/langchain-and-smolagents",
"destination": "/integrations/langchain"
},
{
"source": "/how-to/safety-guardrails",
"destination": "/advanced/security-and-taint-tracking"
},
{
"source": "/dev/constrained-decoding",
"destination": "/advanced/mellea-core-internals"
Expand Down
5 changes: 3 additions & 2 deletions docs/docs/examples/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,8 @@ to run.

| Category | What it shows |
| -------- | ------------- |
| `safety/` | `GuardianCheck` for harm, jailbreak, profanity, social bias, violence, and groundedness; shared backend pattern |
| `intrinsics/` | [Guardian Intrinsics](../how-to/safety-guardrails): `guardian_check()` for harm, jailbreak, social bias, groundedness; `policy_guardrails()`; `factuality_detection()` / `factuality_correction()` |
| `safety/` | *(Examples removed — see README for migration notes, including the `RepairTemplateStrategy` gap)* |

### Integration and deployment

Expand All @@ -77,7 +78,7 @@ to run.
| Category | What it shows |
| -------- | ------------- |
| `aLora/` | Training aLoRA adapters for fast constraint checking; performance optimisation |
| `intrinsics/` | Answer relevance, hallucination detection, citation validation, context relevance — specialised adapter-backed checks |
| `intrinsics/` | *(Non-Guardian)* Answer relevance, hallucination detection, citation validation, context relevance — specialised adapter-backed checks. For Guardian safety functions see [Safety and validation](#safety-and-validation) above |
| `granite-switch/` | Running intrinsics via OpenAI backend with Granite Switch embedded adapters |
| `sofai/` | Two-tier sampling: fast-model iteration with escalation to a slow model; cost optimisation |

Expand Down
3 changes: 2 additions & 1 deletion docs/docs/guide/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,8 @@ Terms that **must** be linked on first use wherever they appear in guide pages (
| `ReAct` | `#react` |
| `RichDocument` | `#richdocument` |
| `LiteLLM` / `LiteLLMBackend` | `#litellm--litellmbackend` |
| `GuardianCheck` / `GuardianRisk` | `#guardiancheck` |
| `guardian_check()` / `CRITERIA_BANK` | `#guardian_check` / `#criteria_bank` |
| `GuardianCheck` / `GuardianRisk` *(deprecated)* | `#guardiancheck` / `#guardianrisk` |
| `m decompose` | `#m-decompose` |

Linking within the **glossary page itself** is not required (the glossary is the definition source).
Expand Down
75 changes: 43 additions & 32 deletions docs/docs/how-to/build-a-rag-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ description: "Combine vector retrieval with Mellea's generative filtering and gr

**Prerequisites:** [Quick Start](../getting-started/quickstart) complete,
`pip install mellea faiss-cpu sentence-transformers`, Ollama running locally.
Step 5 (groundedness checking) additionally requires `pip install "mellea[hf]"`.

Retrieval-augmented generation (RAG) reduces hallucination by grounding the
model's answer in documents you supply. Mellea adds two things a plain RAG loop
Expand All @@ -30,7 +31,7 @@ Embedding model → vector search → top-k candidates
|
v
Final answer
(optional: GuardianCheck groundedness)
(optional: guardian_check groundedness)
```

---
Expand Down Expand Up @@ -178,34 +179,37 @@ answer = m.instruct(

## Step 5: Check groundedness (optional)

After generation, use [`GuardianCheck`](../reference/glossary#guardiancheck) with `GuardianRisk.GROUNDEDNESS` to
verify the answer does not hallucinate beyond the retrieved documents:
After generation, use [`guardian_check()`](../how-to/safety-guardrails) with
`criteria="groundedness"` to verify the answer does not hallucinate beyond the
retrieved documents:

```python
# Requires: mellea
# Returns: bool
from mellea.stdlib.requirements.safety.guardian import GuardianCheck, GuardianRisk

groundedness_check = GuardianCheck(
GuardianRisk.GROUNDEDNESS,
backend_type="ollama",
ollama_url="http://localhost:11434",
context_text="\n\n".join(relevant),
# Requires: mellea[hf]
# Returns: float (0.0–1.0 risk score)
from mellea.backends.huggingface import LocalHFBackend
from mellea.stdlib.components import Document, Message
from mellea.stdlib.components.intrinsic import guardian
from mellea.stdlib.context import ChatContext

guardian_backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")

docs = [Document(text=doc, doc_id=str(i)) for i, doc in enumerate(relevant)]
eval_ctx = (
ChatContext()
.add(Message("user", query))
.add(Message("assistant", str(answer), documents=docs))
)

results = m.validate([groundedness_check])
if results[0]._result:
print("Grounded answer:", str(answer))
score = guardian.guardian_check(eval_ctx, guardian_backend, criteria="groundedness")
if score < 0.5:
print(f"Grounded answer (score: {score:.4f}):", str(answer))
else:
print("Answer may contain hallucinated content:", results[0]._reason)
print(f"Groundedness risk detected (score: {score:.4f})")
```

Pass the same text to `context_text` that you used in `grounding_context` —
this ensures the groundedness model evaluates the answer against exactly what
the generator was given.

> **Backend note:** `GuardianCheck` requires `granite3-guardian:2b` pulled in Ollama.
> Run `ollama pull granite3-guardian:2b` before using it.
Include the same documents in the evaluation context that you passed to
`grounding_context` — this ensures the groundedness model evaluates the answer
against exactly what the generator was given.

---

Expand All @@ -218,8 +222,11 @@ from faiss import IndexFlatIP
from sentence_transformers import SentenceTransformer

from mellea import generative, start_session
from mellea.backends.huggingface import LocalHFBackend
from mellea.stdlib.components import Document, Message
from mellea.stdlib.components.intrinsic import guardian
from mellea.stdlib.context import ChatContext
from mellea.stdlib.requirements import req, simple_validate
from mellea.stdlib.requirements.safety.guardian import GuardianCheck, GuardianRisk


@generative
Expand All @@ -240,6 +247,9 @@ def search(query: str, docs: list[str], index: IndexFlatIP,
return [docs[i] for i in indices[0]]


guardian_backend = LocalHFBackend(model_id="ibm-granite/granite-4.1-3b")


def rag(docs: list[str], query: str) -> str | None:
embedding_model = SentenceTransformer("all-MiniLM-L6-v2")
index = build_index(docs, embedding_model)
Expand All @@ -259,14 +269,15 @@ def rag(docs: list[str], query: str) -> str | None:
requirements=[req("Answer only from the provided documents.")],
)

results = m.validate([GuardianCheck(
GuardianRisk.GROUNDEDNESS,
backend_type="ollama",
ollama_url="http://localhost:11434",
context_text="\n\n".join(relevant),
)])
if not results[0]._result:
print("Warning: groundedness check failed:", results[0]._reason)
docs_for_eval = [Document(text=doc, doc_id=str(i)) for i, doc in enumerate(relevant)]
eval_ctx = (
ChatContext()
.add(Message("user", query))
.add(Message("assistant", str(answer), documents=docs_for_eval))
)
score = guardian.guardian_check(eval_ctx, guardian_backend, criteria="groundedness")
if score >= 0.5:
print(f"Warning: groundedness risk detected (score: {score:.4f})")

return str(answer)
```
Expand All @@ -281,7 +292,7 @@ def rag(docs: list[str], query: str) -> str | None:
| `is_relevant` docstring | How strictly the filter interprets relevance | Adjust phrasing to match your domain |
| `grounding_context` key names | Tracing and debugging in spans | Use descriptive names in production |
| `requirements` on `m.instruct()` | Answer length, citation, tone | Add after baseline quality is good |
| GuardianCheck `context_text` | What the groundedness model checks against | Match exactly what you pass to `grounding_context` |
| `guardian_check` document context | What the groundedness model checks against | Match exactly what you pass to `grounding_context` |

---

Expand Down
Loading
Loading