引言
        大家好,我是山东大学软件学院2023级本科生张钧虹,“字节摇篮队”负责人。

        在前几个阶段中,我主要围绕BabyMind项目的基础业务能力推进开发:先完成了用户注册登录与宝宝档案录入,再逐步实现提醒模块、成长时间轴、健康记录和疫苗计划等功能。到了这一阶段,我开始把关注点进一步转向项目中最核心的一部分能力:如何让系统真正具备“可对话、可检索、可联动”的智能问答能力。

        因为对于BabyMind来说,提醒、时间轴、健康记录、疫苗计划这些模块虽然已经可以独立运转,但如果它们始终只是静态页面和分散接口,那么整个系统仍然缺少一个真正贴近用户使用场景的交互入口。家长最自然的使用方式并不是逐个打开页面找信息,而是直接问一句:

        “宝宝发烧了今晚要不要去医院?”
        “这个月龄现在该打什么疫苗?”
        “宝宝开始加辅食了,哪些食物更合适?”

因此,这一阶段我重点推进了三项工作:

  1. 搭建统一问答入口,让健康、时间轴、营养相关问题能够从同一个接口进入系统;
  2. 接入RAG知识检索能力,让健康问答不再只依赖模型“直接生成”;
  3. 推动问答结果和已有业务模块联动,让AI回答能够进一步影响健康记录、疫苗计划等系统状态。

一、为什么这一阶段要先做统一问答入口

        在项目早期,我也曾想过是否应该为不同模块分别单独做AI入口,比如健康问答页、营养建议页、疫苗咨询页各自独立。但随着项目推进,我越来越意识到,这样做虽然在实现上看似直接,实际上却会让系统交互越来越割裂。

        对于用户来说,真实问题往往并不会天然按模块边界出现,比如:

  • “宝宝发烧了,这周原本安排的疫苗还能不能打?”
  • “宝宝最近腹泻,辅食要不要做调整?”
  • “现在这个月龄有哪些事情需要特别注意?”

        这些问题本身就同时涉及健康、时间轴、疫苗、营养等不同模块。如果仍然要求用户先判断“这个问题到底属于哪个页面”,其实反而增加了使用成本。

        因此,这一阶段我在后端实现了一个统一入口POST /api/v1/qa/ask,对应代码位于app/api/routers/qa.py,核心接口如下:

@router.post("/ask", response_model=QAAskResponse, status_code=status.HTTP_201_CREATED)
def ask_question(payload: QAAskRequest, db: Session = Depends(get_db), current_user: User = Depends(get_current_user)) -> QAAskResponse:
    baby = None
    if payload.baby_profile_id is not None:
        baby = get_baby_profile_for_user(db, current_user, payload.baby_profile_id)
        if baby is None:
            raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Baby profile not found.")
    routed_result = answer_question_with_router(
        db=db,
        user=current_user,
        baby=baby,
        question=payload.question,
        auto_create_health_record=payload.auto_create_health_record,
        preferred_agent=None if payload.preferred_agent == "general" else payload.preferred_agent,
        conversation_history=payload.conversation_history,
        session_id=payload.session_id,
        session_title=(payload.question.strip()[:40] or "新的对话") if not payload.session_id else None
    )
    hr = routed_result.health_record_result
    return QAAskResponse.from_history(
        routed_result.history,
        auto_created_health_record=hr is not None and hr.status == "created",
        health_record_id=hr.record.id if hr and hr.record else None,
        health_record_status=hr.status if hr else None,
        auto_create_reason=hr.reason if hr else None
    )

        这段逻辑的意义在于:前端不再需要决定“我现在应该调健康接口还是营养接口”,而是统一提交问题,再由后端完成路由和处理。

        这说明BabyMind的AI开始有了一个清晰的对外入口,也为后续多Agent协作逻辑预留了统一的承载点。


二、RAG知识库接入:让健康问答不再只靠模型“直觉”

        统一入口建立之后,下一个问题就是:AI到底应该依据什么来回答问题?

        如果完全依赖大模型直接生成,那么在育儿特别是健康建议场景下,最大的风险就是幻觉。模型可能会给出听起来流畅但并不可靠的结论,这在项目里是必须尽量避免的。

        所以这一阶段,我重点推进了RAG能力接入,把本地知识库和问答流程连接起来。RAG相关核心逻辑位于app/services/rag_service.py。

1、知识文件的组织与切分

        目前项目中的知识资料主要放在:

                data/knowledge_base/

        这一目录下又分为:

  • health
  • nutrition
  • development
  • vaccine

        也就是说,在知识文件层面,我已经开始把内容按育儿场景进行分类整理,而不是混成一个大文本集合。这样做的目的,是为了方便后续按模块检索,也方便继续补充权威资料。

        在向量化处理时,我又进一步把这些资料聚合为三类检索集合:

  • health
  • timeline
  • nutrition

        其中,疫苗和成长发育资料也会被映射到对应的检索集合中。核心映射关系如下:

MODULE_TO_COLLECTION = {
    "health": "health",
    "vaccine": "health",
    "timeline": "timeline",
    "development": "timeline",
    "nutrition": "nutrition",
}

        随后,我通过文本切分器将知识文件拆分为适合检索的小块,并写入Chroma向量库。对应逻辑如下:

def ingest_knowledge_base(self) -> None:
    if not self._vector_stores:
        self._vector_stores = self._create_vector_stores()
    from langchain_core.documents import Document
    from langchain_text_splitters import RecursiveCharacterTextSplitter

    base = Path(settings.knowledge_base_path)
    splitter = RecursiveCharacterTextSplitter(
        chunk_size=settings.knowledge_chunk_size,
        chunk_overlap=settings.knowledge_chunk_overlap
    )

    for file_path in self._iter_knowledge_files(base):
        text = file_path.read_text(encoding="utf-8").strip()
        if not text:
            continue
        module = self._extract_module_name(base, file_path)
        collection = MODULE_TO_COLLECTION.get(module)
        if collection is None:
            continue

2、从“找到资料”到“结构化生成答案”

        仅仅能检索还不够。如果只是把检索到的片段原样返回给前端,用户体验仍然很差。因此,我在这一阶段还重点处理了回答格式问题。

        BabyMind中的健康问答,最终不是简单返回一段自然语言,而是尽量约束模型输出结构化结果,包括:

  • 核心结论
  • 建议步骤
  • 注意事项
  • 风险等级
  • 是否建议就医

        对应提示结构位于 app/services/rag_service.py 中,核心要求如下:

Return a JSON object with this schema:
{
  "core_conclusion": "short answer in Chinese",
  "action_steps": ["specific action 1", "specific action 2"],
  "cautions": ["specific caution 1"],
  "risk_level": "medium",
  "should_seek_medical_help": false
}

        这样做的原因很明确:在健康和育儿场景中,我并不希望模型“自由发挥”,而更希望它在固定结构中回答问题。因为一旦输出结构被约束,前端展示、风险提示、后续自动建档等逻辑就都更容易实现。


三、多Agent路由:让不同类型的问题进入不同处理逻辑

        在有了统一问答入口和RAG能力之后,另一个关键问题就是:不同类型的问题,应该如何被送往不同的处理逻辑?

        我在这一阶段没有一开始就做过重的复杂规划,而是先实现了一个轻量但清晰的多Agent路由方案。核心逻辑位于app/services/agent_router_service.py

        我目前将问题主要路由到三类Agent处理逻辑中:

  • health
  • timeline
  • nutrition

        路由规则基于问题关键词、对话上下文和优先级进行判断,例如:

ROUTE_RULES = (
    RouteRule("nutrition", (...), 3),
    RouteRule("timeline", (...), 2),
    RouteRule("health", (...), 1),
)

        在此基础上,通过 preview_route() 对问题做初步分类:

ROUTE_RULES = (
    RouteRule("nutrition", (...), 3),
    RouteRule("timeline", (...), 2),
    RouteRule("health", (...), 1),
)

        这一阶段我是把“多Agent”从一个抽象概念,真正落到了工程实现里。也就是说,现在的BabyMind已经不是只有一个通用聊天模型,而是开始具备如下处理能力:

  • 健康问题走健康问答链路,结合RAG知识库生成结构化建议;
  • 时间轴类问题读取疫苗计划、提醒、时间轴数据做结构化总结;
  • 营养类问题读取喂养阶段、过敏原、饮食限制和食谱数据做个性化回答。

四、从“回答问题”到“影响系统”:问答结果自动联动健康记录和疫苗计划

        这一阶段我最在意的一点,并不是“AI能不能回答问题”,而是AI的结果能不能继续影响系统内部状态。

        如果AI回答完之后只是显示在屏幕上,那它仍然只是一个聊天功能。只有当问答结果可以继续进入健康记录、疫苗计划、时间轴这些模块时,BabyMind才真正具备“系统级联动”能力。

        因此,我在 app/services/health_record_service.py 中实现了从QA结果自动生成健康记录的逻辑。

        核心判断逻辑如下:

def should_auto_create_health_record_from_qa(history: QAHistory) -> tuple[bool, str]:
    if history.agent_type != "health":
        return False, f"agent_type={history.agent_type or 'unknown'} does not support auto health record generation"
    if history.baby_profile_id is None:
        return False, "baby_profile_id is required to create a health record from QA history"

    ...
    if risk_level in AUTO_HEALTH_RECORD_RISK_LEVELS:
        reasons.append(f"risk_level={risk_level}")
    if should_seek is True:
        reasons.append("should_seek_medical_help=true")
    if affects_vaccine_schedule is True:
        reasons.append("affects_vaccine_schedule=true")

        也就是说,如果一次健康问答中已经明确出现:

  • 风险等级较高;
  • 建议就医;
  • 影响疫苗安排;
  • 影响饮食安排;

        那么系统就会尝试进一步把这次问答结果转化为健康记录,而不是只停留在对话层面。

        更重要的是,健康记录一旦创建成功,后面还会继续触发原有的疫苗延期逻辑。这样就形成了这样一条链路:

        健康问答 → 自动生成健康记录 → 影响疫苗计划 → 进入成长时间轴

        这条链路说明项目中的不同模块终于不是并列摆放的功能点,而是开始出现真实的业务依赖关系。也就是说,BabyMind的“智能”不再只是会说,而是开始能把说出来的结果继续传递给系统的其他部分。


五、前端问答页与会话历史:让AI交互真正可持续

        后端统一入口搭建之后,前端如果仍然只是一个简单输入框,其实也很难发挥这套能力的价值。因此,这一阶段我也同步推进了Android端的问答交互逻辑。前端问答状态管理位于frontend/app/src/main/java/com/babymind/ui/viewmodel/QAViewModel.kt

        我在这里重点处理了几件事:

  1. 支持围绕宝宝上下文发起问题;
  2. 支持保留最近若干轮对话上下文,用于继续追问;
  3. 支持记录 session_id,把一次连续对话组织成会话;
  4. 支持自动/手动选择Agent模式。

        核心请求逻辑如下:

val response = RetrofitClient.instance.askQuestion(
    "Bearer $token",
    QAAskRequest(
        question = normalizedQuestion,
        babyProfileId = babyId,
        autoCreateHealthRecord = true,
        preferredAgent = _selectedAgent.value.apiValue,
        conversationHistory = buildConversationHistory(priorMessages),
        sessionId = currentSessionId
    )
)

        这一部分最关键的一点是:前端不只是把问题发给后端,而是在主动维护“对话上下文”这件事。

        也就是说,用户现在可以不是每次都重新完整描述背景,而是基于上一轮回复继续追问。这比一次性问答更贴近真实使用场景。

        除此之外,我还补充了问答历史页的逻辑。对应代码位于frontend/app/src/main/java/com/babymind/ui/viewmodel/QAHistoryViewModel.kt

        我将历史记录按 session_id 分组,形成会话历史,而不是简单堆叠成一长串单条消息。这样做的好处是,用户可以更自然地回看“某一次连续咨询”的完整过程。

        这意味着BabyMind中的AI交互已经开始具备以下特征:

  • 不是单轮请求;
  • 有上下文;
  • 有会话归档;
  • 可以和宝宝档案绑定;
  • 可以继续反向写入业务数据。

六、这一阶段的主要问题与后续计划

        虽然这一阶段统一问答、RAG和多Agent路由已经有了较清晰的原型,但我也很清楚,目前这部分距离稳定成熟还有不少需要继续打磨的地方。

1、知识库还需要继续扩充与清洗

        目前项目已经有了本地知识文件、切分和入库流程,但在真实育儿场景下,仅仅具备“能检索”还不够,更重要的是资料本身是否足够权威、覆盖是否足够全面。后续我会继续补充和清洗育儿领域资料,尤其是在健康建议边界、疫苗说明和营养推荐方面继续完善。

2、当前路由机制仍然偏轻量

        目前多Agent路由以关键词规则为主,这种方式在原型阶段实现快、可控性强,但面对更复杂、更模糊的问题时,仍然可能存在分类不够精准的问题。后续我会继续优化路由逻辑,让系统在多轮对话和复杂问题下的判断更加稳定。

3、结构化输出和风险边界仍需继续优化

        在健康场景中,最重要的问题始终不是“回答得像不像”,而是“边界是否安全、提示是否稳妥”。后续我还会继续调整Prompt和结构化输出规则,进一步压缩幻觉空间,尽量让系统在高风险场景下更明确地给出谨慎提示,而不是生成模糊建议。


七、结语

        这一阶段,我主要围绕统一问答入口、RAG知识检索和多Agent路由推进了BabyMind的AI核心能力开发。相比前几个阶段主要在搭建业务数据结构,这一阶段的重点已经转向:如何让系统真正理解问题、调用知识、输出结构化结果,并继续把回答传递给其他业务模块。

        对我来说,这一步非常关键。因为它意味着BabyMind开始从“一个有多个页面和接口的育儿系统”,逐步转向“一个能够基于上下文进行理解、回答和联动的智能育儿辅助平台”。

        后续,我会继续在这一基础上完善知识库内容、优化路由策略,并推进语音交互和更多模块联动能力,让BabyMind离“真正可用”的目标再近一步。

        欢迎各位老师、同学批评指正!

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐