@ckelsoe/prompt-architect 3.0.2 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/marketplace.json +1 -1
- package/.claude-plugin/plugin.json +1 -1
- package/CHANGELOG.md +264 -264
- package/LICENSE +21 -21
- package/README.md +1064 -1184
- package/adapters/README.md +75 -267
- package/adapters/for-windsurf.md +136 -136
- package/adapters/system-prompt.md +243 -243
- package/package.json +139 -138
- package/scripts/build-skill.js +64 -0
- package/scripts/install.js +4 -54
- package/scripts/test.js +205 -213
- package/scripts/validate-skill.js +350 -350
- package/skills/prompt-architect/SKILL.md +331 -331
- package/skills/prompt-architect/assets/templates/ape_template.txt +5 -5
- package/skills/prompt-architect/assets/templates/bab_template.txt +15 -15
- package/skills/prompt-architect/assets/templates/broke_template.txt +15 -15
- package/skills/prompt-architect/assets/templates/cai-critique-revise_template.txt +18 -18
- package/skills/prompt-architect/assets/templates/care_template.txt +16 -16
- package/skills/prompt-architect/assets/templates/chain-of-density_template.txt +46 -46
- package/skills/prompt-architect/assets/templates/chain-of-thought_template.txt +49 -49
- package/skills/prompt-architect/assets/templates/co-star_template.txt +17 -17
- package/skills/prompt-architect/assets/templates/crispe_template.txt +14 -14
- package/skills/prompt-architect/assets/templates/ctf_template.txt +15 -15
- package/skills/prompt-architect/assets/templates/devils-advocate_template.txt +25 -25
- package/skills/prompt-architect/assets/templates/hybrid_template.txt +101 -101
- package/skills/prompt-architect/assets/templates/least-to-most_template.txt +16 -16
- package/skills/prompt-architect/assets/templates/plan-and-solve_template.txt +7 -7
- package/skills/prompt-architect/assets/templates/pre-mortem_template.txt +27 -27
- package/skills/prompt-architect/assets/templates/race_template.txt +19 -19
- package/skills/prompt-architect/assets/templates/rcot_template.txt +31 -31
- package/skills/prompt-architect/assets/templates/react_template.txt +27 -27
- package/skills/prompt-architect/assets/templates/reverse-role_template.txt +11 -11
- package/skills/prompt-architect/assets/templates/rise-ie_template.txt +23 -23
- package/skills/prompt-architect/assets/templates/rise-ix_template.txt +28 -28
- package/skills/prompt-architect/assets/templates/risen_template.txt +21 -21
- package/skills/prompt-architect/assets/templates/rpef_template.txt +26 -26
- package/skills/prompt-architect/assets/templates/rtf_template.txt +13 -13
- package/skills/prompt-architect/assets/templates/self-refine_template.txt +16 -16
- package/skills/prompt-architect/assets/templates/skeleton-of-thought_template.txt +15 -15
- package/skills/prompt-architect/assets/templates/step-back_template.txt +10 -10
- package/skills/prompt-architect/assets/templates/tidd-ec_template.txt +45 -45
- package/skills/prompt-architect/assets/templates/tree-of-thought_template.txt +30 -30
- package/skills/prompt-architect/references/frameworks/ape.md +200 -200
- package/skills/prompt-architect/references/frameworks/bab.md +242 -242
- package/skills/prompt-architect/references/frameworks/broke.md +242 -242
- package/skills/prompt-architect/references/frameworks/cai-critique-revise.md +230 -230
- package/skills/prompt-architect/references/frameworks/care.md +235 -235
- package/skills/prompt-architect/references/frameworks/chain-of-density.md +479 -479
- package/skills/prompt-architect/references/frameworks/chain-of-thought.md +424 -424
- package/skills/prompt-architect/references/frameworks/co-star.md +256 -256
- package/skills/prompt-architect/references/frameworks/crispe.md +253 -253
- package/skills/prompt-architect/references/frameworks/ctf.md +207 -207
- package/skills/prompt-architect/references/frameworks/devils-advocate.md +206 -206
- package/skills/prompt-architect/references/frameworks/least-to-most.md +226 -226
- package/skills/prompt-architect/references/frameworks/plan-and-solve.md +210 -210
- package/skills/prompt-architect/references/frameworks/pre-mortem.md +197 -197
- package/skills/prompt-architect/references/frameworks/race.md +243 -243
- package/skills/prompt-architect/references/frameworks/rcot.md +203 -203
- package/skills/prompt-architect/references/frameworks/react.md +304 -304
- package/skills/prompt-architect/references/frameworks/reverse-role.md +189 -189
- package/skills/prompt-architect/references/frameworks/rise.md +555 -555
- package/skills/prompt-architect/references/frameworks/risen.md +297 -297
- package/skills/prompt-architect/references/frameworks/rpef.md +195 -195
- package/skills/prompt-architect/references/frameworks/rtf.md +358 -358
- package/skills/prompt-architect/references/frameworks/self-refine.md +205 -205
- package/skills/prompt-architect/references/frameworks/skeleton-of-thought.md +186 -186
- package/skills/prompt-architect/references/frameworks/step-back.md +206 -206
- package/skills/prompt-architect/references/frameworks/tidd-ec.md +470 -470
- package/skills/prompt-architect/references/frameworks/tree-of-thought.md +260 -260
- package/skills/prompt-architect/scripts/framework_analyzer.py +807 -807
- package/skills/prompt-architect/scripts/prompt_evaluator.py +336 -336
- package/adapters/for-cursor.mdc +0 -138
- package/adapters/for-gemini-cli.md +0 -70
- package/adapters/for-github-copilot.md +0 -141
- package/adapters/for-openai-codex-cli.md +0 -158
|
@@ -1,336 +1,336 @@
|
|
|
1
|
-
"""
|
|
2
|
-
Prompt Evaluator - Scores prompts across quality dimensions
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
def evaluate_prompt(prompt_text):
|
|
6
|
-
"""
|
|
7
|
-
Evaluate a prompt across multiple quality dimensions.
|
|
8
|
-
|
|
9
|
-
Args:
|
|
10
|
-
prompt_text (str): The prompt to evaluate
|
|
11
|
-
|
|
12
|
-
Returns:
|
|
13
|
-
dict: Scores and analysis for each dimension
|
|
14
|
-
"""
|
|
15
|
-
results = {
|
|
16
|
-
'clarity': evaluate_clarity(prompt_text),
|
|
17
|
-
'specificity': evaluate_specificity(prompt_text),
|
|
18
|
-
'context': evaluate_context(prompt_text),
|
|
19
|
-
'completeness': evaluate_completeness(prompt_text),
|
|
20
|
-
'structure': evaluate_structure(prompt_text)
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
# Calculate overall score
|
|
24
|
-
results['overall'] = sum(r['score'] for r in results.values()) / len(results)
|
|
25
|
-
|
|
26
|
-
return results
|
|
27
|
-
|
|
28
|
-
def evaluate_clarity(prompt_text):
|
|
29
|
-
"""Evaluate how clear and unambiguous the prompt is."""
|
|
30
|
-
score = 5 # Base score
|
|
31
|
-
issues = []
|
|
32
|
-
strengths = []
|
|
33
|
-
|
|
34
|
-
# Check for vague words
|
|
35
|
-
vague_words = ['thing', 'stuff', 'something', 'anything', 'maybe', 'kind of', 'sort of']
|
|
36
|
-
vague_count = sum(1 for word in vague_words if word in prompt_text.lower())
|
|
37
|
-
if vague_count > 0:
|
|
38
|
-
score -= min(vague_count * 0.5, 3)
|
|
39
|
-
issues.append(f"Contains {vague_count} vague term(s)")
|
|
40
|
-
else:
|
|
41
|
-
strengths.append("No vague language detected")
|
|
42
|
-
|
|
43
|
-
# Check for question words (indicates goal)
|
|
44
|
-
question_words = ['what', 'how', 'why', 'when', 'where', 'who']
|
|
45
|
-
has_clear_goal = any(word in prompt_text.lower() for word in question_words)
|
|
46
|
-
if has_clear_goal:
|
|
47
|
-
score += 2
|
|
48
|
-
strengths.append("Clear goal indicated")
|
|
49
|
-
else:
|
|
50
|
-
issues.append("Goal could be more explicit")
|
|
51
|
-
|
|
52
|
-
# Check for ambiguous pronouns without antecedents
|
|
53
|
-
pronouns = ['it', 'this', 'that', 'they']
|
|
54
|
-
# Simple heuristic: if prompt starts with pronoun, likely unclear
|
|
55
|
-
first_word = prompt_text.split()[0].lower() if prompt_text.split() else ""
|
|
56
|
-
if first_word in pronouns:
|
|
57
|
-
score -= 2
|
|
58
|
-
issues.append("Starts with ambiguous pronoun")
|
|
59
|
-
|
|
60
|
-
return {
|
|
61
|
-
'score': max(0, min(10, score)),
|
|
62
|
-
'issues': issues,
|
|
63
|
-
'strengths': strengths
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
def evaluate_specificity(prompt_text):
|
|
67
|
-
"""Evaluate how specific and detailed the prompt is."""
|
|
68
|
-
score = 5 # Base score
|
|
69
|
-
issues = []
|
|
70
|
-
strengths = []
|
|
71
|
-
|
|
72
|
-
word_count = len(prompt_text.split())
|
|
73
|
-
|
|
74
|
-
# Very short prompts are often not specific enough
|
|
75
|
-
if word_count < 5:
|
|
76
|
-
score -= 3
|
|
77
|
-
issues.append(f"Very brief ({word_count} words) - likely missing details")
|
|
78
|
-
elif word_count < 10:
|
|
79
|
-
score -= 1
|
|
80
|
-
issues.append("Quite brief - could benefit from more specifics")
|
|
81
|
-
elif word_count > 15:
|
|
82
|
-
strengths.append("Good level of detail provided")
|
|
83
|
-
score += 1
|
|
84
|
-
|
|
85
|
-
# Check for quantitative details (numbers, dates, etc.)
|
|
86
|
-
has_numbers = any(char.isdigit() for char in prompt_text)
|
|
87
|
-
if has_numbers:
|
|
88
|
-
score += 1
|
|
89
|
-
strengths.append("Includes quantitative details")
|
|
90
|
-
|
|
91
|
-
# Check for specific named entities (capitals indicating names, places, etc.)
|
|
92
|
-
proper_nouns = sum(1 for word in prompt_text.split() if word and word[0].isupper() and word not in ['I', 'A'])
|
|
93
|
-
if proper_nouns > 0:
|
|
94
|
-
score += 1
|
|
95
|
-
strengths.append(f"Mentions specific entities ({proper_nouns} found)")
|
|
96
|
-
|
|
97
|
-
# Check for specifications (format, length, style mentions)
|
|
98
|
-
spec_keywords = ['format', 'length', 'style', 'words', 'paragraphs', 'sections', 'points']
|
|
99
|
-
spec_count = sum(1 for keyword in spec_keywords if keyword in prompt_text.lower())
|
|
100
|
-
if spec_count > 0:
|
|
101
|
-
score += min(spec_count, 2)
|
|
102
|
-
strengths.append(f"Includes {spec_count} specification(s)")
|
|
103
|
-
else:
|
|
104
|
-
issues.append("No format/length specifications")
|
|
105
|
-
|
|
106
|
-
return {
|
|
107
|
-
'score': max(0, min(10, score)),
|
|
108
|
-
'issues': issues,
|
|
109
|
-
'strengths': strengths
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
def evaluate_context(prompt_text):
|
|
113
|
-
"""Evaluate whether sufficient context is provided."""
|
|
114
|
-
score = 5 # Base score
|
|
115
|
-
issues = []
|
|
116
|
-
strengths = []
|
|
117
|
-
|
|
118
|
-
# Check for context indicators
|
|
119
|
-
context_indicators = [
|
|
120
|
-
'for', 'because', 'since', 'background', 'context', 'situation',
|
|
121
|
-
'currently', 'previously', 'in order to', 'so that'
|
|
122
|
-
]
|
|
123
|
-
context_count = sum(1 for indicator in context_indicators if indicator in prompt_text.lower())
|
|
124
|
-
|
|
125
|
-
if context_count == 0:
|
|
126
|
-
score -= 3
|
|
127
|
-
issues.append("No contextual information provided")
|
|
128
|
-
elif context_count >= 2:
|
|
129
|
-
score += 2
|
|
130
|
-
strengths.append(f"Good contextual framing ({context_count} indicators)")
|
|
131
|
-
else:
|
|
132
|
-
score += 1
|
|
133
|
-
strengths.append("Some context provided")
|
|
134
|
-
|
|
135
|
-
# Check for constraints or limitations
|
|
136
|
-
constraint_words = [
|
|
137
|
-
'must', 'should', 'cannot', 'don\'t', 'avoid', 'limit', 'maximum',
|
|
138
|
-
'minimum', 'required', 'constraint', 'restriction'
|
|
139
|
-
]
|
|
140
|
-
has_constraints = any(word in prompt_text.lower() for word in constraint_words)
|
|
141
|
-
if has_constraints:
|
|
142
|
-
score += 1
|
|
143
|
-
strengths.append("Constraints or requirements specified")
|
|
144
|
-
else:
|
|
145
|
-
issues.append("No constraints or limitations specified")
|
|
146
|
-
|
|
147
|
-
return {
|
|
148
|
-
'score': max(0, min(10, score)),
|
|
149
|
-
'issues': issues,
|
|
150
|
-
'strengths': strengths
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
def evaluate_completeness(prompt_text):
|
|
154
|
-
"""Evaluate whether all necessary information seems present."""
|
|
155
|
-
score = 5 # Base score
|
|
156
|
-
issues = []
|
|
157
|
-
strengths = []
|
|
158
|
-
|
|
159
|
-
# Check if prompt answers: What, Why, How
|
|
160
|
-
has_what = any(word in prompt_text.lower() for word in ['create', 'write', 'analyze', 'generate', 'make', 'develop', 'build'])
|
|
161
|
-
has_why = any(word in prompt_text.lower() for word in ['because', 'for', 'to', 'so that', 'in order to', 'goal', 'purpose'])
|
|
162
|
-
has_how = any(word in prompt_text.lower() for word in ['using', 'with', 'through', 'by', 'via', 'format', 'style', 'approach'])
|
|
163
|
-
|
|
164
|
-
if has_what:
|
|
165
|
-
score += 2
|
|
166
|
-
strengths.append("Task/action clearly stated")
|
|
167
|
-
else:
|
|
168
|
-
score -= 2
|
|
169
|
-
issues.append("What to do is unclear")
|
|
170
|
-
|
|
171
|
-
if has_why:
|
|
172
|
-
score += 1
|
|
173
|
-
strengths.append("Purpose/motivation included")
|
|
174
|
-
else:
|
|
175
|
-
issues.append("Missing purpose or goal")
|
|
176
|
-
|
|
177
|
-
if has_how:
|
|
178
|
-
score += 1
|
|
179
|
-
strengths.append("Approach or method indicated")
|
|
180
|
-
else:
|
|
181
|
-
issues.append("Missing guidance on approach")
|
|
182
|
-
|
|
183
|
-
# Check for output format specification
|
|
184
|
-
format_words = ['format', 'structure', 'as a', 'in the form of', 'list', 'table', 'paragraph', 'json', 'markdown']
|
|
185
|
-
has_format = any(word in prompt_text.lower() for word in format_words)
|
|
186
|
-
if has_format:
|
|
187
|
-
score += 1
|
|
188
|
-
strengths.append("Output format specified")
|
|
189
|
-
else:
|
|
190
|
-
issues.append("Output format not specified")
|
|
191
|
-
|
|
192
|
-
return {
|
|
193
|
-
'score': max(0, min(10, score)),
|
|
194
|
-
'issues': issues,
|
|
195
|
-
'strengths': strengths
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
def evaluate_structure(prompt_text):
|
|
199
|
-
"""Evaluate how well-structured the prompt is."""
|
|
200
|
-
score = 5 # Base score
|
|
201
|
-
issues = []
|
|
202
|
-
strengths = []
|
|
203
|
-
|
|
204
|
-
# Check for sentence structure
|
|
205
|
-
sentences = [s.strip() for s in prompt_text.split('.') if s.strip()]
|
|
206
|
-
if len(sentences) > 1:
|
|
207
|
-
score += 1
|
|
208
|
-
strengths.append(f"Multi-sentence structure ({len(sentences)} sentences)")
|
|
209
|
-
else:
|
|
210
|
-
issues.append("Single sentence - could benefit from more structure")
|
|
211
|
-
|
|
212
|
-
# Check for list/bullet indicators
|
|
213
|
-
has_bullets = any(char in prompt_text for char in ['-', '•', '*']) or '\n' in prompt_text
|
|
214
|
-
if has_bullets:
|
|
215
|
-
score += 1
|
|
216
|
-
strengths.append("Uses lists or structure markers")
|
|
217
|
-
|
|
218
|
-
# Check for section markers
|
|
219
|
-
section_markers = [':', '\n\n', '1.', '2.', 'First', 'Second']
|
|
220
|
-
has_sections = any(marker in prompt_text for marker in section_markers)
|
|
221
|
-
if has_sections:
|
|
222
|
-
score += 1
|
|
223
|
-
strengths.append("Organized into sections")
|
|
224
|
-
|
|
225
|
-
# Check for run-on sentences
|
|
226
|
-
very_long_sentence = any(len(s.split()) > 40 for s in sentences)
|
|
227
|
-
if very_long_sentence:
|
|
228
|
-
score -= 1
|
|
229
|
-
issues.append("Contains very long sentence(s) - could be split")
|
|
230
|
-
|
|
231
|
-
# Check organization
|
|
232
|
-
word_count = len(prompt_text.split())
|
|
233
|
-
if word_count > 30 and not has_sections and not has_bullets:
|
|
234
|
-
score -= 1
|
|
235
|
-
issues.append("Longer prompt would benefit from more structure")
|
|
236
|
-
elif word_count > 30 and (has_sections or has_bullets):
|
|
237
|
-
strengths.append("Well-organized for its length")
|
|
238
|
-
score += 1
|
|
239
|
-
|
|
240
|
-
return {
|
|
241
|
-
'score': max(0, min(10, score)),
|
|
242
|
-
'issues': issues,
|
|
243
|
-
'strengths': strengths
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
def generate_improvement_suggestions(evaluation):
|
|
247
|
-
"""Generate specific improvement suggestions based on evaluation."""
|
|
248
|
-
suggestions = []
|
|
249
|
-
|
|
250
|
-
# Clarity suggestions
|
|
251
|
-
if evaluation['clarity']['score'] < 7:
|
|
252
|
-
suggestions.append("Improve clarity by:")
|
|
253
|
-
for issue in evaluation['clarity']['issues']:
|
|
254
|
-
if 'vague' in issue.lower():
|
|
255
|
-
suggestions.append(" - Replace vague terms with specific descriptions")
|
|
256
|
-
if 'goal' in issue.lower():
|
|
257
|
-
suggestions.append(" - Clearly state what you want to achieve")
|
|
258
|
-
if 'pronoun' in issue.lower():
|
|
259
|
-
suggestions.append(" - Replace ambiguous pronouns with specific nouns")
|
|
260
|
-
|
|
261
|
-
# Specificity suggestions
|
|
262
|
-
if evaluation['specificity']['score'] < 7:
|
|
263
|
-
suggestions.append("Increase specificity by:")
|
|
264
|
-
for issue in evaluation['specificity']['issues']:
|
|
265
|
-
if 'brief' in issue.lower():
|
|
266
|
-
suggestions.append(" - Add more details about requirements")
|
|
267
|
-
if 'specification' in issue.lower():
|
|
268
|
-
suggestions.append(" - Specify desired format, length, or structure")
|
|
269
|
-
|
|
270
|
-
# Context suggestions
|
|
271
|
-
if evaluation['context']['score'] < 7:
|
|
272
|
-
suggestions.append("Add more context:")
|
|
273
|
-
for issue in evaluation['context']['issues']:
|
|
274
|
-
if 'contextual' in issue.lower():
|
|
275
|
-
suggestions.append(" - Explain the background or situation")
|
|
276
|
-
if 'constraint' in issue.lower():
|
|
277
|
-
suggestions.append(" - Mention any limitations or requirements")
|
|
278
|
-
|
|
279
|
-
# Completeness suggestions
|
|
280
|
-
if evaluation['completeness']['score'] < 7:
|
|
281
|
-
suggestions.append("Make it more complete:")
|
|
282
|
-
for issue in evaluation['completeness']['issues']:
|
|
283
|
-
if 'what' in issue.lower():
|
|
284
|
-
suggestions.append(" - Clearly state what action to take")
|
|
285
|
-
if 'why' in issue.lower() or 'purpose' in issue.lower():
|
|
286
|
-
suggestions.append(" - Explain the purpose or goal")
|
|
287
|
-
if 'how' in issue.lower() or 'approach' in issue.lower():
|
|
288
|
-
suggestions.append(" - Indicate preferred approach or method")
|
|
289
|
-
if 'format' in issue.lower():
|
|
290
|
-
suggestions.append(" - Specify how output should be formatted")
|
|
291
|
-
|
|
292
|
-
# Structure suggestions
|
|
293
|
-
if evaluation['structure']['score'] < 7:
|
|
294
|
-
suggestions.append("Improve structure:")
|
|
295
|
-
for issue in evaluation['structure']['issues']:
|
|
296
|
-
if 'single sentence' in issue.lower():
|
|
297
|
-
suggestions.append(" - Break into multiple sentences")
|
|
298
|
-
if 'long sentence' in issue.lower():
|
|
299
|
-
suggestions.append(" - Split long sentences for clarity")
|
|
300
|
-
if 'more structure' in issue.lower():
|
|
301
|
-
suggestions.append(" - Use bullet points or numbered lists")
|
|
302
|
-
|
|
303
|
-
return suggestions
|
|
304
|
-
|
|
305
|
-
if __name__ == "__main__":
|
|
306
|
-
# Example usage
|
|
307
|
-
test_prompts = [
|
|
308
|
-
"Write about AI",
|
|
309
|
-
"Create a detailed blog post about machine learning applications in healthcare for non-technical readers, around 800 words, in a friendly but professional tone.",
|
|
310
|
-
"Analyze the data",
|
|
311
|
-
"Review this code for security vulnerabilities, focusing on SQL injection and XSS. Provide specific line numbers and remediation steps."
|
|
312
|
-
]
|
|
313
|
-
|
|
314
|
-
for prompt in test_prompts:
|
|
315
|
-
print(f"\n{'='*60}")
|
|
316
|
-
print(f"Prompt: {prompt}")
|
|
317
|
-
print(f"{'='*60}")
|
|
318
|
-
|
|
319
|
-
eval_result = evaluate_prompt(prompt)
|
|
320
|
-
|
|
321
|
-
print(f"\nOverall Score: {eval_result['overall']:.1f}/10\n")
|
|
322
|
-
|
|
323
|
-
for dimension, result in eval_result.items():
|
|
324
|
-
if dimension == 'overall':
|
|
325
|
-
continue
|
|
326
|
-
print(f"{dimension.upper()}: {result['score']}/10")
|
|
327
|
-
if result['strengths']:
|
|
328
|
-
print(f" ✓ {', '.join(result['strengths'])}")
|
|
329
|
-
if result['issues']:
|
|
330
|
-
print(f" ✗ {', '.join(result['issues'])}")
|
|
331
|
-
|
|
332
|
-
suggestions = generate_improvement_suggestions(eval_result)
|
|
333
|
-
if suggestions:
|
|
334
|
-
print(f"\nSuggestions:")
|
|
335
|
-
for suggestion in suggestions:
|
|
336
|
-
print(f" {suggestion}")
|
|
1
|
+
"""
|
|
2
|
+
Prompt Evaluator - Scores prompts across quality dimensions
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
def evaluate_prompt(prompt_text):
|
|
6
|
+
"""
|
|
7
|
+
Evaluate a prompt across multiple quality dimensions.
|
|
8
|
+
|
|
9
|
+
Args:
|
|
10
|
+
prompt_text (str): The prompt to evaluate
|
|
11
|
+
|
|
12
|
+
Returns:
|
|
13
|
+
dict: Scores and analysis for each dimension
|
|
14
|
+
"""
|
|
15
|
+
results = {
|
|
16
|
+
'clarity': evaluate_clarity(prompt_text),
|
|
17
|
+
'specificity': evaluate_specificity(prompt_text),
|
|
18
|
+
'context': evaluate_context(prompt_text),
|
|
19
|
+
'completeness': evaluate_completeness(prompt_text),
|
|
20
|
+
'structure': evaluate_structure(prompt_text)
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
# Calculate overall score
|
|
24
|
+
results['overall'] = sum(r['score'] for r in results.values()) / len(results)
|
|
25
|
+
|
|
26
|
+
return results
|
|
27
|
+
|
|
28
|
+
def evaluate_clarity(prompt_text):
|
|
29
|
+
"""Evaluate how clear and unambiguous the prompt is."""
|
|
30
|
+
score = 5 # Base score
|
|
31
|
+
issues = []
|
|
32
|
+
strengths = []
|
|
33
|
+
|
|
34
|
+
# Check for vague words
|
|
35
|
+
vague_words = ['thing', 'stuff', 'something', 'anything', 'maybe', 'kind of', 'sort of']
|
|
36
|
+
vague_count = sum(1 for word in vague_words if word in prompt_text.lower())
|
|
37
|
+
if vague_count > 0:
|
|
38
|
+
score -= min(vague_count * 0.5, 3)
|
|
39
|
+
issues.append(f"Contains {vague_count} vague term(s)")
|
|
40
|
+
else:
|
|
41
|
+
strengths.append("No vague language detected")
|
|
42
|
+
|
|
43
|
+
# Check for question words (indicates goal)
|
|
44
|
+
question_words = ['what', 'how', 'why', 'when', 'where', 'who']
|
|
45
|
+
has_clear_goal = any(word in prompt_text.lower() for word in question_words)
|
|
46
|
+
if has_clear_goal:
|
|
47
|
+
score += 2
|
|
48
|
+
strengths.append("Clear goal indicated")
|
|
49
|
+
else:
|
|
50
|
+
issues.append("Goal could be more explicit")
|
|
51
|
+
|
|
52
|
+
# Check for ambiguous pronouns without antecedents
|
|
53
|
+
pronouns = ['it', 'this', 'that', 'they']
|
|
54
|
+
# Simple heuristic: if prompt starts with pronoun, likely unclear
|
|
55
|
+
first_word = prompt_text.split()[0].lower() if prompt_text.split() else ""
|
|
56
|
+
if first_word in pronouns:
|
|
57
|
+
score -= 2
|
|
58
|
+
issues.append("Starts with ambiguous pronoun")
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
'score': max(0, min(10, score)),
|
|
62
|
+
'issues': issues,
|
|
63
|
+
'strengths': strengths
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
def evaluate_specificity(prompt_text):
|
|
67
|
+
"""Evaluate how specific and detailed the prompt is."""
|
|
68
|
+
score = 5 # Base score
|
|
69
|
+
issues = []
|
|
70
|
+
strengths = []
|
|
71
|
+
|
|
72
|
+
word_count = len(prompt_text.split())
|
|
73
|
+
|
|
74
|
+
# Very short prompts are often not specific enough
|
|
75
|
+
if word_count < 5:
|
|
76
|
+
score -= 3
|
|
77
|
+
issues.append(f"Very brief ({word_count} words) - likely missing details")
|
|
78
|
+
elif word_count < 10:
|
|
79
|
+
score -= 1
|
|
80
|
+
issues.append("Quite brief - could benefit from more specifics")
|
|
81
|
+
elif word_count > 15:
|
|
82
|
+
strengths.append("Good level of detail provided")
|
|
83
|
+
score += 1
|
|
84
|
+
|
|
85
|
+
# Check for quantitative details (numbers, dates, etc.)
|
|
86
|
+
has_numbers = any(char.isdigit() for char in prompt_text)
|
|
87
|
+
if has_numbers:
|
|
88
|
+
score += 1
|
|
89
|
+
strengths.append("Includes quantitative details")
|
|
90
|
+
|
|
91
|
+
# Check for specific named entities (capitals indicating names, places, etc.)
|
|
92
|
+
proper_nouns = sum(1 for word in prompt_text.split() if word and word[0].isupper() and word not in ['I', 'A'])
|
|
93
|
+
if proper_nouns > 0:
|
|
94
|
+
score += 1
|
|
95
|
+
strengths.append(f"Mentions specific entities ({proper_nouns} found)")
|
|
96
|
+
|
|
97
|
+
# Check for specifications (format, length, style mentions)
|
|
98
|
+
spec_keywords = ['format', 'length', 'style', 'words', 'paragraphs', 'sections', 'points']
|
|
99
|
+
spec_count = sum(1 for keyword in spec_keywords if keyword in prompt_text.lower())
|
|
100
|
+
if spec_count > 0:
|
|
101
|
+
score += min(spec_count, 2)
|
|
102
|
+
strengths.append(f"Includes {spec_count} specification(s)")
|
|
103
|
+
else:
|
|
104
|
+
issues.append("No format/length specifications")
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
'score': max(0, min(10, score)),
|
|
108
|
+
'issues': issues,
|
|
109
|
+
'strengths': strengths
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
def evaluate_context(prompt_text):
|
|
113
|
+
"""Evaluate whether sufficient context is provided."""
|
|
114
|
+
score = 5 # Base score
|
|
115
|
+
issues = []
|
|
116
|
+
strengths = []
|
|
117
|
+
|
|
118
|
+
# Check for context indicators
|
|
119
|
+
context_indicators = [
|
|
120
|
+
'for', 'because', 'since', 'background', 'context', 'situation',
|
|
121
|
+
'currently', 'previously', 'in order to', 'so that'
|
|
122
|
+
]
|
|
123
|
+
context_count = sum(1 for indicator in context_indicators if indicator in prompt_text.lower())
|
|
124
|
+
|
|
125
|
+
if context_count == 0:
|
|
126
|
+
score -= 3
|
|
127
|
+
issues.append("No contextual information provided")
|
|
128
|
+
elif context_count >= 2:
|
|
129
|
+
score += 2
|
|
130
|
+
strengths.append(f"Good contextual framing ({context_count} indicators)")
|
|
131
|
+
else:
|
|
132
|
+
score += 1
|
|
133
|
+
strengths.append("Some context provided")
|
|
134
|
+
|
|
135
|
+
# Check for constraints or limitations
|
|
136
|
+
constraint_words = [
|
|
137
|
+
'must', 'should', 'cannot', 'don\'t', 'avoid', 'limit', 'maximum',
|
|
138
|
+
'minimum', 'required', 'constraint', 'restriction'
|
|
139
|
+
]
|
|
140
|
+
has_constraints = any(word in prompt_text.lower() for word in constraint_words)
|
|
141
|
+
if has_constraints:
|
|
142
|
+
score += 1
|
|
143
|
+
strengths.append("Constraints or requirements specified")
|
|
144
|
+
else:
|
|
145
|
+
issues.append("No constraints or limitations specified")
|
|
146
|
+
|
|
147
|
+
return {
|
|
148
|
+
'score': max(0, min(10, score)),
|
|
149
|
+
'issues': issues,
|
|
150
|
+
'strengths': strengths
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
def evaluate_completeness(prompt_text):
|
|
154
|
+
"""Evaluate whether all necessary information seems present."""
|
|
155
|
+
score = 5 # Base score
|
|
156
|
+
issues = []
|
|
157
|
+
strengths = []
|
|
158
|
+
|
|
159
|
+
# Check if prompt answers: What, Why, How
|
|
160
|
+
has_what = any(word in prompt_text.lower() for word in ['create', 'write', 'analyze', 'generate', 'make', 'develop', 'build'])
|
|
161
|
+
has_why = any(word in prompt_text.lower() for word in ['because', 'for', 'to', 'so that', 'in order to', 'goal', 'purpose'])
|
|
162
|
+
has_how = any(word in prompt_text.lower() for word in ['using', 'with', 'through', 'by', 'via', 'format', 'style', 'approach'])
|
|
163
|
+
|
|
164
|
+
if has_what:
|
|
165
|
+
score += 2
|
|
166
|
+
strengths.append("Task/action clearly stated")
|
|
167
|
+
else:
|
|
168
|
+
score -= 2
|
|
169
|
+
issues.append("What to do is unclear")
|
|
170
|
+
|
|
171
|
+
if has_why:
|
|
172
|
+
score += 1
|
|
173
|
+
strengths.append("Purpose/motivation included")
|
|
174
|
+
else:
|
|
175
|
+
issues.append("Missing purpose or goal")
|
|
176
|
+
|
|
177
|
+
if has_how:
|
|
178
|
+
score += 1
|
|
179
|
+
strengths.append("Approach or method indicated")
|
|
180
|
+
else:
|
|
181
|
+
issues.append("Missing guidance on approach")
|
|
182
|
+
|
|
183
|
+
# Check for output format specification
|
|
184
|
+
format_words = ['format', 'structure', 'as a', 'in the form of', 'list', 'table', 'paragraph', 'json', 'markdown']
|
|
185
|
+
has_format = any(word in prompt_text.lower() for word in format_words)
|
|
186
|
+
if has_format:
|
|
187
|
+
score += 1
|
|
188
|
+
strengths.append("Output format specified")
|
|
189
|
+
else:
|
|
190
|
+
issues.append("Output format not specified")
|
|
191
|
+
|
|
192
|
+
return {
|
|
193
|
+
'score': max(0, min(10, score)),
|
|
194
|
+
'issues': issues,
|
|
195
|
+
'strengths': strengths
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
def evaluate_structure(prompt_text):
|
|
199
|
+
"""Evaluate how well-structured the prompt is."""
|
|
200
|
+
score = 5 # Base score
|
|
201
|
+
issues = []
|
|
202
|
+
strengths = []
|
|
203
|
+
|
|
204
|
+
# Check for sentence structure
|
|
205
|
+
sentences = [s.strip() for s in prompt_text.split('.') if s.strip()]
|
|
206
|
+
if len(sentences) > 1:
|
|
207
|
+
score += 1
|
|
208
|
+
strengths.append(f"Multi-sentence structure ({len(sentences)} sentences)")
|
|
209
|
+
else:
|
|
210
|
+
issues.append("Single sentence - could benefit from more structure")
|
|
211
|
+
|
|
212
|
+
# Check for list/bullet indicators
|
|
213
|
+
has_bullets = any(char in prompt_text for char in ['-', '•', '*']) or '\n' in prompt_text
|
|
214
|
+
if has_bullets:
|
|
215
|
+
score += 1
|
|
216
|
+
strengths.append("Uses lists or structure markers")
|
|
217
|
+
|
|
218
|
+
# Check for section markers
|
|
219
|
+
section_markers = [':', '\n\n', '1.', '2.', 'First', 'Second']
|
|
220
|
+
has_sections = any(marker in prompt_text for marker in section_markers)
|
|
221
|
+
if has_sections:
|
|
222
|
+
score += 1
|
|
223
|
+
strengths.append("Organized into sections")
|
|
224
|
+
|
|
225
|
+
# Check for run-on sentences
|
|
226
|
+
very_long_sentence = any(len(s.split()) > 40 for s in sentences)
|
|
227
|
+
if very_long_sentence:
|
|
228
|
+
score -= 1
|
|
229
|
+
issues.append("Contains very long sentence(s) - could be split")
|
|
230
|
+
|
|
231
|
+
# Check organization
|
|
232
|
+
word_count = len(prompt_text.split())
|
|
233
|
+
if word_count > 30 and not has_sections and not has_bullets:
|
|
234
|
+
score -= 1
|
|
235
|
+
issues.append("Longer prompt would benefit from more structure")
|
|
236
|
+
elif word_count > 30 and (has_sections or has_bullets):
|
|
237
|
+
strengths.append("Well-organized for its length")
|
|
238
|
+
score += 1
|
|
239
|
+
|
|
240
|
+
return {
|
|
241
|
+
'score': max(0, min(10, score)),
|
|
242
|
+
'issues': issues,
|
|
243
|
+
'strengths': strengths
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
def generate_improvement_suggestions(evaluation):
|
|
247
|
+
"""Generate specific improvement suggestions based on evaluation."""
|
|
248
|
+
suggestions = []
|
|
249
|
+
|
|
250
|
+
# Clarity suggestions
|
|
251
|
+
if evaluation['clarity']['score'] < 7:
|
|
252
|
+
suggestions.append("Improve clarity by:")
|
|
253
|
+
for issue in evaluation['clarity']['issues']:
|
|
254
|
+
if 'vague' in issue.lower():
|
|
255
|
+
suggestions.append(" - Replace vague terms with specific descriptions")
|
|
256
|
+
if 'goal' in issue.lower():
|
|
257
|
+
suggestions.append(" - Clearly state what you want to achieve")
|
|
258
|
+
if 'pronoun' in issue.lower():
|
|
259
|
+
suggestions.append(" - Replace ambiguous pronouns with specific nouns")
|
|
260
|
+
|
|
261
|
+
# Specificity suggestions
|
|
262
|
+
if evaluation['specificity']['score'] < 7:
|
|
263
|
+
suggestions.append("Increase specificity by:")
|
|
264
|
+
for issue in evaluation['specificity']['issues']:
|
|
265
|
+
if 'brief' in issue.lower():
|
|
266
|
+
suggestions.append(" - Add more details about requirements")
|
|
267
|
+
if 'specification' in issue.lower():
|
|
268
|
+
suggestions.append(" - Specify desired format, length, or structure")
|
|
269
|
+
|
|
270
|
+
# Context suggestions
|
|
271
|
+
if evaluation['context']['score'] < 7:
|
|
272
|
+
suggestions.append("Add more context:")
|
|
273
|
+
for issue in evaluation['context']['issues']:
|
|
274
|
+
if 'contextual' in issue.lower():
|
|
275
|
+
suggestions.append(" - Explain the background or situation")
|
|
276
|
+
if 'constraint' in issue.lower():
|
|
277
|
+
suggestions.append(" - Mention any limitations or requirements")
|
|
278
|
+
|
|
279
|
+
# Completeness suggestions
|
|
280
|
+
if evaluation['completeness']['score'] < 7:
|
|
281
|
+
suggestions.append("Make it more complete:")
|
|
282
|
+
for issue in evaluation['completeness']['issues']:
|
|
283
|
+
if 'what' in issue.lower():
|
|
284
|
+
suggestions.append(" - Clearly state what action to take")
|
|
285
|
+
if 'why' in issue.lower() or 'purpose' in issue.lower():
|
|
286
|
+
suggestions.append(" - Explain the purpose or goal")
|
|
287
|
+
if 'how' in issue.lower() or 'approach' in issue.lower():
|
|
288
|
+
suggestions.append(" - Indicate preferred approach or method")
|
|
289
|
+
if 'format' in issue.lower():
|
|
290
|
+
suggestions.append(" - Specify how output should be formatted")
|
|
291
|
+
|
|
292
|
+
# Structure suggestions
|
|
293
|
+
if evaluation['structure']['score'] < 7:
|
|
294
|
+
suggestions.append("Improve structure:")
|
|
295
|
+
for issue in evaluation['structure']['issues']:
|
|
296
|
+
if 'single sentence' in issue.lower():
|
|
297
|
+
suggestions.append(" - Break into multiple sentences")
|
|
298
|
+
if 'long sentence' in issue.lower():
|
|
299
|
+
suggestions.append(" - Split long sentences for clarity")
|
|
300
|
+
if 'more structure' in issue.lower():
|
|
301
|
+
suggestions.append(" - Use bullet points or numbered lists")
|
|
302
|
+
|
|
303
|
+
return suggestions
|
|
304
|
+
|
|
305
|
+
if __name__ == "__main__":
|
|
306
|
+
# Example usage
|
|
307
|
+
test_prompts = [
|
|
308
|
+
"Write about AI",
|
|
309
|
+
"Create a detailed blog post about machine learning applications in healthcare for non-technical readers, around 800 words, in a friendly but professional tone.",
|
|
310
|
+
"Analyze the data",
|
|
311
|
+
"Review this code for security vulnerabilities, focusing on SQL injection and XSS. Provide specific line numbers and remediation steps."
|
|
312
|
+
]
|
|
313
|
+
|
|
314
|
+
for prompt in test_prompts:
|
|
315
|
+
print(f"\n{'='*60}")
|
|
316
|
+
print(f"Prompt: {prompt}")
|
|
317
|
+
print(f"{'='*60}")
|
|
318
|
+
|
|
319
|
+
eval_result = evaluate_prompt(prompt)
|
|
320
|
+
|
|
321
|
+
print(f"\nOverall Score: {eval_result['overall']:.1f}/10\n")
|
|
322
|
+
|
|
323
|
+
for dimension, result in eval_result.items():
|
|
324
|
+
if dimension == 'overall':
|
|
325
|
+
continue
|
|
326
|
+
print(f"{dimension.upper()}: {result['score']}/10")
|
|
327
|
+
if result['strengths']:
|
|
328
|
+
print(f" ✓ {', '.join(result['strengths'])}")
|
|
329
|
+
if result['issues']:
|
|
330
|
+
print(f" ✗ {', '.join(result['issues'])}")
|
|
331
|
+
|
|
332
|
+
suggestions = generate_improvement_suggestions(eval_result)
|
|
333
|
+
if suggestions:
|
|
334
|
+
print(f"\nSuggestions:")
|
|
335
|
+
for suggestion in suggestions:
|
|
336
|
+
print(f" {suggestion}")
|