项目实训(二)|中医智能诊疗系统数据库模块设计与开发落地
项目实训(二)|中医智能诊疗系统数据库模块设计与开发落地
前言
本阶段是中医智能诊疗系统的数据底座建设阶段,核心目标是搭建稳定、可扩展、可协作的数据库模块。本篇从需求理解、架构选择、设计思路、工程实践四个角度,记录我在本阶段的技术理解与真实开发进度。
后期根据项目整体业务定位,数据库结构已完成迭代升级,新增用户、患者档案、体质记录、养生食疗、药箱管理等表,完善了用户 - 会话 - 诊疗全流程关联,适配后续 RAG、舌诊、食疗安全检查等功能。
一、阶段目标与整体规划
在进入具体编码前,我先明确了本阶段必须完成的核心任务:
- 完成 PostgreSQL + pgvector 环境部署,为后续向量检索预留能力
- 围绕诊疗对话业务,设计会话、消息、症状记录相关表结构
- 基于 SQLAlchemy 完成 ORM 模型封装,实现面向对象的数据操作
- 封装标准化 CRUD,为上层接口提供稳定依赖
- 完成数据库连接管理、脚本规范化,并按团队 Git 规范提交
整个过程遵循先设计、再编码、后验证、再提交的工程化思路,确保每一步都可追溯、可复用、可协作。
二、数据库选型背后的业务思考
在选型时,我没有直接选用轻量级数据库,而是根据项目长期演进路线做出判断:
- 项目未来需要接入中医知识库,需要向量存储
- 团队多人协作,需要支持多用户、高并发
- 诊疗数据具有强业务关系,需要事务与外键约束
- 生产环境要求稳定、可备份、可扩展
PostgreSQL 配合 pgvector 扩展,恰好满足关系型数据与向量数据混合存储的需求。这一决策让项目从一开始就具备长期迭代能力,而不只是满足当前最小可用功能。
三、整体业务架构
整个数据库设计围绕 “用户 → 档案 → 会话 → 消息 → 智能体输出 → 体质记录” 这条业务主线展开。
users (用户)
│
├── user_profiles (用户档案) ← 一对多:一个用户可管理多个档案
│ │
│ ├── sessions (会话) ← 会话是对话的上下文载体
│ │ ├── messages (消息) ← 记录完整对话历史
│ │ └── agent_outputs (智能体输出) ← 记录诊断推理过程
│ │
│ └── constitution_records (体质记录) ← 为个性化推荐提供数据基础
│
└── knowledge_* (知识库表) ← 食材、穴位、方剂、体质、疾病、养生
设计核心思想:
- 用户与档案分离:一个用户可管理多个健康档案(自己、家人),支持多场景使用
- 会话与消息分离:会话管理对话状态,消息记录对话内容,职责清晰
- 智能体输出独立存储:记录七个智能体的推理过程,支撑可解释性
- 体质记录独立成表:支持体质变化趋势跟踪,与个性化推荐联动
四、表结构设计:从业务流程到数据模型
在设计表结构时,我先梳理了诊疗对话全流程:
用户注册 → 完善档案 → 体质识别 → 开启会话 → 多轮交互 → 症状提取 → 诊疗/养生方案 → 记录存档 → 历史对比。
基于项目最新业务定位,我设计了完整的结构化数据表体系,覆盖用户、诊疗、舌诊、养生、RAG知识库、食疗安全等全场景。
4.1 users 用户表
存储用户的基础信息,包括用户名、密码、姓名、角色等。
class User(Base):
__tablename__ = "users"
id = Column(String(36), primary_key=True)
username = Column(String(50), unique=True, nullable=False)
password = Column(String(100), nullable=False) # bcrypt加密
name = Column(String(50), nullable=False)
role = Column(String(20), default="user")
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
profiles = relationship("UserProfile", back_populates="user", cascade="all, delete-orphan")
业务驱动设计:
- 用户表是整个系统的入口,密码使用 bcrypt 加密存储(而非明文),保证安全性
- 用户名设置唯一约束,防止重复注册
- 用户与档案采用一对多关系,一个用户可以创建多个健康档案,支持管理家庭成员或不同时期的健康数据
4.2 user_profiles 用户档案表
记录用户详细信息:性别、年龄、身高、体重、过敏史、病史、电话等,为个性化诊疗提供依据。
class UserProfile(Base):
__tablename__ = "user_profiles"
id = Column(String(36), primary_key=True)
user_id = Column(String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
gender = Column(String(10))
age = Column(Integer)
height = Column(Integer)
weight = Column(Integer)
allergies = Column(Text)
medical_history = Column(Text)
phone = Column(String(20))
current_constitution = Column(String(20))
secondary_constitutions = Column(JSONB, server_default="'[]'")
current_constitution_updated_at = Column(DateTime(timezone=True))
current_tongue_analysis = Column(JSONB, nullable=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
user = relationship("User", back_populates="profiles")
constitution_records = relationship("ConstitutionRecord", back_populates="profile", cascade="all, delete-orphan")
sessions = relationship("Session", back_populates="profile", cascade="all, delete-orphan")
业务驱动设计:
current_constitution字段记录用户当前体质,直接对接知识库查询模块的个性化推荐功能secondary_constitutions用 JSONB 存储兼夹体质(如“气虚兼血瘀”),支持多种体质并存- 档案表还关联了体质记录、舌诊、会话、药箱等多张表,是整个诊疗系统的数据枢纽
- 与
constitution_records表形成一对多关系,支持体质变化的长期跟踪
4.3 constitution_records 体质记录表
存储用户体质问卷答案、体质得分、AI判定结果、解释与建议,支持中医体质辨识。
class ConstitutionRecord(Base):
__tablename__ = "constitution_records"
id = Column(String(36), primary_key=True)
profile_id = Column(String(36), ForeignKey("user_profiles.id", ondelete="CASCADE"), nullable=False)
answers = Column(JSONB, nullable=False) # 问卷答案
scores = Column(JSONB, nullable=False) # 各体质得分
constitution = Column(String(20), nullable=False) # 最终体质
secondary_constitutions = Column(JSONB, server_default="'[]'")
five_elements = Column(JSONB) # 五行分析
bagang = Column(JSONB) # 八纲分析
confidence = Column(Float)
ai_interpretation = Column(Text)
suggestions = Column(JSONB) # 调理建议
created_at = Column(DateTime(timezone=True), server_default=func.now())
profile = relationship("UserProfile", back_populates="constitution_records")
业务驱动设计:
- 每次体质评估产生一条新记录,支持体质变化的长期跟踪
answers和scores用 JSONB 存储,灵活适配不同版本的问卷,无需改表结构constitution字段与user_profiles.current_constitution联动,确保档案表始终同步最新体质suggestions存储调理建议,可直接对接个性化推荐功能five_elements和bagang支持五行八纲分析,扩展中医分析维度
与知识库模块的联动:
用户完成体质问卷 → ConstitutionRecord 记录评估结果
↓
user_profiles.current_constitution 同步更新
↓
个性化推荐功能读取 current_constitution
↓
从食材表/方剂表匹配对应的调理方案
4.4 sessions 会话表
作为诊疗/舌诊的上下文载体,关联用户与档案,支持两种会话类型,存储已提取症状。
class Session(Base):
__tablename__ = "sessions"
id = Column(String(36), primary_key=True)
user_id = Column(String(36), ForeignKey("users.id", ondelete="CASCADE"), nullable=False)
profile_id = Column(String(36), ForeignKey("user_profiles.id", ondelete="CASCADE"), nullable=False)
name = Column(String(100), nullable=False)
type = Column(String(20), nullable=False) # diagnosis / tongue
extracted_symptoms = Column(ARRAY(Text), default=[])
can_start_diagnosis = Column(Boolean, default=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
updated_at = Column(DateTime(timezone=True), server_default=func.now(), onupdate=func.now())
messages = relationship("Message", back_populates="session", cascade="all, delete-orphan")
wellness_records = relationship("WellnessRecord", back_populates="session", cascade="all, delete-orphan")
业务驱动设计:
type字段区分“诊室”和“舌诊”两种业务场景,支持不同类型会话的独立管理extracted_symptoms用 ARRAY 存储已提取的症状列表,支持症状的累积更新,无需额外建表can_start_diagnosis标志控制辨证流程的启动条件,保证业务流程的可控性- 删除会话时级联清理关联的消息和诊疗记录,保证数据完整性
4.5 messages 消息表
记录用户与AI助手的多轮对话内容,保证对话历史可追溯、可复现。
class Message(Base):
__tablename__ = "messages"
id = Column(String(36), primary_key=True)
session_id = Column(String(36), ForeignKey("sessions.id"), nullable=False)
role = Column(String(20), nullable=False) # user / assistant / system
content = Column(Text, nullable=False)
timestamp = Column(DateTime(timezone=True), server_default=func.now())
session = relationship("Session", back_populates="messages")
业务驱动设计:
role字段支持user/assistant/system三种角色,为系统提示词等场景预留扩展timestamp保证消息按时间顺序排列,还原真实对话流程- 消息独立成表,支持大模型多轮对话的上下文构建
- 与会话表形成一对多关系,一个会话可有多条消息
4.6 wellness_records 养生记录表
核心用于食疗养生,包含症状、状态分析、食疗方案、穴位推荐、生活建议、安全警告等。
class WellnessRecord(Base):
__tablename__ = "wellness_records"
id = Column(String(36), primary_key=True)
session_id = Column(String(36), ForeignKey("sessions.id"), nullable=False)
symptoms = Column(ARRAY(String), default=[])
state_analysis = Column(Text)
confidence = Column(Float)
food_therapy = Column(Text)
herbal_reference = Column(Text)
acupoints = Column(ARRAY(String))
lifestyle_advice = Column(Text)
safety_warnings = Column(ARRAY(String))
reasoning_path = Column(JSONB)
created_at = Column(DateTime(timezone=True), server_default=func.now())
业务驱动设计:
reasoning_path用 JSONB 存储推理过程,支撑诊断结果的可解释性safety_warnings存储安全警告,为食疗安全检查提供数据基础- 与
sessions表关联,一次会话对应一条诊疗记录
4.7 agent_outputs 智能体输出表
记录大模型与RAG检索的原始输出,用于幻觉控制、过程回溯与效果验证。
class AgentOutput(Base):
__tablename__ = "agent_outputs"
id = Column(String(36), primary_key=True)
wellness_record_id = Column(String(36), ForeignKey("wellness_records.id", ondelete="CASCADE"), nullable=False)
agent_name = Column(String(50), nullable=False)
output = Column(JSONB, nullable=False)
created_at = Column(DateTime(timezone=True), server_default=func.now())
wellness_record = relationship("WellnessRecord", back_populates="agent_outputs")
业务驱动设计:
- 系统每次诊疗触发七个智能体(辨证、古籍、文献、处方、审方、康复、报告)协同工作
- 每个智能体输出结构不同,
output用 JSONB 存储灵活适配 agent_name标识不同智能体,支撑按名称查询特定智能体的输出- 支撑系统的可解释性——用户可以回溯每个智能体的推理过程,验证诊断结果的合理性
- 为后续的幻觉检测和效果评估提供数据基础
五、设计原则总结
在设计细节上,我坚持几个原则:
| 原则 | 说明 |
|---|---|
| UUID 主键 | 所有表统一使用 UUID 主键,带时区时间戳,保证分布式环境下数据一致性 |
| 外键约束与级联删除 | 保证关联数据不冗余、不异常,删除会话时自动清理关联数据 |
| JSONB / ARRAY 高级类型 | 适配大模型输出与复杂结构存储,无需频繁改表结构 |
| SQL 脚本统一管理 | 支持团队快速初始化、重复执行,保证环境一致性 |
| 密码加密存储 | 使用 bcrypt 加密,限制密码长度为 72 字节,安全性高 |
这套设计不仅覆盖当前业务,更提前为 RAG检索、舌诊模块、食疗安全检查、大模型幻觉控制、历史对比 等功能预留了完整的数据结构支撑。
六、代码架构设计:三层分层与 CRUD 封装
在编码阶段,我采用清晰的三层数据架构:
- 连接层:负责数据库连接、会话管理、连接池配置
- 模型层:将表结构映射为 ORM 类,实现类型安全与对象化操作
- CRUD 层:封装通用数据操作,对外提供稳定接口,避免重复 SQL
6.1 CRUD 目录结构
backend/db/crud/
├── session_crud.py # 用户、档案、会话、诊疗记录、智能体输出的统一 CRUD
├── message_crud.py # 消息表的独立 CRUD
└── agent_output.py # 智能体输出的独立 CRUD
6.2 各模块职责
| 文件 | 包含的 CRUD 操作 | 说明 |
|---|---|---|
session_crud.py |
用户增删查、档案增删改查、会话增删改查、诊疗记录增删查、智能体输出增查 | 核心业务的统一管理类 AsyncDatabaseManager |
message_crud.py |
消息增、查(按会话) | 消息独立管理,支持会话级联删除 |
agent_output.py |
智能体输出增、查(按记录/按名称) | 智能体输出独立管理 |
6.3 统一管理类实现
class AsyncDatabaseManager:
"""封装所有核心表的 CRUD 操作"""
# 用户管理
async def create_user(...) -> User
async def get_user_by_id(...) -> Optional[User]
async def get_user_by_username(...) -> Optional[User]
async def delete_user(...) -> bool
# 档案管理
async def create_user_profile(...) -> UserProfile
async def get_user_profile(...) -> Optional[UserProfile]
async def update_user_profile(...) -> Optional[UserProfile]
# 会话管理
async def create_session(...) -> Session
async def get_session(...) -> Optional[Session]
async def get_sessions_by_user(...) -> List[Session]
async def delete_session(...) -> bool # 级联清理
async def update_session_symptoms(...) -> bool
async def update_can_start_diagnosis(...) -> bool
# 消息管理
async def add_message(...) -> Message
async def get_messages_by_session(...) -> List[Message]
# 诊疗记录
async def create_wellness_record(...) -> WellnessRecord
async def get_wellness_records_by_session(...) -> List[WellnessRecord]
# 智能体输出
async def add_agent_output(...) -> AgentOutput
async def get_agent_outputs_by_wellness_record(...) -> List[AgentOutput]
6.4 设计亮点
- 集中管理:所有数据库操作集中在一个类中,便于维护和查找
- 异步统一:所有方法都是异步的(
async/await),与 FastAPI 的异步特性保持一致 - 事务处理:每个方法内部独立处理
commit和rollback,保证数据一致性 - 级联删除:
delete_session中按依赖顺序清理数据(agent_outputs→wellness_records→messages→session),保证外键约束不被违反 - 动态更新:
update_user_profile使用**kwargs+ 字段白名单,防止意外更新敏感字段
这种架构的优势非常明显:
- 逻辑解耦,便于团队分工维护
- 业务变化时只需修改对应层,不影响整体
- 代码可读性高,符合现代后端工程规范
在实现过程中,我深刻体会到:好的架构不是写最复杂的代码,而是写最容易被别人读懂、维护、扩展的代码。
七、功能验证与进度成果
本阶段最终完成并验证通过的内容包括:
- 数据库环境正常,pgvector 扩展启用成功
- 全套业务表创建完成,关系正确,约束生效,支持用户、档案、会话、诊疗、养生、药箱全流程
- 所有 CRUD 方法均通过真实数据读写测试验证
- 数据库连接稳定,支持并发访问
- 会话创建、消息存储、症状记录等功能全部可用
- 初始化脚本可重复执行,适配团队开发流程
- 代码按规范提交至远程 dev 分支
所有功能模块可直接接入下一阶段的接口开发。
八、技术理解与收获
通过本阶段开发,我对数据库工程化实践有了更真实的理解:
- 数据库设计本质是业务逻辑的持久化映射,必须先懂业务再建表
- 好的数据结构能大幅降低上层代码复杂度
- 连接管理、权限控制、脚本规范是团队协作的基础
- 代码规范、结构清晰、注释合理比单纯实现功能更重要
本阶段完成的不仅是功能,更是整个项目的数据底座与开发规范。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)