问诊教学 demo 的第一天:先追问一句再写报告,拆成 A、B 两条线,服务先不拆。
最初的接口很短:收到一句话,检索资料,把资料和问题拼进 prompt,返回回答。这样接完,一个问诊教学 demo 就能演示了。可用户只说“最近胃不舒服”,页面就铺出一整页,可能原因和待检查事项一项不少。我想演示的对话还没开始,报告倒先写完了。
先问一句,再写报告
我希望它停下来问一句:持续多久,具体哪里不舒服,前面有没有说过相关情况。这些得从用户的回答里接着收集。资料库能提供一般信息,替不了这个人补上没说过的经历。
于是先把工作拆成两份,名字也简单,叫 A 线和 B 线:
- A 线接住上一句,问一个当前需要补充的问题。
- B 线根据已有信息与召回材料整理阶段性报告。报告里可以列待补内容,暂时不知道的地方明确空着。
拆开以后,教学时也方便分别检查:追问有没有重复,报告里的一句话又根据了什么。
文字版
用户继续回答 → A 线选择下一句追问已有会话与资料 → B 线整理阶段性报告为什么一次只问一个
“先问再答”有依据,问诊本来就靠问:一项 80 名门诊病人的前瞻研究里,76% 的人是靠问诊得出最终诊断,体格检查占 12%,化验占 11%,后两者更多是在帮医生排除其他可能、加强把握(Peterson 等,West J Med 1992)。教学 demo 一上来就跳过这一步,等于跳过了最重要的那部分。
一个问题的分量也比想象中大。信息检索那边有个老结果:Qulac 数据集(198 个 TREC 主题、1 万多组问答)上,只问一个好问题,P@1 就能提升 170% 以上,出发点是“用户往往一句话说不清自己要什么”(arXiv:1907.06554)。所以 A 线每轮只问一句,我觉得够了,问多了反而像在填表。
难的是问得对。MediQ 把单轮医学问答改成互动形式,发现直接让最强的模型去提问,表现反而会变差;让模型在没把握时先不下结论、再决定问什么,诊断准确率提高了 22.3%(MediQ,arXiv:2406.00922)。这正好对上 B 线的规矩:不知道的地方明确空着,不硬填。后来的 ALFA 又把“好问题”拆成清晰、相关这类属性逐项训练(arXiv:2502.14860),教学时检查追问,也可以照这个思路一项一项看,而不是凭感觉说“问得还行”。
先定职责,服务先不拆
两条线放在同一个 FastAPI 进程里,后来的同步接口还会等两边都完成才返回。追问已经准备好,只要报告没完成,这次请求就不能返回。这当然拖慢聊天,但先把信息怎么流动讲明白,报告调度留到之后再改。
“之后再改”有几条现成的路,代价各不相同:
| 做法 | 能解决什么 | 代价 |
|---|---|---|
asyncio.gather 在一个请求里并发跑两条线 |
总耗时接近较慢的那条 | 两条线都得是协程;默认一边出错不会取消另一边 |
FastAPI 的 BackgroundTasks |
先返回追问,报告在后面补 | 官方定位是复用应用内变量的小任务 |
| Celery 一类任务队列 | 报告搬到别的进程甚至别的机器 | 要配 RabbitMQ 或 Redis,进程和服务都变多(FastAPI 后台任务文档) |
另外,FastAPI 里用普通 def 写的接口会被扔进线程池再等待,免得阻塞整个服务器(FastAPI 并发说明)。同步写法本身不会卡死别人的请求,慢的只是当前这一个。第一天先接受这份慢,换来的是信息流好讲。
演示环境准备用四个容器:
| 容器 | 用途 |
|---|---|
| Postgres | 保存会话 |
| Qdrant | 向量检索 |
| Neo4j | 图数据 |
| API | 服务本身 |
文本检索与图检索通过模式切换,一次请求先跑一种。这样一轮里检索回来的资料来自哪条路是确定的;会话本身的信息另算,仍和这些资料一起用。两种结果一起用、或按问题自动挑一种,都不在这一天的范围里。
这两件事都有现成做法,只是当天没接线。Qdrant 的 Query API 用 prefetch 让多路各召回一批,再用 rrf 或 dbsf 融合(Qdrant 文档的混合查询一节);按问题挑路,LlamaIndex 叫 router,给它一个查询和几条带说明的候选,它返回选中的一条或几条(LlamaIndex Routers)。缺的是编排层,不是检索能力。
图检索不放进每次请求的默认路径,还有成本上的理由。微软做 LazyGraphRAG,出发点就是完整 GraphRAG 的前期建索引成本可能高到劝退;他们称 LazyGraphRAG 的建索引成本和向量 RAG 相同,只有完整 GraphRAG 的 0.1%(微软研究院博客)。图这条路贵在入库和多次模型调用,按模式单独跑更好控制。模型和 embedding 默认用云端接口,本地模型作备选。
入库、检索和双轨编排,后面的文章分别记,不在第一天算成完成。
第一天想看到的效果很小
这个 demo 用来讲问诊交互和 RAG 编排,不用于真实诊断。WHO 2024 年的大型多模态模型治理指南把“回应病人的书面提问”列为健康用途之一,同时点名这类模型会产生虚假、不准确或不完整的陈述,还可能让医生和病人过度依赖机器(WHO 新闻稿)。报告里宁可空着,也是这个原因。我最想先看见的是:面对那句“最近胃不舒服”,它能继续问清楚,而不是急着把一张报告填满。
留下几句话 读者来信
读到这里,有什么想法?欢迎留下你的看法。