How Prompts Are Structured in the prompts/ Modules for Each bettafish Agent
Each agent engine in the 666ghj/bettafish repository stores its LLM configuration in a dedicated 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, 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 stringbuild_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 limitsbuild_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 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 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 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:
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)
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)
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)
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
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.pymodule containing schemas, system prompts, and helpers. - JSON schemas enforce type-safe data contracts for LLM inputs and outputs, with
ensure_ascii=Falsepreserving 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 and 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, 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.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →