全体目的(C0〜C6の一貫した狙い)
- nlq-dev が分岐ロジックを先に作れるように、Dev-Portal 側の
/analytics/queryを「壊れない入口」に固定した。 - そのために、retrieval/LLM/SQL/実行が未完成でも、必ず契約形(status/reason_code/diagnostics/errors/join_plan等)で返す、という方針を先に確定した。
- 検証ソースを ir_*_src に一本化し、OdooDB はあくまで 実行だけ(ズレで落ちるのは許容、ただし reason_code が運用の命綱)という設計を固めた。
Phase C0: 入口の安全装置(契約固定)
/analytics/queryが 常に HTTP 200 で返り、最低限の固定フィールドを必ず持つ:status,reason_code,diagnostics,errors[](+join_planを返せる形)
- 内部がスタブでも、例外でも、契約だけは崩さない。
- これにより nlq-dev 側は
reason_codeによる UI 分岐を先行実装でき、手戻りを減らす。
Phase C1: ir_*_src 取り込み(検証ソースの唯一性)
- devportal DB に ir_model_src / ir_field_src / ir_view_src を用意し、最低限必要なカラムを揃える前提を固定。
- many2one / one2many 等の存在確認ができる「検証SQL」が通る状態を目指す。
- 取り込み方式は一旦 CSV でもOK(事故はCSV由来であり、将来 Postgres→Postgres 同期に置き換える前提)。
- 重要なのはテーブル名・カラム名をここで確定し、後工程のブレを止めること。
Phase C2: Chroma 起動+collection 常在(top_k>0 の前提)
- Chroma が起動しており、少なくとも
portal_field_japortal_view_common_ja
が 常に存在することを前提化。
- 存在しない場合は起動時に get_or_create し、「collectionが無い」で落ちない。
- ここが固まるまで
top_k=0をデフォルトにして安全運用(ただしレスポンス契約は返す)。
Phase C3: retrieval → allowlist 抽出(材料の安定化)
- retrieval の hits から
allowed_fields(必要ならallowed_models)を 安定して生成できるようにする。 - hits=0 の場合に
RETRIEVAL_NO_HITSを返す設計を固定。 diagnosticsに retrieval 情報(top_k/collections/hits など)を入れられる。- allowlist 抽出の仕様(metadata に model/field を必ず含む等)をここで固定し、後の JOIN/SQL のブレを抑える。
Phase C4: join_planner(View優先+ir_src検証+採否ログ)
- view由来の edges を優先しつつ、LLM提案 edges は「提案」として扱い、最終採否は ir_src + allowlist で検証して決める。
decisions(採否ログ)→accepted_edges→final_joinsを作れる設計を固定。- 採用0件なら
VALIDATION_FAILEDを返せる(join_plan付き)。 - LLMやSQL生成が壊れてもJOIN確定の品質は維持できるように、この工程を分離しているのが要点。
Phase C5: SQL生成 → Odoo実行 → EXECUTION_ERROR_* の分類固定
- Odoo 実行で落ちても、例外を握りつぶさず、必ず
EXECUTION_ERROR_UNDEFINED_TABLEEXECUTION_ERROR_UNDEFINED_COLUMNEXECUTION_ERROR_PERMISSION_DENIEDEXECUTION_ERROR_TIMEOUTEXECUTION_ERROR_SYNTAXEXECUTION_ERROR_OTHER
のいずれかに分類し、reason_code + details(sqlstate等) を返す設計を固定。
- OdooDB 側とのズレで死ぬのは許容。ただし運用上は reason_code が生命線なので 必ず返す。
Phase C6: E2E スモーク(/query→/plan→/act が安定して通る)
top_k>0の代表クエリが通ること。- 失敗ケースでも契約どおりに返ること(
RETRIEVAL_NO_HITS / VALIDATION_FAILED / EXECUTION_ERROR_*)。 timings / sql_hash / guards_appliedなど診断情報が揃うこと。- この段階で「ローカルで成功 → オフショアでもローカル成功 → 本番反映」という運用計画に接続する。
Offshore向け(English summary)
What we implemented in this iteration (Phase C0–C6)
Overall goal
We stabilized Dev-Portal’s /analytics/query as a non-breaking entry point for nlq-dev.
Even if retrieval/LLM/SQL/execution is incomplete or fails, the API must always return a contract-safe response so nlq-dev can build UI branching logic early based on reason_code, minimizing rework.
Phase C0: Contract-first “safe entry”
/analytics/querymust always return HTTP 200 and include the required fields:status,reason_code,diagnostics,errors[](and optionallyjoin_plan)
- Internals can be stubbed initially, but the response contract is fixed and never breaks.
Phase C1: ir_*_src ingestion as the single validation source
- Ensure
ir_model_src,ir_field_src,ir_view_srcexist in the devportal DB with the minimum required columns. - Validation queries (e.g., many2one/one2many existence checks) must work.
- CSV import is acceptable temporarily (issues are CSV-related), with a future plan to replace it with Postgres→Postgres sync.
- Key point: freeze table/column names here to prevent downstream drift.
Phase C2: Chroma availability + collections always exist
- Chroma must be running, and the collections must always exist:
portal_field_japortal_view_common_ja
- If missing, the system must get_or_create them at startup so the API never crashes due to “collection not found”.
- Keep
top_k=0as a safe default until C2 is stable (contract still returned).
Phase C3: Retrieval → allowlist extraction (stabilize “materials”)
- From retrieval hits, build
allowed_fields(and optionallyallowed_models) deterministically. - If hits=0, return
RETRIEVAL_NO_HITS. - Include retrieval diagnostics (
top_k,collections,hits, etc.) indiagnostics. - Freeze metadata requirements (e.g., model/field in metadata) so join/SQL steps don’t drift later.
Phase C4: Join planner (view-first + ir_src validation + decision logs)
- Use view-derived edges as primary, LLM-derived edges only as suggestions.
- Decisions must be validated against ir_src + allowlist, producing:
decisions→accepted_edges→final_joins
- If nothing is accepted, return
VALIDATION_FAILED(withjoin_planattached). - This separation ensures join quality remains stable even if LLM/SQL parts fail.
Phase C5: SQL generation + Odoo execution with strict error classification
- Even when execution fails, return a clean
reason_codemapped by SQLSTATE:EXECUTION_ERROR_UNDEFINED_TABLEEXECUTION_ERROR_UNDEFINED_COLUMNEXECUTION_ERROR_PERMISSION_DENIEDEXECUTION_ERROR_TIMEOUTEXECUTION_ERROR_SYNTAXEXECUTION_ERROR_OTHER
- Odoo DB mismatch is acceptable; the key requirement is always returning reason_code + details (sqlstate, etc.).
Phase C6: End-to-end smoke (Query → Plan → Act)
- Representative queries must work with
top_k>0. - Failure paths must still return contract-safe responses:
RETRIEVAL_NO_HITS / VALIDATION_FAILED / EXECUTION_ERROR_*
- Ensure observability fields are present (e.g.,
timings,sql_hash,guards_applied). - The plan is: local success → offshore local success → production deployment.
コメントを残す