【安心陪诊 Agent】Node.js 20 + Express 4 实战:Web Demo 与规则 Agent 架构

发布时间:2026/11/3 14:34:00

【安心陪诊 Agent】Node.js 20 + Express 4 实战:Web Demo 与规则 Agent 架构 【安心陪诊 Agent】Node.js 20 Express 4 实战Web Demo 与规则 Agent 架构在陪诊产品中最容易被误解的需求是“做一个能聊天的 Agent”。真正落地时用户需要的是一条可执行的任务链确认出发地和医院、整理材料、生成问诊清单、处理家属同步并在涉及诊断和处方时明确交给人工。本文用一个 Web Demo 说明 Page、Node.js API 和规则 Agent 如何协作。​编辑​编辑​编辑​编辑​编辑​编辑​编辑​​编辑编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​编辑​编辑​编辑​编辑​编辑​编辑​编辑​编辑​​编辑编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​编辑​编辑​编辑​编辑​编辑​编辑​编辑​编辑​​编辑编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​编辑一、本文解决什么问题本文聚焦“自然语言输入如何变成稳定任务卡片”。示例环境为 Node.js 20.11.1、Express 4.18.3、Chrome 126前端通过结构化 code 判断页面状态后端不输出诊断结论。层级职责不负责什么Page输入、加载、卡片展示不判断医疗结论API Service校验参数、返回协议不保存无关隐私Rule Agent拆解任务、拦截越界问题不替代医生二、目录和启动方式src/ server.js routes/plan.js services/plan-service.js rules/safety-rule.js public/index.html node --version npm list express npm run dev​编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑先固定 Node.js 和 Express 版本再启动本地服务。这样读者遇到请求体解析或路由行为差异时可以先排除运行时版本问题。三、接口协议先定义状态再写页面import express from express; const app express(); app.use(express.json()); app.post(/api/plan, (req, res) { const { start, hospital, visitTime } req.body || {}; if (!start || !hospital) { return res.status(400).json({ code: MISSING_ROUTE, fields: [start, hospital], message: 请补充出发地和医院 }); } return res.json({ code: OK, route: { start, hospital, visitTime: visitTime || 待确认 }, tasks: [材料清单, 问诊问题, 家属同步] }); });​编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑返回值使用 code、route 和 tasks 三个稳定字段。前端不需要猜测自然语言也能对正常、缺字段和安全拦截分别渲染。四、规则 Agent 的安全边界const blocked [诊断, 处方, 剂量, 停药]; function guard(text) { const hit blocked.find((word) String(text || ).includes(word)); return hit ? { code: SAFE_GUARD, hit, next: 人工确认 } : { code: OK }; }​编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑规则只负责发现风险并给出下一步不输出病情判断。这个边界既能减少误导也让测试用例有明确的预期。五、前端如何消费返回值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.next); return renderTaskCards(data.tasks); }​编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑页面只根据协议渲染状态错误提示可修复安全提示需要人工确认成功状态展示任务卡片。网络失败时还要保留重试按钮和当前输入。六、可复现请求和返回curl -X POST http://localhost:5188/api/plan ^ -H Content-Type: application/json ^ -d {start:杭州西湖文化广场,hospital:浙江省人民医院,visitTime:周三上午} { code: OK, tasks: [材料清单, 问诊问题, 家属同步] }​编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑七、验收清单场景输入预期结果正常规划出发地、医院、时间200、OK、任务非空通过缺少医院hospital 为空400、MISSING_ROUTE通过风险问题包含诊断或剂量SAFE_GUARD、人工确认通过网络失败服务停止显示重试不丢输入通过移动窗口手机宽度打开页面卡片不遮挡按钮通过八、常见问题问题原因处理页面只显示一段文本前端没有按 code 分支统一消费结构化返回接口返回 400缺少必填字段检查 start 和 hospital安全提示不出现规则没有在入口执行在 /api/chat 和 /api/plan 前置 guard九、总结安心陪诊 Agent 的工程价值不在于“什么都能聊”而在于把就医准备拆成可验证任务并对医疗风险保持克制。固定版本、明确协议、保留异常路径和真实验收记录才能让 Web Demo 具备迁移到 HarmonyOS ArkTS 的基础。扩展验证从 Web Demo 迁移到 HarmonyOSWeb Demo 的协议不应该和页面组件绑死。迁移到 HarmonyOS ArkTS 时可以把 PlanResult、TaskItem 和 SafetyNotice 作为公共模型页面只负责状态渲染网络访问放在 ServicePreferences 只保存用户主动勾选的轻量设置。interface TaskItem { title: string; detail: string; done: boolean; } interface PlanResult { code: OK | MISSING_ROUTE | SAFE_GUARD; message?: string; tasks: TaskItem[]; } function canRender(result: PlanResult): boolean { return result.code OK result.tasks.length 0; }​编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑这样迁移时Web 的返回值仍然可以驱动原生任务卡片网络失败、空数据和安全拦截也能保持一致不需要在每个页面重复判断字符串。异常路径和重试策略异常用户看到的状态下一步网络超时服务暂时不可用保留输入并重试接口 400指出缺少的字段回到表单定位修复返回数据为空暂无可生成任务允许重新描述需求命中医疗风险需要人工确认不输出诊断和剂量重试不能无限循环。前端最多自动重试一次之后显示明确按钮服务端记录请求耗时和错误码但不记录不必要的病情细节和家属联系方式。测试矩阵const cases [ { name: normal, body: { start: 杭州, hospital: 省人民医院 }, expect: OK }, { name: missing-hospital, body: { start: 杭州 }, expect: MISSING_ROUTE }, { name: medical-risk, body: { start: 杭州, hospital: 省人民医院, text: 如何调整剂量 }, expect: SAFE_GUARD } ];​编辑​编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑​​编辑编辑​编辑测试名称直接对应接口返回码验收人员可以先跑接口再打开页面核对状态。这样问题能定位到协议、规则还是 UI而不是只记录“按钮点过了”。发布前复查项目检查方式通过标准版本node --version、npm list expressNode 20.11.1、Express 4.18.3接口curl 调用 /api/plan成功与错误码都可复现图片列表页和正文预览封面、流程和项目截图清晰隐私检查日志和请求体不上传无关个人信息移动端Chrome 126 缩小窗口按钮、卡片和错误提示可见完整的陪诊 Agent 不是一个泛聊天框而是一个可解释、可验证、可回退的任务系统。版本、协议、代码和测试记录彼此对应文章才真正能帮助读者复现。可运行接口规则 Agent 如何接收、校验并返回任务以下示例来自 Demo 的 Node.js 20.11.1 与 Express 4.18.3 服务层。它只把用户已经确认的陪诊事项整理为待办不推断病情也不生成诊疗建议。请求体在进入规则层前完成字段校验便于本地复现。import express from express; const app express(); app.use(express.json()); app.post(/api/escort-plan, (req, res) { const { hospital, visitAt, need } req.body ?? {}; if (![hospital, visitAt, need].every((value) typeof value string value.trim())) { return res.status(400).json({ code: INVALID_ARGUMENT, message: hospital、visitAt、need 为必填文本 }); } const tasks [ 提前确认 ${hospital} 的院区和到达时间, 准备证件、既往检查资料和问题清单, 在 ${visitAt} 前预留出行与签到时间 ]; return res.json({ code: OK, version: demo-1.0.0, tasks, boundary: not-medical-diagnosis }); }); app.listen(3000);​编辑​编辑​编辑​​编辑编辑本地验证命令node server.mjs后执行curl -X POST http://127.0.0.1:3000/api/escort-plan -H Content-Type: application/json -d {\hospital\:\门诊楼\,\visitAt\:\09:00\,\need\:\协助取号\}。预期得到 200、三个待办和not-medical-diagnosis边界标记缺失字段时返回 400。验证项输入预期结果正常任务院区、时间、需求齐全200返回 3 条可执行待办字段缺失visitAt 为空400不生成任务医疗边界症状或用药问题提示联系专业医疗人员不作诊断完整接口契约任务生成不是一句提示词在 Demo 里规则 Agent 的输出要先定义成稳定的数据协议再交给页面渲染。否则同一个“帮我准备陪诊”的输入今天可能返回字符串明天变成数组前端会不断增加临时判断。这里的协议只描述流程事项和展示状态明确不携带病情判断、药品剂量或处方内容。export type TaskStatus todo | done | blocked; export interface EscortTask { id: string; title: string; status: TaskStatus; source: rule; } export interface EscortPlanResponse { code: OK | INVALID_ARGUMENT | OUT_OF_SCOPE; message: string; tasks: EscortTask[]; traceId: string; } export function toPlanResponse(input: { hospital: string; visitAt: string; need: string }): EscortPlanResponse { const traceId crypto.randomUUID(); if (![input.hospital, input.visitAt, input.need].every((value) value.trim())) { return { code: INVALID_ARGUMENT, message: 请补全医院、时间和陪诊需求, tasks: [], traceId }; } if (/处方|剂量|确诊|诊断/.test(input.need)) { return { code: OUT_OF_SCOPE, message: 该问题需要由医生或药师处理, tasks: [], traceId }; } return { code: OK, message: 已生成就诊准备清单, traceId, tasks: [ { id: arrival, title: 确认 ${input.hospital} 的院区与到达路线, status: todo, source: rule }, { id: materials, title: 准备证件、病历和检查资料, status: todo, source: rule }, { id: time, title: 在 ${input.visitAt} 前预留签到时间, status: todo, source: rule } ] }; }​编辑​编辑页面只根据code决定状态OK展示任务卡片INVALID_ARGUMENT高亮未完成字段OUT_OF_SCOPE显示医疗边界说明。这样 UI 不解析自然语言也不会把错误信息伪装成成功结果。HTTP 路由、超时与可观察性服务端在 Node.js 20.11.1 和 Express 4.18.3 下运行。每次请求分配 traceId日志只记录流程字段和结果码不记录身份证号、病历图片或具体病情描述。前端超时后保留用户输入并允许再次提交。app.post(/api/escort-plan, (req, res) { const startedAt Date.now(); const result toPlanResponse(req.body ?? {}); console.info(JSON.stringify({ event: escort_plan, traceId: result.traceId, code: result.code, durationMs: Date.now() - startedAt })); const status result.code OK ? 200 : result.code INVALID_ARGUMENT ? 400 : 422; res.status(status).json(result); }); app.use((error, _req, res, _next) { console.error(unexpected_error, error?.message); res.status(500).json({ code: SERVER_ERROR, message: 服务暂不可用请稍后重试, tasks: [] }); });​编辑​编辑本地运行命令为npm ci、npm run dev。使用 Chrome 126 打开页面后在 Network 面板中可核对请求体、状态码和 traceId调用失败时页面展示重试按钮而不是清空已填写的医院与时间。从接口到页面的状态表接口返回页面表现用户下一步日志字段200 / OK显示 3 个待办卡片勾选已准备事项traceId、durationMs、OK400 / INVALID_ARGUMENT定位缺失字段补全后再次生成traceId、INVALID_ARGUMENT422 / OUT_OF_SCOPE显示医疗边界提示联系医生或药师traceId、OUT_OF_SCOPE500 / SERVER_ERROR保留输入和重试入口稍后重试traceId、SERVER_ERROR可复现的测试与验收记录import assert from node:assert/strict; const normal toPlanResponse({ hospital: 门诊楼, visitAt: 09:00, need: 协助取号 }); assert.equal(normal.code, OK); assert.equal(normal.tasks.length, 3); const missing toPlanResponse({ hospital: , visitAt: 09:00, need: 协助取号 }); assert.equal(missing.code, INVALID_ARGUMENT); const boundary toPlanResponse({ hospital: 门诊楼, visitAt: 09:00, need: 这个药吃多少 }); assert.equal(boundary.code, OUT_OF_SCOPE);​编辑​编辑执行node --test test/escort-plan.test.js三条断言应全部通过。最后再进行一轮人工验收窄屏 360px、普通桌面 1280px、请求超时、重复点击提交、医疗边界输入。每一项都应有 loading、success、error 或 disabled 的可见状态。验收项操作通过标准正常生成填入医院、时间、取号需求返回三条任务并可勾选重复提交连续点击两次生成按钮 loading只有一次结果断网浏览器离线后提交输入保留并显示重试边界输入输入诊断/剂量问题不生成医疗建议小屏宽度 360px任务卡和按钮不溢出前端状态机防止重复提交与结果闪烁Web Demo 的交互状态需要独立于接口返回管理。用户点击“生成陪诊清单”后按钮先进入 loading接口成功才进入 success网络异常进入 error在 loading 期间禁用再次点击。这样即使网络抖动也不会出现两次请求覆盖同一组任务的情况。const state { phase: idle, error: , plan: null }; function renderPlanState() { submitButton.disabled state.phase loading; submitButton.textContent state.phase loading ? 正在生成... : 生成陪诊清单; errorBox.hidden state.phase ! error; errorBox.textContent state.error; resultPanel.hidden state.phase ! success; } async function submitPlan(payload) { if (state.phase loading) return; state.phase loading; state.error ; renderPlanState(); try { const response await fetch(/api/escort-plan, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify(payload) }); const data await response.json(); if (!response.ok) throw new Error(data.message || 请求失败); state.plan data; state.phase success; } catch (error) { state.phase error; state.error String(error.message || error); } renderPlanState(); }​编辑可访问性也要在 Demo 中可见错误区域使用rolealertloading 状态使用aria-busytrue任务勾选框必须有文字标签。键盘使用 Tab 可以依次到达医院、时间、需求、提交按钮和重试按钮焦点不会落到被隐藏的结果面板上。交互场景检查动作预期反馈网络慢模拟 3 秒响应按钮禁用且显示正在生成连续点击快速点击提交两次只发送一次请求请求失败返回 500保留表单并显示重试键盘操作仅使用 Tab 与 Enter完整走通提交流程完成上述验证后Demo 的价值不再只是“能跑起来”它有明确输入、稳定接口、可见状态、异常兜底和可被他人复查的测试路径。这些内容也方便后续迁移到 HarmonyOS ArkUI 页面由页面状态、服务层和本地记录共同承担任务闭环。延伸阅读这篇文章和同项目的实现、测试或排错文章可以组合阅读下面两篇给出相邻的工程上下文。查看本系列的相关实践 1查看本系列的相关实践 2
延伸阅读

更多相关文章

2026/10/31 21:12:52

告别繁琐清理!AI 输出的内容粘贴有符号好烦靠 AI 导出鸭一键优化

AI输出的内容粘贴有符号好烦,AI 导出鸭轻松清除冗余符号整洁排版告别繁琐清理!AI输出的内容粘贴有符号好烦靠AI 导出鸭一键优化AI输出的内容粘贴有符号好烦无需手动删减,AI 导出鸭高效规整内容 引言 现如今大家日常使用各类智能AI平台生成文案…

2026/11/2 6:21:15

EU AI Act工程化:把合规条款编译成可运行的Guardrails

1. 项目概述:这不是合规 checklist,而是一套能让你代码跑得更快的“AI刹车片”“EU AI Act Quick Wins: Ship Faster With Guardrails”——这个标题里藏着一个被绝大多数技术团队严重误读的真相:欧盟人工智能法案(EU AI Act&…

2026/10/29 2:46:35

Bently Nevada 133388-01(3500/53 超速保护监测模块)

一、基础信息完整型号:3500/53-02-00物料编号:133388-01定位:汽轮机、风机、压缩机专用电子超速保护模块,满足 API670、API612 机组安全规范,可构建 2 取 2 / 3 取 2 冗余表决 ETS 跳闸回路安装规格:3500 机…

2026/11/3 14:29:05

基于Hadoop与SpringBoot的抖音用户行为分析平台实践

1. 项目背景与核心价值短视频平台的爆发式增长带来了海量用户行为数据,如何从这些数据中挖掘价值成为平台运营的关键。传统单机处理方式在面对TB级用户日志时显得力不从心,这正是Hadoop等大数据技术大显身手的场景。我们团队基于SpringBootHadoop构建的抖…

2026/11/3 14:29:05

复盘方法论:用决策日志和事前验尸,打破后见之明

凌晨两点四十七分,我盯着监控大屏上跳动的错误率曲线,脑子里只有一个念头:为什么下午看代码评审的时候,我没有觉得那个改动有问题。那是我第一次认真面对 hindsight 这个词——后见之明。hindsight 在英文里就是“事后才看清”的意…

2026/11/3 14:29:05

AI工程从零入门:提示工程、RAG与Agent实战路线

最近在复盘一个绕不开的问题:如果一个人真的想“从零进入AI工程”,到底该怎么走,才不会一头扎进论文和框架的海洋里出不来。这个标题“ai-engineering-from-scratch”很有意思,from scratch可以理解成“从零开始自己动手造轮子”&…

2026/11/3 14:29:05

从后见之明到事前预演:复盘方法论如何提升决策质量

聊一个我这些年感触特别深的词:hindsight。中文常翻译成"后见之明",说俗了就是"事后诸葛亮"。这个词乍一听有点贬义,但如果你真的把它研究透,会发现它是普通人成长和做事效率差异的最大分水岭。我在带项目、写…

2026/11/3 14:29:05

Paperclip:面向AI Agent的声明式通信协议与流式响应实践

1. 项目概述:Paperclip 是什么,它解决的到底是什么问题? Paperclip 这个名字乍一听容易让人联想到回形针——简单、轻量、却能牢牢固定住关键信息。但放在当前开源技术生态里,它绝不是个玩具项目。我第一次在 GitHub Trending 上看…

2026/11/3 14:24:04

C#操作Excel单元格格式:Interop属性、避坑与样式封装实践

简介:「C# 操作Excel单元格格式」是一份面向 .NET 开发者、办公自动化学习者与内部报表工具维护人员的实用参考文档,聚焦用 C# 调用 Excel 对象模型完成单元格层面的格式控制,可应对批量生成表格、统一报表样式、导出数据时排版凌乱等常见问题…

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32实战:基于MAX14431数字隔离器的SPI隔离通信方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

工业SPI隔离通信设计:MAX14431BAEE+与STM32L4A6RG实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 1:04:48

STM32+NRF24L01无线抢答器:硬件设计、通信协议与低功耗实现

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/11/3 7:47:06

面向复杂光照与角度的宠物面部识别鲁棒性增强策略

在智慧养宠时代,基于视觉的宠物身份识别技术正逐步从实验室走向家庭应用。然而,与配合度高的人类不同,宠物是典型的“非合作生物识别对象”——它们不会主动配合摄像头调整姿态,更无法控制光照环境。实际应用中,我们常…

2026/11/3 14:24:53

SSM电子书店源码全解析:结构、原理、部署与排错实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑