架构手记(四):驯服“狂野”的大模型——单智能体 ReAct 工作流与 Prompt 架构级调优记录
一、 架构权的转移:当“中台逻辑”变成“提示词”
在传统的医疗软件架构中,业务逻辑层(Service Layer)是由无数个 if-else 和状态机组成的。但在我们的《大模型 Agent 决策引擎》中,我做了一个大胆的架构决策:将部分核心的业务流转权限,交给大模型(Agent)的大脑来接管。
上一篇博客中,我们已经建好了 $O(1)$ 复杂度的医药冲突图谱。现在的核心问题是:如何让大模型乖乖地按照我们设定的路线,去调用这个图谱,并且输出符合上一篇 API 契约的 JSON 数据?
在实训初期,我们尝试过直接用零样本提示(Zero-Shot Prompt)让大模型干活,结果遭遇了灾难:模型要么忘记调用工具自己“瞎编”药理,要么输出一堆包含 Markdown 代码块的非标准文本,导致前端直接白屏崩溃。
为了彻底驯服这头“狂野”的大模型,我们引入了学术界经典的 ReAct (Reason + Act) 架构。
二、 放弃多智能体,拥抱 ReAct 单智能体工作流
在最初的架构评审中,我们曾考虑过使用多智能体(Multi-Agent:一个分诊 Agent + 一个药师 Agent 互相博弈)。但作为架构师,在经过压测后我发现,多智能体在 Web 响应上存在致命缺陷:延迟(Latency)过高。 两个模型互相轮询对话,往往需要 15 秒以上才能返回结果,这在门诊场景下是不可接受的。
因此,我主导团队转向了 基于 ReAct 范式的单智能体(Single-Agent)架构。
ReAct 要求模型在给出最终答案前,必须暴露其“思维过程”。其标准流转图如下:
-
Thought(思考):分析患者主诉,识别提取实体。
-
Action(行动):决定调用哪一个后端函数(Tool Calling)。
-
Observation(观察):接收后端知识图谱返回的绝对客观规则。
-
Final Answer(输出):将规则包装成规定的 JSON 格式下发。
三、 核心代码拆解:架构级的 Prompt Engineering
为了实现上述工作流,我们不再是用“聊天”的口吻写 Prompt,而是像写配置文件一样,构建了极其严密的 System Prompt 和 Tool Schema。
1. 严格约束的 Tool Schema (工具契约)
首先,我们将上一篇博客写好的图谱算法,封装成了大模型可以理解的 Function 工具:
JSON
// 向大模型注册的 Tool 定义
{
"name": "check_graph_conflict",
"description": "查询患者用药和病史之间是否存在医疗冲突。在给出最终建议前,必须优先调用此工具。",
"parameters": {
"type": "object",
"properties": {
"entities": {
"type": "array",
"items": {"type": "string"},
"description": "从主诉中提取的药物名称和患者病史标签列表,例如 ['布洛芬', '消化道溃疡史']"
}
},
"required": ["entities"]
}
}
2. 结构化的 System Prompt 模板
接下来,是整个大模型“大脑”的底层代码——系统提示词。我采用了极具工程化思维的 [Identity] - [Workflow] - [Constraints] 三段式结构:
Markdown
# Role: 严谨的临床用药安全审核专家 (Agent)
# Background
你正在为一个前端 Web 工作站提供支持。你的唯一目标是确保用药安全,并将分析结果输出为严格的 JSON。
# Workflow (基于 ReAct)
1. **Thought**: 仔细阅读用户的输入,提取出所有【药物】和【患者特征/病史】。
2. **Action**: 你必须将提取出的实体作为参数,调用 `check_graph_conflict` 工具。
3. **Observation**: 仔细阅读工具返回的图谱规则。
4. **Final Answer**: 根据工具返回的结果,构建最终的 JSON。
# Strict Constraints (绝对红线)
- 禁绝幻觉:绝对不准依赖你自身的训练数据进行药理判断!必须 100% 依赖工具返回的 Observation!
- 强制 JSON 输出:你的最终输出必须只能是一个 JSON 对象,不能包含任何 Markdown 标记(如 ```json),不能有任何前置或后置的问候语。
- 缺失信息决断:如果工具返回高危风险,且发现上下文缺失关键确认信息(如患者孕史未知),将 JSON 中的 `action_type` 设为 "CLARIFY",并生成追问话术。
四、 踩坑与调优记录:如何保证 100% 的 JSON 解析率?
即使有了上述严谨的 Prompt,大模型偶尔还是会“犯病”,比如在 JSON 结尾多加一个逗号,或者把枚举值拼错。为了保证系统不崩溃,我们在后端(FastAPI + LangChain)加入了双重保险机制:
-
强制 JSON Mode:在调用大模型 API 时,我们在请求头中开启了
response_format: {"type": "json_object"},从 API 底层约束输出。 -
Pydantic Output Parser(输出解析器与自动重试):我们利用 LangChain 的
PydanticOutputParser建立了一道拦截网。如果大模型输出的 JSON 格式不符合我们在第二篇博客中定义的 Schema,拦截器会直接捕获解析异常(ParseError),并将错误信息“喂”回给大模型,强制要求其进行自纠错(Auto-Retry)。
Python
# 核心防御逻辑示例
try:
parsed_json = parser.parse(agent_response)
return parsed_json
except OutputParserException as e:
# 触发自动重试机制,要求大模型修复 JSON 格式
return retry_with_error_feedback(agent_response, str(e))
五、 结语
通过 ReAct 架构与深度的 Prompt 调优,我们成功地为系统打造了一个既具有泛化理解能力,又绝对服从图谱真理的“智能大脑”。
更多推荐




所有评论(0)