PMFlow/docs/architecture/DATAFLOW.md

5.0 KiB
Raw Blame History

DATAFLOW

Signal Planner Flow (Post-Commit Async)

  1. AIPMOKernelService creates signal (signal.create) in transaction.
  2. Transaction commits.
  3. Background task triggers SignalPlannerService.analyze(signal_id, tenant_id, ...).
  4. Planner service opens isolated AsyncSessionLocal and loads context:
    • signal content/project context
    • project members (user_projects -> users -> user_workloads -> user_skill_bindings -> skill_tags)
  5. Planner calls llm_service.generate_structured_object(function_name="signal_planner_analyze") with hard wait timeout (25s).
  6. Structured success:
    • SignalStrategicAnalysisService.merge_and_save(...)
    • update signals.planner_status=completed
    • write planner payload into strategic_analysis.ai_planner
  7. Structured invalid / timeout fallback:
    • build degraded planner payload (fallback_mode=true)
    • still merge_and_save(...) and mark signals.planner_status=completed
  8. Hard failure (DB write / unexpected exception):
    • SignalStrategicAnalysisService.mark_failed(...)
    • update signals.planner_status=failed
    • try enqueue compensate reply via FeishuOutboxService.enqueue(...)

Model Routing Flow

  1. Frontend ModelRoutingConfigPage reads current mapping via /model-routing/functions/{function_name}.
  2. Manager updates mapping via PUT API.
  3. Backend persists override into integrations(type='model_routing').
  4. LLMService resolves function-level override at runtime before default control-plane rules.

Query Route Gateway Flow

  1. AIPMOKernelService.process_ingress() 先完成 plan_mode gate;命中 reply/thread、work_item_id、active requirement context、draft/workspace lock 时继续留在 requirement/draft 主链。
    • 若已绑定 active requirement context 且用户显式说 退出需求模式,必须先把当前带 active draft 的 live requirement topic 挂起,再回到普通 query.answer;同 scope 下后续 idle query topic 不得抢走这次绑定。
  2. 非 plan_mode 的 query.answer 进入 TypedExecutor._execute_query_intent(),在调用 AdaptiveRAG.answer_question() 前先执行 preview_query_route_decision(...)。
  3. AdaptiveRAGQueryRouteGatewayMixin 产出单次结构化 query_profile(needs_private_context / needs_freshness / referenced_objects),并分别运行:
    • InternalProbe:config_hit_count / private_object_hit_count / private_scope_hit / vector_top1_score / vector_topk_support / graph_fact_hit_count
    • ExternalProbe:freshness_required / trusted_domain_hit_count / answerable_page_hit_count / cross_source_agreement / external_entity_hit
  4. Gateway 结合 query_route_memories 的相似样本先验,输出 route_mode / effective_source_policy / decision_origin / reply_contract / probe_snapshot。
  5. 若 route_mode=internal,内部只读查询必须先生成 Query DSL Plan:统一收口 query_type=existence/count/list/status/explain/diagnose/compare/unknown、entity_type、answer_contract、filters、scope 与 retrieval_policy;协议短回复、模式控制、执行动作必须在此之前就被 gate 掉,不得混入 DSL 规划。
  6. Bounded Executor 只按白名单模板执行内部查询:
    • 优先查 semantic_facts
    • facts 不足时再做 db/graph/doc/config 的受控 fallback retrieval
    • 全程自动绑定 tenant_id
    • 不接收自由 SQL
  7. Answer Verifier 在出站前检查“问法合同、证据合同、来源合同”是否一致;若发现 existence/status/compare 被答成 total count、或证据与结果不符,必须重试或显式失败。
  8. AdaptiveRAG.answer_question() 只消费已经收口好的 route 决策和对应结果:internal 只走受控内部查询主链;external 统一走 External Query Planner -> External Query Gateway -> External Provider Registry -> MCP adapter 优先(当前已接通 Microsoft Learn backend-direct runtime)-> bounded fallback live search -> external answer verifier -> ExternalContextPacket -> ExternalAnswerPresenter,禁止再直接混入内部检索结果,也禁止回流旧的 industry_trend/external_trend scene prompt;uncertain 仅允许 external-first 或 clarification。
  9. external presenter 只读取 external-only 输入:
    • question
    • plan summary
    • verified external evidence
    • source summaries 若 verifier 未通过或 evidence 为空,则直接返回“证据不足/需澄清”,不得混入 system_snapshot / user_snapshot / project_context / internal retrieval 补答案。
  10. 回答完成后:
  • QARecord.routing_snapshot、citations、sources_used 继续落盘
  • query_route_memories 追加或更新该次样本
  • QAFeedback / FeedbackCenterRecord 后续会把 route feedback 回写到 query_route_memories.feedback_outcome

Task Brief Flow

  1. Frontend chooses template / trigger generate.
  2. Backend task_brief_service stores template and run records in integrations(type='task_briefs').
  3. Generation run writes summary + artifact path.
  4. /task-briefs/center aggregates latest generated cards for sidebar center.