Skip to content

Commit 8edc05c

Browse files
committed
feat: 新增 A/B 测试功能,支持提示词版本比较和分析
1 parent b1b7d3c commit 8edc05c

9 files changed

Lines changed: 1708 additions & 1 deletion

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ Thumbs.db
7373
# Project specific
7474
.prompt_lock.json
7575
prompts/
76+
.prompt_ab/
7677

7778
.claude/
7879
.ruff_cache/

README.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ A lightweight, code-first Python library for managing LLM prompts using Git and
2020
- 🛠️ **Auto Migration** - One-click conversion of hardcoded prompts to managed format
2121
- 🧪 **Testing Framework** - Define and run test cases for prompts with YAML-based test suites
2222
-**Output Validation** - Validate prompt outputs with JSON schema, regex, length checks, and custom rules
23+
- 🔬 **A/B Testing** - Compare different prompt versions and analyze LLM output effectiveness
2324
- 🎯 **Type Safe** - Full type hints support
2425

2526
## 📦 Installation
@@ -203,6 +204,55 @@ results = runner.run_suite(suite)
203204
- `contains` - Verify substring presence
204205
- `custom` - Custom validation functions
205206

207+
## 🔬 A/B Testing
208+
209+
Compare different prompt versions and analyze their effectiveness:
210+
211+
```python
212+
from prompt_vcs import ABTestManager, ABTestConfig, ABTestVariant
213+
214+
# Create an experiment
215+
manager = ABTestManager.get_instance()
216+
config = ABTestConfig(
217+
name="greeting_test",
218+
prompt_id="user_greeting",
219+
variants=[
220+
ABTestVariant("v1", weight=1.0),
221+
ABTestVariant("v2", weight=1.0),
222+
],
223+
)
224+
manager.create_experiment(config)
225+
226+
# Run experiment
227+
with manager.experiment("greeting_test") as exp:
228+
prompt = exp.get_prompt(name="Alice")
229+
response = my_llm.generate(prompt) # Your LLM call
230+
exp.record(output=response, score=0.8)
231+
232+
# Analyze results
233+
result = manager.analyze("greeting_test")
234+
print(result.summary())
235+
```
236+
237+
**CLI Commands:**
238+
239+
```bash
240+
# Create an A/B test experiment
241+
pvcs ab create my_test user_greeting --variants v1,v2
242+
243+
# List all experiments
244+
pvcs ab list
245+
246+
# View experiment status
247+
pvcs ab status my_test
248+
249+
# Manually record a result
250+
pvcs ab record my_test v1 --score 0.8
251+
252+
# Analyze results
253+
pvcs ab analyze my_test
254+
```
255+
206256
## 📖 CLI Commands
207257

208258
| Command | Description |
@@ -217,6 +267,11 @@ results = runner.run_suite(suite)
217267
| `pvcs test <suite.yaml>` | Run prompt tests from YAML suite |
218268
| `pvcs diff <id> <v1> <v2>` | Compare two versions of a prompt |
219269
| `pvcs log <id>` | Show Git commit history for a prompt |
270+
| `pvcs ab create <name> <id>` | Create an A/B test experiment |
271+
| `pvcs ab list` | List all A/B test experiments |
272+
| `pvcs ab status <name>` | View experiment status and variants |
273+
| `pvcs ab analyze <name>` | Analyze experiment results |
274+
| `pvcs ab record <name> <v>` | Manually record a test result |
220275

221276
## 🤝 Contributing
222277

README.zh-CN.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
- 🛠️ **自动迁移** - 一键将现有硬编码 Prompt 转换为可管理格式
2121
- 🧪 **测试框架** - 使用 YAML 定义测试用例并运行 Prompt 测试
2222
-**输出验证** - 支持 JSON Schema、正则表达式、长度检查和自定义规则验证
23+
- 🔬 **A/B 测试** - 对比不同版本 Prompt 的效果,分析 LLM 输出质量
2324
- 🎯 **类型安全** - 完整的类型提示支持
2425

2526
## 📦 安装
@@ -203,6 +204,55 @@ results = runner.run_suite(suite)
203204
- `contains` - 验证是否包含子字符串
204205
- `custom` - 自定义验证函数
205206

207+
## 🔬 A/B 测试
208+
209+
对比不同版本 Prompt 的效果并分析它们的有效性:
210+
211+
```python
212+
from prompt_vcs import ABTestManager, ABTestConfig, ABTestVariant
213+
214+
# 创建实验
215+
manager = ABTestManager.get_instance()
216+
config = ABTestConfig(
217+
name="greeting_test",
218+
prompt_id="user_greeting",
219+
variants=[
220+
ABTestVariant("v1", weight=1.0),
221+
ABTestVariant("v2", weight=1.0),
222+
],
223+
)
224+
manager.create_experiment(config)
225+
226+
# 运行实验
227+
with manager.experiment("greeting_test") as exp:
228+
prompt = exp.get_prompt(name="Alice")
229+
response = my_llm.generate(prompt) # 你的 LLM 调用
230+
exp.record(output=response, score=0.8)
231+
232+
# 分析结果
233+
result = manager.analyze("greeting_test")
234+
print(result.summary())
235+
```
236+
237+
**CLI 命令:**
238+
239+
```bash
240+
# 创建 A/B 测试实验
241+
pvcs ab create my_test user_greeting --variants v1,v2
242+
243+
# 列出所有实验
244+
pvcs ab list
245+
246+
# 查看实验状态
247+
pvcs ab status my_test
248+
249+
# 手动记录结果
250+
pvcs ab record my_test v1 --score 0.8
251+
252+
# 分析结果
253+
pvcs ab analyze my_test
254+
```
255+
206256
## 📖 CLI 命令
207257

208258
| 命令 | 说明 |
@@ -217,6 +267,11 @@ results = runner.run_suite(suite)
217267
| `pvcs test <suite.yaml>` | 从 YAML 测试套件运行 Prompt 测试 |
218268
| `pvcs diff <id> <v1> <v2>` | 比较两个版本的 Prompt 差异 |
219269
| `pvcs log <id>` | 查看 Prompt 的 Git 提交历史 |
270+
| `pvcs ab create <name> <id>` | 创建 A/B 测试实验 |
271+
| `pvcs ab list` | 列出所有 A/B 测试实验 |
272+
| `pvcs ab status <name>` | 查看实验状态和变体 |
273+
| `pvcs ab analyze <name>` | 分析实验结果 |
274+
| `pvcs ab record <name> <v>` | 手动记录测试结果 |
220275

221276
## 🤝 贡献
222277

examples/ab_testing_demo.py

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
"""
2+
A/B Testing Demo for prompt-vcs.
3+
4+
This example demonstrates how to use the A/B testing features to compare
5+
different versions of prompts.
6+
7+
Run this after:
8+
1. pip install -e .
9+
2. pvcs init
10+
"""
11+
12+
from prompt_vcs import p, ab_test, ABTestManager, ABTestConfig, ABTestVariant
13+
14+
15+
def demo_context_manager_mode():
16+
"""
17+
Demonstrate A/B testing using context manager.
18+
19+
This is the most flexible approach, giving you full control over
20+
the experiment flow.
21+
"""
22+
print("=" * 50)
23+
print(" A/B Testing: Context Manager Mode")
24+
print("=" * 50 + "\n")
25+
26+
# 1. Create an experiment
27+
manager = ABTestManager.get_instance()
28+
29+
config = ABTestConfig(
30+
name="greeting_experiment",
31+
prompt_id="user_greeting",
32+
description="Testing different greeting styles",
33+
variants=[
34+
ABTestVariant("v1", weight=1.0, description="Formal greeting"),
35+
ABTestVariant("v2", weight=1.0, description="Casual greeting"),
36+
],
37+
)
38+
manager.create_experiment(config)
39+
print(f"Created experiment: {config.name}")
40+
print(f" Prompt ID: {config.prompt_id}")
41+
print(f" Variants: v1 (50%), v2 (50%)")
42+
print()
43+
44+
# 2. Run the experiment multiple times
45+
print("Running 10 experiments...\n")
46+
47+
for i in range(10):
48+
user_id = f"user_{i}" # Use user_id for consistent bucketing
49+
50+
with manager.experiment("greeting_experiment", user_id=user_id) as exp:
51+
# Get the prompt (automatically selects variant)
52+
prompt = exp.get_prompt(name="Alice")
53+
54+
# Simulate LLM response (in real usage, call your LLM here)
55+
response = f"AI response to: {prompt[:30]}..."
56+
57+
# Simulate quality score (in real usage, evaluate the response)
58+
import random
59+
score = random.uniform(0.6, 1.0)
60+
61+
# Record the result
62+
exp.record(output=response, score=score)
63+
64+
print(f" User {i}: {exp.variant.version} → score={score:.2f}")
65+
66+
print()
67+
68+
# 3. Analyze results
69+
result = manager.analyze("greeting_experiment")
70+
print("Analysis Results:")
71+
print(result.summary())
72+
print()
73+
74+
75+
def demo_decorator_mode():
76+
"""
77+
Demonstrate A/B testing using the @ab_test decorator.
78+
79+
This is a simpler approach for basic use cases.
80+
"""
81+
print("=" * 50)
82+
print(" A/B Testing: Decorator Mode")
83+
print("=" * 50 + "\n")
84+
85+
# Define a function with A/B testing
86+
@ab_test("farewell_experiment", prompt_id="farewell", variants=["v1", "v2"])
87+
def get_farewell(name: str) -> str:
88+
return p("farewell", "再见,{name}!", name=name)
89+
90+
# Run the experiment
91+
print("Running 5 experiments...\n")
92+
93+
for i in range(5):
94+
result = get_farewell(name="Bob")
95+
print(f" Run {i+1}: {result}")
96+
97+
# Record result (the decorator returns a special object with record method)
98+
import random
99+
result.record(output="AI says goodbye", score=random.uniform(0.7, 1.0))
100+
101+
# Analyze
102+
manager = ABTestManager.get_instance()
103+
analysis = manager.analyze("farewell_experiment")
104+
print("\nAnalysis Results:")
105+
print(analysis.summary())
106+
print()
107+
108+
109+
def demo_cli_workflow():
110+
"""
111+
Demonstrate the CLI workflow for A/B testing.
112+
113+
These commands can be run from the terminal.
114+
"""
115+
print("=" * 50)
116+
print(" A/B Testing: CLI Workflow")
117+
print("=" * 50 + "\n")
118+
119+
print("CLI commands available:\n")
120+
print(" # Create an experiment")
121+
print(" pvcs ab create greeting_test user_greeting --variants v1,v2\n")
122+
123+
print(" # List all experiments")
124+
print(" pvcs ab list\n")
125+
126+
print(" # View experiment status")
127+
print(" pvcs ab status greeting_test\n")
128+
129+
print(" # Manually record a result")
130+
print(" pvcs ab record greeting_test v1 --score 0.8\n")
131+
132+
print(" # Analyze results")
133+
print(" pvcs ab analyze greeting_test\n")
134+
135+
print(" # Clear experiment records")
136+
print(" pvcs ab clear greeting_test --yes\n")
137+
138+
139+
def main():
140+
print("\n" + "=" * 50)
141+
print(" prompt-vcs A/B Testing Demo")
142+
print("=" * 50 + "\n")
143+
144+
demo_context_manager_mode()
145+
demo_decorator_mode()
146+
demo_cli_workflow()
147+
148+
print("=" * 50)
149+
print(" Demo Complete!")
150+
print("=" * 50 + "\n")
151+
152+
153+
if __name__ == "__main__":
154+
main()

src/prompt_vcs/__init__.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,16 @@
77
from prompt_vcs.validator import PromptValidator, ValidationRule, ValidationType
88
from prompt_vcs.testing import TestCase, TestSuite, PromptTestRunner
99
from prompt_vcs.codemod import migrate_file_content
10+
from prompt_vcs.ab_testing import (
11+
ab_test,
12+
ABTestManager,
13+
ABTestConfig,
14+
ABTestVariant,
15+
ABTestRecord,
16+
ABTestResult,
17+
)
1018

11-
__version__ = "0.4.0"
19+
__version__ = "0.5.0"
1220
__all__ = [
1321
"p",
1422
"prompt",
@@ -21,4 +29,11 @@
2129
"TestSuite",
2230
"PromptTestRunner",
2331
"migrate_file_content",
32+
# A/B Testing
33+
"ab_test",
34+
"ABTestManager",
35+
"ABTestConfig",
36+
"ABTestVariant",
37+
"ABTestRecord",
38+
"ABTestResult",
2439
]

0 commit comments

Comments
 (0)