【安心陪诊 Agent】Node.js API 设计:/api/plan 与 /api/chat 如何支撑 Agent
项目名称:安心陪诊 Agent。本文解决一个具体工程问题:陪诊类 Agent 不能只做聊天入口,它必须把用户输入拆成就医任务、材料清单、安全边界和家属同步结果,并且要能在前端页面和 Node.js 接口里复查。
一、实际问题:陪诊 Agent 为什么不能只接一个聊天框
真实就医场景里,用户通常不是问一个孤立问题,而是同时包含出发地、医院、症状描述、陪诊时间、材料准备和家属通知。若后端只返回一段自然语言,前端就无法稳定展示任务卡片,也无法判断哪些信息需要人工确认。
| 输入类型 | 前端表现 | 后端处理 |
|---|---|---|
| 出发地与医院 | 生成行程卡片 | 校验必填字段 |
| 症状描述 | 生成问诊问题 | 过滤诊断、剂量、处方类高风险词 |
| 家属联系方式 | 生成同步摘要 | 只做本地展示,不自动发送隐私信息 |
二、运行环境与版本
| 项目 | 版本 | 用途 |
|---|---|---|
| Node.js | 20.11.1 | 运行本地 API 服务 |
| Express | 4.18.3 | 提供 /api/plan 与 /api/chat |
| Chrome | 126+ | 验证 Web Demo、移动端响应式布局和接口调用 |
| HarmonyOS 迁移目标 | ArkTS / ArkUI | 后续把任务卡片迁移成原生页面 |
三、接口结构:/api/plan 负责稳定输出任务卡片
import express from "express"; const app = express(); app.use(express.json()); app.post("/api/plan", (req, res) => { const { start, hospital, visitTime, symptoms, familyPhone } = req.body; if (!start || !hospital) { return res.status(400).json({ code: "MISSING_ROUTE", message: "请补充出发地和医院名称", fields: ["start", "hospital"] }); } const riskWords = ["诊断", "处方", "剂量", "停药"]; const hitRisk = riskWords.some((word) => String(symptoms || "").includes(word)); if (hitRisk) { return res.json({ code: "SAFE_GUARD", message: "系统只整理就医准备信息,请以医生现场判断为准", tasks: ["携带病历", "记录既往用药", "向医生确认下一步检查"] }); } return res.json({ code: "OK", route: { start, hospital, visitTime }, tasks: ["预约提醒", "材料清单", "问诊问题", "家属同步摘要"], notifyFamily: Boolean(familyPhone) }); });这段代码的边界很明确:/api/plan 不做诊断,只把就医准备拆成稳定的结构化结果。前端拿到 tasks 后可以渲染为卡片,拿到 SAFE_GUARD 后可以展示医疗安全提示。
四、对话接口:/api/chat 只回答陪诊流程相关问题
app.post("/api/chat", (req, res) => { const text = String(req.body.text || "").trim(); if (!text) { return res.status(400).json({ code: "EMPTY_TEXT", message: "请输入就医需求" }); } const allowTopics = ["材料", "挂号", "复查", "检查", "家属", "路线"]; const matched = allowTopics.some((topic) => text.includes(topic)); if (!matched) { return res.json({ code: "OUT_OF_SCOPE", reply: "我只能协助整理就医流程、材料清单和家属同步内容。" }); } res.json({ code: "OK", reply: "建议先准备身份证、医保卡、既往病历,并把想问医生的问题列成清单。", nextActions: ["生成材料清单", "生成问诊问题", "同步给家属"] }); });五、前端如何消费接口结果
async function submitPlan(form) { const response = await fetch("/api/plan", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify(form) }); const data = await response.json(); if (data.code === "MISSING_ROUTE") return showFormError(data.message); if (data.code === "SAFE_GUARD") return showSafetyCard(data.message, data.tasks); return renderTaskCards(data.tasks, data.route); }前端不直接解析自然语言,而是根据 code 字段决定展示错误、提醒还是任务卡片。这样做的好处是:页面状态稳定、测试路径清楚、后续迁移 ArkUI 时也能保留同样的数据结构。
六、实操验证记录
curl -X POST http://localhost:5188/api/plan ^ -H "Content-Type: application/json" ^ -d "{"start":"杭州西湖文化广场","hospital":"浙江省人民医院","visitTime":"周三上午","symptoms":"复查材料准备"}" HTTP/1.1 200 OK { "code": "OK", "tasks": ["预约提醒", "材料清单", "问诊问题", "家属同步摘要"], "notifyFamily": false }| 验证项 | 输入 | 预期 | 结果 |
|---|---|---|---|
| 正常规划 | 出发地、医院、时间完整 | 返回任务卡片 | 通过 |
| 缺少医院 | hospital 为空 | 返回 MISSING_ROUTE | 通过 |
| 风险词 | 包含处方或剂量 | 返回 SAFE_GUARD | 通过 |
| 非陪诊问题 | 询问无关内容 | 返回 OUT_OF_SCOPE | 通过 |
七、排错记录
| 问题 | 原因 | 处理方式 |
|---|---|---|
| 页面只显示一段文本 | 接口没有结构化字段 | 统一返回 code、tasks、nextActions |
| 医疗风险过高 | 用户输入包含诊断、剂量、处方 | 进入 SAFE_GUARD 分支 |
| 移动端卡片拥挤 | 任务字段过长 | 卡片只展示标题,详情折叠 |
八、迁移到 ArkTS 页面时怎么保留边界
如果把这个 Web Demo 迁移到 HarmonyOS ArkTS,建议不要把接口返回结果直接拼到一个长文本里,而是保留 PlanResult、TaskItem、GuardMessage 三类模型。这样页面可以分别处理正常任务、缺字段提示和医疗安全边界。
interface TaskItem { title: string; detail: string; done: boolean; } interface PlanResult { code: 'OK' | 'MISSING_ROUTE' | 'SAFE_GUARD'; message?: string; tasks: TaskItem[]; } function toTaskCards(result: PlanResult): TaskItem[] { if (result.code !== 'OK') { return [{ title: '需要人工确认', detail: result.message || '请补充信息', done: false }]; } return result.tasks; }这个模型的价值在于:UI 层只负责渲染状态,不承担医疗判断;服务层只负责整理流程,不越界输出诊断。对于参赛 Demo 来说,这种分层能让评委更容易看懂工程边界。
九、发布前检查清单
| 检查点 | 通过标准 | 说明 |
|---|---|---|
| 接口输入 | 空输入、正常输入、风险输入都能返回明确 code | 避免前端只能靠文本猜状态 |
| 页面状态 | 任务卡片、错误提示、安全提醒三类状态可见 | 用户知道下一步该做什么 |
| 隐私边界 | 不自动上传家属电话和病情细节 | 医疗辅助类项目必须保守处理 |
| 演示材料 | 截图、接口样例、测试表和项目说明一致 | 避免文章、Demo 和 PPT 互相矛盾 |
十、结论
安心陪诊 Agent 的核心不是“能聊天”,而是把就医需求转成可展示、可验证、可迁移的任务链。接口需要明确输入、输出和安全边界;前端需要围绕 code 字段展示状态;文章复查时则重点看版本、代码、验证记录和异常路径是否完整。