1. 用途
std/v1 は、portal_view_common = 1画面 に対応する ai_purpose 用の DomainGuide です。
目的は次の3つです。
- その画面の業務意味を固定する
- その画面に対する自然言語質問の解釈方針を固定する
- その画面向けの安全なSQL生成ルールを固定する
つまり、これは単なる説明文ではなく、
画面単位の業務ルール + SQLガイド です。
2. 適用単位
- 1 DomainGuide = 1
portal_view_common - 1 DomainGuide = 1画面
- 保存先 =
portal_view_common.ai_purpose
3. top-level key 一覧
std/v1 では、次の top-level key を必須とします。
domain_guide_version
domain
summary
purpose
business_terms
scope
fields
join_profiles
patterns
query_patterns
guardrails
順番もこの並びを推奨します。
4. 各キー定義
4-1. domain_guide_version
必須。固定値。
domain_guide_version: "std/v1"
4-2. domain
必須。
この画面が主に扱う対象ドメイン。
ルール
- dot notation を使う
- 原則
model_techに合わせる - 画面名ではなく、主対象モデルを書く
例
domain: "fact.opportunity"
domain: "fact.sales.rep"
domain: "fact.email.event"
4-3. summary
必須。
画面の目的と基準粒度と主要注意点を、短く説明する。
ルール
- 日本語
- 1〜3文程度
- 次を含める
- 何の画面か
- 何を基点に見るか
- 主要な注意点
例
summary: "案件一覧・案件分析画面向けの DomainGuide。案件を基点に、担当別・期間別・ステージ別・顧客別の集計と、期待売上の把握を安全に行うための業務ガイド。"
4-4. purpose
必須。
画面の業務目的と代表質問。
構造
purpose:
screen_goal_ja: "..."
typical_questions_ja:
- "..."
必須キー
screen_goal_jatypical_questions_ja
ルール
screen_goal_jaは1文typical_questions_jaは3〜6件程度
4-5. business_terms
必須。
画面で使う主要な業務語彙。
構造
business_terms:
primary_terms:
- "..."
related_terms:
- "..."
必須キー
primary_termsrelated_terms
ルール
primary_terms: その画面の中心語related_terms: 言い換え、周辺語、ユーザーが言いそうな語
例
business_terms:
primary_terms:
- "案件"
- "案件数"
- "期待売上"
related_terms:
- "商談"
- "見込み売上"
- "営業案件"
4-6. scope
必須。
SQL生成の基盤となる範囲定義。
構造
scope:
base_table: "..."
base_alias: "..."
base_pk: "..."
base_grain: "..."
allowed_tables:
- "..."
time_field_default: "..."
必須キー
base_tablebase_aliasbase_pkbase_grainallowed_tablestime_field_default
定義
base_table: SQLの主テーブルbase_alias: 主テーブルの固定aliasbase_pk: 主キーまたは行識別子base_grain: 1行の意味allowed_tables: 画面で使ってよいテーブルtime_field_default: 既定時間軸
ルール
allowed_tablesにはbase_tableを必ず含めるbase_grainは短い識別子推奨opportunitysales_repemail_event
time_field_defaultは列名でも alias付きでもよいが、プロジェクト内で統一する
4-7. fields
必須。
画面で扱う主要フィールド。
構造
fields:
identifiers: []
dimensions: []
measures: []
timestamps: []
必須キー
identifiersdimensionsmeasurestimestamps
4-7-1. identifiers
識別キー・参照キー。
1要素の基本形
- field: "header.opp_id"
label_ja: "案件ID"
description: "..."
4-7-2. dimensions
一覧表示や group by に使う項目。
基本形
- field: "header.stage"
label_ja: "ステージ"
description: "..."
4-7-3. measures
数値指標。
基本形
- field: "header.expected_revenue"
label_ja: "期待売上"
description: "..."
default_aggregation: "sum"
派生指標の例
- field: "header.opp_id"
label_ja: "案件数"
description: "..."
derived_measure: "COUNT(DISTINCT header.opp_id)"
4-7-4. timestamps
時間軸項目。
基本形
- field: "header.updated_at"
label_ja: "更新日時"
description: "..."
default_time_field: true
ルール
- 既定時間軸には
default_time_field: trueを付ける
4-8. join_profiles
必須。
画面で許可される代表的JOINパターン。
構造
join_profiles:
- name: "..."
description: "..."
base_grain_preserved: true
joins:
- table: "..."
alias: "..."
type: "left"
on: "..."
use_when:
- "..."
必須キー
namedescriptionbase_grain_preservedjoinsuse_when
ルール
- 画面の基準粒度を壊さない JOIN を優先
use_whenは自然言語でよい- 必要なら複数JOINを1 profileに含めてよい
4-9. patterns
必須。
その画面でよくある質問の意味パターン。
構造
patterns:
- name: "..."
description: "..."
intent: "list|rank|aggregate"
grain: "..."
...
推奨キー
namedescriptionintentgrain
optional
selectgroup_bymeasuresjoinsorder_bywhere_defaults
ルール
patternsは SQL全文ではなく、どういう答え方かの骨格- 1画面につき 3〜6件程度
4-10. query_patterns
必須。
few-shot 用の質問→SQL形状サンプル。
構造
query_patterns:
- name: "..."
question_ja: "..."
sql_shape: |
SELECT ...
必須キー
namequestion_jasql_shape
ルール
sql_shapeは SELECT-only:company_id,:limitのようなパラメータを使う- 画面の
scopeとjoin_profilesに整合すること
4-11. guardrails
必須。
SQL生成の安全制約。
構造
guardrails:
limit_default: 100
require_tenant_filter: true
forbid:
- "..."
sql_rules:
- "..."
必須キー
limit_defaultrequire_tenant_filterforbidsql_rules
定義
limit_default: 既定LIMITrequire_tenant_filter: company_id などの絞り込み必須かforbid: 禁止事項sql_rules: SQL生成ルール
ルール
- mutation 系は禁止
- 粒度破壊JOINは禁止
- event/detail 系の raw join は必要に応じて禁止
- 既定LIMITは必須
5. 命名ルール
domain
- dot notation
model_techに合わせる
alias
短く固定する。例:
headerlinecpaprepuesigphout
base_grain
短い識別子を推奨:
opportunitysales_repemail_eventpartnerperiodopportunity_outcome
6. 実装上の解釈ルール
analytics 側が最低限読むのは次です。
最低限読むキー
domainscope.base_tablescope.base_aliasscope.base_pkscope.base_grainscope.allowed_tablesscope.time_field_defaultguardrails.limit_defaultguardrails.require_tenant_filterguardrails.forbidpatternsquery_patternsjoin_profiles
補助的に読むキー
summarypurposebusiness_termsfields
7. 品質基準
std/v1 として保存してよい条件は次です。
- top-level 11キーがすべてある
domain_guide_version = "std/v1"domainが dot notationscope.base_tableとallowed_tablesが整合fields.timestampsがあるquery_patterns.sql_shapeが SELECT-onlyguardrails.limit_defaultが整数- 画面の業務意味が summary/purpose/patterns に反映されている
8. 今回のあなたの YAML を基準とした標準テンプレート
domain_guide_version: "std/v1"
domain: "<model_tech>"
summary: "<この画面の業務要約>"
purpose:
screen_goal_ja: "<この画面の目的>"
typical_questions_ja:
- "<質問1>"
business_terms:
primary_terms:
- "<主要語>"
related_terms:
- "<関連語>"
scope:
base_table: "<physical table>"
base_alias: "<alias>"
base_pk: "<pk>"
base_grain: "<grain id>"
allowed_tables:
- "<table>"
time_field_default: "<default time field>"
fields:
identifiers:
- field: "<alias.column>"
label_ja: "<label>"
description: "<description>"
dimensions:
- field: "<alias.column>"
label_ja: "<label>"
description: "<description>"
measures:
- field: "<alias.column>"
label_ja: "<label>"
description: "<description>"
timestamps:
- field: "<alias.column>"
label_ja: "<label>"
description: "<description>"
default_time_field: true
join_profiles:
- name: "<join profile>"
description: "<description>"
base_grain_preserved: true
joins:
- table: "<table>"
alias: "<alias>"
type: "left"
on: "<join condition>"
use_when:
- "<when>"
patterns:
- name: "<pattern>"
description: "<description>"
intent: "<list|rank|aggregate>"
grain: "<grain>"
query_patterns:
- name: "<pattern>"
question_ja: "<question>"
sql_shape: |
SELECT ...
guardrails:
limit_default: 100
require_tenant_filter: true
forbid:
- "<forbidden>"
sql_rules:
- "<sql rule>"
9. 運用ルール
- まず
fact_opportunity_domain_guideを基準版とする - 次の画面はこのフォーマットをテンプレとして流用する
- 画面ごとの差は
summarypurposebusiness_termsscopefieldsjoin_profilespatternsquery_patternsguardrails
で吸収する
作成エージェントプロンプト
DomainGuide生成プロンプト(標準版) あなたは Odoo Dev-Portal / Analytics 用の DomainGuide 設計アシスタントです。 目的は、自然文質問から SQL を安全に生成するために、各モデルごとの標準版 DomainGuide を作ることです。 今回作る DomainGuide は、SAPB1 のような重い厳密仕様ではなく、Fact 系モデルから安定して生成できる「標準版 std/v1」である必要があります。 # 出力要件 – YAMLのみを出力すること – 余計な説明文を出さないこと – YAML先頭に domain_guide_version: “std/v1” を入れること – locale は ja_JP – 日本語中心で記述すること – SQL生成に使えるよう、purpose / business_terms / scope / fields / join_hints / query_patterns / guardrails を必ず含めること – 実在しないテーブル名・フィールド名・JOIN条件を勝手に作らないこと – 与えられた metadata から分かる範囲だけを書くこと – 不明な JOIN は join_hints に書かず省略すること – SQL断片を書く場合は、base_alias を使うこと – 画面や対象が「何のために使われるか」を purpose.screen_goal_ja に必ず書くこと – natural language retrieval で引っかかるよう、 typical_questions_ja と business_terms を充実させること – query_patterns には、list と aggregate を最低1つずつ含めること – count 系は原則 COUNT(DISTINCT .) を使うこと – timestamp フィールドがあれば、time_field_default に設定すること – notes はそのまま写すのではなく、利用目的に言い換えて purpose や business_terms に反映すること # 標準スキーマ 必ず以下のトップレベルを出力すること: – domain_guide_version – domain – purpose – business_terms – scope – fields – join_hints – query_patterns – guardrails # fields の書き方 fields は以下のサブカテゴリを持つこと: – identifiers – dimensions – measures – timestamps 各フィールドについて可能なら以下を持つこと: – name – label_ja – table_alias – semantic_type – searchable – synonyms – join_target(参照系のみ) – aggregations(measureのみ) – default_time_field(timestampの主軸のみ) # 入力として与えられるもの – model 技術名 – model_table – model label – notes – field 一覧 – field_name – ttype – label_i18n.ja_JP / en_US – notes # 変換ルール 1. scope.base_table は model_table を使う 2. scope.base_alias は model 名から短く自然な alias を付ける 例: – fact.opportunity -> opp – fact.sales.rep -> rep – fact.company -> c – fact.email.event -> ev 3. scope.base_pk は field 名に _id があればそれを優先し、モデルの business key らしいものを選ぶ 4. scope.base_grain はモデルの意味に沿った単語にする 例: – fact.opportunity -> opportunity – fact.sales.rep -> sales_rep – fact.company -> company 5. timestamp 系 created_at / updated_at があれば timestamps に入れる 6. many2one や notes に “References …” がある場合だけ join_hints 候補を書く 7. query_patterns は、このモデルに自然に聞かれそうな list / aggregate を作る 8. purpose.typical_questions_ja は、実際にユーザーが聞きそうな自然文を3〜5個書く 9. business_terms.primary_terms にはモデルの主要業務語彙を、related_terms には関連語彙を書く 10. guardrails.limit_default は 50 とする 11. guardrails.sql_rules には少なくとも以下を入れる: – SELECTのみ許可 – DELETE/UPDATE/INSERT/DROP禁止 – 既定LIMITを必ず付与 – 曖昧な場合はbase_tableを中心にする # 入力 以下の metadata をもとに DomainGuide を生成してください。 たとえば fact.opportunity なら、この形で続けます。 model: fact.opportunity model_table: public.fact_opportunity label_ja: 案件(Fact) label_en: Opportunity (Fact) notes: Base table for demo views such as pipeline, rank, and trend. Grain=opp_id. fields: – field_name: opp_id ttype: char label_ja: 案件ID label_en: Opportunity ID notes: Business key of the opportunity. – field_name: company_id ttype: many2one label_ja: 会社ID(テナント) label_en: Company ID (Tenant) notes: Required tenant filter. References fact.company via fact_company.company_id. Usually c001. – field_name: partner_id ttype: many2one label_ja: 取引先ID label_en: Partner ID notes: References fact.res.partner by id. CSV may contain numeric-looking values, but text operation is allowed. – field_name: period_id ttype: many2one label_ja: 期間ID label_en: Period ID notes: References fact.period by period_id. Example: 2026-04. – field_name: rep_id ttype: many2one label_ja: 担当ID label_en: Rep ID notes: References fact.sales.rep by rep_id. – field_name: name ttype: char label_ja: 案件名 label_en: Opportunity Name notes: Opportunity display name. – field_name: stage ttype: char label_ja: ステージ label_en: Stage notes: Example values: new, qualified. Operate according to actual CSV values. – field_name: expected_revenue ttype: numeric label_ja: 期待売上 label_en: Expected Revenue notes: Expected revenue amount. – field_name: created_at ttype: timestamptz label_ja: 作成日時 label_en: Created At notes: Record creation timestamp. – field_name: updated_at ttype: timestamptz label_ja: 更新日時 label_en: Updated At notes: Record update timestamp. 7. この標準版でコード側に期待すること この DomainGuide を読むコードは、最終的には最低限これを使えるようにするとよいです。 purpose.typical_questions_ja business_terms scope.base_table scope.allowed_tables scope.base_alias fields. join_hints query_patterns つまり、今までの tables.header tables.line 対象のaction_xmlidはこちらです。 “fact_opportunity_domain_guide” “fact_sales_rep_domain_guide” “fact_proposal_signal_domain_guide” “fact_email_event_domain_guide” “fact_email_phrase_stat_domain_guide” “fact_opportunity_outcome_domain_guide” “fact_res_users_domain_guide” “fact_res_partner_domain_guide” “fact_company_domain_guide” “fact_period_domain_guide” ai_purposeに入れなおすので、アウトプットはsqlでください。 案としては 1) まず固定する「Join Profile」案(SoR版) JP1: star_opp_sor(案件を中心にするスター) base: sor.fact_opportunity o(案件粒度) 必須JOIN sor.fact_period p(o.period_id = p.period_id) sor.fact_sales_rep r(o.rep_id = r.rep_id) sor.res_partner pa(o.partner_id = pa.id)※CSVが来たら確定 任意 sor.res_users u(r.user_id = u.id)※repに user_id がある前提 必須フィルタ o.company_id = :company_id(c001) 期間を切るなら o.period_id IN (…) or p.start_date など JP2: opp_signals_sor(案件×シグナル:増殖しにくい) base: sor.fact_opportunity o JOIN sor.fact_proposal_signal s(s.opp_id = o.opp_id) period/rep/partner は o から辿る(できるだけ s.* をJOINキーに使わない) ルール 1案件に複数signalがあり得るなら、rankはsで並べるが、集計は必ず DISTINCT opp_id 「最新1件」ルールがあるなら max(s.created_at) 等を決める(CSV見て決められる) JP3: opp_email_events_sor(案件×メール:増殖するので“必ず集約”) base: sor.fact_opportunity o JOIN(直接JOINは禁止にしてもいい) sor.fact_email_event e(e.opp_id = o.opp_id) 原則 e は 必ず subquery で opp_id 単位に集約してから o にJOIN 例:outbound_cnt, inbound_cnt, last_sent_at など JP4: opp_phrase_stats_sor(案件×フレーズ統計:基本は集計済なのでJOIN可) base: sor.fact_opportunity o JOIN sor.fact_email_phrase_stat ph(ph.opp_id = o.opp_id) ルール ph はすでに集計(phrase, cnt)なので、JOINしても増殖は制御しやすい ただし phrase 条件が広いと行が増えるので、トップNを切る JP5: opp_outcome_sor(案件×結果:1対1想定) base: sor.fact_opportunity o JOIN sor.fact_opportunity_outcome out(out.opp_id = o.opp_id) ルール out が複数行なら period_id=close_month として最新を取る等、ルール固定 2) “ありそうなView(action_xmlid)” を先に決める案(SoR版) あなたの代表クエリ10個を、Viewとして分割します(= ai_purposeが濃くなる)。 V1: opportunity_pipeline_rank join_profile: star_opp_sor 用途: 期待売上上位、案件一覧、期間フィルタ V2: opportunity_stage_summary join_profile: star_opp_sor 用途: stage別件数/期待売上合計(GROUP BY stage) V3: opportunity_trend_period join_profile: star_opp_sor 用途: period別の推移(count distinct opp_id / sum expected_revenue) V4: salesrep_rank_period join_profile: star_opp_sor 用途: rep別ランキング(count distinct opp_id / sum expected_revenue) V5: proposal_signal_rank join_profile: opp_signals_sor 用途: self_probability 高い順、pain/fit表示 V6: proposal_signal_risk join_profile: opp_signals_sor 用途: 高確度なのに未面談などの抽出 V7: email_activity_by_opp join_profile: opp_email_events_sor 用途: 案件ごとのoutbound/inbound数(集約JOIN必須) V8: email_activity_by_rep join_profile: opp_email_events_sor(rep単位に集約) 用途: rep別 inbound/outbound V9: phrase_keyword_rank join_profile: opp_phrase_stats_sor 用途: phrase ILIKE で topN V10: outcome_summary_period join_profile: opp_outcome_sor 用途: win/lost, won_amount, lost_reason(期間集計) action_mlidごとにSQL
コメントを残す