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>
312 lines
14 KiB
Python
312 lines
14 KiB
Python
# -*- 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})
|