Files
aitsc/src/flask_prompt_master/routes/expert_generate_5.py
renjianbo 1c258ef2bd fix: differentiate prompt generation strategy by intent category
A/B test (20 cases) showed one-size-fits-all meta-prompt degrades
quality in non-technical domains. New approach:
- 技术: keep full structure (tested +0.6 score improvement)
- 创意: light structure, emphasize creative exploration (was -0.4)
- 分析: methodology-driven, not format-driven (was -1.0)
- 咨询: minimal structure, decision-maker perspective (was -1.8)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-06-28 09:05:07 +08:00

312 lines
14 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- coding: utf-8 -*-
"""
智能提示词优化5号专家 — 三阶段流水线
阶段1:消歧增强意图分析(复用4号)
阶段2:生成优化提示词(核心产出,用户可复制复用)
阶段3:用优化提示词立即调模型产出样例(证明提示词质量)
"""
from flask import Blueprint, render_template, request, jsonify
from openai import OpenAI
import hashlib
import json
import logging
import os
import time
from datetime import datetime
from src.flask_prompt_master import db
from src.flask_prompt_master.models.models import User, Prompt
from src.flask_prompt_master.models.history_models import PromptHistory, UserStatistics
logger = logging.getLogger(__name__)
expert_generate_5_bp = Blueprint('expert_generate_5', __name__)
_dedup_cache = {}
client = OpenAI(
api_key=os.environ.get('LLM_API_KEY') or 'sk-fdf7cc1c73504e628ec0119b7e11b8cc',
base_url=os.environ.get('LLM_API_URL') or 'https://api.deepseek.com/v1'
)
# 阶段1:消歧增强意图分析(与4号完全相同)
INTENT_PROMPT_V4 = """你是一位资深的意图分析专家。你的任务是精确理解用户需求,尤其要处理中文多义词的歧义。
## 消歧规则(优先级从高到低)
### 规则1:"设计"的多义性
| 上下文 | 判定 |
|--------|------|
| 系统设计、架构设计、数据库设计、API设计、模块设计、技术方案设计 | **技术** |
| UI设计、海报设计、品牌设计、视觉设计、创意设计、艺术设计 | **创意** |
| 流程设计、组织设计、商业模式设计、制度设计 | **咨询** |
### 规则2:"方案"的多义性
| 上下文 | 判定 |
|--------|------|
| 技术方案、架构方案、实施方案、部署方案 | **技术** |
| 营销方案、活动方案、传播方案、内容方案 | **创意** |
| 管理方案、策略方案、优化方案、治理方案 | **咨询** |
### 规则3:"分析"的多义性
| 上下文 | 判定 |
|--------|------|
| 数据分析、日志分析、性能分析、安全分析 | **分析** |
| 需求分析、竞品分析、市场分析 | **咨询** |
| 色彩分析、构图分析、文案分析 | **创意** |
### 规则4:技术关键词强信号
看到以下词时,优先判为技术:
Agent、API、SDK、架构、微服务、数据库、后端、前端、部署、DevOps、容器化、分布式、协议、接口、中间件、算法、模型训练、推理、向量、RAG、Pipeline、CI/CD、Kubernetes、Docker、Git
## 判定流程
1. 提取核心名词+动词组合
2. 查询上述消歧表
3. 判断用户最终要产出什么
4. 给出判定 + 置信度
## 输出格式
严格返回以下JSON,不要任何额外内容:
{
"core_intent": "技术",
"sub_category": "多Agent协作系统设计",
"domain": "二级精确领域",
"confidence": 0.92,
"disambiguation_note": "判定依据简述",
"alternative_intent": "咨询",
"key_requirements": ["需求1", "需求2", "需求3"],
"expected_output": "精确的预期产出描述",
"constraints": ["约束1", "约束2"],
"keywords": ["关键词1", "关键词2", "关键词3"]
}
"""
# 阶段2:生成优化提示词的 meta-prompt(每种领域不同结构)
PROMPT_GENERATOR_TEMPLATES = {
"技术": """你是一位资深提示词工程师,专精于技术领域。你的任务是生成一个高质量的提示词,让下游LLM能够输出专业的技术方案。
意图分析:
{analysis}
请生成一个完整的提示词,必须包含以下要素:
1. **角色设定**:明确LLM扮演什么技术专家角色(架构师/开发者/技术顾问),给出具体的专业背景
2. **任务描述**:清晰陈述要完成的技术任务,拆解为2-4个可执行步骤
3. **输出结构**:定义输出的章节和每章要包含的具体内容(不要只列标题,要说明每章怎么写)
4. **质量标准**:给出具体的质量要求(如"每个API必须给出字段级规范"而非"详细描述")
5. **约束条件**:明确禁止什么、必须包含什么
关键原则:
- 你生成的是提示词,不是最终答案
- 提示词必须自包含——用户复制后可以直接在任何LLM中使用
- 使用具体的技术术语和可验证的标准
- 每个章节指引都应该是"如何写"而非"写什么"
请在末尾附上一句给用户的简短说明(用「」括起来),解释这个提示词适合什么场景使用。""",
"创意": """你是一位资深提示词工程师,专精于创意领域。你的任务是生成一个高质量的提示词,让下游LLM能够输出富有创意的方案。
意图分析:
{analysis}
请生成一个提示词。核心原则:
- **轻结构、重启发**:不要定义死板的章节结构。给出2-3个创意探索维度,让LLM自主发挥。
- **受众共鸣**:提示词中必须引导LLM先分析目标受众的情感和需求,再展开创意。
- **可感知的质量标准**:避免"高端大气"等空话。使用具体、可感知的描述(如"这个slogan应该让读者在3秒内产生好奇心")。
- **发散后再收敛**:引导LLM先给出多个不同方向的创意,再选出最优方案并说明理由。
- **角色设定**:根据任务设定一个合适的创意角色(如创意总监/品牌策划/文案),给出风格倾向而非强制风格。
关键原则:
- 你生成的是提示词,不是最终作品
- 提示词应该激发创意,而非限制创意
- 保持提示词简洁(控制在800字以内),过多的规则会扼杀创意
- 只给出方向性引导,不预设具体答案
请在末尾附上一句给用户的简短说明(用「」括起来),解释这个提示词适合什么场景使用。""",
"分析": """你是一位资深提示词工程师,专精于数据分析领域。你的任务是生成一个高质量的提示词,让下游LLM能够输出有洞察力的分析报告。
意图分析:
{analysis}
请生成一个提示词。核心原则:
- **方法论驱动,而非格式驱动**:重点引导LLM使用什么分析思维(MECE/假设驱动/探索式/对比分析),而不是规定输出章节。
- **推理过程可见**:提示词必须要求LLM展示推理链条,说明"为什么得出这个结论",而非只给结论。
- **不确定性标注**:要求LLM诚实区分"数据支撑的结论"和"推测性判断",标注置信度。
- **洞察优先于描述**:引导LLM产出可行动的洞察(insight),而非对数据的简单描述(description)。
- 保持提示词简洁,控制在600字以内。过多的格式要求会让LLM产出机械化的模板报告。
请在末尾附上一句给用户的简短说明(用「」括起来),解释这个提示词适合什么场景使用。""",
"咨询": """你是一位资深提示词工程师,专精于管理咨询领域。你的任务是生成一个高质量的提示词,让下游LLM能够输出真正有价值的咨询建议。
意图分析:
{analysis}
请生成一个提示词。核心原则:
- **情境化思考,不要模板化输出**:不要规定"诊断→方案→推荐→路线图→风险"这种僵化结构。让LLM根据具体问题自主选择最合适的分析框架(可以是SWOT、波特五力、MECE、JTBD等,也可以自由组合)。
- **决策者视角**:提示词应引导LLM站在决策者角度思考——"如果我是CEO,我最关心什么?",而非像教科书一样面面俱到。
- **选项+权衡**:要求LLM给出2-3个可选方案,每个方案说明适用条件、代价和风险,帮助决策者做选择,而非只给单一建议。
- **可执行性**:每个建议必须有"第一步做什么"的具体行动指引。
- **假设透明**:要求LLM明确列出分析所依赖的关键假设,以及假设不成立时的备选方案。
- 保持提示词简洁,控制在500字以内。咨询的核心价值在于判断力,而非长篇大论。
请在末尾附上一句给用户的简短说明(用「」括起来),解释这个提示词适合什么场景使用。"""
}
def _get_user_id():
try:
from flask_login import current_user
if current_user.is_authenticated:
return getattr(current_user, 'id', None) or getattr(current_user, 'uid', None)
except Exception:
pass
from flask import session
uid = session.get('user_id')
if uid is not None:
return uid
try:
u = User.query.filter_by(login_name='admin').first()
return u.uid if u else 1
except Exception as e:
logger.warning("5号专家 获取默认用户失败: %s", e)
return 1
@expert_generate_5_bp.route('/expert-generate-5', methods=['GET'])
def expert_generate_5_page():
return render_template('expert_generate_5.html')
@expert_generate_5_bp.route('/api/expert-generate-5/generate', methods=['POST'])
def expert_generate_5_api():
"""三阶段流水线:消歧分析 → 生成提示词 → 执行样例"""
try:
if not request.is_json:
return jsonify({'code': 400, 'message': '请求必须是JSON格式', 'data': None})
payload = request.get_json() or {}
raw_input = (payload.get('input_text') or '').strip()
if not raw_input:
return jsonify({'code': 400, 'message': '请输入您的需求', 'data': None})
uid = _get_user_id()
req_key = (uid, hashlib.md5(raw_input.encode()).hexdigest())
now_ts = time.time()
if req_key in _dedup_cache and (now_ts - _dedup_cache[req_key]) < 8:
return jsonify({'code': 429, 'message': '请勿重复提交', 'data': None})
_dedup_cache[req_key] = now_ts
if len(_dedup_cache) > 500:
_dedup_cache.clear()
# ===== 阶段1:消歧意图分析 =====
logger.info("5号专家 阶段1 开始")
resp1 = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": INTENT_PROMPT_V4},
{"role": "user", "content": raw_input}
],
temperature=0.05,
timeout=60
)
intent_raw = (resp1.choices[0].message.content or "").strip()
intent_raw = intent_raw.replace('```json', '').replace('```', '').strip()
try:
intent_data = json.loads(intent_raw)
for f in ['core_intent', 'domain', 'key_requirements', 'expected_output', 'constraints', 'keywords']:
if f not in intent_data:
raise ValueError(f"缺少字段: {f}")
if intent_data['core_intent'] not in ('技术', '创意', '分析', '咨询'):
intent_data['core_intent'] = '技术'
for arr_f in ['key_requirements', 'constraints', 'keywords']:
v = intent_data.get(arr_f)
if not isinstance(v, list) or len(v) == 0:
intent_data[arr_f] = ['未指定']
intent_data.setdefault('sub_category', intent_data['domain'])
intent_data.setdefault('confidence', 0.75)
intent_data.setdefault('disambiguation_note', '')
intent_data.setdefault('alternative_intent', '')
except (json.JSONDecodeError, ValueError) as e:
logger.error("5号专家 JSON解析失败: %s", e)
return jsonify({'code': 500, 'message': '意图分析格式有误,请重试', 'data': None})
logger.info("5号专家 阶段1完成 | intent=%s | confidence=%.2f",
intent_data['core_intent'], intent_data.get('confidence', 0))
# ===== 阶段2:生成优化提示词 =====
logger.info("5号专家 阶段2 开始")
core_intent = intent_data['core_intent']
meta_prompt = PROMPT_GENERATOR_TEMPLATES[core_intent]
analysis_str = json.dumps(intent_data, ensure_ascii=False, indent=2)
resp2 = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": meta_prompt.format(analysis=analysis_str)},
{"role": "user", "content": f"用户需求:{raw_input}\n\n请基于上述意图分析,生成一个高质量的提示词。"}
],
temperature=0.5,
max_tokens=1500,
timeout=90
)
optimized_prompt = (resp2.choices[0].message.content or "").strip()
if not optimized_prompt:
return jsonify({'code': 500, 'message': '提示词生成失败', 'data': None})
logger.info("5号专家 阶段2完成 | prompt_len=%d", len(optimized_prompt))
# ===== 阶段3:执行样例 =====
logger.info("5号专家 阶段3 开始")
resp3 = client.chat.completions.create(
model="deepseek-chat",
messages=[
{"role": "system", "content": optimized_prompt},
{"role": "user", "content": raw_input}
],
temperature=0.7,
max_tokens=1200,
timeout=90
)
sample_output = (resp3.choices[0].message.content or "").strip()
if not sample_output:
sample_output = "(模型未返回样例,请直接用上方提示词调用)"
logger.info("5号专家 阶段3完成 | sample_len=%d", len(sample_output))
# 保存
try:
db.session.add(Prompt(
input_text=raw_input,
generated_text=optimized_prompt,
user_id=uid,
created_at=datetime.utcnow()
))
db.session.commit()
except Exception as e:
db.session.rollback()
logger.warning("5号专家 保存失败: %s", e)
try:
PromptHistory.add_history(
user_id=uid,
original_input=raw_input,
generated_prompt=optimized_prompt,
template_name=f'智能提示词优化5号专家(三阶段-{core_intent})'
)
UserStatistics.update_statistics(uid)
except Exception as e:
logger.warning("5号专家 历史保存失败: %s", e)
return jsonify({
'code': 200,
'message': 'success',
'data': {
'method': 'three-stage-pipeline',
'api_calls': 3,
'intent_analysis': intent_data,
'optimized_prompt': optimized_prompt,
'sample_output': sample_output
}
})
except Exception as e:
logger.exception("5号专家 生成失败")
return jsonify({'code': 500, 'message': str(e) or '生成失败,请重试', 'data': None})