# RAG Chunk Quality Auditor (`danielmichalek/rag-chunk-quality-auditor`) Actor

Check up to 500 supplied RAG chunks for empty text, conflicting IDs, exact duplicates and source reference format. Get a JSON report and CSV with original record positions. Send your chunks to review the data before ingestion.

- **URL**: https://apify.com/danielmichalek/rag-chunk-quality-auditor.md
- **Developed by:** [Daniel Michałek](https://apify.com/danielmichalek) (community)
- **Categories:** Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$30.00 / 1,000 complete rag chunk quality reports

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## RAG Chunk Quality Auditor

### Overview

Audit up to 500 supplied chunks before ingestion. The report checks empty or invalid text, configured character thresholds, repeated IDs, exact duplicate content and source reference format. Each record retains its original inputIndex. Chunk boundaries are preserved.

A successful audit can return qualityStatus ERRORS_FOUND. That means the report found data issues. The Actor returns observations for every supported record. Structural batch contract violations fail before delivery.

### Input example

```json
{
  "chunks": [
    {
      "id": "chunk-001",
      "text": "A source paragraph with enough context for a structural chunk quality review.",
      "sourceUrl": "https://example.com/guide"
    },
    {
      "id": "chunk-001",
      "text": "A different source paragraph explains the service terms and the delivery process.",
      "sourceId": "terms"
    },
    {
      "id": "chunk-003",
      "text": "A source paragraph with enough context for a structural chunk quality review.",
      "sourceUrl": "https://example.com/copy"
    },
    {
      "id": "",
      "text": ""
    },
    {
      "id": "0005",
      "text": "Short note",
      "sourceUrl": "relative/path"
    },
    {
      "id": "chunk-006",
      "text": "Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text ",
      "sourceId": "long-source"
    }
  ],
  "minimumCharacters": 40,
  "maximumCharacters": 1600,
  "maxItems": 1
}
```

The default example intentionally includes conflicting IDs, repeated text, missing values and a malformed source URL. examples/input-clean.json supplies a passing example. Only id, text, sourceId and sourceUrl are accepted within a record. Field values may be missing or malformed and become findings. Map extra metadata before upload.

### Output

One complete report is one dataset item and RAG_QUALITY JSON. RAG_CSV has one row per original record, and REPORT summarizes the findings. Per-record metadata includes ID, characterCount, textSha256, source references, qualityStatus and findings. Original text is represented by its hash and length.

IDs and duplicate text use literal case-sensitive equality. Duplicate IDs distinguish identical, conflicting and unverifiable text. Duplicate text groups retain every inputIndex, ID counts, missing references and distinct full valid reference tuples. Review repeated text in its intended context before deciding which copies to retain.

Counts of rows with errors and warnings can overlap. errorFindings and warningFindings count individual findings. passedRows contains records with zero findings. Character measurements use Unicode code points, including combining characters individually. Model token limits require separate evaluation.

A source ID or structurally valid HTTP or HTTPS URL establishes a provided reference. URL credentials are rejected and omitted from output. Query strings and fragments are removed from exported URLs, while fingerprints distinguish full valid reference tuples. Source availability and factual citation support require separate verification. Remove secrets and unnecessary personal information before upload. The original INPUT follows your Apify storage retention settings.

### Existing RAG Delta workflow

Map an existing RAG Delta export into the supported input shape.

```javascript
const chunks = delta.upserts.map(({ id, text, sourceUrl }) => ({ id, text, sourceUrl }));
const input = { chunks, minimumCharacters: 40, maximumCharacters: 1600, maxItems: 1 };
```

### Pricing and cost

The unit is one completed rag-quality-report for up to 500 supplied chunks. The factory proposal is USD 0.03 per report. Release receipts and the Store specify active pricing. Direct demand and matched competitor pricing are pending research, with competitorMedianUsd explicitly unknown in PRICING.json. The proposal remains at a partial commercial stage.

The audit uses supplied records and standard algorithms. No AI service, embedding API, proxy or content request is required. Cloud execution cost and margin require separate measurement.

### Limits and known scope

Input is limited to 2 MB and 500 objects. IDs and source IDs support up to 160 Unicode code points, and source URLs up to 2048. Invalid field values become findings. Review thresholds range up to 20000 characters. The application budget is cooperative and checked by the shared runner. Acceptance also applies a process timeout and measures RSS. Semantic quality and model-specific ingestion suitability require their own evaluation.

### Development and recovery

Use Node 22 or newer and the pinned lock. Install with npm ci --offline --ignore-scripts --omit=dev --no-audit --no-fund when cache is available, then npm test and npm start. Normal start and test:local use --max-old-space-size=128 --max-semi-space-size=8. Docker uses npm start. Shared libraries are vendored from \_factory/lib.

PREPARED precedes report effects. COMPLETE requires one physical report and the expected named event count. Replay checks the complete effective input fingerprint, report and export hashes, runtime, pricing and physical dataset before reusing the result. The input fingerprint also binds malformed values represented by generic findings. Markers store hashes. Inconsistent effects require reconciliation. Preserve storage and use a single writer per job. A new intentional job uses fresh storage. CSV cells are quoted, formula prefixes neutralized and numeric IDs retained as text.

# Actor input Schema

## `chunks` (type: `array`):

Supply 1 to 500 objects using only id, text, sourceId and sourceUrl. Field values may be missing or malformed so the auditor can report quality findings. Record boundaries are preserved. Map additional metadata before upload. Total input limit is 2 MB.

## `minimumCharacters` (type: `integer`):

Unicode code points, from 0 to 20000. Empty text is always reported as an error.

## `maximumCharacters` (type: `integer`):

Unicode code points, from 1 to 20000, at least minimumCharacters. These are review thresholds. Model token limits require separate evaluation.

## `maxItems` (type: `integer`):

One report includes every input record and all duplicate groups.

## Actor input object example

```json
{
  "chunks": [
    {
      "id": "chunk-001",
      "text": "A source paragraph with enough context for a structural chunk quality review.",
      "sourceUrl": "https://example.com/guide"
    },
    {
      "id": "chunk-001",
      "text": "A different source paragraph explains the service terms and the delivery process.",
      "sourceId": "terms"
    },
    {
      "id": "chunk-003",
      "text": "A source paragraph with enough context for a structural chunk quality review.",
      "sourceUrl": "https://example.com/copy"
    },
    {
      "id": "",
      "text": ""
    },
    {
      "id": "0005",
      "text": "Short note",
      "sourceUrl": "relative/path"
    },
    {
      "id": "chunk-006",
      "text": "Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text ",
      "sourceId": "long-source"
    }
  ],
  "minimumCharacters": 40,
  "maximumCharacters": 1600,
  "maxItems": 1
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `analysis` (type: `string`):

No description

## `csv` (type: `string`):

No description

## `report` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "chunks": [
        {
            "id": "chunk-001",
            "text": "A source paragraph with enough context for a structural chunk quality review.",
            "sourceUrl": "https://example.com/guide"
        },
        {
            "id": "chunk-001",
            "text": "A different source paragraph explains the service terms and the delivery process.",
            "sourceId": "terms"
        },
        {
            "id": "chunk-003",
            "text": "A source paragraph with enough context for a structural chunk quality review.",
            "sourceUrl": "https://example.com/copy"
        },
        {
            "id": "",
            "text": ""
        },
        {
            "id": "0005",
            "text": "Short note",
            "sourceUrl": "relative/path"
        },
        {
            "id": "chunk-006",
            "text": "Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text ",
            "sourceId": "long-source"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("danielmichalek/rag-chunk-quality-auditor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "chunks": [
        {
            "id": "chunk-001",
            "text": "A source paragraph with enough context for a structural chunk quality review.",
            "sourceUrl": "https://example.com/guide",
        },
        {
            "id": "chunk-001",
            "text": "A different source paragraph explains the service terms and the delivery process.",
            "sourceId": "terms",
        },
        {
            "id": "chunk-003",
            "text": "A source paragraph with enough context for a structural chunk quality review.",
            "sourceUrl": "https://example.com/copy",
        },
        {
            "id": "",
            "text": "",
        },
        {
            "id": "0005",
            "text": "Short note",
            "sourceUrl": "relative/path",
        },
        {
            "id": "chunk-006",
            "text": "Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text ",
            "sourceId": "long-source",
        },
    ] }

# Run the Actor and wait for it to finish
run = client.actor("danielmichalek/rag-chunk-quality-auditor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "chunks": [
    {
      "id": "chunk-001",
      "text": "A source paragraph with enough context for a structural chunk quality review.",
      "sourceUrl": "https://example.com/guide"
    },
    {
      "id": "chunk-001",
      "text": "A different source paragraph explains the service terms and the delivery process.",
      "sourceId": "terms"
    },
    {
      "id": "chunk-003",
      "text": "A source paragraph with enough context for a structural chunk quality review.",
      "sourceUrl": "https://example.com/copy"
    },
    {
      "id": "",
      "text": ""
    },
    {
      "id": "0005",
      "text": "Short note",
      "sourceUrl": "relative/path"
    },
    {
      "id": "chunk-006",
      "text": "Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text Long text ",
      "sourceId": "long-source"
    }
  ]
}' |
apify call danielmichalek/rag-chunk-quality-auditor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,danielmichalek/rag-chunk-quality-auditor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/lAhNVt4eoLBs0Ypn8/builds/RiSrrgJzH69IGiePX/openapi.json
