# How Prompts Are Structured in the prompts/ Modules for Each bettafish Agent

> Discover how prompts are structured in the bettafish repository. Learn about JSON schemas, system prompt f-strings, and serialization for agent LLM configurations.

- Repository: [BaiFu/bettafish](https://github.com/666ghj/bettafish)
- Tags: internals
- Published: 2026-02-23

---

**Each agent engine in the 666ghj/bettafish repository stores its LLM configuration in a dedicated [`prompts/prompts.py`](https://github.com/666ghj/bettafish/blob/main/prompts/prompts.py) file, organizing instructions into JSON schemas, system prompt f-strings, and serialization helpers that convert Python dictionaries into formatted JSON payloads.**

The 666ghj/bettafish project implements four specialized engines—Report, Query, Media, and Insight—that each rely on structured prompt modules to communicate with LLMs. Understanding how prompts are structured in the prompts/ modules for each agent reveals a declarative architecture where data contracts, behavioral instructions, and payload serialization remain cleanly separated. This design ensures type-safe interactions with language models while maintaining readability for Chinese and multilingual content.

## ReportEngine Prompt Components

Located at [`ReportEngine/prompts/prompts.py`](https://github.com/666ghj/bettafish/blob/main/ReportEngine/prompts/prompts.py), the ReportEngine module defines the most extensive set of prompt utilities, handling complex document generation workflows.

### JSON Schemas for Data Contracts

The module declares strict **JSON schemas** that enforce the shape of LLM inputs and outputs. Key schemas include `output_schema_template_selection` for choosing document templates, `chapter_generation_input_schema` for structuring chapter content, and `output_schema_report_structure` for overall document outlines. These schemas use standard JSON Schema syntax with typed properties, ensuring the model produces valid, predictable structures.

### System Prompts and GraphRAG Enhancement

System prompts are defined as multi-line f-strings that establish the model's role and constraints. The `SYSTEM_PROMPT_CHAPTER_GRAPH_ENHANCEMENT` constant (built from `GRAPHRAG_CHAPTER_ENHANCEMENT_INTRO` at lines 19-33) injects knowledge-graph context into chapter generation. This prompt wraps graph query results in XML-like tags (`<知识图谱查询结果>`), instructing the LLM to embed retrieved knowledge when drafting content.

### Serialization Helpers

ReportEngine provides specialized helper functions to prepare payloads:

- **`build_chapter_user_prompt`** (lines 68-74): Serializes chapter metadata and research reports into a JSON string
- **`build_chapter_repair_prompt`**: Creates recovery payloads that include the tail of raw LLM output (`raw_output[-8000:]`) to help diagnose validation errors without exceeding context limits
- **`build_graphrag_enhanced_user_prompt`**: Combines base chapter data with graph enhancement blocks

All helpers use `json.dumps(payload, ensure_ascii=False, indent=2)` to preserve Unicode characters and maintain readable indentation.

## QueryEngine Prompt Components

The [`QueryEngine/prompts/prompts.py`](https://github.com/666ghj/bettafish/blob/main/QueryEngine/prompts/prompts.py) file handles search planning and information retrieval workflows with a leaner, schema-centric approach.

### Search Planning Schemas

The module defines input and output schemas such as `input_schema_first_search` (lines 22-28) and `output_schema_first_search` that specify exact fields for query formulation. These schemas require properties like `search_query`, `search_tool`, and `reasoning`, creating a strict contract for the LLM's planning phase.

### Tool Enumeration in System Prompts

The `SYSTEM_PROMPT_FIRST_SEARCH` (lines 42-84) embeds an enumerated list of six news-search tools—including `basic_search_news`, `deep_search_news`, and specialized variants—directly within the system message. The prompt also dynamically inserts the JSON schema using `{json.dumps(schema, indent=2, ensure_ascii=False)}`, ensuring the model sees exact field names and types it must obey when selecting tools and formulating queries.

## MediaEngine Prompt Components

[`MediaEngine/prompts/prompts.py`](https://github.com/666ghj/bettafish/blob/main/MediaEngine/prompts/prompts.py) reuses QueryEngine's data contracts while adapting the system prompts for multimodal workflows.

### Multimodal Tool Specifications

The `SYSTEM_PROMPT_FIRST_SEARCH` (lines 46-78) lists five media-specific tools: `comprehensive_search`, `web_search_only`, `search_for_structured_data`, `search_last_24_hours`, and `search_last_week`. Unlike the QueryEngine, this variant emphasizes that **no extra parameters** are required for these multimodal tools, focusing the LLM on selecting the appropriate search strategy for text-plus-image content.

## InsightEngine Prompt Components

The [`InsightEngine/prompts/prompts.py`](https://github.com/666ghj/bettafish/blob/main/InsightEngine/prompts/prompts.py) module extends the base schemas to support local opinion mining and sentiment analysis.

### Local Opinion-Mining Parameters

This engine's `SYSTEM_PROMPT_FIRST_SEARCH` (lines 71-115) describes six specialized tools for Chinese social media analysis, including `search_hot_content`, `search_topic_globally`, `search_topic_by_date`, `get_comments_for_topic`, and `search_topic_on_platform`. The accompanying extended schemas add fields like `platform`, `time_period` (accepting values `'24h'`, `'week'`, `'year'`), `enable_sentiment`, and `texts`, allowing fine-grained control over sentiment analysis and platform-specific searches.

## Common Serialization Pattern Across Engines

Despite varying complexity, all engines follow a consistent helper pattern for payload preparation:

```python
def build_xyz_prompt(payload: dict) -> str:
    """Serialize a dict as a LLM-friendly JSON string."""
    return json.dumps(payload, ensure_ascii=False, indent=2)

```

This approach guarantees **consistent formatting** with 2-space indentation and explicit Unicode handling. By centralizing serialization in the prompts module, downstream engine code can embed the resulting strings directly into system or user messages without additional processing.

## Practical Implementation Examples

### Building a Chapter Prompt (ReportEngine)

```python
from ReportEngine.prompts import build_chapter_user_prompt

payload = {
    "section": {"title": "市场趋势", "order": 1},
    "globalContext": {"query": "2025年AI行业发展"},
    "reports": {"query_engine": "...", "media_engine": "...", "insight_engine": "..."},
}
user_prompt = build_chapter_user_prompt(payload)

# Returns a pretty-printed JSON string with Chinese characters preserved

```

### Selecting a Search Tool (QueryEngine)

```python
from QueryEngine.prompts import SYSTEM_PROMPT_FIRST_SEARCH, input_schema_first_search
import json

system_msg = SYSTEM_PROMPT_FIRST_SEARCH.format(
    schema=json.dumps(input_schema_first_search, indent=2, ensure_ascii=False)
)

# The LLM returns: {"search_query":"AI监管政策2024","search_tool":"deep_search_news","reasoning":"需要深度分析官方文件"}

```

### Adding GraphRAG Enhancement (ReportEngine)

```python
from ReportEngine.prompts import build_graphrag_enhanced_user_prompt, GRAPHRAG_CHAPTER_ENHANCEMENT_INTRO

payload = {
    "section": {"title": "技术演进"},
    "graph_enhancement_prompt": GRAPHRAG_CHAPTER_ENHANCEMENT_INTRO.format(
        graph_results="【节点】AI模型 2023‑2025 发展 ..."
    ),
}
full_prompt = build_graphrag_enhanced_user_prompt(payload)

# Combines base JSON payload with graph context block

```

### Repairing Failed Chapter Generation

```python
from ReportEngine.prompts import build_chapter_repair_prompt

# When validation fails, include tail of raw output for debugging

repair_payload = build_chapter_repair_prompt(
    original_payload=chapter_data,
    raw_output=failed_llm_output[-8000:]  # Last 8000 chars only

)

```

## Summary

- Each bettafish engine maintains a self-contained [`prompts/prompts.py`](https://github.com/666ghj/bettafish/blob/main/prompts/prompts.py) module containing schemas, system prompts, and helpers.
- **JSON schemas** enforce type-safe data contracts for LLM inputs and outputs, with `ensure_ascii=False` preserving Chinese characters.
- **System prompts** are multi-line f-strings that enumerate available tools and behavioral constraints, often embedding dynamic schema definitions.
- **ReportEngine** offers the richest helper suite, including GraphRAG enhancement and repair utilities that truncate raw output to manage context windows.
- **QueryEngine**, **MediaEngine**, and **InsightEngine** vary their tool lists and schema extensions to match their specialized domains—news search, multimodal content, and local opinion mining respectively.
- All modules rely on `json.dumps(..., indent=2, ensure_ascii=False)` for consistent, readable payload serialization.

## Frequently Asked Questions

### How does the ReportEngine handle failed LLM outputs during chapter generation?

The ReportEngine provides `build_chapter_repair_prompt` and `build_chapter_recovery_payload` helpers that capture the last 8000 characters of the raw LLM output (`raw_output[-8000:]`) and embed them into a new prompt. This allows the validation logic to pinpoint JSON syntax errors or schema violations without resubmitting the entire failed response, keeping repair prompts within token limits while preserving diagnostic context.

### Why do the QueryEngine and MediaEngine share identical JSON schemas?

Both engines perform parallel search workflows—QueryEngine for text-based news retrieval and MediaEngine for multimodal content—requiring the same core data contracts for query formulation and result formatting. By reusing schemas like `output_schema_report_structure` and `input_schema_first_search` across [`QueryEngine/prompts/prompts.py`](https://github.com/666ghj/bettafish/blob/main/QueryEngine/prompts/prompts.py) and [`MediaEngine/prompts/prompts.py`](https://github.com/666ghj/bettafish/blob/main/MediaEngine/prompts/prompts.py), the codebase maintains consistency while differentiating behavior through distinct system prompt tool lists and instructions.

### What distinguishes the InsightEngine's prompt structure from the other agents?

According to the source code in [`InsightEngine/prompts/prompts.py`](https://github.com/666ghj/bettafish/blob/main/InsightEngine/prompts/prompts.py), this engine extends the base schemas to include opinion-mining specific fields like `platform`, `time_period`, and `enable_sentiment`. Its `SYSTEM_PROMPT_FIRST_SEARCH` (lines 71-115) enumerates six local search tools designed for Chinese social media analysis, whereas QueryEngine focuses on general news search and MediaEngine on multimodal retrieval. These extensions enable fine-grained sentiment analysis and platform-specific querying unique to opinion monitoring workflows.

### How are JSON schemas dynamically embedded into system prompts?

The system prompt strings in all engines use Python f-string interpolation to inject schema definitions at runtime. For example, QueryEngine's `SYSTEM_PROMPT_FIRST_SEARCH` contains placeholders like `{json.dumps(schema, indent=2, ensure_ascii=False)}`, which renders the exact JSON schema the LLM must follow directly into the prompt text. This technique ensures the model receives up-to-date field specifications without hardcoding schema details into the prompt constants.