添加其他格式文档的解析
This commit is contained in:
444
backend/app/services/prompt_service.py
Normal file
444
backend/app/services/prompt_service.py
Normal file
@@ -0,0 +1,444 @@
|
||||
"""
|
||||
提示词工程服务
|
||||
|
||||
管理和优化与大模型交互的提示词
|
||||
"""
|
||||
import json
|
||||
import logging
|
||||
from dataclasses import dataclass, field
|
||||
from enum import Enum
|
||||
from typing import Any, Dict, List, Optional
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class PromptType(Enum):
|
||||
"""提示词类型"""
|
||||
DOCUMENT_PARSING = "document_parsing" # 文档解析
|
||||
FIELD_EXTRACTION = "field_extraction" # 字段提取
|
||||
TABLE_FILLING = "table_filling" # 表格填写
|
||||
QUERY_GENERATION = "query_generation" # 查询生成
|
||||
TEXT_SUMMARY = "text_summary" # 文本摘要
|
||||
INTENT_CLASSIFICATION = "intent_classification" # 意图分类
|
||||
DATA_CLASSIFICATION = "data_classification" # 数据分类
|
||||
|
||||
|
||||
@dataclass
|
||||
class PromptTemplate:
|
||||
"""提示词模板"""
|
||||
name: str
|
||||
type: PromptType
|
||||
system_prompt: str
|
||||
user_template: str
|
||||
examples: List[Dict[str, str]] = field(default_factory=list) # Few-shot 示例
|
||||
rules: List[str] = field(default_factory=list) # 特殊规则
|
||||
|
||||
def format(
|
||||
self,
|
||||
context: Dict[str, Any],
|
||||
user_input: Optional[str] = None
|
||||
) -> List[Dict[str, str]]:
|
||||
"""
|
||||
格式化提示词
|
||||
|
||||
Args:
|
||||
context: 上下文数据
|
||||
user_input: 用户输入
|
||||
|
||||
Returns:
|
||||
格式化后的消息列表
|
||||
"""
|
||||
messages = []
|
||||
|
||||
# 系统提示词
|
||||
system_content = self.system_prompt
|
||||
|
||||
# 添加规则
|
||||
if self.rules:
|
||||
system_content += "\n\n【输出规则】\n" + "\n".join([f"- {rule}" for rule in self.rules])
|
||||
|
||||
# 添加示例
|
||||
if self.examples:
|
||||
system_content += "\n\n【示例】\n"
|
||||
for i, ex in enumerate(self.examples):
|
||||
system_content += f"\n示例 {i+1}:\n"
|
||||
system_content += f"输入: {ex.get('input', '')}\n"
|
||||
system_content += f"输出: {ex.get('output', '')}\n"
|
||||
|
||||
messages.append({"role": "system", "content": system_content})
|
||||
|
||||
# 用户提示词
|
||||
user_content = self._format_user_template(context, user_input)
|
||||
messages.append({"role": "user", "content": user_content})
|
||||
|
||||
return messages
|
||||
|
||||
def _format_user_template(
|
||||
self,
|
||||
context: Dict[str, Any],
|
||||
user_input: Optional[str]
|
||||
) -> str:
|
||||
"""格式化用户模板"""
|
||||
content = self.user_template
|
||||
|
||||
# 替换上下文变量
|
||||
for key, value in context.items():
|
||||
placeholder = f"{{{key}}}"
|
||||
if placeholder in content:
|
||||
if isinstance(value, (dict, list)):
|
||||
content = content.replace(placeholder, json.dumps(value, ensure_ascii=False, indent=2))
|
||||
else:
|
||||
content = content.replace(placeholder, str(value))
|
||||
|
||||
# 添加用户输入
|
||||
if user_input:
|
||||
content += f"\n\n【用户需求】\n{user_input}"
|
||||
|
||||
return content
|
||||
|
||||
|
||||
class PromptEngineeringService:
|
||||
"""提示词工程服务"""
|
||||
|
||||
def __init__(self):
|
||||
self.templates: Dict[PromptType, PromptTemplate] = {}
|
||||
self._init_templates()
|
||||
|
||||
def _init_templates(self):
|
||||
"""初始化所有提示词模板"""
|
||||
|
||||
# ==================== 文档解析模板 ====================
|
||||
self.templates[PromptType.DOCUMENT_PARSING] = PromptTemplate(
|
||||
name="文档解析",
|
||||
type=PromptType.DOCUMENT_PARSING,
|
||||
system_prompt="""你是一个专业的文档解析专家。你的任务是从各类文档(Word、Excel、Markdown、纯文本)中提取关键信息。
|
||||
|
||||
请严格按照JSON格式输出解析结果:
|
||||
{
|
||||
"success": true/false,
|
||||
"document_type": "文档类型",
|
||||
"key_fields": {"字段名": "字段值", ...},
|
||||
"summary": "文档摘要(100字内)",
|
||||
"structured_data": {...} // 提取的表格或其他结构化数据
|
||||
}
|
||||
|
||||
重要规则:
|
||||
- 只提取明确存在的信息,不要猜测
|
||||
- 如果是表格数据,请以数组格式输出
|
||||
- 日期请使用 YYYY-MM-DD 格式
|
||||
- 金额请使用数字格式
|
||||
- 如果无法提取某个字段,设置为 null""",
|
||||
user_template="""请解析以下文档内容:
|
||||
|
||||
=== 文档开始 ===
|
||||
{content}
|
||||
=== 文档结束 ===
|
||||
|
||||
请提取文档中的关键信息。""",
|
||||
examples=[
|
||||
{
|
||||
"input": "合同金额:100万元\n签订日期:2024年1月15日\n甲方:张三\n乙方:某某公司",
|
||||
"output": '{"success": true, "document_type": "合同", "key_fields": {"金额": 1000000, "日期": "2024-01-15", "甲方": "张三", "乙方": "某某公司"}, "summary": "甲乙双方签订的金额为100万元的合同", "structured_data": null}'
|
||||
}
|
||||
],
|
||||
rules=[
|
||||
"只输出JSON,不要添加任何解释",
|
||||
"使用严格的JSON格式"
|
||||
]
|
||||
)
|
||||
|
||||
# ==================== 字段提取模板 ====================
|
||||
self.templates[PromptType.FIELD_EXTRACTION] = PromptTemplate(
|
||||
name="字段提取",
|
||||
type=PromptType.FIELD_EXTRACTION,
|
||||
system_prompt="""你是一个专业的数据提取专家。你的任务是从文档内容中提取指定字段的信息。
|
||||
|
||||
请严格按照以下JSON格式输出:
|
||||
{
|
||||
"value": "提取到的值,找不到则为空字符串",
|
||||
"source": "数据来源描述",
|
||||
"confidence": 0.0到1.0之间的置信度
|
||||
}
|
||||
|
||||
重要规则:
|
||||
- 严格按字段名称匹配,不要提取无关信息
|
||||
- 置信度反映你对提取结果的信心程度
|
||||
- 如果字段不存在或无法确定,value设为空字符串,confidence设为0.0
|
||||
- value必须是实际值,不能是"未找到"之类的描述""",
|
||||
user_template="""请从以下文档内容中提取指定字段的信息。
|
||||
|
||||
【需要提取的字段】
|
||||
字段名称:{field_name}
|
||||
字段类型:{field_type}
|
||||
是否必填:{required}
|
||||
|
||||
【用户提示】
|
||||
{hint}
|
||||
|
||||
【文档内容】
|
||||
{context}
|
||||
|
||||
请提取字段值。""",
|
||||
examples=[
|
||||
{
|
||||
"input": "文档内容:姓名张三,电话13800138000,邮箱zhangsan@example.com",
|
||||
"output": '{"value": "张三", "source": "文档第1行", "confidence": 1.0}'
|
||||
}
|
||||
],
|
||||
rules=[
|
||||
"只输出JSON,不要添加任何解释"
|
||||
]
|
||||
)
|
||||
|
||||
# ==================== 表格填写模板 ====================
|
||||
self.templates[PromptType.TABLE_FILLING] = PromptTemplate(
|
||||
name="表格填写",
|
||||
type=PromptType.TABLE_FILLING,
|
||||
system_prompt="""你是一个专业的表格填写助手。你的任务是根据提供的文档内容,填写表格模板中的字段。
|
||||
|
||||
请严格按照以下JSON格式输出:
|
||||
{
|
||||
"filled_data": {{"字段1": "值1", "字段2": "值2", ...}},
|
||||
"fill_details": [
|
||||
{{"field": "字段1", "value": "值1", "source": "来源", "confidence": 0.95}},
|
||||
...
|
||||
]
|
||||
}
|
||||
|
||||
重要规则:
|
||||
- 只填写模板中存在的字段
|
||||
- 值必须来自提供的文档内容,不要编造
|
||||
- 如果某个字段在文档中找不到对应值,设为空字符串
|
||||
- fill_details 中记录每个字段的详细信息""",
|
||||
user_template="""请根据以下文档内容,填写表格模板。
|
||||
|
||||
【表格模板字段】
|
||||
{fields}
|
||||
|
||||
【用户需求】
|
||||
{hint}
|
||||
|
||||
【参考文档内容】
|
||||
{context}
|
||||
|
||||
请填写表格。""",
|
||||
examples=[
|
||||
{
|
||||
"input": "字段:姓名、电话\n文档:张三,电话是13800138000",
|
||||
"output": '{"filled_data": {"姓名": "张三", "电话": "13800138000"}, "fill_details": [{"field": "姓名", "value": "张三", "source": "文档第1行", "confidence": 1.0}, {"field": "电话", "value": "13800138000", "source": "文档第1行", "confidence": 1.0}]}'
|
||||
}
|
||||
],
|
||||
rules=[
|
||||
"只输出JSON,不要添加任何解释"
|
||||
]
|
||||
)
|
||||
|
||||
# ==================== 查询生成模板 ====================
|
||||
self.templates[PromptType.QUERY_GENERATION] = PromptTemplate(
|
||||
name="查询生成",
|
||||
type=PromptType.QUERY_GENERATION,
|
||||
system_prompt="""你是一个SQL查询生成专家。你的任务是根据用户的自然语言需求,生成相应的数据库查询语句。
|
||||
|
||||
请严格按照以下JSON格式输出:
|
||||
{
|
||||
"sql_query": "生成的SQL查询语句",
|
||||
"explanation": "查询逻辑说明"
|
||||
}
|
||||
|
||||
重要规则:
|
||||
- 只生成 SELECT 查询语句,不要生成 INSERT/UPDATE/DELETE
|
||||
- 必须包含 WHERE 条件限制查询范围
|
||||
- 表名和字段名使用反引号包裹
|
||||
- 确保SQL语法正确
|
||||
- 如果无法生成有效的查询,sql_query设为空字符串""",
|
||||
user_template="""根据以下信息生成查询语句。
|
||||
|
||||
【数据库表结构】
|
||||
{table_schema}
|
||||
|
||||
【RAG检索到的上下文】
|
||||
{rag_context}
|
||||
|
||||
【用户查询需求】
|
||||
{user_intent}
|
||||
|
||||
请生成SQL查询。""",
|
||||
examples=[
|
||||
{
|
||||
"input": "表:orders(订单号, 金额, 日期, 客户)\n需求:查询2024年1月销售额超过10000的订单",
|
||||
"output": '{"sql_query": "SELECT * FROM `orders` WHERE `日期` >= \\'2024-01-01\\' AND `日期` < \\'2024-02-01\\' AND `金额` > 10000", "explanation": "筛选2024年1月销售额超过10000的订单"}'
|
||||
}
|
||||
],
|
||||
rules=[
|
||||
"只输出JSON,不要添加任何解释",
|
||||
"禁止生成 DROP、DELETE、TRUNCATE 等危险操作"
|
||||
]
|
||||
)
|
||||
|
||||
# ==================== 文本摘要模板 ====================
|
||||
self.templates[PromptType.TEXT_SUMMARY] = PromptTemplate(
|
||||
name="文本摘要",
|
||||
type=PromptType.TEXT_SUMMARY,
|
||||
system_prompt="""你是一个专业的文本摘要专家。你的任务是对长文档进行压缩,提取关键信息。
|
||||
|
||||
请严格按照以下JSON格式输出:
|
||||
{
|
||||
"summary": "摘要内容(不超过200字)",
|
||||
"key_points": ["要点1", "要点2", "要点3"],
|
||||
"keywords": ["关键词1", "关键词2", "关键词3"]
|
||||
}""",
|
||||
user_template="""请为以下文档生成摘要:
|
||||
|
||||
=== 文档开始 ===
|
||||
{content}
|
||||
=== 文档结束 ===
|
||||
|
||||
生成简明摘要。""",
|
||||
rules=[
|
||||
"只输出JSON,不要添加任何解释"
|
||||
]
|
||||
)
|
||||
|
||||
# ==================== 意图分类模板 ====================
|
||||
self.templates[PromptType.INTENT_CLASSIFICATION] = PromptTemplate(
|
||||
name="意图分类",
|
||||
type=PromptType.INTENT_CLASSIFICATION,
|
||||
system_prompt="""你是一个意图分类专家。你的任务是分析用户的自然语言输入,判断用户的真实意图。
|
||||
|
||||
支持的意图类型:
|
||||
- upload: 上传文档
|
||||
- parse: 解析文档
|
||||
- query: 查询数据
|
||||
- fill: 填写表格
|
||||
- export: 导出数据
|
||||
- analyze: 分析数据
|
||||
- other: 其他/未知
|
||||
|
||||
请严格按照以下JSON格式输出:
|
||||
{
|
||||
"intent": "意图类型",
|
||||
"confidence": 0.0到1.0之间的置信度,
|
||||
"entities": {{"实体名": "实体值", ...}}, // 识别出的关键实体
|
||||
"suggestion": "建议的下一步操作"
|
||||
}""",
|
||||
user_template="""请分析以下用户输入,判断其意图:
|
||||
|
||||
【用户输入】
|
||||
{user_input}
|
||||
|
||||
请分类。""",
|
||||
rules=[
|
||||
"只输出JSON,不要添加任何解释"
|
||||
]
|
||||
)
|
||||
|
||||
# ==================== 数据分类模板 ====================
|
||||
self.templates[PromptType.DATA_CLASSIFICATION] = PromptTemplate(
|
||||
name="数据分类",
|
||||
type=PromptType.DATA_CLASSIFICATION,
|
||||
system_prompt="""你是一个数据分类专家。你的任务是判断数据的类型和格式。
|
||||
|
||||
请严格按照以下JSON格式输出:
|
||||
{
|
||||
"data_type": "text/number/date/email/phone/url/amount/other",
|
||||
"format": "具体格式描述",
|
||||
"is_valid": true/false,
|
||||
"normalized_value": "规范化后的值"
|
||||
}""",
|
||||
user_template="""请分析以下数据的类型和格式:
|
||||
|
||||
【数据】
|
||||
{value}
|
||||
|
||||
【期望类型(如果有)】
|
||||
{expected_type}
|
||||
|
||||
请分类。""",
|
||||
rules=[
|
||||
"只输出JSON,不要添加任何解释"
|
||||
]
|
||||
)
|
||||
|
||||
def get_prompt(
|
||||
self,
|
||||
type: PromptType,
|
||||
context: Dict[str, Any],
|
||||
user_input: Optional[str] = None
|
||||
) -> List[Dict[str, str]]:
|
||||
"""
|
||||
获取格式化后的提示词
|
||||
|
||||
Args:
|
||||
type: 提示词类型
|
||||
context: 上下文数据
|
||||
user_input: 用户输入
|
||||
|
||||
Returns:
|
||||
消息列表
|
||||
"""
|
||||
template = self.templates.get(type)
|
||||
if not template:
|
||||
logger.warning(f"未找到提示词模板: {type}")
|
||||
return [{"role": "user", "content": str(context)}]
|
||||
|
||||
return template.format(context, user_input)
|
||||
|
||||
def get_template(self, type: PromptType) -> Optional[PromptTemplate]:
|
||||
"""获取提示词模板"""
|
||||
return self.templates.get(type)
|
||||
|
||||
def add_template(self, template: PromptTemplate):
|
||||
"""添加自定义提示词模板"""
|
||||
self.templates[template.type] = template
|
||||
logger.info(f"已添加提示词模板: {template.name}")
|
||||
|
||||
def update_template(self, type: PromptType, **kwargs):
|
||||
"""更新提示词模板"""
|
||||
template = self.templates.get(type)
|
||||
if template:
|
||||
for key, value in kwargs.items():
|
||||
if hasattr(template, key):
|
||||
setattr(template, key, value)
|
||||
|
||||
def optimize_prompt(
|
||||
self,
|
||||
type: PromptType,
|
||||
feedback: str,
|
||||
iteration: int = 1
|
||||
) -> List[Dict[str, str]]:
|
||||
"""
|
||||
根据反馈优化提示词
|
||||
|
||||
Args:
|
||||
type: 提示词类型
|
||||
feedback: 优化反馈
|
||||
iteration: 迭代次数
|
||||
|
||||
Returns:
|
||||
优化后的提示词
|
||||
"""
|
||||
template = self.templates.get(type)
|
||||
if not template:
|
||||
return []
|
||||
|
||||
# 简单优化策略:根据反馈添加规则
|
||||
optimization_rules = {
|
||||
"准确率低": "提高要求,明确指出必须从原文提取,不要猜测",
|
||||
"格式错误": "强调JSON格式要求,提供更详细的格式示例",
|
||||
"遗漏信息": "添加提取更多细节的要求",
|
||||
}
|
||||
|
||||
new_rules = []
|
||||
for keyword, rule in optimization_rules.items():
|
||||
if keyword in feedback:
|
||||
new_rules.append(rule)
|
||||
|
||||
if new_rules:
|
||||
template.rules.extend(new_rules)
|
||||
|
||||
return template.format({}, None)
|
||||
|
||||
|
||||
# ==================== 全局单例 ====================
|
||||
|
||||
prompt_service = PromptEngineeringService()
|
||||
Reference in New Issue
Block a user