Agent检验解读怎样做成风险提示助手而不是越界诊断检验报告解读类 Agent 很容易从“提示异常和建议复查”滑向“判断疾病、给出治疗建议”。本文只讨论技术架构和工程流程示例不提供诊断、治疗、分诊或用药建议文中的阈值、风险分层、升级规则均为示例规则真实项目必须由医疗专业人员和机构规范确认。问题背景Agent 为什么容易越界在检验报告场景里用户通常上传一组指标希望系统解释“有没有问题”“严重不严重”“下一步怎么办”。如果直接把结构化指标丢给 LLM模型很可能生成诊断性表达例如“考虑某疾病”“建议使用某药物”等这在产品边界、合规审计和用户安全上都不可接受。工程上要解决的不是“让模型更会医学”而是把 Agent 约束为一个风险提示助手。它只做三件事识别报告中的异常项基于可配置规则生成风险提示输出复查或咨询专业人员的建议。它不做疾病判断不给药物方案不替代医生决策。这类系统的关键不是单点 Prompt而是“规则引擎 LLM 模板 输出校验 审计日志”的闭环。技术目标和边界定义本文示例面向 Python、FastAPI、规则引擎和 LLM API 的后端实现。目标是构建一个可回溯、可配置、可拦截的检验报告风险提示服务。建议先把输出边界写成机器可执行的策略而不是只写在产品文档里允许输出异常项名称、检测值、参考范围、风险提示、复查建议、就医咨询提醒禁止输出疾病诊断、治疗方案、药物建议、分诊结论、确定性因果判断必须声明结果仅为技术系统生成的风险提示不能替代医疗专业判断必须记录输入指标、命中的示例规则、LLM 原始输出、最终输出、拦截原因在真实项目中参考范围、阈值和提示等级需要来自机构确认的规则库。代码里的规则只用于演示工程结构。方案概览把 Agent 拆成四层一个相对稳妥的架构可以拆成以下流程通过不通过检验指标输入字段标准化示例规则引擎受控 Prompt 生成LLM 输出边界校验器风险提示结果降级模板输出审计日志字段标准化负责把“白细胞”“WBC”“白细胞计数”等映射到统一编码。规则引擎只判断“是否触发提示”不生成诊断。LLM 只负责把规则结果改写成用户可读文本。边界校验器负责拦截越界内容必要时退回模板输出。这样设计的重点是LLM 不是事实来源也不是最终裁判。最终输出必须被规则和校验器约束。数据结构先把报告输入结构化实际业务中检验报告可能来自 OCR、PDF 解析或接口数据。本文从结构化 JSON 开始避免把重点放到文档解析上。一个最小输入可以这样定义{report_id:rpt_001,items:[{code:WBC,name:白细胞计数,value:12.1,unit:10^9/L,ref_low:3.5,ref_high:9.5},{code:ALT,name:丙氨酸氨基转移酶,value:68,unit:U/L,ref_low:7,ref_high:40}]}注意这里没有年龄、性别、病史等上下文因此系统不能推导诊断。即使补充更多上下文也应按照机构规范明确允许的输出范围。核心实现规则命中、LLM 改写和边界拦截下面是一个简化版 FastAPI 服务。它演示了三件事用示例规则生成风险提示用 Prompt 限制 LLM 角色再用关键词和结构校验拦截越界表达。fromfastapiimportFastAPIfrompydanticimportBaseModelfromtypingimportList,Optionalfromdatetimeimportdatetimeimportreimportuuid appFastAPI(titleLab Risk Hint Agent Demo)classLabItem(BaseModel):code:strname:strvalue:floatunit:strref_low:Optional[float]Noneref_high:Optional[float]NoneclassLabReport(BaseModel):report_id:stritems:List[LabItem]classRuleHit(BaseModel):code:strname:strlevel:strmessage:strFORBIDDEN_PATTERNS[r诊断为,r确诊,r考虑.*病,r建议使用.*药,r服用,r治疗方案,r无需就医,r立即手术]defrun_rules(items:List[LabItem])-List[RuleHit]:hits[]foriteminitems:ifitem.ref_lowisNoneoritem.ref_highisNone:continueifitem.valueitem.ref_high:hits.append(RuleHit(codeitem.code,nameitem.name,levelattention,messagef{item.name}高于本次报告参考上限建议结合近期状态按机构规则复查或咨询专业人员。))ifitem.valueitem.ref_low:hits.append(RuleHit(codeitem.code,nameitem.name,levelattention,messagef{item.name}低于本次报告参考下限建议结合近期状态按机构规则复查或咨询专业人员。))returnhitsdefbuild_prompt(report:LabReport,hits:List[RuleHit])-str:hit_text\n.join([f-{h.name}{h.message}forhinhits])returnf 你是检验报告风险提示助手不是医生。 只能基于已命中的规则输出风险提示和复查建议。 禁止输出疾病诊断、治疗方案、药物建议、分诊结论。 必须包含“不能替代医疗专业判断”的说明。 报告ID{report.report_id}规则命中{hit_text}请用三段输出 1. 异常项概览 2. 风险提示 3. 复查或咨询建议 defmock_llm_call(prompt:str)-str:return(异常项概览本次报告存在部分指标超出参考范围。\n风险提示白细胞计数和丙氨酸氨基转移酶需关注建议结合近期状态观察变化。\n复查或咨询建议建议按机构规则复查或咨询医疗专业人员。本结果不能替代医疗专业判断。)defvalidate_output(text:str)-tuple[bool,List[str]]:reasons[]forpatterninFORBIDDEN_PATTERNS:ifre.search(pattern,text):reasons.append(f命中禁止表达{pattern})required不能替代医疗专业判断ifrequirednotintext:reasons.append(缺少边界声明)returnlen(reasons)0,reasonsdeffallback_output(hits:List[RuleHit])-str:ifnothits:return未发现基于示例规则触发的风险提示。本结果不能替代医疗专业判断。lines[以下为基于示例规则生成的风险提示]forhinhits:lines.append(f-{h.name}{h.message})lines.append(本结果不能替代医疗专业判断。)return\n.join(lines)defwrite_audit_log(report_id:str,hits:List[RuleHit],raw:str,final:str,reasons:List[str]):audit_event{event_id:str(uuid.uuid4()),report_id:report_id,time:datetime.utcnow().isoformat(),rule_hits:[h.dict()forhinhits],llm_raw_output:raw,final_output:final,blocked_reasons:reasons}print(audit_event)app.post(/lab-risk-hint)deflab_risk_hint(report:LabReport):hitsrun_rules(report.items)promptbuild_prompt(report,hits)raw_outputmock_llm_call(prompt)ok,reasonsvalidate_output(raw_output)final_outputraw_outputifokelsefallback_output(hits)write_audit_log(report.report_id,hits,raw_output,final_output,reasons)return{report_id:report.report_id,risk_level:attentionifhitselsenone,output:final_output,blocked:notok,blocked_reasons:reasons}本地运行时可以先用mock_llm_call等流程稳定后再接入真实 LLM API。接入时建议保留原始输出和最终输出便于排查“模型是否越界”以及“拦截器是否误伤”。排查重点越界内容通常从哪里漏出来第一类问题是 Prompt 写得太宽。比如“请解读报告并给出建议”会诱导模型扩展到诊断和处置应改成“只能改写规则命中结果”。第二类问题是规则和文案混在一起。规则层应输出结构化结果例如code、level、message不要在规则里写大段医学解释否则后续难以审计。第三类问题是只做输入控制不做输出控制。医疗健康场景下输出校验是必要防线。关键词拦截不是万能方案但可以作为第一层再叠加分类模型、人工抽检和灰度发布。第四类问题是没有降级策略。当 LLM 输出不合规时系统不能直接报错给用户也不能放行原文。更合适的做法是回退到规则模板保证输出仍然可读且边界清晰。审计回溯让每一次提示都能解释风险提示助手上线后日志不是普通调试信息而是问题定位的依据。建议至少记录以下字段报告 ID 和请求时间标准化后的指标数据命中的示例规则版本LLM Prompt 摘要或模板版本LLM 原始输出最终展示输出拦截原因和降级结果规则库也需要版本号。否则同一份报告在不同时间得到不同提示时很难判断是规则调整、模型变化还是输入解析问题。如果涉及真实用户数据还需要做脱敏、访问控制和留存周期管理。日志系统不应成为新的敏感数据泄露点。扩展建议从 Demo 到可上线服务从工程落地看可以按三个阶段推进。第一阶段只做结构化输入和规则模板输出不接 LLM。目标是把指标标准化、规则配置、审计日志跑通。第二阶段引入 LLM 改写但只允许它基于规则命中结果生成自然语言。此时必须上线输出校验和降级模板。第三阶段再增加质量评估例如抽样复核、越界率统计、规则命中分布、用户反馈闭环。评估指标不应只看“回答是否流畅”更应关注“是否越界”“是否可回溯”“是否稳定”。总结检验报告 Agent 的工程重点不是让模型自由发挥而是把它限制在风险提示助手的角色内。一个可控方案通常包括结构化输入、可配置示例规则、受控 Prompt、输出拦截、降级模板和审计日志。本文代码只展示技术架构思路不构成医疗建议。真实项目中的参考范围、风险等级和升级规则需要由医疗专业人员和机构规范确认后再进入规则库。下一步可以把规则配置外置到数据库并增加规则版本管理、自动化测试集和人工复核后台。本文作者超能文献团队(https://suppr.wilddata.cn/)