Merge pull request #207 from ggozad/feat/prompt-overrides
Add prompt customization and domain preable
This commit is contained in:
commit
e9657c2044
9 changed files with 173 additions and 9 deletions
|
|
@ -1,6 +1,13 @@
|
|||
# Changelog
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
- **Prompt Customization**: Configure agent prompts via `prompts` config section
|
||||
- `domain_preamble`: Prepended to all agent prompts for domain context
|
||||
- `qa`: Full replacement for QA agent prompt
|
||||
- `synthesis`: Full replacement for research synthesis prompt
|
||||
|
||||
### Changed
|
||||
|
||||
- **Embeddings**: Migrated to pydantic-ai's embeddings module
|
||||
|
|
|
|||
|
|
@ -114,6 +114,11 @@ agui:
|
|||
cors_methods: ["GET", "POST", "OPTIONS"]
|
||||
cors_headers: ["*"]
|
||||
|
||||
prompts:
|
||||
domain_preamble: "" # Prepended to all agent prompts
|
||||
qa: null # Custom QA agent prompt (null = use default)
|
||||
synthesis: null # Custom research synthesis prompt (null = use default)
|
||||
|
||||
processing:
|
||||
converter: docling-local # docling-local or docling-serve
|
||||
chunker: docling-local # docling-local or docling-serve
|
||||
|
|
@ -189,3 +194,4 @@ For detailed configuration of specific topics, see:
|
|||
- **[Search and Question Answering](qa-research.md)** - Search settings, question answering, and research workflows
|
||||
- **[Document Processing](processing.md)** - Document conversion, chunking, and file monitoring
|
||||
- **[Storage](storage.md)** - Database, remote storage, and vector indexing
|
||||
- **[Prompts](prompts.md)** - Customize agent prompts for your domain
|
||||
|
|
|
|||
108
docs/configuration/prompts.md
Normal file
108
docs/configuration/prompts.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# Prompt Customization
|
||||
|
||||
Customize the prompts used by haiku.rag's AI agents to better match your domain and use case.
|
||||
|
||||
## Configuration
|
||||
|
||||
```yaml
|
||||
prompts:
|
||||
# Prepended to all agent prompts
|
||||
domain_preamble: |
|
||||
You are answering questions about our internal documentation.
|
||||
Technical terms like "time travel" refer to database versioning features.
|
||||
|
||||
# Full replacement for QA agent prompt (optional)
|
||||
qa: null
|
||||
|
||||
# Full replacement for research synthesis prompt (optional)
|
||||
synthesis: null
|
||||
```
|
||||
|
||||
## Domain Preamble
|
||||
|
||||
The `domain_preamble` field is prepended to **all** agent prompts (QA, research planning, search, evaluation, and synthesis). Use this to:
|
||||
|
||||
- Add domain context that clarifies terminology
|
||||
- Set the tone or personality of responses
|
||||
- Specify what the knowledge base contains
|
||||
|
||||
**Example:**
|
||||
|
||||
```yaml
|
||||
prompts:
|
||||
domain_preamble: |
|
||||
You are a technical support assistant for Acme Corp products.
|
||||
The knowledge base contains product documentation, FAQs, and troubleshooting guides.
|
||||
Always be helpful and professional.
|
||||
```
|
||||
|
||||
## Custom QA Prompt
|
||||
|
||||
Replace the default QA agent prompt entirely by setting `prompts.qa`. The prompt should instruct the agent how to:
|
||||
|
||||
1. Use the `search_documents` tool to find relevant content
|
||||
2. Interpret search results with scores and metadata
|
||||
3. Cite sources using chunk IDs
|
||||
4. Handle insufficient information
|
||||
|
||||
**Example:**
|
||||
|
||||
```yaml
|
||||
prompts:
|
||||
qa: |
|
||||
You are a concise technical assistant. Answer questions using only the knowledge base.
|
||||
|
||||
Process:
|
||||
1. Search for relevant documents using the search_documents tool
|
||||
2. Review results and their relevance scores
|
||||
3. Provide a brief, direct answer based on retrieved content
|
||||
|
||||
Guidelines:
|
||||
- Use only information from search results
|
||||
- Include chunk IDs in cited_chunks for sources you use
|
||||
- If information is insufficient, say so clearly
|
||||
- Be concise - avoid unnecessary elaboration
|
||||
```
|
||||
|
||||
## Custom Synthesis Prompt
|
||||
|
||||
Replace the research report synthesis prompt by setting `prompts.synthesis`. This controls how the multi-agent research workflow generates its final report.
|
||||
|
||||
The prompt should produce a `ResearchReport` with: `title`, `executive_summary`, `main_findings`, `conclusions`, `recommendations`, `limitations`, and `sources_summary`.
|
||||
|
||||
**Example:**
|
||||
|
||||
```yaml
|
||||
prompts:
|
||||
synthesis: |
|
||||
Generate a research report based on the gathered evidence.
|
||||
|
||||
Output format:
|
||||
- title: 5-12 word title
|
||||
- executive_summary: 3-5 sentence overview
|
||||
- main_findings: 4-8 bullet points of key findings
|
||||
- conclusions: 2-4 bullet points
|
||||
- recommendations: 2-5 actionable recommendations
|
||||
- limitations: 1-3 limitations or gaps
|
||||
- sources_summary: Brief description of sources used
|
||||
|
||||
Guidelines:
|
||||
- Base all content strictly on collected evidence
|
||||
- Be specific and objective
|
||||
- Avoid meta-commentary like "This report covers..."
|
||||
```
|
||||
|
||||
## Programmatic Configuration
|
||||
|
||||
```python
|
||||
from haiku.rag.config import AppConfig
|
||||
from haiku.rag.config.models import PromptsConfig
|
||||
|
||||
config = AppConfig(
|
||||
prompts=PromptsConfig(
|
||||
domain_preamble="You are answering questions about our product documentation.",
|
||||
qa=None, # Use default QA prompt
|
||||
synthesis=None, # Use default synthesis prompt
|
||||
)
|
||||
)
|
||||
```
|
||||
|
|
@ -16,6 +16,7 @@ from haiku.rag.config.models import (
|
|||
MonitorConfig,
|
||||
OllamaConfig,
|
||||
ProcessingConfig,
|
||||
PromptsConfig,
|
||||
ProvidersConfig,
|
||||
QAConfig,
|
||||
RerankingConfig,
|
||||
|
|
@ -35,6 +36,7 @@ __all__ = [
|
|||
"MonitorConfig",
|
||||
"OllamaConfig",
|
||||
"ProcessingConfig",
|
||||
"PromptsConfig",
|
||||
"ProvidersConfig",
|
||||
"QAConfig",
|
||||
"RerankingConfig",
|
||||
|
|
|
|||
|
|
@ -162,6 +162,12 @@ class AGUIConfig(BaseModel):
|
|||
cors_headers: list[str] = ["*"]
|
||||
|
||||
|
||||
class PromptsConfig(BaseModel):
|
||||
domain_preamble: str = ""
|
||||
qa: str | None = None
|
||||
synthesis: str | None = None
|
||||
|
||||
|
||||
class AppConfig(BaseModel):
|
||||
environment: str = "production"
|
||||
storage: StorageConfig = Field(default_factory=StorageConfig)
|
||||
|
|
@ -175,3 +181,4 @@ class AppConfig(BaseModel):
|
|||
search: SearchConfig = Field(default_factory=SearchConfig)
|
||||
providers: ProvidersConfig = Field(default_factory=ProvidersConfig)
|
||||
agui: AGUIConfig = Field(default_factory=AGUIConfig)
|
||||
prompts: PromptsConfig = Field(default_factory=PromptsConfig)
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ from haiku.rag.graph.research.prompts import (
|
|||
SYNTHESIS_PROMPT,
|
||||
)
|
||||
from haiku.rag.graph.research.state import ResearchDeps, ResearchState
|
||||
from haiku.rag.utils import get_model
|
||||
from haiku.rag.utils import build_prompt, get_model
|
||||
|
||||
|
||||
def format_context_for_prompt(context: ResearchContext) -> str:
|
||||
|
|
@ -76,6 +76,18 @@ def build_research_graph(
|
|||
Configured Research graph
|
||||
"""
|
||||
model_config = config.research.model
|
||||
|
||||
# Build prompts with system_context if configured
|
||||
plan_prompt = build_prompt(
|
||||
PLAN_PROMPT
|
||||
+ "\n\nUse the gather_context tool once on the main question before planning.",
|
||||
config,
|
||||
)
|
||||
search_prompt = build_prompt(SEARCH_PROMPT, config)
|
||||
decision_prompt = build_prompt(DECISION_PROMPT, config)
|
||||
synthesis_prompt = build_prompt(
|
||||
config.prompts.synthesis or SYNTHESIS_PROMPT, config
|
||||
)
|
||||
g = GraphBuilder(
|
||||
state_type=ResearchState,
|
||||
deps_type=ResearchDeps,
|
||||
|
|
@ -98,10 +110,7 @@ def build_research_graph(
|
|||
plan_agent = Agent(
|
||||
model=get_model(model_config, config),
|
||||
output_type=ResearchPlan,
|
||||
instructions=(
|
||||
PLAN_PROMPT
|
||||
+ "\n\nUse the gather_context tool once on the main question before planning."
|
||||
),
|
||||
instructions=plan_prompt,
|
||||
retries=3,
|
||||
output_retries=3,
|
||||
deps_type=ResearchDependencies,
|
||||
|
|
@ -178,7 +187,7 @@ def build_research_graph(
|
|||
agent = Agent(
|
||||
model=get_model(model_config, config),
|
||||
output_type=ToolOutput(RawSearchAnswer, max_retries=3),
|
||||
instructions=SEARCH_PROMPT,
|
||||
instructions=search_prompt,
|
||||
retries=3,
|
||||
deps_type=ResearchDependencies,
|
||||
)
|
||||
|
|
@ -281,7 +290,7 @@ def build_research_graph(
|
|||
agent = Agent(
|
||||
model=get_model(model_config, config),
|
||||
output_type=EvaluationResult,
|
||||
instructions=DECISION_PROMPT,
|
||||
instructions=decision_prompt,
|
||||
retries=3,
|
||||
output_retries=3,
|
||||
deps_type=ResearchDependencies,
|
||||
|
|
@ -438,7 +447,7 @@ def build_research_graph(
|
|||
agent = Agent(
|
||||
model=get_model(model_config, config),
|
||||
output_type=ResearchReport,
|
||||
instructions=SYNTHESIS_PROMPT,
|
||||
instructions=synthesis_prompt,
|
||||
retries=3,
|
||||
output_retries=3,
|
||||
deps_type=ResearchDependencies,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
from haiku.rag.client import HaikuRAG
|
||||
from haiku.rag.config import AppConfig, Config
|
||||
from haiku.rag.qa.agent import QuestionAnswerAgent
|
||||
from haiku.rag.qa.prompts import QA_SYSTEM_PROMPT
|
||||
from haiku.rag.utils import build_prompt
|
||||
|
||||
|
||||
def get_qa_agent(
|
||||
|
|
@ -13,11 +15,18 @@ def get_qa_agent(
|
|||
Args:
|
||||
client: HaikuRAG client instance.
|
||||
config: Configuration to use. Defaults to global Config.
|
||||
system_prompt: Optional custom system prompt.
|
||||
system_prompt: Optional custom system prompt (overrides config).
|
||||
|
||||
Returns:
|
||||
A configured QuestionAnswerAgent instance.
|
||||
"""
|
||||
# Determine the base prompt: explicit > config > default
|
||||
if system_prompt is None:
|
||||
system_prompt = config.prompts.qa or QA_SYSTEM_PROMPT
|
||||
|
||||
# Prepend system_context if configured
|
||||
system_prompt = build_prompt(system_prompt, config)
|
||||
|
||||
return QuestionAnswerAgent(
|
||||
client=client,
|
||||
model_config=config.qa.model,
|
||||
|
|
|
|||
|
|
@ -398,6 +398,21 @@ def get_default_data_dir() -> Path:
|
|||
return data_path
|
||||
|
||||
|
||||
def build_prompt(base_prompt: str, config: "AppConfig") -> str:
|
||||
"""Build a prompt with domain_preamble prepended if configured.
|
||||
|
||||
Args:
|
||||
base_prompt: The base prompt to use
|
||||
config: AppConfig with prompts.domain_preamble
|
||||
|
||||
Returns:
|
||||
Prompt with domain_preamble prepended if configured
|
||||
"""
|
||||
if config.prompts.domain_preamble:
|
||||
return f"{config.prompts.domain_preamble}\n\n{base_prompt}"
|
||||
return base_prompt
|
||||
|
||||
|
||||
async def is_up_to_date() -> tuple[bool, Version, Version]:
|
||||
"""Check whether haiku.rag is current.
|
||||
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ nav:
|
|||
- Search and Question Answering: configuration/qa-research.md
|
||||
- Document Processing: configuration/processing.md
|
||||
- Storage: configuration/storage.md
|
||||
- Prompts: configuration/prompts.md
|
||||
- CLI: cli.md
|
||||
- Python: python.md
|
||||
- Custom Pipelines: custom-pipelines.md
|
||||
|
|
|
|||
Loading…
Reference in a new issue