From ca89aba5480cb2ccd6327ee219f39154c4e08331 Mon Sep 17 00:00:00 2001 From: mengyonghao <1533512157@qq.com> Date: Fri, 26 Dec 2025 17:34:38 +0800 Subject: [PATCH] perf(prompt_opt): improve prompt optimization and model output quality --- api/app/core/workflow/nodes/configs.py | 2 + .../nodes/parameter_extractor/node.py | 4 +- api/app/services/prompt_optimizer_service.py | 80 +++++++------------ .../prompt/prompt_optimizer_system.jinja2 | 54 +++++++++++++ .../prompt/prompt_optimizer_user.jinja2 | 5 ++ 5 files changed, 93 insertions(+), 52 deletions(-) create mode 100644 api/app/templates/prompt/prompt_optimizer_system.jinja2 create mode 100644 api/app/templates/prompt/prompt_optimizer_user.jinja2 diff --git a/api/app/core/workflow/nodes/configs.py b/api/app/core/workflow/nodes/configs.py index 12bb18cb..a8363421 100644 --- a/api/app/core/workflow/nodes/configs.py +++ b/api/app/core/workflow/nodes/configs.py @@ -19,6 +19,7 @@ from app.core.workflow.nodes.llm.config import LLMNodeConfig, MessageConfig from app.core.workflow.nodes.start.config import StartNodeConfig from app.core.workflow.nodes.transform.config import TransformNodeConfig from app.core.workflow.nodes.variable_aggregator.config import VariableAggregatorNodeConfig +from app.core.workflow.nodes.parameter_extractor.config import ParameterExtractorNodeConfig __all__ = [ # 基础类 @@ -38,4 +39,5 @@ __all__ = [ "HttpRequestNodeConfig", "JinjaRenderNodeConfig", "VariableAggregatorNodeConfig", + "ParameterExtractorNodeConfig", ] diff --git a/api/app/core/workflow/nodes/parameter_extractor/node.py b/api/app/core/workflow/nodes/parameter_extractor/node.py index f991e7dc..0eb3bfd4 100644 --- a/api/app/core/workflow/nodes/parameter_extractor/node.py +++ b/api/app/core/workflow/nodes/parameter_extractor/node.py @@ -68,10 +68,10 @@ class ParameterExtractorNode(BaseNode): config = ModelConfigService.get_model_by_id(db=db, model_id=model_id) if not config: - raise BusinessException("配置的模型不存在", BizCode.NOT_FOUND) + raise BusinessException("Configured model does not exist", BizCode.NOT_FOUND) if not config.api_keys or len(config.api_keys) == 0: - raise BusinessException("模型配置缺少 API Key", BizCode.INVALID_PARAMETER) + raise BusinessException("Model configuration is missing API Key", BizCode.INVALID_PARAMETER) api_config = config.api_keys[0] model_name = api_config.model_name diff --git a/api/app/services/prompt_optimizer_service.py b/api/app/services/prompt_optimizer_service.py index 6af794b1..5f325a1b 100644 --- a/api/app/services/prompt_optimizer_service.py +++ b/api/app/services/prompt_optimizer_service.py @@ -1,8 +1,10 @@ import re import uuid +import json_repair from langchain_core.prompts import ChatPromptTemplate from sqlalchemy.orm import Session +from jinja2 import Template from app.core.error_codes import BizCode from app.core.exceptions import BusinessException @@ -170,68 +172,45 @@ class PromptOptimizerService: api_key=api_config.api_key, base_url=api_config.api_base ), type=ModelType(model_config.type)) + try: + with open('app/templates/prompt/prompt_optimizer_system.jinja2', 'r', encoding='utf-8') as f: + opt_system_prompt = f.read() + rendered_system_message = Template(opt_system_prompt).render() + + with open('app/templates/prompt/prompt_optimizer_user.jinja2', 'r', encoding='utf-8') as f: + opt_user_prompt = f.read() + except FileNotFoundError: + raise BusinessException(message="System prompt template not found", code=BizCode.NOT_FOUND) + + except Exception as e: + logger.error(f"Failed to load system prompt template: {e}") + raise BusinessException(message="Internal server error", code=BizCode.INTERNAL_ERROR) + rendered_user_message = Template(opt_user_prompt).render( + current_prompt=current_prompt, + user_require=user_require + ) # build message messages = [ # init system_prompt ( RoleType.SYSTEM.value, - "Your task is to optimize the original prompt provided by the user so that it can be directly used by AI tools," - "and the variables that the user needs to insert must be wrapped in {{}}. " - "The optimized prompt should align with the optimization direction specified by the user (if any) and ensure clear logic, explicit instructions, and strong executability. " - "Please follow these rules when optimizing: " - '1. Ensure variables are wrapped in {{}}, e.g., optimize "Please enter your question" to "Please enter your {{question}}"' - "2. Instructions must be specific and operable, avoiding vague expressions" - "3. If the original prompt lacks key elements (such as output format requirements), supplement them completely " - "4. Keep the language concise and avoid redundancy " - "5. If the user does not specify an optimization direction, the default optimization is to make the prompt structurally clear and with explicit instructions" - "Please directly output the optimized prompt without additional explanations. The optimized prompt should be directly usable with correct variable positions." + rendered_system_message ), + ] - # base model limit - (RoleType.SYSTEM.value, - "Optimization Rules:\n" - "1. Fully adjust the prompt content according to the user's requirements.\n" - "When variables are required, use double curly braces {{variable_name}} as placeholders." - "Variable names must be derived from the user's requirements.\n" - "3. Keep the prompt logic clear and instructions explicit.\n" - "4. Ensure that the modified prompt can be directly used.\n\n") - ] messages.extend(session_history[:-1]) # last message is current message - user_message_template = ChatPromptTemplate.from_messages([ - (RoleType.USER.value, "[original_prompt]\n{current_prompt}\n[user_require]\n{user_require}") - ]) - formatted_user_message = user_message_template.format(current_prompt=current_prompt, user_require=user_require) - messages.extend([(RoleType.USER.value, formatted_user_message)]) + messages.extend([(RoleType.USER.value, rendered_user_message)]) logger.info(f"Prompt optimization message: {messages}") - optim_prompt = await llm.ainvoke(messages) - optim_desc = [ - ( - RoleType.SYSTEM.value, - "You are a prompt optimization assistant.\n" - "Compare the original prompt, the user's requirements, " - "and the optimized prompt.\n" - "Summarize the changes made during optimization.\n\n" - "Rules:\n" - "1. Output must be a single short sentence.\n" - "2. Be concise and factual.\n" - "3. Do not explain the prompts themselves.\n" - "4. Do not include any extra text." - ), - ( - "[Original Prompt]\n" - f"{current_prompt}\n\n" - "[User Requirements]\n" - f"{user_require}\n\n" - "[Optimized Prompt]\n" - f"{optim_prompt.content}" - ) - ] - optim_desc = await llm.ainvoke(optim_desc) + optim_resp = await llm.ainvoke(messages) + logger.info(optim_resp.content) + optim_result = json_repair.repair_json(optim_resp.content, return_objects=True) + prompt = optim_result.get("prompt") + desc = optim_result.get("desc") return OptimizePromptResult( - prompt=optim_prompt.content, - desc=optim_desc.content + prompt=prompt, + desc=desc ) @staticmethod @@ -253,6 +232,7 @@ class PromptOptimizerService: def replace_var(match): var_name = match.group(1) return variables.get(var_name, match.group(0)) + result = re.sub(pattern, replace_var, prompt) return result except Exception as e: diff --git a/api/app/templates/prompt/prompt_optimizer_system.jinja2 b/api/app/templates/prompt/prompt_optimizer_system.jinja2 new file mode 100644 index 00000000..ae19a6ab --- /dev/null +++ b/api/app/templates/prompt/prompt_optimizer_system.jinja2 @@ -0,0 +1,54 @@ +{% raw %} +Role: AI Prompt Optimization Expert + +Profile +description: An expert specialized in optimizing and generating prompts that can be directly used in AI tools, capable of transforming original prompts into a clear, immediately executable format based on user requirements. +background: Extensive experience in natural language processing and AI interaction design, skilled at analyzing user intent and converting it into precise instruction structures. +personality: Rigorous, detail-oriented, logical, focused on precision and executability of instructions. +expertise: Prompt engineering, instruction structuring, requirement analysis, AI interaction optimization. +target_audience: AI tool users, prompt engineers, professionals interacting with AI systems. + +Skills +Core Optimization Skills +Requirement Analysis: Accurately understand the relationship between the user’s current needs and the original prompt. +Structural Reconstruction: Transform vague requirements into clear, block-structured instructions. +Variable Handling: Identify and standardize dynamic variables in prompts. +Conflict Resolution: Prioritize current requirements when historical requirements conflict with current needs. + +Auxiliary Generation Skills +Completeness Check: Ensure all necessary elements (input, output, constraints, etc.) are explicitly defined. +Language Consistency: Maintain consistency between label language and user input language. +Executability Verification: Ensure optimized prompts can be directly used in AI tools. +Format Standardization: Strictly adhere to specified output format requirements. + +Rules +Basic Principles +Priority Rule: When historical requirements conflict with current requirements, unconditionally prioritize current requirements. +Completeness Rule: If the original prompt is empty, generate a complete prompt based on the current requirements. +Structure Rule: Use a clear block structure including [Role], [Task], [Requirements], [Input], [Output], [Constraints] labels. +Language Rule: All label languages must fully match the user input language. + +Behavior Guidelines +Precision Guideline: All instructions must be precise and directly executable, avoiding ambiguity. +Readability Guideline: Ensure optimized prompts have good readability and logical flow. +Variable Handling Guideline: Use lowercase English variable names wrapped in {{}} when variables are needed. +Constraint Handling Guideline: Do not mention variable-related limitations under the [Constraints] label. + +Constraints +Output Constraint: Must output in JSON format including the fields "prompt" and "desc". +Content Constraint: Must not include any explanations, analyses, or additional comments. +Language Constraint: Must use clear and concise language. +Completeness Constraint: Must fully define all missing elements (input details, output format, constraints, etc.). + +Workflows +Goal: Optimize or generate AI prompts that can be directly used according to user requirements. +Step 1: Receive the user’s current requirement description {{user_require}} and the original prompt {{original_prompt}}. +Step 2: Analyze requirements, identify conflicts, and prioritize current requirements. +Step 3: Optimize or generate the prompt in a block-structured format, ensuring all elements are fully defined. +Step 4: Generate a JSON output containing the optimized prompt and its description. + +Expected Outcome: Obtain a clear, directly executable AI prompt accompanied by an optimization description. + +Initialization +As an AI Prompt Optimization Expert, you must follow the above Rules and execute tasks according to the Workflows. +{% endraw %} \ No newline at end of file diff --git a/api/app/templates/prompt/prompt_optimizer_user.jinja2 b/api/app/templates/prompt/prompt_optimizer_user.jinja2 new file mode 100644 index 00000000..cbbc3249 --- /dev/null +++ b/api/app/templates/prompt/prompt_optimizer_user.jinja2 @@ -0,0 +1,5 @@ +[original_prompt] +{{current_prompt}} + +[user_require] +{{user_require}} \ No newline at end of file