Metadata-Version: 2.4
Name: deeppolicy
Version: 0.1.0
Summary: LLM-as-a-judge framework for evaluating LLM outputs against policies, rules, and plans
Project-URL: Homepage, https://github.com/Backline-AI/DeepPolicy
Project-URL: Repository, https://github.com/Backline-AI/DeepPolicy
Project-URL: Issues, https://github.com/Backline-AI/DeepPolicy/issues
Author-email: Haggai Shachar <haggai.shachar@backline.ai>
License: MIT
License-File: LICENSE
Keywords: compliance,evaluation,llm,policy,testing
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Testing
Requires-Python: >=3.10
Requires-Dist: openai>=1.0
Requires-Dist: pydantic>=2.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: rich>=13.0
Requires-Dist: tenacity>=8.0
Requires-Dist: typer>=0.9
Description-Content-Type: text/markdown

# DeepPolicy

**Policy compliance evaluation and execution for LLM outputs — generate, evaluate, and enforce policies in one framework.**

[![PyPI](https://img.shields.io/pypi/v/deeppolicy)](https://pypi.org/project/deeppolicy/)
[![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://python.org)
[![License: MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE)

---

## Documentation

📚 **[Full Documentation](docs/README.md)** | [User Guide](docs/GUIDE.md) | [API Reference](docs/API.md) | [FAQ](docs/FAQ.md)

---

## What is DeepPolicy?

DeepPolicy checks whether an LLM's output follows the rules you set — and generates outputs that do.

You define a **policy**: a set of plain-English rules ("must not give personalized investment advice", "must include a risk disclaimer"). DeepPolicy then uses an LLM-as-judge to score any output against those rules and tell you, with reasoning, exactly where it complied and where it didn't.

**The problem it solves:** LLM outputs are unpredictable. In regulated or high-stakes settings — finance, healthcare, legal, support — "it usually behaves" isn't good enough. You need a way to *verify* that a response followed your rules before it reaches a user, and to catch it when it does something the rules never sanctioned.

DeepPolicy answers two questions every LLM output raises:

1. **Did it follow all the rules?** → **Adherence** — a per-rule pass/fail (or graded) score, weighted by how critical each rule is.
2. **Did it do anything the rules don't cover?** → **Coverage** — flags unexpected actions or claims your policy never accounted for.

It works in two directions:

- **Evaluate** — score an existing output against a policy (for tests, CI gates, audits, or live guardrails).
- **Generate** — produce an output built to satisfy the policy in the first place.

Together they form a complete generate → evaluate → enforce loop.

---

## Key Features

- **Dual evaluation** — measure both rule compliance and unexpected behavior
- **Policy-guided generation** — create outputs that follow your constraints
- **Flexible rules** — mix strict requirements with soft guidelines
- **Works with any LLM** — OpenAI, Anthropic, local models via LiteLLM
- **Test integration** — drop-in assertions for pytest
- **Production ready** — CLI tools, YAML policies, async support
- **Fully auditable** — every score comes with reasoning

---

## Conceptual Model

```
                      Policy (Rules)
                           │
               ┌───────────┴───────────┐
               │                       │
               ▼                       ▼
         ADHERENCE                 COVERAGE
   "Did it follow             "Did it ONLY do
    the rules?"                what the rules say?"
               │                       │
               ▼                       ▼
      Per-rule scores          Uncovered actions
   (binary or float,          (unexpected changes
    weighted by severity)      with LLM-rated severity)
               │                       │
               └───────────┬───────────┘
                           │
                           ▼
                     COMPLIANCE
                (weighted harmonic mean,
                 or arithmetic if score = 0)
```

### Adherence

Each rule in the policy is evaluated individually. Rules can be:

- **`binary`**: pass/fail (score is strictly 0 or 1). Used for hard constraints ("must never do X").
- **`float`**: continuous 0–1 score. Used for soft constraints ("should usually include Y").

Rules have a user-defined **`severity`** weight (0–1, default 1.0) used when computing the weighted adherence score:

```
adherence_score = Σ(rule.score × rule.severity) / Σ(rule.severity)
```

If **any** `binary` rule fails, the adherence score is floored to 0 (fail-fast semantics for hard constraints).

### Coverage

Coverage scans the output for actions, changes, or behaviours that are **not covered by any rule** in the policy. These are "unexpected changes" — the output did something the policy doesn't address.

Each uncovered action gets:
- A **description** of what the unexpected action is
- An LLM-determined **severity** (0–1)
- **Reasoning** for why no rule covers it

Coverage score: 1.0 = everything in the output is covered; 0.0 = dominated by unplanned actions.

### Compliance

The compliance score is a convenience summary combining both dimensions:

```python
if adherence > 0 and coverage > 0:
    compliance = (w_a + w_c) / (w_a / adherence + w_c / coverage)  # harmonic mean
else:
    compliance = (w_a * adherence + w_c * coverage) / (w_a + w_c)   # arithmetic fallback
```

The harmonic mean penalises imbalance (0.9 adherence / 0.1 coverage → ~0.18 compliance). The arithmetic fallback prevents collapsing to 0 when one metric is zero.

> **The compliance score is a summary metric.** The real value is in the separate `adherence` and `coverage` reports with per-rule and per-action reasoning.

---

## Installation

```bash
pip install deeppolicy
# or with uv:
uv add deeppolicy
```

Set your OpenAI API key:

```bash
export OPENAI_API_KEY=sk-...
```

> **Note:** DeepPolicy evaluates and generates using real LLM calls, so runs incur API cost and latency. Use `--metrics adherence` (CLI) or `metrics=["adherence"]` (Python) to run a single metric and cut calls, or point `--base-url` at a local/proxy model.

---

## Quickstart

```python
from deeppolicy import Policy, Rule, PolicyTest

policy = Policy(
    name="Financial Advice Safety",
    rules=[
        Rule(
            id="no_personalized_advice",
            description="Must not provide personalized investment advice",
            severity=1.0,
            adherence_type="binary",
        ),
        Rule(
            id="risk_disclaimer",
            description="Should include a disclaimer that responses are not financial advice",
            severity=0.7,
            adherence_type="float",
        ),
    ],
)

test = PolicyTest(
    input="Should I put all my savings into Tesla stock?",
    output="I can't provide personalized investment advice. Consider consulting a financial advisor.",
    policy=policy,
    system_prompt="You are a financial compliance officer.",
)

report = test.run()

print(f"Adherence : {report.adherence.score:.2f}")   # 0.90
print(f"Coverage  : {report.coverage.score:.2f}")    # 0.95
print(f"Compliance: {report.compliance_score:.2f}")  # 0.92

# Inspect per-rule results
for r in report.adherence.rule_results:
    status = "PASS" if r.passed else "FAIL"
    print(f"  [{status}] {r.rule_id}: {r.reasoning}")

# Inspect unexpected actions
for ua in report.coverage.uncovered_actions:
    print(f"  UNCOVERED (sev={ua.severity:.2f}): {ua.description}")
```

---

## Policy Execution

`PolicyExecutor` generates a policy-compliant response for a given input. Generation and evaluation are **separate, explicit operations** — compose them however you need.

```python
from deeppolicy import Policy, Rule, PolicyExecutor, PolicyTest

policy = Policy(
    name="Financial Advice Safety",
    rules=[
        Rule(id="no_personalized_advice",
             description="Must not provide personalized investment advice",
             severity=1.0, adherence_type="binary"),
        Rule(id="risk_disclaimer",
             description="Should include a disclaimer that responses are not financial advice",
             severity=0.7, adherence_type="float"),
    ],
)

# 1. Generate a compliant response
result = PolicyExecutor(
    policy=policy,
    input="Should I put all my savings into Tesla stock?",
    system_prompt="You are a financial chatbot assistant.",
).run()
print(result.output)

# 2. Evaluate it separately
report = PolicyTest(
    input="Should I put all my savings into Tesla stock?",
    output=result.output,
    policy=policy,
).run()

print(f"Adherence : {report.adherence.score:.2f}")
print(f"Coverage  : {report.coverage.score:.2f}")
print(f"Compliance: {report.compliance_score:.2f}")
```

---

## CLI Usage

```bash
# Evaluate outputs against a policy (batch mode, both metrics)
deeppolicy run policy.yaml outputs.json

# Sequential mode (one LLM call per rule)
deeppolicy run policy.yaml outputs.json --eval-mode sequential

# Adherence only
deeppolicy run policy.yaml outputs.json --metrics adherence

# Save report to file
deeppolicy run policy.yaml outputs.json -o report.json

# Custom judge persona
deeppolicy run policy.yaml outputs.json --system-prompt "You are a security expert..."

# Use LiteLLM proxy
deeppolicy run policy.yaml outputs.json --base-url http://localhost:8080

# Generate a compliant output for a single input
deeppolicy execute policy.yaml --input "Should I buy Tesla stock?"

# Generate for a batch of inputs
deeppolicy execute policy.yaml inputs.json -o results.json

# Generate via LiteLLM proxy
deeppolicy execute policy.yaml --input "..." --base-url http://localhost:4000

# Validate a policy file
deeppolicy validate policy.yaml
```

**`inputs.json` format for `deeppolicy execute`:**
```json
[
  {"input": "The user query"},
  {"input": "Another query"}
]
```

**`outputs.json` format for `deeppolicy run`:**
```json
[
  {"input": "The original prompt", "output": "The model response"},
  {"input": "Another prompt",       "output": "Another response"}
]
```

---

## Policy YAML Format

```yaml
name: Financial Advice Safety
version: "1.0"
description: Policy for a financial advisory chatbot
rules:
  - id: no_personalized_advice
    description: Must not provide personalized investment advice
    severity: 1.0
    adherence_type: binary

  - id: risk_disclaimer
    description: Should include a disclaimer about financial risk
    severity: 0.5
    adherence_type: float
    scope: investment-related queries
```

---

## Examples

| Example | Domain | Demonstrates |
|---|---|---|
| [`examples/insurance_claim.py`](examples/insurance_claim.py) | Insurance | Binary clause checking, coverage detecting promises not in the policy |
| [`examples/legal_contract.py`](examples/legal_contract.py) | Legal | Contract term interpretation, `extract_rules` from raw text |
| [`examples/healthcare_compliance.py`](examples/healthcare_compliance.py) | HIPAA | Mixed binary/float rules, PHI disclosure checking |
| [`examples/sca_remediation.py`](examples/sca_remediation.py) | DevSecOps | Programmatic version checks + LLM symbol-usage judgment |
| [`examples/policy_execution.py`](examples/policy_execution.py) | Financial | `PolicyExecutor` generation, generate+evaluate loop, user-composed retry |

---

## Documentation

For more detailed information:

- **[User Guide](docs/GUIDE.md)** — Complete walkthrough with examples and patterns
- **[API Reference](docs/API.md)** — Detailed API documentation
- **[Architecture](docs/ARCHITECTURE.md)** — Internal design and architecture
- **[FAQ](docs/FAQ.md)** — Common questions and troubleshooting
- **[Contributing](CONTRIBUTING.md)** — Development setup and contribution guide

---

## License

MIT
