这次我们来看一个医疗问诊 Agent 的实现案例。这个项目不是一个具体的开源工具包,而是一个典型的 AI Agent 应用场景构建过程,它清晰地展示了如何利用 LangChain、LangGraph 和 LangSmith 这三个核心框架来打造一个具备复杂逻辑的智能体。对于想入门 AI Agent 开发,特别是想理解这几个框架如何协同工作的开发者来说,这个案例非常有价值。

它的核心不是提供一个“开箱即用”的医疗诊断工具,而是通过一个贴近实际的场景,拆解 Agent 开发中的关键环节:如何编排任务流程、如何管理状态、如何集成工具、以及如何调试和监控。本文将带你从零开始,理解如何将这些框架组合起来,构建一个能处理多轮对话、调用知识库、并生成结构化诊疗建议的智能体。

本文适合有一定 Python 基础,对 LLM 应用开发感兴趣,希望从“调用 API”进阶到“构建智能工作流”的开发者。我们将重点关注这三个框架的分工、集成方式、以及在实际开发中可能遇到的坑。虽然不涉及显存或 GPU 门槛,但我们会关注另一个关键“资源”:Token 消耗与 API 成本控制。

1. 核心能力速览:框架分工与项目定位

首先,我们需要明确 LangChain、LangGraph 和 LangSmith 在这个医疗问诊 Agent 项目中各自扮演的角色。它们不是三个可任选其一的替代品,而是构建生产级 Agent 的不同层面的工具。

能力项 说明 在医疗问诊 Agent 中的体现
LangChain 基础组件与标准接口 。提供与 LLM 对话、连接向量数据库、调用工具(如计算器、搜索)的标准模块。 用于封装与 OpenAI/Gemini 等模型的对话链(Chain),集成医疗知识库的检索器(Retriever),定义“症状分析”、“用药查询”等基础工具(Tool)。
LangGraph 复杂工作流与状态管理 。用于构建有状态、多步骤、带循环和条件分支的 Agent 执行图。 用于定义问诊流程:用户输入 -> 意图判断 -> 检索知识 -> 分析症状 -> 生成建议 -> 是否需要追问 -> (循环) -> 最终输出。它管理整个对话的“状态”(State)。
LangSmith 开发调试与运维监控 。提供链/图的跟踪、可视化、测试、评估和监控平台。 用于记录每一次问诊的完整执行轨迹,查看 LLM 的输入输出,分析耗时和 Token 消耗,评估 Agent 回复的质量,监控生产环境下的运行情况。
项目类型 AI Agent 应用开发示范 一个教学/示范性质的项目,展示如何将三个框架组合解决复杂问题。
硬件门槛 无特殊要求,依赖云 LLM API 主要成本为 LLM API 调用费用(如 OpenAI GPT-4)。本地运行只需能运行 Python 的环境。
核心功能 多轮医疗问诊、知识检索、结构化输出 模拟医生问诊流程,结合医学知识库,生成包含可能疾病、建议检查、生活建议的结构化回答。
适合场景 AI Agent 学习、复杂工作流原型开发、LLM 应用调试 开发者学习 Agent 架构,企业构建内部专家系统原型,需要可观测性的 LLM 应用场景。

简单来说: LangChain 提供了砖块(工具、记忆、检索),LangGraph 提供了设计图和施工流程(将砖块组装成有逻辑的房子),而 LangSmith 提供了监理和质检(确保房子盖得对、盖得好)。

2. 适用场景与使用边界

这个医疗问诊 Agent 案例主要服务于学习和原型验证目的。

它适合谁:

  1. AI 应用开发者 :想了解如何超越简单问答,构建具有复杂逻辑链的智能体。
  2. 技术决策者/架构师 :评估 LangChain 生态是否适合用于构建企业内部的智能客服、审批流程、诊断系统等。
  3. 学生与研究人员 :需要一个完整的、可运行的案例来理解 Agent 的架构思想和实现细节。

它能解决什么问题:

  1. 技术选型困惑 :直观展示 LangChain、LangGraph、LangSmith 分别做什么,以及为什么需要它们三者。
  2. 工作流设计样板 :提供一个包含“判断-执行-循环”的图结构样板,可快速修改用于其他领域(如法律咨询、技术支持)。
  3. 调试与监控实践 :给出一个从开发到观测的完整闭环,让开发者体验如何追踪一个复杂 Agent 的每一次内部决策。

它不适合什么场景:

  1. 直接用于真实医疗诊断 :这是一个技术演示项目,其医学知识库通常是公开的、通用的数据集(如医学百科),不具备临床诊断的准确性和权威性。 绝对不可 用于真实病情诊断。
  2. 开箱即用的生产系统 :它缺乏用户认证、数据加密、审计日志、模型备案等生产级功能,需要大量二次开发和合规改造。
  3. 替代简单的 LLM 调用 :如果需求只是单轮问答或文本总结,直接调用 LLM API 或使用 LangChain 的简单 Chain 即可,引入 LangGraph 会增加不必要的复杂度。

重要边界与合规提醒:

  • 非医疗设备 :本项目构建的 Agent 是软件原型,不属于医疗器械。任何涉及生命健康的领域,应用都必须遵循相关法律法规,并接受专业人员的监督。
  • 知识库版权 :使用的医学知识库必须确保来源合法,拥有使用授权。
  • 数据隐私 :如果处理真实用户问诊数据,必须实施严格的匿名化、加密和访问控制,符合《个人信息保护法》等数据安全法规。
  • 结果免责 :必须向最终用户明确提示,输出内容仅为参考信息,不能替代专业医生诊断。

3. 环境准备与前置条件

在开始构建之前,需要准备好基础的开发环境和必要的账户。

1. 基础开发环境:

  • 操作系统 :Windows 10/11, macOS, 或 Linux (如 Ubuntu 20.04+)。
  • Python 版本 :推荐 Python 3.10 或 3.11。避免使用 Python 3.12+ 可能存在的某些库兼容性问题。
  • 包管理工具 :使用 pip conda

2. 核心框架安装: 我们将安装 LangChain 的核心包、LangGraph 以及 LangSmith 的 SDK。

# 创建并激活虚拟环境(推荐)
python -m venv venv
# Windows:
venv\Scripts\activate
# Linux/macOS:
source venv/bin/activate

# 安装核心框架
pip install langchain langgraph langsmith

# 安装可选但常用的依赖
pip install openai tiktoken  # 用于 OpenAI 模型调用和 Token 计数
pip install chromadb pypdf  # 用于构建示例知识库(向量数据库和 PDF 解析)

3. 云服务 API 密钥:

  • LLM 提供商 :你需要一个 OpenAI API 密钥(或 Anthropic、Gemini 等 LangChain 支持的模型)。本项目以 OpenAI 为例。
    • 访问 OpenAI Platform 创建密钥。
    • 将密钥设置为环境变量:
      # Windows (PowerShell)
      $env:OPENAI_API_KEY="your-api-key-here"
      
      # Linux/macOS
      export OPENAI_API_KEY="your-api-key-here"
      
  • LangSmith 账户 (用于跟踪和监控):
    • 访问 LangSmith 注册并创建 API 密钥。
    • 同样设置为环境变量:
      export LANGCHAIN_API_KEY="your-langsmith-api-key-here"
      export LANGCHAIN_TRACING_V2="true"
      export LANGCHAIN_PROJECT="Medical-Agent-Demo" # 你的项目名
      
    • 设置后,所有运行记录将自动同步到你的 LangSmith 项目面板。

4. 知识库素材(可选,用于模拟检索): 准备一些医学相关的文本或 PDF 文件,例如公共卫生指南、疾病百科摘要等,用于构建一个本地的示例向量数据库。

4. 项目结构与核心模块搭建

我们按照“自底向上”的顺序来构建这个 Agent:先准备工具和知识,再定义单步动作,最后用图编排整个流程。

4.1 第一步:利用 LangChain 构建基础能力

首先,我们用 LangChain 创建这个 Agent 所需的“砖块”。

1. 创建 LLM 调用实例: 这是所有智能的源头。

from langchain_openai import ChatOpenAI

# 使用 GPT-4 或 GPT-3.5-Turbo。注意控制成本。
llm = ChatOpenAI(model="gpt-4-turbo-preview", temperature=0.1)
# temperature 调低使输出更稳定,适合任务型 Agent。

2. 创建医疗知识检索器: 模拟一个拥有医学知识的“大脑外挂”。

from langchain_community.document_loaders import PyPDFLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.vectorstores import Chroma
from langchain_openai import OpenAIEmbeddings

# 1. 加载文档 (示例:加载一个假设的“家庭医疗指南.pdf”)
loader = PyPDFLoader("./data/family_medical_guide.pdf") # 请准备你的PDF文件
documents = loader.load()

# 2. 分割文本
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
texts = text_splitter.split_documents(documents)

# 3. 创建向量数据库
embeddings = OpenAIEmbeddings() # 需要 OPENAI_API_KEY
vectorstore = Chroma.from_documents(texts, embeddings, persist_directory="./chroma_db")
retriever = vectorstore.as_retriever(search_kwargs={"k": 3}) # 检索最相关的3个片段

这段代码创建了一个本地向量数据库。在生产环境中,你可能需要连接已有的医学知识库或使用更专业的向量数据库如 Weaviate、Pinecone。

3. 定义 Agent 可用的工具: 工具是 Agent 与世界交互的手脚。我们定义几个简单的工具。

from langchain.tools import tool
from typing import Optional

@tool
def search_medical_knowledge(query: str) -> str:
    """根据用户问题,检索相关的医学知识。"""
    docs = retriever.get_relevant_documents(query)
    return "\n\n".join([doc.page_content for doc in docs])

@tool
def analyze_symptoms(symptom_description: str) -> str:
    """分析症状描述,初步归纳可能的疾病方向。调用LLM进行分析。"""
    from langchain_core.prompts import ChatPromptTemplate
    prompt = ChatPromptTemplate.from_messages([
        ("system", "你是一位经验丰富的全科医生助理。请根据以下症状描述,列出3-5种最可能的疾病方向,并简要说明理由。只输出分析结果。"),
        ("human", "症状:{symptoms}")
    ])
    chain = prompt | llm
    return chain.invoke({"symptoms": symptom_description}).content

@tool
def format_final_advice(disease_analysis: str, knowledge_context: str) -> str:
    """整合疾病分析和医学知识,生成最终给患者的建议,包括就医建议和家庭护理。"""
    from langchain_core.prompts import ChatPromptTemplate
    prompt = ChatPromptTemplate.from_messages([
        ("system", "你正在生成一份患者咨询报告。请基于疾病可能性分析和相关医学知识,生成一份结构清晰、语气关切的最终建议。"),
        ("human", "疾病可能性分析:\n{analysis}\n\n相关医学知识:\n{context}")
    ])
    chain = prompt | llm
    return chain.invoke({"analysis": disease_analysis, "context": knowledge_context}).content

现在,我们有了知识库 ( retriever )、大模型 ( llm ) 和三个工具 ( search_medical_knowledge , analyze_symptoms , format_final_advice )。接下来,需要用 LangGraph 把它们串起来。

5. 使用 LangGraph 编排问诊工作流

LangGraph 的核心是 State(状态) Graph(图) 。状态是一个字典,保存着对话的上下文;图由节点(函数)和边(条件)组成,定义了执行流程。

5.1 定义状态

首先,我们定义这个医疗问诊 Agent 需要记住哪些信息。

from typing import TypedDict, Annotated, List
import operator

class AgentState(TypedDict):
    """定义Agent的对话状态。"""
    # 用户输入
    user_input: str
    # 当前对话轮次
    conversation_turn: int
    # 从用户描述中提取的关键症状
    extracted_symptoms: str
    # 检索到的医学知识
    medical_knowledge: str
    # 症状分析结果
    symptom_analysis: str
    # 是否需要进一步追问(由LLM判断)
    need_clarification: bool
    # 追问的问题
    clarification_question: str
    # 最终输出的建议
    final_advice: str
    # 执行过程中的消息记录(用于LLM上下文)
    messages: Annotated[List, operator.add]

5.2 构建图节点

每个节点是一个函数,它读取和修改 State

节点1:路由节点(判断意图) 这是第一个节点,决定本次对话要做什么。

from langgraph.graph import StateGraph, END

def route_question(state: AgentState):
    """根据用户输入和历史,判断是开始新问诊、继续追问还是结束。"""
    from langchain_core.prompts import ChatPromptTemplate
    prompt = ChatPromptTemplate.from_messages([
        ("system", "你是医疗问诊Agent的调度中心。请分析用户输入。如果用户描述了新的症状,请说'new_case'。如果用户是在回答上一个追问,请说'clarify'。如果用户表示感谢或结束,请说'end'。只输出这三个词之一。"),
        ("human", "用户输入:{input}\n当前轮次:{turn}")
    ])
    chain = prompt | llm
    decision = chain.invoke({"input": state["user_input"], "turn": state["conversation_turn"]}).content.strip().lower()

    if decision == "new_case":
        return {"conversation_turn": state["conversation_turn"] + 1, "extracted_symptoms": state["user_input"]}
    elif decision == "clarify":
        return {"need_clarification": False} # 收到澄清,继续流程
    elif decision == "end":
        return {"final_advice": "感谢咨询,请保重身体。"}
    else:
        # 默认按新病例处理
        return {"conversation_turn": state["conversation_turn"] + 1, "extracted_symptoms": state["user_input"]}

节点2:检索知识节点

def retrieve_knowledge(state: AgentState):
    """根据提取的症状,检索相关医学知识。"""
    knowledge = search_medical_knowledge.invoke(state["extracted_symptoms"])
    return {"medical_knowledge": knowledge}

节点3:分析症状节点

def analyze_symptoms_node(state: AgentState):
    """调用工具分析症状。"""
    analysis = analyze_symptoms.invoke(state["extracted_symptoms"])
    return {"symptom_analysis": analysis}

节点4:判断是否需要追问节点

def should_clarify(state: AgentState):
    """根据现有信息,判断是否需要向用户追问更多细节。"""
    from langchain_core.prompts import ChatPromptTemplate
    context = f"症状:{state['extracted_symptoms']}\n初步分析:{state['symptom_analysis']}\n相关知识:{state['medical_knowledge'][:500]}..."
    prompt = ChatPromptTemplate.from_messages([
        ("system", "作为医生,根据现有信息,你是否需要询问患者更多细节(如症状持续时间、具体部位、年龄等)才能给出更靠谱的建议?如果需要,请生成一个具体的追问问题。如果不需要,请说'NO'。"),
        ("human", "{context}")
    ])
    chain = prompt | llm
    result = chain.invoke({"context": context}).content.strip()
    if result != "NO" and len(result) > 5:
        return {"need_clarification": True, "clarification_question": result}
    else:
        return {"need_clarification": False}

节点5:生成最终建议节点

def generate_advice(state: AgentState):
    """整合所有信息,生成最终建议。"""
    advice = format_final_advice.invoke({
        "disease_analysis": state["symptom_analysis"],
        "knowledge_context": state["medical_knowledge"]
    })
    return {"final_advice": advice}

节点6:生成追问节点

def ask_clarification(state: AgentState):
    """直接返回需要追问的问题。"""
    return {"final_advice": state["clarification_question"]}

5.3 组装图并设置条件边

现在,我们把所有节点组装起来,并定义它们之间的流转逻辑。

# 初始化图
workflow = StateGraph(AgentState)

# 添加节点
workflow.add_node("route", route_question)
workflow.add_node("retrieve", retrieve_knowledge)
workflow.add_node("analyze", analyze_symptoms_node)
workflow.add_node("decide_clarify", should_clarify)
workflow.add_node("generate", generate_advice)
workflow.add_node("ask", ask_clarification)

# 设置入口点
workflow.set_entry_point("route")

# 添加边(定义节点执行后的流向)
workflow.add_edge("route", "retrieve") # 路由后总是先检索知识
workflow.add_edge("retrieve", "analyze") # 检索后分析症状
workflow.add_edge("analyze", "decide_clarify") # 分析后决定是否追问

# 条件边:根据是否需要追问,决定下一步
from langgraph.graph import END
def decide_after_clarify(state):
    if state.get("need_clarification"):
        return "ask" # 需要追问,跳转到提问节点
    else:
        return "generate" # 不需要,直接生成建议

workflow.add_conditional_edges(
    "decide_clarify",
    decide_after_clarify,
    {
        "ask": "ask",
        "generate": "generate",
    }
)

# 设置终点
workflow.add_edge("ask", END) # 追问后,本轮结束,等待用户下一次输入(新一轮`route`)
workflow.add_edge("generate", END) # 生成建议后,本轮结束

# 编译图
app = workflow.compile()

至此,一个具备基本多轮对话能力的医疗问诊 Agent 图就构建完成了。你可以通过 app.invoke() 来运行它。

6. 运行、测试与 LangSmith 监控

6.1 运行你的 Agent

# 初始化一个状态
initial_state = {
    "user_input": "我最近三天一直头痛,还有点发烧。",
    "conversation_turn": 0,
    "extracted_symptoms": "",
    "medical_knowledge": "",
    "symptom_analysis": "",
    "need_clarification": False,
    "clarification_question": "",
    "final_advice": "",
    "messages": []
}

# 运行图
try:
    final_state = app.invoke(initial_state)
    print("=== 最终建议 ===")
    print(final_state["final_advice"])
except Exception as e:
    print(f"运行出错:{e}")

6.2 在 LangSmith 中查看执行轨迹

这是 LangSmith 的核心价值所在。只要你正确设置了 LANGCHAIN_API_KEY ,上面的 app.invoke() 调用会自动在 LangSmith 上创建一次跟踪(Trace)。

  1. 打开 LangSmith 并登录。
  2. 进入你设置的项目(如 Medical-Agent-Demo )。
  3. 你应该能看到刚刚运行的记录。点击进入详情。
  4. 在这里,你可以看到:
    • 完整的执行流程图 :清晰地展示了从 route retrieve analyze decide_clarify ,再到 generate ask 的完整路径。
    • 每个节点的输入输出 :点击任意节点,可以看到调用工具时的具体参数、LLM 的 Prompt 和 Response。
    • 耗时分析 :每个步骤花费的时间,帮你定位性能瓶颈。
    • Token 消耗 :每次调用 LLM 消耗的 Token 数,用于成本核算。
    • 异常信息 :如果运行出错,会在这里清晰显示。

通过 LangSmith,调试 Agent 从“黑盒”变成了“白盒” 。你可以精确地知道是哪个节点的 LLM 判断失误,还是工具调用返回了空信息,从而有针对性地优化 Prompt 或逻辑。

7. 功能测试与效果验证策略

对于这样一个工作流复杂的 Agent,测试不能只靠一次运行。我们需要系统性地验证各个环节。

测试类型 测试目的 输入示例 预期结果与成功标准
单轮完整问诊 验证主流程是否通畅。 “我喉咙痛,咳嗽有黄痰。” 1. 成功检索到“上呼吸道感染”等相关知识。
2. 症状分析节点输出合理的疾病可能性列表。
3. 最终生成包含“建议就医”、“多喝水”等要点的结构化建议。
触发追问分支 验证条件逻辑是否正确。 “我肚子疼。”(信息不完整) 1. decide_clarify 节点判断 need_clarification 为 True。
2. 流程走向 ask 节点。
3. 最终输出一个具体的追问问题,如“请问疼痛具体在哪个部位?是左上腹还是右下腹?”
多轮对话衔接 验证状态管理是否有效。 第一轮: “我头痛。” -> Agent追问: “是哪种痛?胀痛还是刺痛?”
第二轮: “是胀痛,还有点头晕。”
1. 第二轮输入时, route 节点能正确识别为 clarify
2. Agent 能结合第一轮的症状(头痛)和第二轮的澄清(胀痛、头晕)进行综合分析和检索。
3. 最终建议应比第一轮更精准。
知识检索有效性 验证向量数据库是否工作。 输入一个知识库中存在的特定术语,如“糖尿病足护理”。 retrieve 节点返回的 medical_knowledge 字段包含相关文本片段,而不是无关内容。
异常输入处理 验证鲁棒性。 输入“谢谢,不用了。”或无关文本“今天天气真好”。 1. route 节点能识别为 end 或合理处理。
2. 流程正常结束,不抛出未处理异常。
LangSmith 跟踪 验证可观测性。 任何一次正常调用。 在 LangSmith 平台能查到本次运行的完整轨迹图,所有节点的输入输出可见。

效果验证的核心 :不仅要看最终输出是否“通顺”,更要通过 LangSmith 跟踪 ,检查每个中间节点的决策是否符合预期。例如, should_clarify 节点生成的追问问题是否具体、必要? route 节点的意图分类是否准确?

8. 资源占用、性能与成本观察

对于此类基于云 LLM API 的 Agent,主要“资源”是 API 调用成本 响应延迟

1. Token 消耗与成本:

  • 主要消耗点
    • route_question :每次用户输入都调用,但 Prompt 短,消耗少。
    • analyze_symptoms format_final_advice :这两个节点包含主要分析任务,Prompt 较长,消耗 Token 最多。
    • should_clarify :每次判断是否追问时调用。
    • search_medical_knowledge :检索本身不消耗 Token,但检索到的文本会作为上下文送入后续的 LLM 调用, 显著增加 Token 数
  • 优化策略
    • 知识检索优化 :调整 search_kwargs={"k": 3} 中的 k 值,返回更少但更精确的片段。使用 MMR 等搜索类型去重。
    • 上下文压缩 :在将检索结果喂给 LLM 前,使用 ContextualCompressionRetriever 进行摘要或过滤。
    • 选择模型 :在非核心分析环节(如 route )使用更便宜的模型(如 gpt-3.5-turbo )。

2. 响应延迟:

  • 主要瓶颈
    • LLM API 调用 :尤其是 GPT-4,每次生成响应可能有数百毫秒到数秒的延迟。
    • 网络延迟 :与 OpenAI 服务器的网络状况。
    • 检索延迟 :如果向量数据库在远程或数据量大,检索可能变慢。
  • 优化策略
    • 异步调用 :LangGraph 支持异步节点,如果流程中某些步骤不严格依赖前序结果,可考虑异步执行。
    • 缓存 :对频繁出现的相似用户查询(如“感冒症状”),可以使用 LangChain 的缓存组件,避免重复调用 LLM 和检索。
    • 本地小模型 :对于路由、分类等简单任务,可尝试使用本地部署的小模型(如通过 Ollama 运行 llama3 ),大幅降低延迟和成本。

3. 本地资源占用:

  • 内存/CPU :运行 LangChain/LangGraph 脚本本身占用很小。主要压力来自:
    • 向量数据库 :Chroma 在本地运行时会加载索引到内存。知识库越大,内存占用越高。
    • 嵌入模型 :如果使用本地嵌入模型(如 all-MiniLM-L6-v2 ),推理时需要 CPU/GPU 资源。
  • 磁盘空间 :用于存储向量数据库索引文件( ./chroma_db )和缓存的模型文件。

9. 常见问题与排查方法

在开发此类 Agent 时,你会遇到一些典型问题。以下是排查思路。

问题现象 可能原因 排查方式 解决方案
运行时报 KeyError State 中引用了尚未定义的键。 检查报错行数,对应节点的返回值字典中是否包含了 State 中定义的所有必需键? 确保每个节点函数返回的字典键名与 AgentState 定义完全一致。初始化 initial_state 时给所有键赋初始值(空字符串或空列表)。
Agent 陷入死循环 条件边逻辑有误,导致在两个节点间来回跳转。 在 LangSmith 中查看执行轨迹图,检查循环发生在哪两个节点之间。检查 decide_after_clarify 这类条件函数的逻辑。 确保条件函数返回的结果一定能映射到某个已定义的边。为循环设置最大迭代次数,在 State 中添加 step_count 并在图中检查。
LLM 调用超时或失败 API 密钥错误、网络问题、额度不足、模型超载。 查看 LangSmith 中失败节点的详细日志。在代码中捕获 openai.APIError 异常。 检查环境变量 OPENAI_API_KEY 。添加重试机制(LangChain 内置)。考虑切换模型或备用 API 端点。
知识检索结果不相关 嵌入模型不匹配、文本分割不当、搜索参数 k 值不合适。 检查检索到的文本片段,看是否与查询语义相关。尝试不同的 chunk_size chunk_overlap 优化文本分割策略。尝试不同的嵌入模型。使用混合搜索(MMR)平衡相关性与多样性。清洗知识库源数据。
route 节点判断不准 Prompt 指令不清晰或示例不足。 在 LangSmith 中查看 route 节点的输入和输出,看 LLM 是否误解了指令。 优化 Prompt,提供更明确的指令和少量示例(Few-shot)。或者,使用更简单的规则(如关键词匹配)进行初筛。
最终建议空洞或格式化错误 format_final_advice 工具的 Prompt 不够具体,或输入信息质量差。 检查输入给该工具的参数 disease_analysis knowledge_context 是否充实。 强化该工具的 Prompt,要求其以特定格式(如 Markdown 列表)输出。在前置节点确保输入信息的质量。
LangSmith 看不到跟踪记录 环境变量未生效、项目名错误、网络问题。 1. 在 Python 中打印 os.getenv(“LANGCHAIN_API_KEY”) 确认。
2. 检查 LangSmith 网站上的项目名是否匹配。
确保在运行脚本的终端中正确设置了环境变量。检查 LANGCHAIN_TRACING_V2 是否为 ”true”

10. 最佳实践与项目演进建议

基于这个医疗问诊 Agent 原型,你可以遵循以下实践将其变得更实用、更健壮。

1. 工程化与代码组织:

  • 模块化 :将工具定义、图构建、状态定义、Prompt 模板分别放在不同的 .py 文件中。
  • 配置管理 :使用 pydantic-settings python-dotenv 管理 API 密钥、模型名称、检索参数等配置。
  • 版本控制 :对 Prompt、图结构、工具定义进行版本管理,便于回滚和对比实验。

2. 提升 Agent 能力:

  • 更复杂的工具 :集成真实的医疗 API(需合规授权),如药品数据库查询、医院科室推荐。
  • 记忆机制 :使用 LangChain 的 ConversationBufferMemory ConversationSummaryMemory ,让 Agent 记住更长的对话历史。
  • 多智能体协作 :使用 LangGraph 的 MultiAgent 特性,模拟“分诊护士”、“专科医生”、“药剂师”等多个角色协作问诊。
  • 流式输出 :对于最终建议,实现逐字或逐句的流式输出,提升用户体验。

3. 强化评估与监控:

  • 定义评估指标 :在 LangSmith 中创建数据集,定义“建议相关性”、“医学安全性”、“回答完整性”等评估标准。
  • 自动化测试 :编写 pytest 用例,模拟各种用户输入,确保核心流程稳定。
  • 生产环境监控 :利用 LangSmith 的监控功能,设置警报,关注异常高的失败率或延迟。

4. 合规与安全加固:

  • 输入输出过滤 :对用户输入和 Agent 输出进行敏感词过滤和内容安全审核。
  • 审计日志 :记录所有用户交互和 Agent 决策,满足合规审计要求。
  • 医生审核回路 :设计机制,将高风险或不确定的建议标记出来,交由人类医生复核。

构建一个实用的 AI Agent 是一个迭代过程。从这个医疗问诊的案例出发,理解 LangChain、LangGraph、LangSmith 如何各司其职,你就掌握了拆解复杂问题、设计工作流、并实现可观测、可调试智能系统的核心方法。接下来,你可以尝试将这套架构应用到客服、教育、内容创作等更多领域,打造真正解决实际问题的智能体。

更多推荐