Prompt Engineering

In production AI applications, prompts are not written once and forgotten. User needs change, model capabilities evolve, and competitors iterate—prompts also need continuous optimization. But without version management and A/B testing, prompt iteration becomes a black-box operation of "tuning by feel." Engineering-grade prompt management should include: version control (every change has a record and description), A/B testing (new versions are validated with small traffic before full rollout), and rollback mechanisms (quickly revert to the previous version when performance degrades).

Prompt Version Management System

Prompts can be managed with Git like code—store prompts in separate .prompt files, commit each change with a reason. Go further by building a prompt management platform: store all historical versions, associate prompts with model versions, and record metric changes for each modification. Key metadata includes: creation time, modifier, applicable model, target scenario, performance baseline (score on standard test sets), and dependent variables and external data.

A/B Testing Framework Implementation

import json, time, random
from openai import OpenAI

client = OpenAI(api_key="your-deepseek-api-key", base_url="https://api.deepseek.com")

class PromptABTester:
    def __init__(self):
        self.variants = {}   # {variant_name: (prompt_template, traffic_ratio)}
        self.metrics = {}

    def register_variant(self, name, prompt, ratio):
        self.variants[name] = {"prompt": prompt, "ratio": ratio}
        self.metrics[name] = {"calls": 0, "positive": 0, "latency": [], "tokens": []}

    def select_variant(self, user_id=None):
        """Consistent hashing routing based on user ID"""
        if user_id:
            h = hash(user_id) % 100
            cumulative = 0
            for name, v in self.variants.items():
                cumulative += v["ratio"] * 100
                if h < cumulative:
                    return name
        # Random assignment when no user ID
        r = random.random()
        cumulative = 0
        for name, v in self.variants.items():
            cumulative += v["ratio"]
            if r < cumulative:
                return name
        return list(self.variants.keys())[0]

    def execute(self, user_input, user_id=None, **kwargs):
        variant = self.select_variant(user_id)
        prompt = self.variants[variant]["prompt"]
        full_prompt = prompt.replace("{input}", user_input)

        start = time.time()
        resp = client.chat.completions.create(model="deepseek-chat",
            messages=[{"role":"user","content":full_prompt}], **kwargs)
        latency = time.time() - start

        output = resp.choices[0].message.content
        usage = resp.usage.total_tokens

        # Record metrics
        self.metrics[variant]["calls"] += 1
        self.metrics[variant]["latency"].append(latency)
        self.metrics[variant]["tokens"].append(usage)

        return {"variant": variant, "output": output}

    def report(self):
        """Generate A/B test report"""
        report = {}
        for name, m in self.metrics.items():
            if m["calls"] == 0:
                continue
            report[name] = {
                "calls": m["calls"],
                "avg_latency": sum(m["latency"]) / len(m["latency"]),
                "avg_tokens": sum(m["tokens"]) / len(m["tokens"]),
                "positive_rate": m["positive"] / m["calls"] if m["calls"] else 0
            }
        return report

tester = PromptABTester()
tester.register_variant("v1-basic", "回答以下问题:{input}", 0.5)
tester.register_variant("v2-detailed", "作为专家详细回答:{input}", 0.5)
result = tester.execute("解释量子计算")
print(f"使用 {result['variant']}: {result['output'][:100]}")

Experimental Design and Statistical Significance

The reliability of A/B testing depends on proper experimental design: sample size calculation (calculate the minimum sample size based on expected effect size and statistical power; typically at least 1000 calls to detect a 5% improvement), randomization (use user ID hashing to ensure the same user always sees the same version, avoiding inconsistent experiences), Simpson's paradox (be aware of distribution differences across user segments; analyze stratified by user type), multiple comparison correction (use Bonferroni correction when comparing multiple metrics to avoid false positives).

Progressive Rollout and Automatic Rollback

The release of new prompts should follow a progressive strategy: 5% traffic (1 day) → 25% (1 day) → 50% (1 day) → 100%. The upgrade condition for each stage is: no significant degradation in core metrics, no significant increase in negative user feedback, and performance metrics like latency within acceptable range. Set automatic rollback rules—if key metrics (such as user satisfaction score) drop beyond a threshold (e.g., 10%), automatically revert to the previous version and alert. A good experimentation platform makes prompt iteration as controllable and traceable as code deployment.

Managing User Perception in A/B Testing

A/B testing changes the user experience, so user perception must be managed carefully. Some lessons: maintain consistency with external commitments—don't let users discover on social media that "others get better responses than me," avoid discussing test details publicly; exclude critical scenarios—paid users, VIP users, and complaining users should be excluded from A/B testing to provide a stable best experience; minimum test duration—A/B tests should run for at least one full business cycle (usually a week) to avoid erroneous conclusions due to weekend/weekday user differences; predefine stopping rules—define stopping conditions before the experiment starts (e.g., "stop immediately if negative feedback rate rises by more than 3%"), don't decide based on results during the experiment—this leads to confirmation bias.

Multi-Armed Bandit: Dynamic Traffic Allocation Beyond A/B Testing

The limitation of A/B testing is "treating all variants equally until the experiment ends"—even if group B is clearly better than group A, 50% of traffic is still allocated to the inferior group A until the end, causing opportunity cost. Multi-Armed Bandit algorithms solve this: they dynamically adjust traffic allocation based on real-time performance—better-performing variants get more traffic, worse ones are gradually eliminated. Implementation: use Thompson Sampling, maintain a Beta distribution for each variant (α=successes+1, β=failures+1), sample from each variant's Beta distribution on each request, and serve the variant with the highest sample value. Experimental comparison: on the same set of prompts, multi-armed bandit reduces traffic loss by 40% compared to fixed-allocation A/B testing while achieving the same statistical confidence. Suitable for high-traffic and fast-iteration scenarios.

Want to orchestrate this skill chain yourself?

Open in Skill Chain →