30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度这次我们来看一个医疗问诊 Agent 的构建过程它不是一个现成的、可以一键启动的软件包而是一个基于 LangChain、LangGraph 和 LangSmith 三大框架的技术实现方案。如果你正在学习如何构建一个复杂、可编排的 AI Agent特别是想了解如何将 LangChain 的模块化、LangGraph 的状态流图、LangSmith 的调试监控结合起来解决实际问题这篇文章就是为你准备的。本文的核心不是提供一个开箱即用的“医疗问诊.exe”而是通过一个具体的医疗场景带你彻底看懂这三个框架各自扮演什么角色、如何协同工作。你将了解到LangChain 如何作为“工具箱”提供基础能力LangGraph 如何像“流程图”一样编排复杂的多步骤、多角色问诊流程LangSmith 又如何作为“监控中心”来追踪、调试和优化整个 Agent 的运行。对于开发者而言这比单纯跑通一个模型更有价值因为它关乎如何工程化地构建可靠、可维护的智能应用。接下来我们会从零开始拆解这个医疗问诊 Agent 的架构设计并给出关键代码示例和部署验证思路。无论你是想入门 AI Agent 开发还是已经接触过 LangChain 但对 LangGraph 和 LangSmith 感到困惑都能从这里获得清晰的路径。1. 核心能力速览三大框架定位解析在深入医疗问诊案例之前我们先快速厘清 LangChain、LangGraph 和 LangSmith 的核心定位与能力边界。这有助于你理解在构建复杂 Agent 时何时该用哪个工具。框架核心定位在医疗问诊 Agent 中的角色关键能力学习门槛LangChain模块化工具箱提供基础“医疗工具”如问诊对话链、病历检索、知识库查询等。连接 LLM、管理提示词、处理记忆、集成外部工具如搜索、数据库。较低适合快速搭建单一功能链。LangGraph状态流图编排器绘制“就诊流程图”定义患者从分诊到专科问诊的完整状态流转逻辑。基于有向图编排多步骤、多角色、带循环和条件分支的复杂工作流。中等需要理解状态机和图的概念。LangSmith开发与运维监控平台充当“医院监控中心”追踪每次问诊的完整日志、性能和分析问题。全链路追踪、调试提示词、评估 Agent 表现、监控成本和延迟。较低但需要额外部署或使用云服务。简单来说用 LangChain 造工具比如打造一个“症状分析器”或“药品查询器”。用 LangGraph 连流程定义患者来了先分诊再根据分诊结果决定是转内科还是外科每个科室问诊后可能还需要检查检查完再回来复诊——这一整套流程。用 LangSmith 看效果查看每一次分诊是否准确问诊对话是否有效哪里耗时最长哪个工具调用出错了。理解了这三者的分工我们就能明白一个强大的 Agent 往往是LangChain (工具) LangGraph (流程) LangSmith (洞察)的组合拳。下面我们就用医疗问诊这个典型场景把这三者串起来。2. 适用场景与使用边界适合谁AI 应用开发者希望构建超越简单问答的、具备复杂逻辑和状态管理的智能体。技术团队负责人需要评估 LangChain 生态是否适合用于生产级 Agent 项目。学习者对 LangChain 有初步了解想通过一个完整项目深化对 LangGraph 和 LangSmith 的理解。能解决什么问题复杂流程自动化模拟真实世界多步骤、多决策点的业务流程如客服、审核、诊断。状态持久化与管理在长时间、多轮交互中保持和更新上下文状态如患者病历随时间更新。模块化与可维护性将大 Agent 拆解为可复用、可独立测试的小工具Tool或节点Node。可观测性与调试对“黑盒”Agent 的内部运行过程进行记录、分析和优化。不适合什么场景单一、简单的问答如果只是调用一次 LLM 就能完成直接使用 LangChain 的LLMChain或更基础的 SDK 即可引入 LangGraph 反而增加复杂度。对延迟极其敏感的场景多步骤的图执行和 LangSmith 的追踪都会引入额外开销。缺乏 Python 开发环境这是一个代码开发项目不是提供可执行文件的软件。重要边界与提醒非真实医疗诊断本文案例仅为技术演示所构建的 Agent 不具备任何真实的医疗诊断能力切勿用于真实医疗场景。数据隐私与合规如果处理真实用户问诊数据必须严格遵守相关法律法规做好数据脱敏和加密。模型依赖与成本Agent 能力受底层大语言模型如 GPT-4, Claude, 本地模型限制需关注 API 成本或本地算力需求。3. 环境准备与前置条件构建这样一个 Agent你需要一个标准的 Python 开发环境。以下是通用的准备清单具体版本请根据项目需求调整。Python 环境推荐 Python 3.10 或 3.11。使用conda或venv创建独立的虚拟环境是最佳实践。conda create -n med-agent python3.10 conda activate med-agent核心框架安装通过 pip 安装 LangChain 全家桶。pip install langchain langgraph langsmith注意langsmith是用于追踪的客户端库如需使用其可视化平台需注册账号并配置 API 密钥。大语言模型 (LLM)你需要一个 LLM 的接入点。可以选择OpenAI APIpip install openai并设置环境变量OPENAI_API_KEY。Azure OpenAI安装openai并配置相应端点。本地模型通过langchain-community集成 Ollama、vLLM 等。例如pip install langchain-community ollama。其他云模型如 Anthropic Claude, Google Gemini 等安装对应 SDK。可选工具包根据你的 Agent 需要可能还要安装向量数据库用于构建知识库如pip install chromadb。网络搜索如pip install duckduckgo-search。计算工具如pip install numexpr。代码编辑器VS Code, PyCharm 等均可。LangSmith 账户可选但推荐前往 LangSmith官网 注册获取 API 密钥。它将用于可视化的追踪和调试。4. 项目架构设计与核心概念在写代码之前我们先基于搜索材料中提到的“医院”比喻设计这个医疗问诊 Agent 的架构。类比理解LangChain 工具 专科医生与设备每个工具是一个“专科医生”如内科诊断工具、药品查询工具或一台“检查设备”如化验单解读工具。LangGraph 流程图 医院就诊流程定义患者从进入医院开始到分诊台路由到各科室就诊工具调用到缴费取药状态更新最后离开结束的完整路径。LangSmith 医院监控系统记录每个患者每次会话的流动路径、在每个科室的停留时间延迟、医生的诊断记录输入输出用于优化流程和培训医生。我们的医疗问诊 Agent 设计如下状态 (State)定义一个共享的状态字典记录整个问诊过程的信息。这是 LangGraph 的核心。from typing import TypedDict, Annotated import operator class AgentState(TypedDict): # 患者输入 user_input: str # 当前会话历史 chat_history: list # 分诊结果 (如 内科, 外科, 急诊) triage_result: str # 当前问诊科室 current_department: str # 已收集的症状信息 symptoms: list # 初步诊断建议 preliminary_advice: str # 是否需要进一步检查 need_check: bool # 检查结果 check_result: str # 最终建议 final_advice: str节点 (Nodes)每个节点是一个函数代表流程中的一个步骤。triage_node: 分诊节点。根据患者主诉判断应去哪个科室。general_qa_node: 通用问答节点。处理挂号、费用等非医疗问题。internal_medicine_node: 内科问诊节点。进行详细的症状收集和初步分析。surgery_node: 外科问诊节点。check_node: 检查节点。模拟开具检查单并解读结果。pharmacy_node: 药房节点。根据诊断提供用药建议。边 (Edges)决定流程的走向。通常是条件判断。患者输入 - 判断是否为医疗问题 - 是去分诊否去通用问答。分诊后 - 根据triage_result- 路由到对应科室节点。科室问诊后 - 判断need_check- 是去检查节点否去药房节点。检查后 - 返回对应科室节点进行复诊或去药房节点。工具 (Tools)被节点调用的具体能力用 LangChain 定义。search_medical_knowledge_base: 查询医学知识库的工具。analyze_symptoms: 症状分析工具调用 LLM。generate_advice: 生成建议工具。5. 分步实现用 LangChain 构建工具首先我们用 LangChain 实现几个核心工具。这里以调用 OpenAI GPT-4 为例。import os from langchain_openai import ChatOpenAI from langchain.tools import tool from langchain.prompts import ChatPromptTemplate from langchain.schema.output_parser import StrOutputParser # 1. 初始化 LLM os.environ[OPENAI_API_KEY] your-api-key-here # 请替换为你的密钥 llm ChatOpenAI(modelgpt-4-turbo-preview, temperature0.2) # 2. 定义症状分析工具 tool def analyze_symptoms(symptom_description: str) - str: 根据症状描述进行初步的医学分析。 prompt ChatPromptTemplate.from_messages([ (system, 你是一位经验丰富的全科医生。根据患者的症状描述提供可能的病因方向和分析务必保持谨慎并建议就医。), (human, 患者主诉{symptoms}) ]) chain prompt | llm | StrOutputParser() return chain.invoke({symptoms: symptom_description}) # 3. 定义药品查询工具 (模拟) tool def query_drug_info(drug_name: str) - str: 查询药品的基本信息、用法用量和注意事项。 # 这里可以连接真实的药品数据库此处为模拟 drug_db { 阿莫西林: 抗生素用于敏感菌所致的感染。用法用量请遵医嘱。, 布洛芬: 非甾体抗炎药用于缓解轻至中度疼痛。对胃肠道有刺激建议饭后服用。 } return drug_db.get(drug_name, f未找到药品 {drug_name} 的详细信息请咨询药师。) # 4. 定义分诊工具 tool def triage_patient(complaint: str) - str: 根据患者主诉进行初步分诊推荐就诊科室。 prompt ChatPromptTemplate.from_messages([ (system, 你是医院的分诊护士。根据患者主诉判断最可能属于哪个科室的范畴。只返回科室名称如内科、外科、骨科、儿科、急诊。如果无法判断或情况紧急返回急诊。), (human, 患者主诉{complaint}) ]) chain prompt | llm | StrOutputParser() return chain.invoke({complaint: complaint})这些工具就是我们的“专科医生”和“设备”。接下来我们需要用 LangGraph 把他们组织到“就诊流程图”中。6. 核心实现用 LangGraph 编排问诊流程现在我们创建 LangGraph 的StateGraph并将上述工具和逻辑封装成节点。from langgraph.graph import StateGraph, END from langgraph.graph.message import add_messages from typing import Literal # 定义状态类型 (简化版) class State(TypedDict): messages: Annotated[list, add_messages] triage: str department: str symptoms: list need_check: bool check_result: str # 初始化图 workflow StateGraph(State) # 1. 定义节点函数 def triage_node(state: State): 分诊节点 last_message state[messages][-1] complaint last_message.content if hasattr(last_message, content) else str(last_message) # 调用分诊工具 department triage_patient.invoke(complaint) return {triage: department, department: department} def internal_medicine_node(state: State): 内科问诊节点 # 收集症状这里简化处理取最后一条消息 last_message state[messages][-1] symptom_text last_message.content if hasattr(last_message, content) else str(last_message) # 调用症状分析工具 analysis analyze_symptoms.invoke(symptom_text) # 模拟判断是否需要检查例如症状中包含“持续疼痛” need_check 持续 in symptom_text or 剧烈 in symptom_text new_message {role: assistant, content: f【内科分析】{analysis} (\n建议您进行进一步检查。 if need_check else )} return {messages: [new_message], symptoms: [symptom_text], need_check: need_check} def check_node(state: State): 检查节点模拟 # 模拟检查结果 check_result 血常规检查显示白细胞计数轻度升高提示可能存在感染。 new_message {role: assistant, content: f【检查结果】{check_result}} return {messages: [new_message], check_result: check_result, need_check: False} # 检查完成 def pharmacy_node(state: State): 药房节点 # 根据症状和检查结果模拟推荐药品 advice 根据您的情况可以考虑使用布洛芬缓解疼痛并多休息。若为细菌感染需医生处方抗生素。 new_message {role: assistant, content: f【用药建议】{advice}\n问诊结束请遵医嘱。} return {messages: [new_message]} # 2. 添加节点到图中 workflow.add_node(triage, triage_node) workflow.add_node(internal_medicine, internal_medicine_node) workflow.add_node(check, check_node) workflow.add_node(pharmacy, pharmacy_node) # 3. 设置入口点 workflow.set_entry_point(triage) # 4. 定义条件边 (路由逻辑) def route_after_triage(state: State) - Literal[internal_medicine, general_qa, emergency]: 分诊后的路由逻辑 dept state.get(triage, ) if 内科 in dept: return internal_medicine elif 外科 in dept: # 这里可以路由到外科节点本例中我们简化也路由到内科 return internal_medicine else: # 其他情况如通用问答或急诊结束流程 return general_qa # 假设有一个通用问答节点这里为简化直接指向 END def route_after_consult(state: State) - Literal[check, pharmacy, END]: 问诊后的路由逻辑是否需要检查 if state.get(need_check): return check else: return pharmacy def route_after_check(state: State) - Literal[internal_medicine, pharmacy]: 检查后的路由逻辑返回复诊或直接取药 # 这里可以根据检查结果决定是回科室复诊还是直接取药 # 本例简化检查后直接去药房 return pharmacy # 5. 添加条件边 workflow.add_conditional_edges( triage, route_after_triage, { internal_medicine: internal_medicine, general_qa: END, # 简化处理直接结束 } ) workflow.add_conditional_edges( internal_medicine, route_after_consult, { check: check, pharmacy: pharmacy, } ) workflow.add_conditional_edges( check, route_after_check, { pharmacy: pharmacy, } ) # 6. 设置终点 workflow.add_edge(pharmacy, END) # 7. 编译图 app workflow.compile()至此一个最简单的、包含分诊-内科问诊-检查-取药流程的医疗问诊 Agent 图就构建完成了。app就是一个可执行的智能体。7. 功能测试与效果验证现在我们来测试这个 Agent 的工作流。我们将模拟一次患者问诊。# 测试1简单症状直接取药 print( 测试1头痛问诊 ) initial_state {messages: [{role: user, content: 我有点轻微头痛没其他症状。}]} for event in app.stream(initial_state, stream_modevalues): event.get(messages, [])[-1] if event.get(messages) else None # 预期流程triage - internal_medicine - pharmacy # 输出应包含【内科分析】和【用药建议】 # 测试2复杂症状需要检查 print(\n 测试2持续腹痛问诊 ) initial_state {messages: [{role: user, content: 我肚子持续剧烈疼痛两天了。}]} for event in app.stream(initial_state, stream_modevalues): if messages in event and event[messages]: last_msg event[messages][-1] if hasattr(last_msg, content): print(last_msg.content) else: print(last_msg) # 预期流程triage - internal_medicine - check - pharmacy # 输出应包含【内科分析】、【检查结果】和【用药建议】。 # 使用 LangSmith 进行可视化追踪需配置 API 密钥 import os os.environ[LANGCHAIN_TRACING_V2] true os.environ[LANGCHAIN_API_KEY] your-langsmith-api-key # 请替换 os.environ[LANGCHAIN_PROJECT] Medical-Agent-Demo # 再次运行这次会被记录到 LangSmith final_state app.invoke({messages: [{role: user, content: 我咳嗽有痰喉咙痛。}]}) print(final_state.get(messages, [])[-1].content if final_state.get(messages) else No final message)如何判断成功流程正确对于不同的输入Agent 能走通不同的路径如测试1直接取药测试2走了检查节点。状态更新state字典中的triage,need_check,check_result等字段能随着流程推进而正确更新。输出合理每个节点返回的助手消息内容符合该节点的角色设定如分诊、分析、建议。LangSmith 有记录配置好 LangSmith 后在 LangSmith 网站 上能看到本次调用的完整轨迹图包括每个节点的输入输出、耗时和工具调用。8. 集成 LangSmith 进行调试与监控LangSmith 是提升开发效率的关键。上面我们已经配置了环境变量运行后即可在 LangSmith 平台查看。追踪查看在 LangSmith 项目的 “Traces” 页面你会看到每次app.invoke()或app.stream()的调用记录。调试提示词点击任意一个 Trace可以展开看到每个节点如triage_node的详细输入输出。你可以检查 LLM 调用时的实际提示词Prompt这对于优化提示词至关重要。性能分析LangSmith 会记录每个步骤的延迟帮助你发现性能瓶颈例如是哪个工具调用或 LLM 调用最耗时。评估与测试你可以在 LangSmith 中创建“数据集”(Datasets)用一批测试用例如不同的患者主诉来批量运行你的 Agent并自动评估其输出是否符合预期例如分诊科室是否正确。关键价值没有 LangSmith当流程复杂时如果最终输出不对你很难定位是哪个环节出了问题。有了 LangSmith就像给整个 Agent 装上了“飞行记录仪”一切尽在掌握。9. 扩展与优化打造更真实的 Agent上面的例子是高度简化的。一个真实的医疗问诊 Agent 需要考虑更多更丰富的状态与记忆使用LangGraph的Checkpointer或集成ChatMessageHistory来支持多轮对话让 Agent 记住之前的交流。更复杂的路由逻辑支持更多科室外科、儿科、骨科并实现科室间的转诊逻辑。集成真实工具连接医学知识库如将医学文献存入向量数据库实现 RAG。集成预约挂号系统 API。连接药品数据库。人机协作节点在流程中设置“人工审核”节点对于不确定或高风险的情况交由真人医生处理。错误处理与重试在图中添加错误处理节点当某个工具调用失败时可以重试或转入备用流程。10. 部署与运行考量这个项目是代码库部署方式取决于你想如何提供服务。本地脚本运行直接运行 Python 脚本适用于开发和测试。python medical_agent_demo.py封装为 API 服务使用 FastAPI 或 Flask 将app包装成 HTTP 接口。from fastapi import FastAPI from pydantic import BaseModel app_fastapi FastAPI() class Query(BaseModel): message: str app_fastapi.post(/chat) async def chat(query: Query): result app.invoke({messages: [{role: user, content: query.message}]}) return {response: result[messages][-1].content}批量处理可以读取一个包含大量模拟问诊的 CSV 文件循环调用app.invoke()进行批量测试并结合 LangSmith 评估整体效果。资源占用主要取决于你使用的 LLM。如果使用本地大模型如通过 Ollama则需要关注 GPU 显存或 CPU 内存。如果使用 OpenAI 等 API则主要关注网络延迟和 Token 消耗成本。LangGraph 和 LangSmith 本身的开销很小。11. 常见问题与排查方法问题现象可能原因排查方式解决方案运行报错ModuleNotFoundError依赖未安装或环境不对。检查pip list确认langchain,langgraph,langsmith已安装。在正确的虚拟环境中重新安装。LangSmith 无追踪记录API 密钥未设置或项目名错误。1. 检查LANGCHAIN_API_KEY环境变量。2. 检查LANGCHAIN_PROJECT是否存在。正确配置环境变量确保项目在 LangSmith 平台已存在。Agent 流程未按预期路由条件边 (add_conditional_edges) 的逻辑函数返回了未定义的键。1. 打印条件函数route_after_triage(state)的返回值。2. 检查add_conditional_edges的映射字典是否包含所有可能的返回值。确保条件函数的所有输出都在映射字典中有对应的节点名。状态 (State) 更新不生效节点函数返回值格式错误或未修改应修改的状态字段。1. 使用 LangSmith 查看每个节点的输入和输出状态。2. 检查节点函数返回值是否为字典且键名与 State 定义匹配。确保节点函数返回的字典键名正确例如return {need_check: True}。LLM 调用超时或报错API 密钥无效、网络问题、或模型服务不可用。1. 单独测试 LLM 调用是否成功。2. 查看 LangSmith 中该 LLM 调用的详细错误信息。检查 API 密钥和网络考虑增加超时时间或使用备用模型。图编译失败节点未正确定义或边指向不存在的节点。检查workflow.add_node和workflow.add_edge的节点名称是否一致。确保所有被边引用的节点都已通过add_node添加。12. 最佳实践与使用建议从简单开始先构建一个只有 2-3 个节点的最小可行图确保基础流程能跑通再逐步增加复杂性。善用 LangSmith 调试在开发初期就配置好 LangSmith它是你理解 Agent 内部运行的最强工具。多用它的“Playground”功能交互式调试提示词。状态设计要精简只把需要在节点间传递的信息放入 State。避免状态过于庞大影响可读性和性能。节点功能要单一每个节点最好只完成一件明确的事情。这有利于复用、测试和调试。为关键决策点添加人工审核在涉及重大业务逻辑如医疗诊断结论、金融审批的路由条件处可以设计节点将决策抛给人工确保安全可控。编写单元测试为每个节点函数和条件路由函数编写单元测试模拟不同的输入状态验证其输出是否符合预期。版本控制与文档使用 Git 管理你的 Agent 图定义和提示词。对复杂的业务逻辑绘制流程图作为文档。通过这个医疗问诊 Agent 的构建之旅你应该能清晰地看到 LangChain、LangGraph 和 LangSmith 是如何各司其职又紧密协作的。LangChain 提供了构建智能体的砖瓦LangGraph 提供了组装这些砖瓦的蓝图和粘合剂而 LangSmith 则提供了检验这栋建筑质量的全套检测仪器。下次当你需要构建一个涉及多步骤决策、状态管理和工具调用的复杂 AI 应用时不妨回想这个“医院”的比喻它会帮你找到清晰的技术选型和实现路径。 30款热门AI模型一站整合DeepSeek/GLM/Qwen 随心用限时 5 折。 点击领海量免费额度