/** * WPML compatibility functions * * @global array $duplicated_posts Array to store the posts being duplicated. * * @package Yoast\WP\Duplicate_Post * @since 3.2 */ add_action( 'admin_init', 'duplicate_post_wpml_init' ); /** * Add handlers for WPML compatibility. */ function duplicate_post_wpml_init() { if ( defined( 'ICL_SITEPRESS_VERSION' ) ) { add_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10, 3 ); add_action( 'shutdown', 'duplicate_wpml_string_packages', 11 ); } } global $duplicated_posts; // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: Renaming a global variable is a BC break. $duplicated_posts = []; /** * Copy post translations. * * @global SitePress $sitepress Instance of the Main WPML class. * @global array $duplicated_posts Array of duplicated posts. * * @param int $post_id ID of the copy. * @param WP_Post $post Original post object. * @param string $status Status of the new post. */ function duplicate_post_wpml_copy_translations( $post_id, $post, $status = '' ) { global $sitepress; global $duplicated_posts; remove_action( 'dp_duplicate_page', 'duplicate_post_wpml_copy_translations', 10 ); remove_action( 'dp_duplicate_post', 'duplicate_post_wpml_copy_translations', 10 ); $current_language = $sitepress->get_current_language(); $trid = $sitepress->get_element_trid( $post->ID ); if ( ! empty( $trid ) ) { $translations = $sitepress->get_element_translations( $trid ); $new_trid = $sitepress->get_element_trid( $post_id ); foreach ( $translations as $code => $details ) { if ( $code !== $current_language ) { if ( $details->element_id ) { $translation = get_post( $details->element_id ); if ( ! $translation ) { continue; } $new_post_id = duplicate_post_create_duplicate( $translation, $status ); if ( ! is_wp_error( $new_post_id ) ) { $sitepress->set_element_language_details( $new_post_id, 'post_' . $translation->post_type, $new_trid, $code, $current_language ); } } } } // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: see above. $duplicated_posts[ $post->ID ] = $post_id; } } /** * Duplicate string packages. * * @global array() $duplicated_posts Array of duplicated posts. */ function duplicate_wpml_string_packages() { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: renaming the function would be a BC-break. global $duplicated_posts; foreach ( $duplicated_posts as $original_post_id => $duplicate_post_id ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $original_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $original_post_id ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. $new_string_packages = apply_filters( 'wpml_st_get_post_string_packages', false, $duplicate_post_id ); if ( is_array( $original_string_packages ) ) { foreach ( $original_string_packages as $original_string_package ) { $translated_original_strings = $original_string_package->get_translated_strings( [] ); foreach ( $new_string_packages as $new_string_package ) { $cache = new WPML_WP_Cache( 'WPML_Package' ); $cache->flush_group_cache(); $new_strings = $new_string_package->get_package_strings(); foreach ( $new_strings as $new_string ) { if ( isset( $translated_original_strings[ $new_string->name ] ) ) { foreach ( $translated_original_strings[ $new_string->name ] as $language => $translated_string ) { do_action( // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals -- Reason: using WPML native filter. 'wpml_add_string_translation', $new_string->id, $language, $translated_string['value'], $translated_string['status'] ); } } } } } } } } nlq-dev/decikg役割分担 – Raqqa

nlq-dev/decikg役割分担

下のほうが具体性あり

1) 固有名詞(案件名など)を何とかする:DeciKG側で「Entity Resolver」を持つ

「自然文→パラメータ化」をDeciKGでやるなら、LLMに いきなりCypher全文を書かせる より、2段に分けるのが安定です。

1-A. まず “固有名詞候補” を抽出(LLM)

例:「PoCという名前が付く案件」「担当者が佐藤の案件」から

  • entity_type: opportunity / partner / rep
  • mention: “PoC” / “佐藤”
  • match: exact / contains / startswith
  • company_id(あれば)・期間(now/30日)・limit

1-B. 次に “候補解決”(非LLM)

LLMが出した mention をもとに、DeciKG内部で 候補検索してIDに落とします。

  • OpportunityResolver: Opportunity.name を contains で引いて opp_id 候補リスト
  • RepResolver: User/Rep.name を contains で引いて rep_id 候補
  • PartnerResolver: Partner.name を contains で引いて partner_id 候補

ここは ベクトル検索でも良いし、単純containsでもOK(まずは軽い実装で十分)。
**重要なのは「候補が複数なら、その事実を返す」**ことです(勝手に決めない)。

1-C. 最後に Cypher を組み立てる(テンプレ+最小LLM)

IDが決まれば、Cypherはテンプレで安定します。

  • 候補が1件に絞れた → WHERE o.opp_id=$opp_id のように確定
  • 候補が複数 → WHERE o.opp_id IN $opp_ids で実行し、結果と一緒に「曖昧だった」情報も返す

2) nlq-dev が分析できるように:DeciKGが「列定義メタ」を返す

おっしゃる通り、nlq-dev は 列の意味を知らないと分析が崩れます。
でも、nlq-dev のプロンプトに “全DB定義” を入れる必要はありません。

結論:DeciKGが返すレスポンスに「最小限のデータ定義」を同梱する

nlq-dev はそれをそのままプロンプトに入れて分析します。

おすすめはこういう形です(add-onlyで今の契約にも載せやすい):

  • diagnostics.cypher / diagnostics.params(これはもうOKになった)
  • diagnostics.schema_hint(追加)
    • primary_entity: “Opportunity”
    • columns: {name: "...", type: "...", meaning: "...", unit: "...", grain: "..."}
    • joins_used: もしJOINしたなら “何と何” だけ(on句は不要)
  • analysis_pack(各rowの explanation は既に入れてるので、ここに “集計の意味” も入れる)

例(イメージ):

  • email_event_count: 「直近30日(params.now基準)で関連EmailEventの件数」
  • score: 「signal3 + email2 + phrase1 + outcome1 の加重スコア(仕様v0.1)」

これだけで nlq-dev は

  • 「上位5件の理由」
  • 「スコアの内訳」
  • 「次に確認すべき案件」
    を自然に語れます。

専門用語が多い問題
→ 定義メタに 日本語の意味(meaning_ja) を入れて解決します。
nlq-dev の分析は“その meaning_ja を引用しながら”やればいい。


3) “DeciKGにLLMを入れる”ときの境界線(安全でブレない設計)

あなたの方針だと、LLMはDeciKGの中でこう使うのが一番安定します。

LLMがやること

  • 質問文からの 意図分類(rank/detail/search…)
  • 固有名詞の抽出(案件名・会社名・担当者名)
  • 期間・limit・フィルタの推定(なければデフォルト)
  • 「必要なresolver」を選ぶ(OpportunityResolver/RepResolver…)

LLMにやらせないこと(やらせると壊れやすい)

  • 生Cypherを自由作文させる(いまのdynamic fallbackは便利だが、まずは “最小範囲” に留める)
  • 勝手に定義を作る(列の意味は“仕様として固定”し、返却メタはテンプレから生成)

4) いまの実装(dynamic fallback)をどう位置づけるか

現状の dynamic fallback は「contains検索」みたいな便利レイヤとしては良いです。
ただ、nlq-dev分析に繋げるなら、次のどちらかに寄せるのが良いです:

  • A: dynamicは“検索系だけ”に限定(name contains、担当者 contains、など)
  • B: dynamicでも必ず schema_hint を返す(列の意味を付ける)

いま起きていた「cypher/paramsがassist側にだけある問題」は直ったので、次は schema_hintの整備がボトルネックになります。

具体的に「どんな定義データを返すべきか」最小セット

nlq-devが分析できる最低限はこれです:

  1. result_grain(粒度)
    • “1行=案件(Opportunity)” なのか
    • “1行=メール” なのか
    • “1行=担当者×期間” なのか
  2. columnsの意味(日本語)
    • meaning_ja(短文でOK)
    • type(int/string/date)
    • filters(この結果に適用済の制約:company_id / 直近30日 / limit)
  3. score/ランキングロジック(ある場合だけ)
    • スコア式、重み、並び順

これを diagnostics.schema_hintanalysis_pack.meta に入れて返すと、nlq-devの分析が一気に楽になります。

意味はありました。ただ、**「どこで何をやるか」**の切り方が今の方針と少しズレていただけです。

Cypher_then_sql が“効く”場面

Cypher_then_sql は本質的にこれです:

  • (1) Cypherで対象集合を確定する(IDリスト・サブグラフ・関係の抽出)
  • (2) その結果(IDやキー)を使ってSQLで集計/精算する(数値集計、期間集計、重いJOIN、整形)

つまり 「グラフで絞り込み」「RDBで集計」 の二段階が必要なときに強い。

例:

  • 「メール反応が多い案件」
    → Cypherで opp_id を“メールイベントとの関係”で拾う(ただの名前検索じゃない)
    → SQLで fact_email_event を期間条件で集計してランキング
  • 「担当者Aの案件で、直近30日の反応率が高い順」
    → Cypherで担当者→案件の関係から opp_id を確定
    → SQLでメール/アウトカム/売上などを集計

今回 “意味が薄く見えた” 理由

あなたが今やっている DeciKG の動的フォールバックは多くが

  • Opportunity.name contains $q みたいな 単体ノード検索

になっていて、ここだと SQLに渡すべき “グラフ由来の価値” がほぼ出ません。
(SQLだけでも同じ絞り込みができるから)

さらに、あなたの新方針は

  • DeciKGはCypherと結果だけ返す
  • 分析はnlq-dev

なので、Cypher_then_sql をやるなら DeciKG側がSQLまで叩く責務を持つ必要が出てきます。
(そこが方針と衝突して “意味がない” 体感になった)

結論:Cypher_then_sql は「捨て」ではなく「出番の再定義」

今の設計だと、Cypher_then_sql はこう整理すると生きます:

A) 現方針(DeciKGはCypher実行まで)を優先するなら

  • route: CYPHER_ONLY / CYPHER_THEN_CYPHER(=追加Cypher) に寄せる
  • SQL集計は nlq-dev(or Dev-Portal)でやる
  • その代わり DeciKGが返すものに
    • opp_ids(確定集合)
    • scope_hint(粒度/期間/意味)
      を入れて、nlq-devがSQLを作りやすくする

B) 「集計はSQLの方が正しい/速い」領域を残したいなら

  • Cypher_then_sql は “グラフで集合確定 → SQLで集計” の専用ルートとして残す
  • ただしその場合は SQL実行主体をどこに置くかを決める必要がある
    • DeciKGがSQLも叩く(責務が増える)
    • nlq-devがSQLを叩く(DeciKGは集合とヒントだけ返す)
    • Dev-PortalがSQLを叩く(nlq-devがオーケストレーション)

あなたの今の方針だと、自然なのは 「nlq-devがSQLを叩く」 です。

どういうときに“本当に必要”か(判断基準)

Cypher_then_sql を使う価値があるのは、Cypherが 単なるcontains検索を超えて 次をやるときです:

  • 関係を辿って集合を作る(担当者→案件→メール、顧客→案件→アウトカム等)
  • パス/近傍/グルーピングで集合を作る(イベント系列、類似案件の近傍)
  • “RDBにはない関係” を使って対象を絞る(ここが一番大きい)

逆に、Opportunity 単体の属性検索(name contains等)だけなら Cypher_then_sql は薄いです。


あなたの現状だと、

  • 固有名詞解決(案件名/担当者名)→ opp_id確定 は DeciKGが強い
  • 集計(直近30日で多い、率、ランキング) は SQLが強い

なので、Cypher_then_sql を「無意味」と結論づけるより、

Cypher_then_sql は “分析のための集合確定ルート” としては有用。
ただし SQL実行主体を DeciKGに置かないなら、実体は「CypherでIDs返してnlq-devがSQL」になる。

…という整理が一番しっくり来ます。

もし「Cypher_then_sql を残すならどんなI/Fにすべきか」を次に決めたいなら、
あなたの route enum(SQL_ONLY / CYPHER_ONLY / CYPHER_THEN_SQL / …)の現行定義を貼ってください。そこに合わせて、DeciKG→nlq-dev で返すべき ids + schema_hint + sql_seed の最小契約を提案します。

その流れでいけます。ポイントは「1回の質問→1回で終わらない」前提のパイプを、最初から“会話ではなくワークフロー”として固定することです。

以下の形にすると、いまの方針(DeciKGはCypher実行まで/分析はnlq-dev)と矛盾しません。


目標のパイプ(LLMが自分で次の質問を作って回す)

ステージ0: User Question(自然文)

  • 例「直近30日でメール反応が多い案件を上位5件。理由も」

ステージ1: DeciKG(NL→Cypher→実行→“材料”返却)

DeciKGの責務:

  • Cypherを作る(LLMでもルールでもOK)
  • Neo4jで実行する
  • 結果行 + “説明に必要な材料” を返す
  • 次のデータ要求(follow-ups) を提案する(ここが重要)

返すべきもの(追加のみでOK):

  • diagnostics.cypher / diagnostics.params(あなたが今直したやつ)
  • rows[]
  • analysis_pack(トップレベルでも各rowでも)
    • narrative_draft(まずは箇条書きでもいい)
    • followup_questions[](nlq-devに投げる次の質問の候補)
    • followup_requests[](構造化:目的・必要データ・想定SQL側など)

ここで「こんなデータもあったら良いな」を 文章ではなく“要求”として構造化して返す のが肝です。


ステージ2: nlq-dev(分析→追加質問生成→Dev-Portalへ)

nlq-devの責務:

  • DeciKGの結果を読んで「分析文」を仕上げる(LLM)
  • followup_questions を優先度付けし、必要なら整形して Dev-Portal に投げる
  • Dev-Portal のSQL結果を受けて、最終文章をアップデートする

nlq-devが持つべき“最低限のプロンプト材料”は2種類だけ:

  1. Dev-Portal側のデータ辞書(domain guide / view catalog / KPI定義)
  2. DeciKGが返した“今回の文脈”(cypher、rows、analysis_pack)

「専門用語ばかりになる」問題はここで潰せます。
nlq-devは “専門用語→一般語の言い換え辞書” を持つ(固定の辞書でOK、LLMに任せすぎない)。


ステージ3: Dev-Portal(SQL生成→実行→根拠データ返却)

Dev-Portalの責務:

  • 質問(nlq-devが作ったfollow-up)を受け、SQL生成・検証・実行
  • 結果(rows)+ diagnostics(sql、guards、citations)返却

ステージ4: nlq-dev(統合・最終出力)

nlq-devで最終的に返す:

  • final_narrative(文章)
  • evidence(DeciKG/Dev-Portalの根拠リンク・行数・クエリ)
  • next_questions(次のアクション)

これを成立させる “最小の契約” 追加(おすすめ)

今すぐ作るなら、DeciKGレスポンスにこれを追加するとパイプが回ります。

A) DeciKG → nlq-dev 用の follow-up 形式(超小)

analysis_pack.followups を追加:

{
  "analysis_pack": {
    "followups": [
      {
        "target": "dev_portal",
        "question": "上位5件の案件について、直近30日のメール返信率(返信/送信)を出して",
        "priority": 80,
        "why": "“反応が多い”が送信数の多さ由来か、返信率が高いのかを判別するため",
        "inputs": {
          "opp_ids": ["op0124", "op0173", "op0066", "op0095", "op0250"],
          "window_days": 30,
          "now": "2026-02-12"
        }
      }
    ]
  }
}

ここで questionnlq-devがそのままDev-Portalに投げられる文章にしておくのがコツです。
(nlq-dev側で頑張りすぎない)

B) “専門用語問題” の対策は nlq-dev の固定プロンプトで吸収

  • opp_id / signal_count / phrase_stat などを、人間向けの語にマップする辞書を固定化
  • 文章生成時は「表示名(やさしい語)」「内部名(括弧で)」の併記を基本にする

実装順(迷わない最短)

  1. DeciKG: まず analysis_pack.followups[] だけ追加(ルール生成でOK。LLM不要)
    • 例:rank系なら「返信率」「ステージ別」「担当者別」「顧客規模別」などテンプレ化
  2. nlq-dev: followups をそのまま Dev-Portal に投げる“ループ”を作る(LLM無しでOK)
  3. nlq-dev: 最後に文章生成(LLM)を入れる
    • 入力は「DeciKG結果+Dev-Portal結果+辞書」
  4. DeciKG: 余力が出たら、固有名詞解決やCypher生成にLLMを入れる

重要な割り切り(成功しやすい)

  • 「LLMでCypher作って分析して文章…」を 最初から全部LLMに任せない
  • まずは
    • DeciKG: 結果+followupテンプレ
    • nlq-dev: followup実行ループ
      だけで“パイプ”を完成させる
  • その後に「followupの自動生成の質」や「文章の質」を上げる

次、パイプ用に nlq-dev側の“followup実行ループ”のI/Fを固めたいです。

あなたの nlq-dev のコントラクト(/nlq/plan /nlq/execute /nlq/analysis)に合わせて、

  • AnalysisResponsefollowups[] をどう乗せるか
  • Dev-Portal呼び出し結果をどこに入れて最終文章に反映するか

を、追加のみで設計します。

今の nlq-dev の ExecuteResponse v0.2 のフィールド名(route/stub_used/warnings/errors/timings/providers/sql_result/…)に合わせたいので、そのレスポンスの雛形JSON(空でもOK)を1つ貼ってください。こちらで“追加だけ”で流れる形に落とします。

役割分担(あなたの定義のまま固定)

DeciKG(ここで止める)

  • 入力:question-only(自然文だけでも可)
  • 出力:
    1. cypher(実行したもの)
    2. params
    3. rows(結果データ)
    4. result_schema(データ定義) ←これが重要
    5. provenance(根拠):graphのどのノード/リレーション/期間で取ったか、など(機械向け)

DeciKGは文章を書かない。ランキング理由も書かない。「データとその意味(定義)」だけ返す。

nlq-dev(分析だけ)

  • DeciKGの rows + result_schema + provenance + cypher を入力に
  • 分析文・要約・示唆・注意点 を生成
  • 追加データが必要になったら、人が質問を作る(ここもあなたの定義)

Dev-Portal(追加データ取得だけ)

  • 人が作った質問を受けてSQL結果を返す
  • nlq-devがそれを再分析(必要なら)

「専門用語ばかりで解析できない」問題の解き方

nlq-devに“専門用語の意味”を全部プロンプトで覚えさせるのは重いので、DeciKGが返す result_schema をソース・オブ・トゥルースにします。

DeciKGが返すべき最小メタ(result_schema)

rowsの列について、nlq-devが文章化できる最低限:

  • field: 列名(opp_id, name, score…)
  • label_ja: 表示名(案件ID、案件名、スコア)
  • description_ja: 意味(何を表すか)
  • unit: 件/回/%/円…
  • calc: 算出定義(例:score=signal3+email2+phrase1+outcome1)
  • grain: 行の粒度(例:1行=1案件)
  • dimensions/measures: 次元/指標

これがあると nlq-dev は「内部名」を知らなくても分析できます。


具体例(DeciKGレスポンスに足すだけ:add-only)

今のレスポンスに、analysis_pack を“文章”ではなく schema_pack として使うのが一番自然です(既存互換も壊さない)。

例(イメージ):

{
  "status":"ok",
  "diagnostics": {
    "cypher":"MATCH ...",
    "params": {"company_id":"c001","limit":5}
  },
  "rows":[
    {"opp_id":"op0124","name":"...", "score": 12, "email_event_count": 5}
  ],
  "analysis_pack": {
    "schema_pack": {
      "entity": "Opportunity",
      "grain": "one_row_per_opportunity",
      "fields":[
        {"field":"opp_id","label_ja":"案件ID","description_ja":"案件の一意ID","type":"string","role":"dimension"},
        {"field":"score","label_ja":"反応スコア","description_ja":"反応の多さを示す合成スコア","type":"number","role":"measure",
         "calc":"signal_count*3 + email_event_count*2 + phrase_stat_count*1 + outcome_count*1"}
      ]
    }
  }
}

nlq-devはこれだけで「スコアとは何か」を説明できます。


いまの実装状況との整合

あなたが直した通り、dynamic fallback の場合でも

  • diagnostics.cypher
  • diagnostics.params
    が埋まるようになったので、nlq-dev側は “Cypherと結果” を確実に受け取れる状態になっています。

あとは result_schema を返すだけで、役割分担が完成します。


次にやるべき最短タスク

  1. DeciKG:analysis_pack.schema_pack を追加(固定テンプレでOK、LLM不要)
    • action_xmlidごとに schema_pack を用意(opportunity_pipeline rank/detail 等)
    • dynamic fallback(部分一致検索)時は、最低限 grainfields(opp_id/nameなど)だけでも返す
  2. nlq-dev:schema_pack をプロンプトに差し込む
    • 「このfields定義に基づいて、日本語で分析文を書け」
    • 専門用語はschema_packのlabel_ja/description_jaを優先して使う

必要なら、次の返信でこちらから DeciKG側の schema_pack テンプレ(opportunity_pipeline rank / dynamic search) を“追加のみ”で書ける形で提示します。今のDeciKGの action_xmlid(opportunity_pipeline / opportunity_detail など)だけ教えてくれれば、それに合わせて出します。

デバックしやすいようにDeciKGにLLM仕込んでパラメータ化してそこからCypher作りたいんですよね。

了解。**DeciKGの中で「自然文→パラメータ化→(テンプレ or 生成)Cypher」**に寄せるのは、デバッグ性かなり上がります。やるなら “LLMはCypherを直接書かない” にして、まず Params(構造化)だけを吐かせるのが一番安定します(ログも差分も取りやすい)。


目標の形(デバッグ最優先)

DeciKG内部でこう分けます:

  1. LLM: question → intent + params(JSON)
  2. deterministic: params → cypher(テンプレ組み立て)
  3. execute → rows
  4. 返す:cypher / params / rows / schema_pack

LLMが壊れても「paramsが壊れた」のか「テンプレが壊れた」のかが一発で分かります。


1) LLMが出す “paramsスキーマ” を固定する

まずは最小で十分(今のユースケースに直結):

共通(全クエリ)

  • spec_key: どのクエリ種類か(例:opportunity.search_by_name_contains / opportunity.rank_by_email_reaction_last30d
  • company_id(必須に寄せたいならここで)
  • limit(default 5)
  • now(YYYY-MM-DD。無ければ今日を埋める or require)
  • filters(配列)

filters(例)

  • { "field": "name", "op": "contains", "value": "PoC" }
  • { "field": "rep_name", "op": "contains", "value": "佐藤" }
  • { "field": "days", "op": "lte", "value": 30 }

ここまでを LLMが確実に JSON で返すようにする。


2) Cypherは “テンプレのみ” にする(LLMは書かない)

たとえば search_by_name_contains は固定:

MATCH (n:Opportunity {company_id: $company_id})
WHERE toLower(n.name) CONTAINS toLower($q)
RETURN n.opp_id AS opp_id, n.name AS name, n.partner_id AS partner_id, n.rep_id AS rep_id
LIMIT $limit

LLMが返した params から:

  • q = filters[name contains].value
  • limit = params.limit
  • company_id = slots.company_id or params.company_id

これでデバッグは “JSONだけ” 見ればOKになります。


3) デバッグ用の診断出力を固定(add-only)

あなたが今整備した diagnostics.cypher/params に加えて、LLMを入れるならここを追加するとめちゃ見やすいです:

diagnostics.assist.param_llm = { used, model, prompt_hash, parsed_json, errors[] }

そして 必ず

  • diagnostics.params ← “最終的にテンプレに渡したparams”
  • diagnostics.assist.param_llm.parsed_json ← “LLMの生出力(正規化前)”
    を両方残す。

「LLMが言ったこと」と「最終採用」を分離して保存、がデバッグの肝です。


4) “固有名詞が難しい” 問題の解き方(DeciKG内で完結)

固有名詞は LLMに当てさせず、手堅くやるのが良いです:

  • LLMは「検索したい対象は 案件名」「キーは PoC」みたいな 意図だけ出す
  • 候補の正規化は graph側でやる
    • toLower CONTAINS
    • 可能なら name_norm(ひらがな/カナ/英数正規化)を事前生成して一致率UP

「佐藤」みたいに人名が絡むなら、LLMは rep_name contains "佐藤" までで止める。
Cypher側で (:Opportunity)-[:OWNED_BY]->(:SalesRep) とか、あなたのデータモデルに合わせてテンプレ化。


5) nlq-dev連携は “Cypher + params + schema_pack” だけで足りる

nlq-devは分析担当なので、DeciKGが返すべきは:

  • diagnostics.cypher(必須)
  • diagnostics.params(必須)
  • rows
  • analysis_pack.schema_pack(rowsの意味定義)

これで nlq-dev は専門用語を知らなくても文章化できます。


実装順(最短で壊れにくい)

  1. DeciKGに param_llm を1本入れる(spec_key + q + limit だけ)
  2. Cypherは今の dynamic fallback テンプレをそのまま使う(LLMは書かない)
  3. diagnosticsに
    • assist.param_llm.parsed_json
    • params(最終採用)
      を出す
  4. その後、spec_keyを増やす(rank系/担当者系/期間系)

もし次に進めるなら、こちらから

  • param_llm固定JSONスキーマ
  • プロンプト(短く・失敗しにくい)
  • dynamic_cypher を “params駆動テンプレ” に置き換えるための関数の追加案(最小差分)
    を、修正部分だけで出します。
    いまDeciKGで「rank/detail/search」みたいに 最初に対応したいspec_key候補を3つだけ挙げてくれれば、それに合わせて作ります。

Comments

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です