DEV Community

Cover image for Optimizing OpenAI’s GPT-4o-mini to Detect AI-Generated Text Using DSPy
Bryan Doss
Bryan Doss

Posted on

Optimizing OpenAI’s GPT-4o-mini to Detect AI-Generated Text Using DSPy

Detecting AI-generated text has become a hot topic, with researchers and practitioners debating its feasibility and ethical implications. As models grow more sophisticated, distinguishing between human-written and AI-generated text becomes both an exciting challenge and a critical need.

In this post, we’ll explore how to harness DSPy’s optimization capabilities to fine-tune OpenAI’s GPT-4o-mini for this task using a fascinating dataset of 1.39 million text samples. By the end, you’ll know how to implement, evaluate, and optimize a basic AI-text detector using DSPy—no manual prompt engineering required.


Dataset Loading

First, let’s load the dataset, which contains text samples labeled as either human-written or AI-generated from varied human and LLM sources. To get started, ensure you’ve installed Python 3, along with the DSPy and hugging face datasets libraries:

pip install dspy datasets
Enter fullscreen mode Exit fullscreen mode

The dataset is approximately 2GB in size, so depending on your internet speed, this step may take a few minutes.

Here’s the code to load and split the dataset evenly for training and testing:

from datasets import load_dataset

# Load the dataset
ds = load_dataset("artem9k/ai-text-detection-pile", split="train")

# For simplicity, we’ll do an even split of data for testing and training
NUM_EXAMPLES = 80  # Adjust this to experiment with dataset size
ds = ds.train_test_split(test_size=NUM_EXAMPLES, train_size=NUM_EXAMPLES)
Enter fullscreen mode Exit fullscreen mode

Tip: You can adjust NUM_EXAMPLES to experiment with larger datasets or to reduce costs when running optimizations.


Model Setup

Next, we’ll create a basic DSPy predictor using OpenAI’s GPT-4o-mini. GPT-4o-mini is a lightweight version of OpenAI’s GPT-4o model, making it cost-efficient for experimentation. DSPy simplifies this process by using signatures, which define structured input-output mappings.

Replace "YOUR_API_KEY" with your OpenAI API key before running the code:

import dspy
from typing import Literal

# Initialize the OpenAI GPT-4o-mini model
lm = dspy.LM('openai/gpt-4o-mini', api_key="YOUR_API_KEY")
dspy.configure(lm=lm, experimental=True)

# Define the AI text detector signature
class DetectAiText(dspy.Signature):
    """Classify text as written by human or by AI."""
    text: str = dspy.InputField()
    source: Literal['ai', 'human'] = dspy.OutputField()

# Create a basic predictor
detector = dspy.Predict(DetectAiText)
Enter fullscreen mode Exit fullscreen mode

Notice that we haven’t done any prompt engineering here. Instead, we rely on DSPy to handle that, as well as the input-output relationships automatically.

You can test the "detector" with some sample input:

print(detector(text="Hello world (this definitely wasn't written by AI)"))
Enter fullscreen mode Exit fullscreen mode

The prediction will appear in the 'source' field of the output.


Evaluating the Detector

Now that we have a basic detector, let’s evaluate its performance using DSPy’s evaluation tools. For this, we’ll define a simple metric that checks if the model correctly predicts the text’s source (human or AI).

Here’s the code to set up and run the evaluation:

from dspy.evaluate import Evaluate

# Define a simple evaluation metric
def validate_text_source(example: dspy.Example, pred, trace=None) -> int:
    return 1 if example.source.lower() == pred.source.lower() else 0

# Transform the dataset into DSPy-compatible "Example" objects
dspy_trainset = [
    dspy.Example(source=x['source'], text=x['text']).with_inputs('text') for x in ds['train']
]
dspy_devset = [
    dspy.Example(source=x['source'], text=x['text']).with_inputs('text') for x in ds['test']
]

# Evaluate the detector
evaluator = Evaluate(devset=dspy_devset, num_threads=12)  # Adjust threads based on your system
evaluator(detector, metric=validate_text_source)
Enter fullscreen mode Exit fullscreen mode

In my initial tests, I achieved an accuracy of 76%–81%. Note that results may vary due to the random sampling of the dataset.

Initial evaluation


Optimizing with DSPy

The real power of DSPy lies in its optimization capabilities. By using the MIPROv2 optimizer, we can improve the detector’s performance without manually tweaking prompts. The optimizer automates this process using few-shot examples, dynamic templates, and self-supervised techniques.

Here’s how to set up and run the optimizer:

import time
from dspy.teleprompt import MIPROv2

# Initialize the optimizer
teleprompter = MIPROv2(
    metric=validate_text_source, 
    auto="light"  # Options: light, medium, heavy
)

# Run the optimization
optimized_program = teleprompter.compile(
    detector.deepcopy(),  # Make a copy of the detector to optimize
    trainset=dspy_trainset,
    valset=dspy_devset,
)

# Save the optimized program for future use
optimized_program.save(f'detect_ai_mipro_optimized_{time.time()}.dspy')
Enter fullscreen mode Exit fullscreen mode

Note: The cost for a single optimization run with the "light" preset is typically less than $0.50 for a dataset of 80 examples.


Results and Iteration

After running the optimization, I observed a significant performance boost. My first run achieved an accuracy of 91.25%, compared to the baseline’s 76%–81%. Subsequent runs ranged between 81.2% and 91.25%, demonstrating consistent improvements with minimal effort.

MIPRO Optimization

To load the optimized model for further use:

detector.load(path='detect_ai_mipro_optimized_XXXXX.dspy')
Enter fullscreen mode Exit fullscreen mode

You can iterate further by:

  • Adjusting the optimizer’s auto parameter (light, medium, heavy), or setting hyper-parameters yourself.
  • Increasing the dataset size for training and evaluation.
  • Testing with more advanced or updated LLMs.

Conclusion

In just a few steps, we demonstrated how DSPy simplifies LLM optimization for real-world use cases. Without any manual prompt engineering, we achieved a measurable improvement in detecting AI-generated text. While this model isn’t perfect, DSPy’s flexibility allows for continuous iteration, making it a valuable tool for scalable AI development.

I'd highly recommend a read-through of DSPy’s documentation and experiment with other optimizers and LLM patterns.


Full code available on GitHub.

Question? Comments? Let me know, I look forward to seeing what you build with DSPy!

You can find me on LinkedIn | CTO & Partner @ EES.

Top comments (0)