開発ステップ(確定案)
工程1:DomainGuide Pack(YAML)Import と反映(最優先)
目的
- **View単位(action_xmlid単位)**の “開発の入口” を DeciKG 側に取り込み、以後の開発は このPackを前提に進める。
- Dev-portal が更新したYAMLを 再importで安全に更新できるようにする(冪等)。
やること(DeciKG側)
- Pack保存先を決める(推奨:Postgresに原本、Neo4jに反映)
- Postgres:
decikg_view_pack(原文yaml_text / 正規化json_doc / source_hash / action_xmlid PK) - Neo4j:
(:ViewCommon {action_xmlid,...})-[:HAS_GUIDE]->(:DomainGuide {action_xmlid,...})
- Importer(バッチ)実装
- 入力:
packs/*.yaml(今回作ったファイル群) - 処理:
- YAML parse → 正規化(json_doc)
action_xmlidで UPSERTsync.source_hashが同じなら NOP、違えば更新- Neo4j へ反映(MERGE + SET)
- 更新のDoD(必須)
- 同じYAMLを2回 import → 2回目はNOP
- YAMLの一部を修正 → importで更新される(source_hash差分)
ここまでで「Dev-portalが吐いたPackをDeciKGに取り込んで、開発開始できる」状態が成立します。
工程2:観測データ(fact/odoo-like)Import(LLMなし)
目的
- 推論やランキングの根拠となる “観測” をグラフに載せる。
やること
- 入力:
import_dir/materials/*.csvまたは*.jsonl - 実装:
kind -> handlerのレジストリ方式(辞書) - まず最低限:
- Company / Period / SalesRep / Opportunity / ProposalSignal / Outcome / EmailEvent / PhraseStat
- (必要に応じて)CRM系(Lead/Message/Activity)・SAPB1(Order/Line)
DoD
- import後、Neo4jで基本リレーションを確認できる(例:Opportunity→Signal/Outcome、Opp→EmailEvent、Opp→PhraseStat)
工程3:固定Cypher(View単位)で /graph/query 相当の結果を返す(LLMなし)
※あなたの方針どおり「追加開発は基本ここで完結」できる骨格にします。
目的
- Pack(action_xmlid) を入口にして、固定Cypherで結果を返す。
- 外部VPC問題があるので API前提ではなくバッチで回る形を先に作る。
実装(確定)
- QueryEngine
run(action_xmlid, query_key, slots, options) -> GraphQueryResponse- query_key は最初は固定で良い(例:
rank,detail,summary,calibration)
- Registry(固定Cypher)
- action_xmlid ごとに
required_slotsshape_normalizedcypher_templatepostprocess(集計や整形)
を登録
- 実行形態(初期はバッチ)
- 入力:
requests.jsonl(GraphQueryRequestの配列) - 出力:
responses.jsonl
ここで LLMなしで Q1/Q2 相当を返せる状態が完成します。
DoD
- 例の4 pack について、各1本ずつ固定クエリが動く
- opportunity_pipeline(ランキング)
- opportunity_detail(1件詳細+根拠)
- customer_360(顧客サマリ)
- rep_calibration(較正レポート)
工程4:推論(受注確度)と根拠(explanation_json)を“ルール”で実装(LLMなし)
目的
- 「担当者の勘」を 再現可能なルールに落とし、結果と根拠を構造化して返す。
やること
win_prob.py(ルール)- 入力:latest_signal / comms集計
- 出力:
probabilityとfactors[](寄与要因の配列)
- QueryEngineはランキング時にこのルールを適用して
analysis_packに格納
DoD
- “理由付きランキング” が返る(上位ほど要因が明確)
- 同じデータなら結果が再現される(決定論)
工程5:graph/query 契約(追加のみ)を「ファイル入出力」として固定(最初から)
あなたの環境制約(DeciKGがVPC外、叩けない)に合わせて、APIではなく契約として固定します。
GraphQueryRequest(v0.1)
action_xmlid(必須)query_key(必須:rank/detail/summary/calibration など)slots(期間など)options(dry_run, limit など)
GraphQueryResponse(v0.1)
status / reason_codeshape_normalizeddata(columns/rows でも items でもOK、ただし固定)analysis_pack(後から拡張)confidence(後述。まずはルールで付与)
DoD
- requests.jsonl → responses.jsonl が1コマンドで生成できる
LLM推論拡張(後工程:ただし“器”だけ先に入れる)
あなたの提案(Flexibility / Grounding)を 後工程に回しますが、YAMLのschema上は最初から任意項目として受け取れるようにしておきます(追加のみのため)。
工程6(後):llm_reinforcement_contract をPackに追加(enabled=false)
- importer は 保存するだけ(解釈しない)
- DeciKGエンジンは 無視(enabled=false の間)
工程7(後):Semantic Search / Dynamic Cypher / Confidence(LLMあり)
- semantic_search_targets → ベクトル検索(Chroma等)
- dynamic_generation_rules → 制約付きText-to-Cypher(fallbackのみ)
- confidence_scoring → 100/60などのスコア+注釈
旧工程
工程0:契約固定(KPI追加の“入口”を固定する)
目的:追加開発を工程1+2に閉じるための“枠”を作る
やること
- domain_guideファイル仕様を固定(domain/module/locale + decikg.sql_contract など)
/graph/queryのリクエスト・レスポンス契約を固定(追加のみ)- pattern_key命名規約を固定(例:
kpi::opportunity_pipeline::win_rate)
実装
api/app/services/contracts/domain_guide_schema.py(軽いバリデーション)api/app/services/contracts/query_contract.py(shape_normalizedの型)pattern_keyの規約コメント(READMEでもOK)
DoD
- 新KPIを追加しても工程3以降に影響しない契約が固まっている
工程1A:YAML(domain_guide)をファイルで管理し、Neo4jへ取り込み
目的:企業差分の“意味”をdomain_guideに閉じ込める経路を確立(=KPI追加の第一手)
やること
domain_guides/*.yamlを読み込み → Neo4j(:DomainGuide)にMERGEcompany_idで差分を持てるようにする(ここが肝)- 例:DomainGuideに
tenant/company_idを持たせる、またはoverrides.company_idを持たせる
- 例:DomainGuideに
おすすめ設計(差分の閉じ込め先)
- DomainGuideノードに以下を持つ:
domain(例:opportunity_pipeline)company_id(例:demo_company_001)※複数企業対応の布石yaml_text(raw)json_doc(正規化したJSON)
実装
api/app/services/materials_loader.py(yamlロード)api/app/services/importer.pyにimport_domain_guides(import_dir)追加
DoD
- domain_guide YAML を増やすだけで Neo4j に意味が載る(idempotent)
工程1B:JSONL(観測データ)をNeo4jへ取り込み(必要ならkind追加)
目的:KPIの根拠となる“観測”を入れる(KPI追加の第二手)
やること
- kind最小セットで import(Company/Rep/Period/Opp/Signal/Outcome)
- KPI追加で必要なら kind を追加しても handler追加だけで済む構造にする
実装
api/app/services/importer.py- kind→handlerのレジストリ方式(switchではなく辞書)
api/app/routers/admin_import.pyPOST /admin/import(import_dir指定)
DoD
- import後に指定のリレーションが確認できる(あなたのDoDそのまま)
工程2:固定Cypher(pattern_keyごと)で結果を返す(KPI追加はここでCypher追加)
目的:追加KPI開発を工程2で完結できるようにする(Cypher追加OK)
工程2のキモ(追加開発を工程2に閉じる条件)
Cypherテンプレは 必ず domain_guide を参照します。
company_id + domainでDomainGuideを引くsql_contract(distinct_keyやforbid)やtables/join/metrics/dimensionsを参照して- クエリの粒度やDISTINCTを守る
- 期間・repなどのフィルタの列をブレさせない
※ここは「Cypher自体は追加していい」方針なので、
“domain_guideを読んで自動生成”までは不要です。
ただし **テンプレの中で domain_guide を読む(参照する)**のをルール化します。
これで「企業差分=domain_guide」に閉じ込められます。
実装
api/app/services/query_engine.pyrun_pattern(pattern_key, slots)->ShapeResult- patternごとに
cypher_template + required_slots + shapeを登録
api/app/services/domain_guide_repo.pyget(company_id, domain)->DomainGuideDoc
api/app/routers/graph_query.pyPOST /graph/query- 最初は
pattern_key必須(自然文分類は工程5以降)
DoD
- Q1/Q2が返る(現状のDoDを維持)
- さらに KPIパターンを1本追加すると工程1+2だけで動くことをデモできる
- 例:
kpi::customer_360::email_count_last_7dみたいな“追加KPI”を1本作って証明
- 例:
今回の工程における「KPI追加」の具体手順(追加開発時)
あなたの狙い通り、追加開発ではこれだけで済むようにします:
- 工程1A:
domain_guides/<company>/<domain>.yamlを追加 or 更新 - 工程1B:必要なら観測データkindを追加してimport(または既存データで足りるなら不要)
- 工程2:
pattern_registryに Cypherテンプレを1本追加(pattern_key追加)
👉 これで 工程3以降を触らずに新KPIが返せる。
工程3:暗黙知の核心(予測+理由=Explanationの最小実装)
目的:「理由付き」の最小実装を“ルールベースで再現可能”にする
やること
- proposal_signal特徴量から
predicted_probabilityを出す(ルール) - 寄与特徴を
explanation_jsonに格納(文章ではなく構造化でOK) - Q2結果に同梱
実装内容
api/app/services/win_prob.py(新規)predict(signal)->{prob, factors[]}
query_rank_oppsがlatest_signalを使って説明を生成(オンザフライでOK)
DoD
- “理由付きランキング” が返る(上位ほど理由が明確)
- 予測ロジックが固定で再現可能
工程4:較正(当たる/当たらないを“補正”として出す)
目的:人格評価ではなく「傾向/補正」として扱う
やること
- rep別に自己申告と実結果を集計
- over/under を数値で返す(サンプル少ない場合は抑制)
実装内容
query_engine.pyに追加pattern::calibration_reportpattern::rep_bias_rank
- 指標:brier / calibration_bias / hit_rate_at_0_7 / sample_size
DoD
- 「佐藤さんは高めに言う傾向(+0.08)」的な結果が返る
- 少サンプル時は「不確実」と明示
工程5:自然文→pattern選定(LLM無しで開始、LLMは後)
目的:UIから自然文で投げても“壊れない”
やること
- まずはルール(キーワード)で pattern を選ぶ
- slot抽出は最初は期間だけでもOK
実装内容
api/app/services/intent_router.pypick_pattern(question)->pattern_keyextract_slots(question)->slots
DoD
- pattern_key無しでもQ1/Q2/Q4系が動く
工程6:analysis_pack の確定出力(nlq-devが使える形に)
目的:nlq-devがコメント生成できる“材料”をDeciKGが保証する
やること
/graph/queryレスポンスにanalysis_packを追加(追加のみ)- evidence_trace(簡易:参照したsignal/outcome/featureのID)
実装内容
api/app/services/analysis_pack_builder.py- shape_normalized + findings + evidence_trace + timings 等
DoD
- nlq-devが analysis_pack だけでコメント生成できる
工程7:Dev-Portal “燃料”差し替え準備(今はダミー)
目的:後でdev-portal exportに置換できる状態にする(今回は連携しないが壊れない設計)
やること
materials.jsonl / domain_guides.yamlの契約を固定- importerを kind追加しやすい設計(handler登録方式)にする
実装内容
api/app/services/importer.pyをhandlers: dict[kind]->funcに寄せるDomainGuide取り込みは既に工程1Aで成立済みなので、後は差し替えだけで済む
DoD
- ダミーmaterialsでもimportが壊れない
- 後でdev-portalが吐くJSONL/YAMLに置換できる見通しが立つ
重要:Chromaの位置づけ(今回の工程では必須ではない)
- 工程1AのYAML取り込みで「後でChromaに詰める材料」は確保できます
- 工程2〜6は Chromaなしで成立(固定Cypher+構造化理由+analysis_pack)
- Chromaが必要になるのは「自然文分類をLLM/ベクトルで強化」「domain_guide引用」「説明の文章化」をやる段階
コメントを残す