BodySense Treatment Vertical Slice
L2 的差分学习总览:跳过 Diagnosis 已掌握的 Agent 基础,只学习 Treatment 从可审核 proposal 走向 acceptance、executable Intervention、Outcome、BodyState feedback 与持续 review 时新增的领域和权限问题。
[!info] related notes
- 所属 MOC: bodysense-moc、agent-moc
- 相关概念:
- 易混淆概念:
- 相关资源:
BodySense Treatment Vertical Slice
范围:L2 不重新学习 Diagnosis
L2 的学习方法是 Knowledge Delta,不是把 Diagnosis 的生产 Agent 架构复制一遍。
Diagnosis 已经学会并可直接迁移的内容包括:
- PydanticAI typed
Agent[Deps, Output]; - immutable Agent Configuration;
- LiteLLM logical model / provider boundary;
- EvidenceGap / EvidenceBudget / EvidenceAttempt;
user_fact ≠ external knowledge;- Evidence Admissibility;
- deterministic DecisionAuthority、deny-overrides、fail closed;
- DecisionTrace / Configuration Provenance / Execution Provenance;
- Historical / Counterfactual Replay;
- Behavioral Contract;
- Eval / qualification / Shadow / Canary / Promotion。
这些概念在 Treatment 中再次出现时,只做映射,不重新作为新课学习。
[!abstract] L2 真正的问题 Diagnosis 主要回答“当前可能是什么?”;Treatment 开始回答“接下来准备做什么?这个动作现在是否仍被允许?执行以后发生了什么?”。
从 epistemic artifact 进入 action artifact 后,权限、时间和反馈闭环都更复杂了。
当前真实实现已经具备什么
BodySense 当前 Treatment 并不是一个待从零搭建的 Demo。代码已经存在:
Python Treatment Agent
├─ TreatmentAgentOutput(status = proposed)
├─ immutable Treatment Agent configurations
├─ EvidenceGap / bounded acquisition
├─ qualification / evidence / promotion evals
└─ execution provenance
Go Treatment Domain
├─ Treatment aggregate
├─ immutable TreatmentRevision
├─ Intervention
├─ Outcome
├─ Generation Decision
├─ Acceptance Decision
├─ Replay / Rollout
└─ BodyState feedback projection
Python 的 output contract 甚至直接写明:
AI proposal. It is not current until Go records explicit acceptance.
因此 L2 最有价值的是理解为什么要这样分层。
L2 的五个知识增量
1. Proposal → Acceptance → Execution 是三种不同权限状态
Treatment 不是:
LLM output
→ 直接成为当前方案
而是:
LLM Treatment Proposal
↓
Generation Authority
↓
TreatmentRevision(proposed)
↓
Explicit Acceptance
↓
Acceptance Authority
↓
Accepted TreatmentRevision
↓
Durable Intervention
↓
实际执行
所以要区分:
- proposal authority:允许 AI 提出什么;
- acceptance authority:这个提案现在是否仍允许成为当前 Treatment;
- execution semantics:接受后的 Intervention 才是可以进入实际执行/记录的业务对象。
详见 treatment-proposal-acceptance-execution-authority。
2. 合法生成 ≠ 稍后仍合法接受
Treatment Proposal 会跨越时间。
10:00 R50 + D20
↓
Proposal P3 generated
15:00 BodyState → R51
↓
用户才点击 Accept
P3 当时生成合法,不代表 15:00 仍合法接受。
Acceptance 前需要重新验证:
- source Diagnosis 是否仍 ready;
- Diagnosis freshness;
- Candidate Assessment 是否仍完整;
- 当前 SafetyState;
- BodyState revision 是否向前变化;
- 新 revision 是否构成 material change。
这就是 Temporal Validity / Reauthorization。
3. Treatment 不是一堆 immutable Analysis,而是“长期 Aggregate + immutable revisions”
Diagnosis 常见模型:
D100 immutable
D101 immutable
D102 immutable
Treatment 则是:
Treatment T1
├─ current_revision = 3
├─ status = active / review_recommended / paused / ...
│
├─ Revision 1 immutable
├─ Revision 2 immutable
└─ Revision 3 immutable
原因是产品既要:
- 保留每个历史方案的不可变事实;
- 又要有一个“用户当前正在执行哪个方案”的可变业务身份。
详见 bodysense-treatment-aggregate-and-immutable-revisions。
4. Treatment 第一次真正形成 Action → Observation → State Update
Diagnosis 的主环是:
BodyState
→ Analysis
Treatment 则形成:
BodyState
→ Diagnosis
→ Treatment
→ Intervention
→ Outcome
→ new BodyState Revision
→ Review current Treatment
当前代码中 RecordOutcome() 的顺序非常有意义:
persist Outcome
↓
project accepted semantic effect into BodyState
↓
create/link new BodyState revision
↓
EvaluateCurrentReview
这不是普通 CRUD,而是纵向健康系统真正的反馈闭环。详见 intervention-outcome-body-state-feedback-loop。
5. “做了以后变好”不能自动升级为“因为它所以变好”
当前 Outcome 默认:
causality_level = association_only
例如:
用户开始 Intervention A
↓
两天后疼痛下降
系统可以记录:
疼痛下降发生在 Intervention A 之后。
但不能自动声称:
Intervention A 导致疼痛下降。
这是 association-vs-causation-in-intervention-outcomes 的核心。
Diagnosis 与 Treatment 的最重要差异表
| 维度 | Diagnosis | Treatment |
|---|---|---|
| 核心产物 | Analysis / Candidate | Proposal / Revision / Intervention |
| 主要语义 | 对当前世界的解释 | 对未来行动的建议与执行 |
| 历史模型 | Analysis 基本全量 immutable | Aggregate 可变 + Revisions immutable |
| Authority | 是否允许交付分析 | 是否允许生成 + 是否允许接受 |
| 时间问题 | 新事实 → 新 Analysis | 提案等待期间可能过期,需要 reauthorize |
| 执行后反馈 | 间接 | Intervention → Outcome → BodyState |
| 因果风险 | 主要是推理正确性 | 还要防止把时间关联误写成干预因果 |
| 长期状态 | Analysis 作为历史 | active / review_recommended / paused / superseded / completed |
一次完整 Treatment Case
假设当前:
BodyState R70
Diagnosis D30 completed
Candidate Assessments ready
Safety clear
A. Generate Proposal
Go 先形成 generation facts:
diagnosis ready = true
freshness = fresh
candidate assessment ready = true
safety blocker = false
DecisionPolicy:
→ allow-proposal
Python 才生成:
TreatmentAgentOutput
status = proposed
interventions = [...]
warning_signs = [...]
review_triggers = [...]
Go 校验 config identity / plan contract,并持久化:
TreatmentRevision R1
acceptance_state = proposed
source_body_state_revision = 70
source_diagnosis_analysis_id = D30
此时 R1 不是当前 Treatment。
B. User Accepts Later
用户过了一段时间点击 Accept。
Go 不直接改成 accepted,而是重新读取:
current BodyState
source Diagnosis
Diagnosis freshness
candidate assessments
material revisions since R70
如果一切仍满足:
→ allow-acceptance
→ R1 accepted
→ Intervention rows become durable executable units
如果出现 material change:
→ block
→ proposal outdated / review required
C. Execute and Record Outcome
用户执行 Intervention I7,之后记录 Outcome O9。
O9 persisted
↓
BodyState.RecordOutcome(O9)
↓
BodyState R71
↓
EvaluateCurrentReview
如果 R71 对当前 Treatment 构成重要变化:
Treatment.status
active
→ review_recommended
然后可能产生新的 TreatmentRevision R2,而不是修改 R1 的历史内容。
L2 快速学习顺序
[!tip] 建议不要从 Python Agent 源码开始 先从业务状态机理解“为什么需要这些对象”,再看代码会快很多。
推荐顺序:
- treatment-proposal-acceptance-execution-authority
- treatment-temporal-validity-and-reauthorization
- bodysense-treatment-aggregate-and-immutable-revisions
- intervention-outcome-body-state-feedback-loop
- association-vs-causation-in-intervention-outcomes
然后回到当前源码对照:
apps/ai-service/src/models/treatment.py
apps/ai-service/src/prompts/treatment.py
apps/api/internal/model/treatment.go
apps/api/internal/model/intervention_outcome.go
apps/api/internal/service/treatment_decision_policy.go
apps/api/internal/service/treatment_service.go
哪些内容看到时直接跳过
如果源码再次出现这些词,不需要重新学原理:
AgentConfiguration
EvidenceGap
EvidenceBudget
EvidenceAttempt
Configuration Provenance
Execution Provenance
Replay
Qualification
Shadow / Canary
只问一句:
Treatment 对这个已经掌握的机制,有没有新增 domain-specific invariant?
有,就记录 Delta;没有,就继续。
L2 完成标准
不要求背 Treatment 所有类,而要能回答:
- 为什么
TreatmentAgentOutput只能是proposed? - 为什么 proposal generation 和 acceptance 要有两次不同的 deterministic authority check?
- 为什么 BodyState 变化后,旧 proposal 可能不能再接受?
- 为什么 Treatment 需要 mutable Aggregate + immutable Revision?
- 什么东西只有 acceptance 后才能成为 durable Intervention?
- Outcome 为什么先持久化,再投影进 BodyState?
- 为什么
association_only是一个重要安全语义? - 一个 active Treatment 为什么需要持续 review,而不是“批准一次永久有效”?
如果这八个问题能解释清楚,L2 的新知识就已经基本掌握。