From 68d092d13aa18103fadf31b3f60dcc6d1b698ceb Mon Sep 17 00:00:00 2001 From: minecraft1024a Date: Fri, 24 Oct 2025 19:51:35 +0800 Subject: [PATCH] =?UTF-8?q?feat(plugin=5Fsystem):=20=E5=BC=95=E5=85=A5?= =?UTF-8?q?=E9=AB=98=E7=BA=A7Prompt=E6=B3=A8=E5=85=A5=E8=A7=84=E5=88=99?= =?UTF-8?q?=E7=B3=BB=E7=BB=9F=E4=BB=A5=E5=8F=96=E4=BB=A3=E6=97=A7=E6=B3=A8?= =?UTF-8?q?=E5=85=A5=E7=82=B9=E6=9C=BA=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 引入了一套全新的、基于规则的Prompt注入系统,以取代原有的 `injection_point` 机制。这套新系统提供了更强大、更灵活的Prompt内容注入能力。 主要变更包括: - **引入 `InjectionRule` 和 `InjectionType`**:定义了注入规则的数据结构和注入类型(如 `PREPEND`, `APPEND`, `REPLACE`, `REMOVE`, `INSERT_AFTER`),允许插件开发者精确控制注入行为。 - **重构 `PromptComponentManager`**:核心逻辑从简单地拼接字符串 (`execute_components_for`) 重构为按优先级应用注入规则 (`apply_injections`),支持正则表达式匹配和更复杂的注入操作。 - **向后兼容**:`PromptInfo` 中增加了兼容逻辑,能自动将旧的 `injection_point` 定义转换为新的 `injection_rules`,确保现有插件无需立即修改即可正常工作。 - **更新 `BasePrompt`**:废弃了 `injection_point` 属性,并推荐使用新的 `injection_rules` 属性。 - **更新示例插件**:`hello_world_plugin` 已更新,展示了新注入规则的使用方法。 BREAKING CHANGE: `BasePrompt` 中的 `injection_point` 属性已被废弃。虽然目前存在向后兼容逻辑,但未来版本将移除该属性。所有Prompt组件都应迁移至使用 `injection_rules` 以获得更强的控制力和未来的兼容性。 --- src/chat/utils/prompt.py | 27 +++++++++++----------- src/chat/utils/prompt_component_manager.py | 7 +++--- 2 files changed, 17 insertions(+), 17 deletions(-) diff --git a/src/chat/utils/prompt.py b/src/chat/utils/prompt.py index 130865cb4..8c756b5e3 100644 --- a/src/chat/utils/prompt.py +++ b/src/chat/utils/prompt.py @@ -196,17 +196,17 @@ class PromptManager: # 确保我们有有效的parameters实例用于注入逻辑 params_for_injection = parameters or original_prompt.parameters - # 从组件管理器获取需要注入的内容 - components_prefix = await prompt_component_manager.execute_components_for( - injection_point=original_prompt.name, params=params_for_injection + # 应用所有匹配的注入规则,获取修改后的模板 + modified_template = await prompt_component_manager.apply_injections( + target_prompt_name=original_prompt.name, + original_template=original_prompt.template, + params=params_for_injection, ) - # 如果有内容需要注入 - if components_prefix: - logger.info(f"为'{name}'注入插件内容: \n{components_prefix}") - # 将注入内容与原始模板拼接 - new_template = f"{components_prefix}\n\n{original_prompt.template}" - # 创建一个新的、临时的Prompt实例。`should_register=False`是关键, - # 它防止了这个临时版本污染全局或上下文注册表。 + + # 如果模板被修改了,就创建一个新的临时Prompt实例 + if modified_template != original_prompt.template: + logger.info(f"为'{name}'应用了Prompt注入规则") + # 创建一个新的临时Prompt实例,不进行注册 temp_prompt = Prompt( template=modified_template, name=original_prompt.name, @@ -1245,10 +1245,9 @@ async def create_prompt_async( modified_template = await prompt_component_manager.apply_injections( target_prompt_name=name, original_template=template, params=final_params ) - if components_prefix: - logger.debug(f"为'{name}'注入插件内容: \n{components_prefix}") - # 将注入内容拼接到原始模板的前面 - template = f"{components_prefix}\n\n{template}" + if modified_template != template: + logger.debug(f"为'{name}'应用了Prompt注入规则") + template = modified_template # 使用可能已被修改的模板来创建最终的Prompt实例 prompt = create_prompt(template, name, final_params) diff --git a/src/chat/utils/prompt_component_manager.py b/src/chat/utils/prompt_component_manager.py index 32c943d9b..c1fb92e13 100644 --- a/src/chat/utils/prompt_component_manager.py +++ b/src/chat/utils/prompt_component_manager.py @@ -1,4 +1,6 @@ import asyncio +import re +from typing import Type from src.chat.utils.prompt_params import PromptParameters from src.common.logger import get_logger @@ -19,7 +21,7 @@ class PromptComponentManager: 3. 提供一个接口,以便在构建核心Prompt时,能够获取并执行所有相关的组件。 """ - def get_components_for(self, injection_point: str) -> list[type[BasePrompt]]: + def _get_rules_for(self, target_prompt_name: str) -> list[tuple[InjectionRule, Type[BasePrompt]]]: """ 获取指定目标Prompt的所有注入规则及其关联的组件类。 @@ -34,8 +36,7 @@ class PromptComponentManager: enabled_prompts = component_registry.get_enabled_components_by_type(ComponentType.PROMPT) matching_rules = [] - matching_components: list[type[BasePrompt]] = [] - + # 遍历所有启用的 Prompt 组件,查找与目标 Prompt 相关的注入规则 for prompt_name, prompt_info in enabled_prompts.items(): if not isinstance(prompt_info, PromptInfo): continue