mirror of
https://github.com/imartinez/privateGPT.git
synced 2026-07-17 11:29:56 +00:00
feat: add skill prompt
This commit is contained in:
@@ -109,6 +109,13 @@ class PromptConfig(BaseModel):
|
||||
"available paths) when any code execution tool is present."
|
||||
),
|
||||
)
|
||||
skills: bool = Field(
|
||||
default=False,
|
||||
description=(
|
||||
"Enable skill management instructions (when to load/unload skills, "
|
||||
"workflow guidance) when any skill management tool is present."
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class System(BaseModel):
|
||||
|
||||
@@ -554,6 +554,29 @@ class PromptBuilderService:
|
||||
logger.warning("PromptBuilder: failed to render %s: %s", template_path, exc)
|
||||
return PromptTemplate(template="")
|
||||
|
||||
def create_skills_prompt(
|
||||
self,
|
||||
tools: list["ToolSpec"],
|
||||
few_shots: bool = False,
|
||||
) -> BasePromptTemplate:
|
||||
"""Create the skill management instructions prompt.
|
||||
|
||||
Renders ``chat/tools/skills.j2`` with the active skill tool namespace.
|
||||
Returns an empty template when the template is missing or rendering fails.
|
||||
"""
|
||||
namespace = _build_tool_namespace(tools)
|
||||
template_path = "chat/tools/skills.j2"
|
||||
try:
|
||||
template = self.template_service.get_template(template_path)
|
||||
rendered = template.render(
|
||||
namespace=namespace,
|
||||
few_shots=str(few_shots),
|
||||
)
|
||||
return PromptTemplate(template=rendered.strip())
|
||||
except Exception as exc:
|
||||
logger.warning("PromptBuilder: failed to render %s: %s", template_path, exc)
|
||||
return PromptTemplate(template="")
|
||||
|
||||
def create_thinking_guidelines(self, few_shots: bool = True) -> BasePromptTemplate:
|
||||
"""Create the thinking/reasoning guidelines prompt.
|
||||
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
{% set list_tool = namespace.tools.get("list_skills_tool_name") %}
|
||||
{% set load_tool = namespace.tools.get("load_skill_tool_name") %}
|
||||
{% set unload_tool = namespace.tools.get("unload_skill_tool_name") %}
|
||||
<skills>
|
||||
Skills are curated instruction sets that give you specialised knowledge and workflows for specific domains. Use them whenever the user's request falls within a skill's area of expertise.
|
||||
|
||||
**When to use skills:**
|
||||
- The user's request mentions a topic or task that a skill might cover.
|
||||
- A task requires domain-specific steps, tools, or conventions you wouldn't know otherwise.
|
||||
- The user explicitly asks you to use a skill.
|
||||
|
||||
**Workflow:**
|
||||
1. Call `{{ list_tool }}` to see available skills and their descriptions.
|
||||
2. Call `{{ load_tool }}` with the skill name that best matches the request.
|
||||
3. Follow the instructions returned by `{{ load_tool }}` when completing the task.
|
||||
4. Call `{{ unload_tool }}` when the task is done and the skill is no longer needed.
|
||||
|
||||
**Rules:**
|
||||
- Always list skills before loading to confirm the name is correct.
|
||||
- Load at most one skill at a time unless the task clearly spans multiple domains.
|
||||
- If no skill matches the request, proceed without loading any.
|
||||
- Never invent skill names; only use names returned by `{{ list_tool }}`.
|
||||
|
||||
{% if few_shots == "True" %}
|
||||
Examples:
|
||||
- User asks to "analyse this dataset using the data-science skill" → call `{{ list_tool }}`, then `{{ load_tool }}` with name `data-science`.
|
||||
- User asks a general question unrelated to any skill → skip skill tools and answer directly.
|
||||
- After finishing a skill-guided task → call `{{ unload_tool }}` with the skill name.
|
||||
{% endif %}
|
||||
</skills>
|
||||
@@ -19,7 +19,10 @@ from private_gpt.components.engines.chat_loop.models.chat_loop_phase import (
|
||||
)
|
||||
from private_gpt.components.engines.citations.types import Document
|
||||
from private_gpt.components.prompts.prompt_builder import PromptBuilderService
|
||||
from private_gpt.components.tools.tool_names import CODE_EXECUTION_INTERNAL_TOOLS
|
||||
from private_gpt.components.tools.tool_names import (
|
||||
CODE_EXECUTION_INTERNAL_TOOLS,
|
||||
SKILL_MANAGEMENT_TOOLS,
|
||||
)
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from private_gpt.chat.input_models import PromptConfig
|
||||
@@ -31,6 +34,7 @@ _SOURCE_TOOL_INSTRUCTIONS = "platform:tool_instructions"
|
||||
_SOURCE_CITATIONS = "platform:citations"
|
||||
_SOURCE_THINKING = "platform:thinking"
|
||||
_SOURCE_CODE_EXECUTION = "platform:code_execution"
|
||||
_SOURCE_SKILLS = "platform:skills"
|
||||
|
||||
_ALL_PLATFORM_SOURCES = frozenset(
|
||||
{
|
||||
@@ -38,6 +42,7 @@ _ALL_PLATFORM_SOURCES = frozenset(
|
||||
_SOURCE_CITATIONS,
|
||||
_SOURCE_THINKING,
|
||||
_SOURCE_CODE_EXECUTION,
|
||||
_SOURCE_SKILLS,
|
||||
}
|
||||
)
|
||||
|
||||
@@ -86,6 +91,10 @@ class PlatformGuidelinesInterceptor(ChatRequestLoopInterceptor):
|
||||
if prompt.code_execution and self._has_code_execution_tool(tools):
|
||||
stack = self._inject_code_execution(stack, tools)
|
||||
|
||||
# 5. Skill management instructions
|
||||
if prompt.skills and self._has_skill_management_tool(tools):
|
||||
stack = self._inject_skills(stack, tools)
|
||||
|
||||
state.input.context_stack = stack
|
||||
context.set_state(state)
|
||||
|
||||
@@ -154,6 +163,20 @@ class PlatformGuidelinesInterceptor(ChatRequestLoopInterceptor):
|
||||
)
|
||||
return stack
|
||||
|
||||
def _inject_skills(
|
||||
self, stack: ContextStack, tools: list[ToolSpec]
|
||||
) -> ContextStack:
|
||||
content = self._prompt_builder.create_skills_prompt(tools).format()
|
||||
if content:
|
||||
stack = stack.append_layer(
|
||||
ToolInstructionsLayer(
|
||||
tool_name="skills",
|
||||
instructions=content,
|
||||
source=_SOURCE_SKILLS,
|
||||
)
|
||||
)
|
||||
return stack
|
||||
|
||||
@staticmethod
|
||||
def _has_code_execution_tool(tools: list[ToolSpec]) -> bool:
|
||||
for tool in tools:
|
||||
@@ -165,6 +188,17 @@ class PlatformGuidelinesInterceptor(ChatRequestLoopInterceptor):
|
||||
return True
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
def _has_skill_management_tool(tools: list[ToolSpec]) -> bool:
|
||||
for tool in tools:
|
||||
try:
|
||||
canonical = tool.get_original_tool_name()
|
||||
except ValueError:
|
||||
canonical = tool.name or ""
|
||||
if canonical in SKILL_MANAGEMENT_TOOLS:
|
||||
return True
|
||||
return False
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Cached content loaders
|
||||
# ------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user