ClickHouse Assistant chat エージェント は、エージェントのシステムプロンプトに対するセマンティックレイヤーとして機能する特別な保存クエリ AGENTS.md を通じて、固有のビジネスロジック、データ構造、ドメイン知識を理解できるようにカスタマイズできます。
AGENTS.md ファイルを作成すると、各会話の冒頭に挿入されるカスタム指示を追加でき、組織固有の要件、計算、慣例に基づいた SQL クエリの生成やデータ分析を促せます。
Cloud Console で “AGENTS.md” (大文字と小文字を区別) という名前のクエリを保存すると:
- メッセージ送信時に、ClickHouse Assistant chat エージェントがこのファイルを自動的に読み込みます
- 内容は構造化されたコンテンツタグ内に配置され、エージェントのシステムプロンプトに挿入されます
- これらの指示は、そのサービス内のすべての ClickHouse Assistant chat の会話に適用されます
保存クエリを作成する
- Cloud Console で新しいクエリを作成します
- 名前を “AGENTS.md” に正確に設定します (大文字と小文字は区別されます)
- クエリテキストのエディタにカスタムの指示を記述します (実際の SQL は入力しません)
- クエリを保存します
指示を追加する
明確で実行しやすい表現で指示を構成します。以下を含めてください。
- ビジネスルールと計算式
- データ構造に関するガイダンス
- ドメイン固有の用語
- 一般的なクエリパターン
- パフォーマンス最適化のルール
コンテキストは貴重です。トークンを使うたびに、エージェントの「注意の予算」が削られていきます。作業記憶に限りがある人間と同じように、言語モデルもコンテキストが増えるにつれて性能が低下します。つまり、望ましい結果を得られる可能性を最大化するには、情報価値の高いトークンをできるだけ少なく絞り込むことが重要です。
両極端の間でバランスを取りましょう。
- 具体的すぎる: 壊れやすい if-else ロジックをハードコードしてしまい、脆さや保守の複雑さを招く
- 曖昧すぎる: 具体的な手がかりを示せず、共有された文脈があることを誤って前提にしてしまう高レベルなガイダンス
最適な粒度とは、振る舞いを効果的に導けるだけの具体性を備えつつ、モデルが強力なヒューリスティクスを適用できるだけの柔軟性もある状態です。まずは利用可能な最良のモデルに対して最小限のプロンプトから始め、確認された失敗パターンに応じて明確な指示を追加してください。
XMLタグやMarkdownの見出しを使って、区切りが明確でひと目で把握しやすいセクションを作成します。
<background_information>
Context about your data and domain
</background_information>
<calculation_rules>
Specific formulas and business logic
</calculation_rules>
<tool_guidance>
How to use specific ClickHouse features
</tool_guidance>
例は、いわば「百聞は一見にしかず」です。あらゆるエッジケースをプロンプトに詰め込むのではなく、期待される振る舞いが効果的に伝わるよう、焦点を絞って多様な例を厳選してください。
- 頻繁に必要となる指示だけを含める
- 簡潔にする — コンテキストが長すぎると「コンテキストの劣化」によりパフォーマンスが低下する
- 古くなったルールやほとんど使われないルールは削除する
- 望ましい挙動を導くのに十分な情報を確保する
最小限とは、必ずしも短いことを意味するわけではありません。エージェントが期待どおりに動作するために必要な詳細は含めつつ、不必要に冗長にならないようにしてください。
メトリクスの取得にカラムへの直接アクセスではなく特定の計算が必要な場合は、その旨をエージェントに指示します。
<metric_calculations>
IMPORTANT: "active_sessions" is NOT a column. It must be calculated.
To calculate active sessions:
COUNT(DISTINCT session_id || '|' || user_id) AS active_sessions
This counts unique combinations of session and user identifiers.
When the user asks for "active sessions" or "session count", always use this formula:
SELECT
date,
COUNT(DISTINCT session_id || '|' || user_id) AS active_sessions
FROM events
GROUP BY date;
</metric_calculations>
ドメイン固有の計算や分類を定義します。
<business_rules>
Revenue Calculation:
- Exclude refunded transactions: WHERE transaction_status != 'refunded'
- Apply regional tax rates using CASE expressions
- Use MRR for subscriptions:
SUM(CASE
WHEN billing_cycle = 'monthly' THEN amount
WHEN billing_cycle = 'yearly' THEN amount / 12
ELSE 0
END) AS mrr
Traffic Source Classification:
Use CASE expression to categorize:
CASE
WHEN traffic_source IN ('google', 'bing', 'organic') THEN 'Organic Search'
WHEN traffic_source IN ('facebook', 'instagram', 'social') THEN 'Social Media'
WHEN traffic_source = 'direct' THEN 'Direct'
ELSE 'Other'
END AS source_category
Customer Segmentation:
- Enterprise: annual_contract_value >= 100000
- Mid-Market: annual_contract_value >= 10000 AND annual_contract_value < 100000
- SMB: annual_contract_value < 10000
Always include these categorizations when generating traffic or revenue reports.
</business_rules>
一般的でないデータフォーマットや、レガシーなスキーマ設計上の判断を記載します。
<data_structure_notes>
The user_status column uses numeric codes, not strings:
- 1 = 'active'
- 2 = 'inactive'
- 3 = 'suspended'
- 99 = 'deleted'
When filtering or displaying user status, always use:
CASE user_status
WHEN 1 THEN 'active'
WHEN 2 THEN 'inactive'
WHEN 3 THEN 'suspended'
WHEN 99 THEN 'deleted'
END AS status_label
The product_metadata column contains JSON strings that must be parsed:
SELECT
product_id,
JSONExtractString(product_metadata, 'category') AS category,
JSONExtractInt(product_metadata, 'inventory_count') AS inventory
FROM products;
</data_structure_notes>
ビジネス用語を技術的な実装に対応付けます:
<terminology>
When users refer to "conversions", they mean:
- For e-commerce: transactions WHERE transaction_type = 'purchase'
- For SaaS: subscriptions WHERE subscription_status = 'active' AND first_payment_date IS NOT NULL
"Churn" is calculated as:
COUNT(DISTINCT user_id) WHERE last_active_date < today() - INTERVAL 90 DAY
AND previous_subscription_status = 'active'
"DAU" (Daily Active Users) means:
COUNT(DISTINCT user_id) WHERE activity_date = today()
"Qualified leads" must meet ALL criteria:
- lead_score >= 70
- company_size >= 50
- budget_confirmed = true
- contact_role IN ('Director', 'VP', 'C-Level')
</terminology>