Automate medical coding with Step Functions and Amazon Bedrock AgentCore

TL;DR · AI 摘要
Automate medical coding with Step Functions and Amazon Bedrock AgentCore AWS Architecture Blog Automate medical coding w...
核心要点
- 主题聚焦:Automate medical coding with Step Functions and
- 来源:AWS Architecture Blog,建议结合原文判断细节。
- AI 分析暂不可用,本条为保底评分与摘要。
使用 Step Functions 和 Amazon Bedrock AgentCore 自动化医疗编码 | AWS 架构博客
使用 Step Functions 和 Amazon Bedrock AgentCore 自动化医疗编码
通过 AI 代理,可以在保持工作流程确定性、可审计性和需人工审批的前提下实现医疗编码自动化。关键在于分工协作:工作流引擎负责步骤排序和审批控制,而代理则在各自独立的有限步骤内进行推理。将整个工作流交由代理处理会导致运行路径成为模型推理的属性,这使得审查和回放变得困难。
医疗编码使这一概念具体化。团队必须在分析或报告数据前,将类似“migrane”(拼写错误)或“有时胸部有 flutter 感觉”这样的自由文本临床术语转换为标准化编码。目标词汇表包括 MedDRA(用于不良事件)和 WHODrug(用于药品)等受控医学词典。这项工作具有安全性要求,因为编码错误可能导致不良事件被错误归类到安全信号中。但目前主要依赖人工重复操作,熟练编码员需逐条审核术语。机会在于自动处理明确案例,仅将模糊案例转交人工处理。
本文将展示如何通过 AWS Step Functions 和 Amazon Bedrock AgentCore 的集成(Amazon Bedrock AgentCore 的托管功能)结合确定性编排与有限代理推理。我们将逐步演示一个按成本优先级递进的医疗编码工作流:首先检查安全黑名单,然后进行精确匹配,最后仅对需要判断的术语使用 AI 代理。我们还将解释保持模型有限性的设计决策。完整示例(包括基础设施代码和预置测试数据集)可在 aws-samples GitHub 仓库中找到。
请注意,MedDRA 是国际制药企业协会联合会(IFPMA)的注册商标,由 MedDRA 维护和支持服务组织(MSSO)管理。WHODrug 由乌普萨拉监测中心(UMC)维护。两者均为专有授权词典。使用它们需要有效订阅。示例数据集包含生成的研究标识符和口语化表述,以及最小化说明性词典条目,且不包含任何患者数据。本示例中使用的 AWS 服务(包括 Amazon Aurora 和 Amazon Bedrock)在签署 AWS 业务关联附加协议(BAA)后符合 HIPAA 要求。在处理受保护健康信息前,请参阅 HIPAA 合格服务参考和 AWS HIPAA 合规性概览。
解决方案概述
该设计遵循一个原则:优先使用最经济且确定性最强的机制对术语进行编码,仅在无法确定时升级处理。大型语言模型(LLM)代理功能强大但成本高且非确定性,因此不是默认选择。即使如此,工作流而非模型本身掌控所有路由决策。代理可能选择医疗编码及置信度,但不会决定后续操作。合规审查员可通过阅读状态机定义,独立于任何代理的运行时推理理解执行路径。
该解决方案使用 AWS Step Functions 来编排编码决策,使用 AWS Lambda 实现确定性步骤,使用 Amazon Bedrock AgentCore 的代理步骤。Amazon Bedrock AgentCore Gateway 是 Amazon Bedrock AgentCore 的一项功能,用于暴露代理的工具。Amazon Aurora PostgreSQL 兼容版(Serverless v2)结合 pgvector 扩展,作为参考数据及其嵌入的单一存储,无需单独的向量存储进行同步。
图 1 展示了架构。
图 1:医学编码工作流解决方案架构
每个 Step Functions 执行处理一个原始条目:确定性直接查找、仅在未命中时运行的代理语义搜索、基于代理置信度的分数阈值路由,以及将结果写回至同一研究记录。状态机被有意设计为标准工作流。执行过程保证精确一次,可查询的历史记录是按术语的审计跟踪。对于受监管的编码流程,回答“为何使用该术语、由什么处理、何时处理”是强制要求。此示例中的错误路径最终会将术语保留为开放状态,因此每条记录都会获得终端状态。在生产环境中,应将重试后仍存在的错误发送至 Fail 状态。执行失败后会在 Amazon CloudWatch 中显示为失败状态,修复原因后可重新驱动执行。
写回步骤会存储每个症状条目完整的医学家族树,而不仅仅是孤立的代码。例如,“肌肉痉挛”症状会链接到其上层分类“肌肉骨骼和结缔组织疾病”。安全团队可以在任意层级汇总信号,而不仅限于最低层级。此外,代理会记录一条解释其决策的句子。这确保了当类似症状(如抽筋)在不同研究中被归类不同时,团队可以追踪导致差异的确切研究上下文。他们无需根据通用置信度评分进行猜测。
图 2 展示了使用统一建模语言(UML)活动符号表示的编码决策流程。
图 2:使用 UML 活动符号表示的医学编码决策流程与三个终端结果
注意:此示例仅用于演示目的,不适用于临床使用。在生产环境中使用此模式前,请使用已知正确数据集进行验证,并测量编码精度和错误自动编码率。
演练
演练将跟踪一个原始条目通过状态机的全过程,重点关注每个阶段所编码的架构决策。
先决条件
开始前,请确保具备以下条件:
- 具有创建 Step Functions 状态机、Lambda 函数、Aurora PostgreSQL 集群、Amazon Bedrock AgentCore 资源以及 AWS 身份和访问管理(IAM)角色权限的 AWS 账户。
- 在支持的 AWS 区域中访问 Amazon Bedrock AgentCore 的权限。该框架使用 Claude Sonnet 5(us.anthropic.claude-sonnet-5),字典搜索使用 Amazon Titan Text Embeddings V2(amazon.titan-embed-text-v2:0)。这两个模型默认已启用,但 Anthropic 模型在首次使用前需要提交一次性使用申请表,您可以通过 Amazon Bedrock 的 Playground 提交。有关各区域模型可用性,请参阅 Amazon Bedrock 中的《按 AWS 区域划分的支持模型》。
- Node.js 24+、AWS 云开发工具包(AWS CDK)CLI 以及已配置的目标账户。
预估成本
最大的成本来自 Aurora Serverless v2 集群。它始终保持最低 0.5 个 Aurora 容量单元(ACUs)的容量,因此即使处于空闲状态,也会按每小时运行时间计费。当前费率请参见 Amazon Aurora 定价。要停止计费,请按照 [清理](#clean-up) 部分所述删除堆栈。
第 1 步:优先处理确定性案例
第一个任务状态调用的 Lambda 函数按特定顺序执行两项检查。它首先检查一个禁止自动编码的术语黑名单(terms-not-to-autocode)。这些是真实词典术语,如 "HAEMORRHAGE",由于出血位置不同会导致编码结果变化,因此这类术语过于宽泛无法自动分配。若匹配成功,工作流将终止并保留该术语供人工处理。由于这项检查在任何模型调用之前执行,属于硬性控制规则:置于模型之前的规则无法通过提示绕过,且执行成本为零。
同一函数随后对词典和精选同义词列表(如 "Hypothyroid" 映射到 "Hypothyroidism")进行大小写不敏感的精确匹配。只有在匹配结果唯一对应一个明确编码时才会接受。在示例工作负载中,12 个案例中有 5 个在此步骤完成:1 个安全黑名单项和 4 个自动编码项(置信度 1.00),每个案例仅需一次索引查询。超过三分之一的工作负载甚至从未触发代理处理。
第 2 步:在工作流定义中声明编码代理
我们在此步骤使用代理,因为决定何时引入研究上下文属于判断性决策而非固定规则。在我们的测试运行中,代理仅对模糊术语调用 study-info 工具,而跳过明显拼写错误和无意义输入。这类判断难以用阈值编码,且代理后续可添加新工具而无需重新设计工作流。这也是代理被置于最后的原因,因为它在两个更便宜的确定性检查之后执行。
只有在前两步均未匹配成功时,Step Functions 才会调用代理,使用 AgentCore 优化集成接口。该集成接口仅声明模型本身,系统提示、工具和允许的工具名称通过任务状态动态传入。因此代理的完整契约可在工作流定义中直接读取,无需构建或运行容器。以下为精简摘录示例,完整定义请参见示例。无论 TimeoutSeconds 设置如何,InvokeHarness 任务状态均有严格的 15 分钟执行上限,因此需要多次工具交互的术语可能触发此限制。示例中采用的双工具单轮交互设计远低于此限制。
CodingAgent:
Type: Task
Resource: arn:aws:states:::bedrockagentcore:invokeHarness
Arguments:
HarnessArn: "${CodingHarnessArn}"
RuntimeSessionId: "{% $uuid() %}"
Messages:
- Role: user
Content:
- Text: >-
{% 'Code this verbatim term: "' & $verbatim & '". Dictionary='
& $dictionary & ' version=' & $dictionaryVersion
& ' study=' & $study & '.' %}
Tools:
- Type: agentcore_gateway
Name: gateway
Config:
AgentCoreGateway:
GatewayArn: "${GatewayArn}"
AllowedTools:
- "@gateway/search-dictionary___search_dictionary"
- "@gateway/study-info___get_study_info"
SystemPrompt:
- Text: |-
You are a clinical medical-coding expert...代理恰好拥有两个工具,通过 AgentCore 网关以模型上下文协议(MCP)工具的形式暴露。search_dictionary 工具将原文原样嵌入 Amazon Titan Text Embeddings V2 并执行 pgvector 相似性搜索。它会严格按照原文进行搜索,因为拼写错误本身就是关键信号。get_study_info 工具返回研究的自由文本协议描述。该工具存在是因为相似性搜索可能返回多个临床合理但仅凭文本无法区分的候选结果,此时需要人类编码员根据研究知识来打破平局。此工具为代理提供相同的上下文信息且不附加其他内容:仅返回文本描述,不返回编码。
最清晰的示例是同一原文在两个不同研究中被编码的情况。"cramps" 在两个研究中返回完全相同的候选列表,仅研究描述不同。在监测肌肉痉挛作为特殊关注不良事件的肿瘤学研究中,代理将其编码为 "muscle spasms"。而在预期出现腹痛但不将肌骨骼事件作为终点的反流研究中,相同原文被编码为 "abdominal pain"。在此次运行中,肿瘤学结果得分为 0.92 并被自动编码,而胃肠(GI)结果得分为 0.85 并被发送给人类编码员复核。在两种情况下,代理的职责都是将正确的候选结果置于顶部并提供可验证的理由。这就是熟悉研究协议的编码员会做出判断的方式。
第 3 步:基于编码置信度而非检索相似度进行路由
最重要的设计决策是路由阈值的设定依据。基于检索相似度(两个嵌入向量之间的距离)进行路由是可衡量的错误。表 1 通过示例说明了这一问题。
| 原文 | 选定术语 | 检索相似度 | 代理置信度 | |------|----------|------------|------------| | migrane | Migraine | 0.37 | 0.97 | | flutters in my chest sometimes | Cardiac flutter | 0.65 | 0.75 |
表 1. 示例术语的检索相似度与代理置信度(一次运行,Claude Sonnet 5)
表 1 展示了问题所在。拼写错误 "migrane" 与 "Migraine" 在文本上差异显著,因此相似度得分较低,但正确编码却显而易见。"flutters in my chest sometimes" 与 "Cardiac flutter" 共享更多词汇,因此相似度得分更高,但正确编码的确定性却更低。相似度排名将这两种情况颠倒了,任何阈值都无法修正这一问题。因此,代理通过系统提示中预设的三个置信度区间报告其自身选择的置信度:匹配明确时报告 0.95-1.00,原文模糊或需要研究上下文辅助选择时报告 0.70-0.94,无匹配项时报告低于 0.70。例如,在胃肠研究中 "cramps" 可能指肌肉痉挛或胃痉挛,代理通过检查研究描述进行选择并报告 0.85(中置信度区间)。这些区间描述了模型的置信度。0.90 自动编码阈值是工作流中独立的固定规则,由后续的 Choice 状态应用。
ScoreThreshold:
Type: Choice
Choices:
- Condition: "{% $agentScore >= 0.9 %}"
Next: WriteBack
- Condition: "{% $agentScore >= 0.7 %}"
Next: MarkForReview
Default: MarkOpen注意路由编号由模型生成。黑名单检查在任何模型调用之前执行,阈值是状态机定义中可审计的配置。写回操作会检查代码是否存在,所有低于自动编码门限的内容都会被转交给人类处理。另外请注意代理被指示不得拒绝处理。对于无意义输入,它仍会以较低置信度返回最佳候选,门限会将其丢弃。代理对候选进行评分,工作流决定后续处理方式。
第4步:带有伪造防护的写回操作
终端任务将结果持久化到同一研究记录中:状态、代码、层级、评分以及一个区分机器编码和人工操作的status_changed_by标记。写入前会检查所选代码是否存在于目标词典和版本中。提示信息要求代理不得编造代码,此检查强制执行了该规则。这很重要,因为代理会读取自由文本的研究元数据,这类输入容易诱使从协议描述中复制看似合理的编号。未通过检查的代码会安全地保持术语开放状态,并记录原因。此检查存在一个限制:无法判断代码是否为搜索结果之一,因为工作流仅获取代理的最终响应,而非工具返回的内容。要验证这一点,请查看AgentCore Observability中的代理工具调用,这是Amazon Bedrock AgentCore的一项功能。
部署和测试解决方案
该示例通过三个命令部署并初始化了12个测试用例以覆盖所有分支:
npm install && npm run build
npx cdk deploy
npm run seed每个测试用例作为一次Step Functions执行(仓库README显示了精确的CLI调用)。下表显示了实时运行结果:
路由 | 得分 | 结果 --- | --- | --- HAEMORRHAGE | block-list | n/a(安全封锁开放) Dislocated shoulder | 1.00 | 自动编码 Hypothyroid | 同义词匹配 | ibuprofen FULVESTRANT | 精确匹配(仅衍生) | agent nexiuum | 0.95 | 自动编码(NEXIUM) cramps(肿瘤学研究) | 0.92 | 自动编码(肌肉痉挛) cramps(GI研究) | 0.85 | 审核(腹痛) review(心房颤动) | heart races when I stand up | 0.80 | 审核(心动过速) asdfghjkl | <0.70 | 开放
表2. 示例术语的评分与结果(与表1为同一次运行)
仅衍生匹配(FULVESTRANT行):WHODrug成分级别的精确匹配,写回操作仅更新通用名衍生和ATC层级字段,不分配新词典术语。
代理对明确的拼写错误和无意义输入跳过了研究信息工具,仅在模糊情况下调用该工具。每次执行的流程图均可在Step Functions控制台中检查,AgentCore Observability在Amazon CloudWatch中记录了代理的工具调用和令牌使用情况。
注意:在本示例中,相同输入的重复运行中,所选代码始终稳定,但置信度评分在一定范围内波动。因此,接近0.90自动编码门限的案例可能在一次运行中自动编码,在另一次运行中被转交审核。在我们的测试中,肿瘤学痉挛案例在六次运行中得分在0.75至0.92之间波动,两次自动编码,四次转交审核,而"Muscle spasms"始终被选中。请在测试中断言所选代码而非精确评分,并将自动编码阈值设置在0.90以下的合理范围而非直接使用0.90。
Scaling beyond one verbatim : This walkthrough codes one verbatim per execution so each decision stays straightforward to inspect. To code a full study, wrap the workflow in a Step Functions Distributed Map state that reads verbatims from an Amazon Simple Storage Service (Amazon S3) manifest, and set MaxConcurrency based on your account’s Amazon Bedrock quota. To size MaxConcurrency , divide your model’s tokens-per-minute quota by the tokens one agent run burns ( model calls * (input tokens + 10 * output tokens) for Sonnet 5). Then multiply by the runtime duration in minutes, divide by the share of verbatims that reach the agent, and apply a safety margin. In our testing, 12 concurrent executions against a cluster that had scaled to zero failed 8 of 12 while still reporting SUCCEEDED , which is why the sample keeps a 0.5 ACU minimum and retries the resume errors. Most verbatims resolve in the two deterministic steps, so only a small share ever reaches the agent. For the quotas that apply to your model, see Quotas for Amazon Bedrock .
Clean up
To avoid future charges, delete the deployed resources with npx cdk destroy . All sample data is reseedable, so nothing needs to be retained.
Recognizing the pattern
This pattern fits when the execution path must be reviewable independently of model reasoning, most of the workload is deterministic, only a judgment-heavy minority needs a model, and “escalate to a human” is a first-class outcome rather than an error. It is not limited to clinical trials: the same pattern applies to medical summaries, case narratives, registry intake, study data, and other adjudication workflows such as laboratory test coding, claims triage, and document classification.
You can extend the AgentCore harness with AgentCore Memory to carry context across invocations, Skills to provide task-specific instructions on demand, and AgentCore Gateway to connect MCP servers, knowledge bases, and other tools. Models, tools, and system prompts can also be selected per invocation from the Step Functions task state. Treat a model change like any other release. Rerun your evaluation set, compare the selected codes and confidence scores with the current model’s, and recalibrate the thresholds before you switch. Through all of this, the workflow remains responsible for sequencing and the audit trail.
This isn’t a pattern for open-ended conversations. If the agent must decide what happens next, a workflow engine that owns sequencing is the wrong boundary. Retrieval quality also constrains the agent: if a term isn’t surfaced, it can’t be chosen. In the sample, “flutters in my chest sometimes” would normally be coded to Palpitations, but vector search ranks Palpitations 19th, so the agent does not see it and selects Cardiac flutter instead. The confidence gate still sent it to a coder, but no prompt or study context can recover a term that retrieval never returns. For production dictionaries, use hybrid retrieval, such as lexical search or curated synonym expansion alongside vectors, and calibrate thresholds against your own verbatim distribution.
Conclusion
在本文中,我们展示了当确定性编排与智能体推理的边界明确时,二者如何形成互补关系。AWS Step Functions 负责流程编排、阈值控制和审计追踪。智能体则在单个步骤内进行有限判断,并向工作流报告其置信度。最终形成的工作流能够以查询成本实现常见场景的编码,将专业开发人员聚焦于模糊的少数情况,并将低于置信度阈值的术语路由给人类处理。执行历史记录会明确显示每个决策是由哪种机制做出的。声明式框架集成确保智能体始终处于边界范围内,以可读的配置形式呈现,而非容器内的代码。
后续步骤
使用 AWS 云开发工具包(AWS CDK)部署示例解决方案,运行十二个黄金测试用例,随后替换为自己的参考数据并根据测量精度调整阈值。背景信息请参见 AWS Step Functions 服务集成、Amazon Bedrock AgentCore 文档以及 Amazon Aurora PostgreSQL 上的 pgvector。
如需进一步了解,请参阅:Step Functions 如何从任务状态调用 Amazon Bedrock AgentCore 框架、AgentCore 框架开发者指南,以及在 Step Functions 中使用 JSONata 转换数据。如需大规模运行研究,请参见用于大规模并行工作负载的分布式映射和 Amazon Bedrock 的配额限制。服务详情请参见 AWS Step Functions 和 Amazon Bedrock AgentCore。
作者简介
'"`