- 在继续操作前收集保修信息。
- 将问题分类为硬件或软件问题。
- 提供解决方案或升级到人工支持。
- 在多轮对话中维护会话状态。
设置
安装
本教程需要langchain 包:
pip install langchain
uv add langchain
conda install langchain -c conda-forge
LangSmith
设置 LangSmith 以检查智能体内部发生的情况。然后设置以下环境变量:export LANGSMITH_TRACING="true"
export LANGSMITH_API_KEY="..."
import getpass
import os
os.environ["LANGSMITH_TRACING"] = "true"
os.environ["LANGSMITH_API_KEY"] = getpass.getpass()
选择一个LLM
从LangChain的集成套件中选择一个聊天模型:- OpenAI
- Anthropic
- Azure
- Google Gemini
- AWS Bedrock
- HuggingFace
- OpenRouter
👉 阅读 OpenAI 聊天模型集成文档
pip install -U "langchain[openai]"
import os
from langchain.chat_models import init_chat_model
os.environ["OPENAI_API_KEY"] = "sk-..."
model = init_chat_model("gpt-5.5")
import os
from langchain_openai import ChatOpenAI
os.environ["OPENAI_API_KEY"] = "sk-..."
model = ChatOpenAI(model="gpt-5.5")
👉 阅读 Anthropic 聊天模型集成文档
pip install -U "langchain[anthropic]"
import os
from langchain.chat_models import init_chat_model
os.environ["ANTHROPIC_API_KEY"] = "sk-..."
model = init_chat_model("claude-sonnet-4-6")
import os
from langchain_anthropic import ChatAnthropic
os.environ["ANTHROPIC_API_KEY"] = "sk-..."
model = ChatAnthropic(model="claude-sonnet-4-6")
👉 阅读 Azure 聊天模型集成文档
pip install -U "langchain[openai]"
import os
from langchain.chat_models import init_chat_model
os.environ["AZURE_OPENAI_API_KEY"] = "..."
os.environ["AZURE_OPENAI_ENDPOINT"] = "..."
os.environ["OPENAI_API_VERSION"] = "2025-03-01-preview"
model = init_chat_model(
"azure_openai:gpt-5.5",
azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"],
)
import os
from langchain_openai import AzureChatOpenAI
os.environ["AZURE_OPENAI_API_KEY"] = "..."
os.environ["AZURE_OPENAI_ENDPOINT"] = "..."
os.environ["OPENAI_API_VERSION"] = "2025-03-01-preview"
model = AzureChatOpenAI(
model="gpt-5.5",
azure_deployment=os.environ["AZURE_OPENAI_DEPLOYMENT_NAME"]
)
👉 阅读 Google GenAI 聊天模型集成文档
pip install -U "langchain[google-genai]"
import os
from langchain.chat_models import init_chat_model
os.environ["GOOGLE_API_KEY"] = "..."
model = init_chat_model("google_genai:gemini-2.5-flash-lite")
import os
from langchain_google_genai import ChatGoogleGenerativeAI
os.environ["GOOGLE_API_KEY"] = "..."
model = ChatGoogleGenerativeAI(model="gemini-2.5-flash-lite")
👉 阅读 AWS Bedrock 聊天模型集成文档
pip install -U "langchain[aws]"
from langchain.chat_models import init_chat_model
# 请按照此页面的步骤配置您的凭证:
# https://docs.aws.amazon.com/bedrock/latest/userguide/getting-started.html
model = init_chat_model(
"us.anthropic.claude-sonnet-4-6",
model_provider="bedrock_converse",
)
from langchain_aws import ChatBedrock
model = ChatBedrock(model="us.anthropic.claude-sonnet-4-6")
👉 阅读 HuggingFace 聊天模型集成文档
pip install -U "langchain[huggingface]"
import os
from langchain.chat_models import init_chat_model
os.environ["HUGGINGFACEHUB_API_TOKEN"] = "hf_..."
model = init_chat_model(
"microsoft/Phi-3-mini-4k-instruct",
model_provider="huggingface",
temperature=0.7,
max_tokens=1024,
)
import os
from langchain_huggingface import ChatHuggingFace, HuggingFaceEndpoint
os.environ["HUGGINGFACEHUB_API_TOKEN"] = "hf_..."
llm = HuggingFaceEndpoint(
repo_id="microsoft/Phi-3-mini-4k-instruct",
temperature=0.7,
max_length=1024,
)
model = ChatHuggingFace(llm=llm)
👉 阅读 OpenRouter 聊天模型集成文档
pip install -U "langchain-openrouter"
import os
from langchain.chat_models import init_chat_model
os.environ["OPENROUTER_API_KEY"] = "sk-..."
model = init_chat_model(
"auto",
model_provider="openrouter",
)
import os
from langchain_openrouter import ChatOpenRouter
os.environ["OPENROUTER_API_KEY"] = "sk-..."
model = ChatOpenRouter(model="auto")
1. 定义自定义状态
首先,定义一个自定义状态模式来跟踪当前活动的步骤:from langchain.agents import AgentState
from typing_extensions import NotRequired
from typing import Literal
# 定义可能的流程步骤
SupportStep = Literal["warranty_collector", "issue_classifier", "resolution_specialist"]
class SupportState(AgentState):
"""客户支持工作流的状态。"""
current_step: NotRequired[SupportStep]
warranty_status: NotRequired[Literal["in_warranty", "out_of_warranty"]]
issue_type: NotRequired[Literal["hardware", "software"]]
current_step 字段是状态机模式的核心——它决定了每一轮加载哪个配置(提示词 + 工具)。
2. 创建管理流程状态的工具
创建更新工作流状态的工具。这些工具允许智能体记录信息并过渡到下一步。 关键是使用Command 来更新状态,包括 current_step 字段:
from langchain.tools import tool, ToolRuntime
from langchain.messages import ToolMessage
from langgraph.types import Command
@tool
def record_warranty_status(
status: Literal["in_warranty", "out_of_warranty"],
runtime: ToolRuntime[None, SupportState],
) -> Command:
"""记录客户的保修状态并过渡到问题分类。"""
return Command(
update={
"messages": [
ToolMessage(
content=f"保修状态已记录为: {status}",
tool_call_id=runtime.tool_call_id,
)
],
"warranty_status": status,
"current_step": "issue_classifier",
}
)
@tool
def record_issue_type(
issue_type: Literal["hardware", "software"],
runtime: ToolRuntime[None, SupportState],
) -> Command:
"""记录问题类型并过渡到解决方案专家。"""
return Command(
update={
"messages": [
ToolMessage(
content=f"问题类型已记录为: {issue_type}",
tool_call_id=runtime.tool_call_id,
)
],
"issue_type": issue_type,
"current_step": "resolution_specialist",
}
)
@tool
def escalate_to_human(reason: str) -> str:
"""将案例升级到人工支持专家。"""
# 在实际系统中,这将创建工单、通知员工等。
return f"正在升级到人工支持。原因: {reason}"
@tool
def provide_solution(solution: str) -> str:
"""为客户提供问题的解决方案。"""
return f"已提供解决方案: {solution}"
record_warranty_status 和 record_issue_type 如何返回更新数据(warranty_status、issue_type)和 current_step 的 Command 对象。这就是状态机的工作原理——工具控制工作流的进展。
3. 定义步骤配置
为每个步骤定义提示词和工具。首先,为每个步骤定义提示词:查看完整的提示词定义
查看完整的提示词定义
# 将提示词定义为常量以便引用
WARRANTY_COLLECTOR_PROMPT = """你是一位帮助解决设备问题的客户支持代理。
当前阶段: 保修验证
在此步骤中,你需要:
1. 热情地问候客户
2. 询问他们的设备是否在保修期内
3. 使用 record_warranty_status 记录他们的回答并移动到下一步
保持对话性和友好性。不要一次问多个问题。"""
ISSUE_CLASSIFIER_PROMPT = """你是一位帮助解决设备问题的客户支持代理。
当前阶段: 问题分类
客户信息: 保修状态为 {warranty_status}
在此步骤中,你需要:
1. 要求客户描述他们的问题
2. 确定是硬件问题(物理损坏、损坏的部件)还是软件问题(应用崩溃、性能问题)
3. 使用 record_issue_type 记录分类并移动到下一步
如果不清楚,在分类前先询问澄清问题。"""
RESOLUTION_SPECIALIST_PROMPT = """你是一位帮助解决设备问题的客户支持代理。
当前阶段: 解决方案
客户信息: 保修状态为 {warranty_status},问题类型为 {issue_type}
在此步骤中,你需要:
1. 对于软件问题:使用 provide_solution 提供故障排除步骤
2. 对于硬件问题:
- 如果在保修期内:使用 provide_solution 解释保修维修流程
- 如果超出保修期:escalate_to_human 处理付费维修选项
提供具体且有帮助的解决方案。"""
# 步骤配置:将步骤名称映射到(提示词、工具、必需状态)
STEP_CONFIG = {
"warranty_collector": {
"prompt": WARRANTY_COLLECTOR_PROMPT,
"tools": [record_warranty_status],
"requires": [],
},
"issue_classifier": {
"prompt": ISSUE_CLASSIFIER_PROMPT,
"tools": [record_issue_type],
"requires": ["warranty_status"],
},
"resolution_specialist": {
"prompt": RESOLUTION_SPECIALIST_PROMPT,
"tools": [provide_solution, escalate_to_human],
"requires": ["warranty_status", "issue_type"],
},
}
- 可以一目了然地查看所有步骤
- 添加新步骤(只需添加另一个条目)
- 理解工作流依赖关系(
requires字段) - 使用带有状态变量的提示模板(例如,
{warranty_status})
4. 创建基于步骤的中间件
创建读取状态中current_step 并应用相应配置的中间件。我们将使用 @wrap_model_call 装饰器来实现一个简洁的实现:
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse
from typing import Callable
@wrap_model_call
def apply_step_config(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse],
) -> ModelResponse:
"""根据当前步骤配置智能体行为。"""
# 获取当前步骤(首次交互默认为 warranty_collector)
current_step = request.state.get("current_step", "warranty_collector")
# 查找步骤配置
stage_config = STEP_CONFIG[current_step]
# 验证必需的状态是否存在
for key in stage_config["requires"]:
if request.state.get(key) is None:
raise ValueError(f"在达到 {current_step} 之前必须设置 {key}")
# 用状态值格式化提示词(支持 {warranty_status}、{issue_type} 等)
system_prompt = stage_config["prompt"].format(**request.state)
# 注入系统提示词和特定于步骤的工具
request = request.override(
system_prompt=system_prompt,
tools=stage_config["tools"],
)
return handler(request)
- 读取当前步骤:从状态中获取
current_step(默认为 “warranty_collector”)。 - 查找配置:在
STEP_CONFIG中查找匹配的条目。 - 验证依赖关系:确保必需的状态字段存在。
- 格式化提示词:将状态值注入提示词模板。
- 应用配置:覆盖系统提示词和可用工具。
request.override() 方法是关键——它允许我们根据状态动态更改智能体的行为,而无需创建单独的智能体实例。
5. 创建智能体
现在使用基于步骤的中间件和用于状态持久化的检查点创建智能体:from langchain.agents import create_agent
from langgraph.checkpoint.memory import InMemorySaver
# 从所有步骤配置中收集所有工具
all_tools = [
record_warranty_status,
record_issue_type,
provide_solution,
escalate_to_human,
]
# 创建具有基于步骤配置的智能体
agent = create_agent(
model,
tools=all_tools,
state_schema=SupportState,
middleware=[apply_step_config],
checkpointer=InMemorySaver(),
)
为什么需要检查点? 检查点在对话轮次之间维护状态。没有它,
current_step 状态会在用户消息之间丢失,从而破坏工作流。6. 测试工作流
测试完整的工作流:from langchain.messages import HumanMessage
from langchain_core.utils.uuid import uuid7
# 此对话线程的配置
thread_id = str(uuid7())
config = {"configurable": {"thread_id": thread_id}}
# 轮次 1: 初始消息 - 从 warranty_collector 步骤开始
print("=== 轮次 1: 保修信息收集 ===")
result = agent.invoke(
{"messages": [HumanMessage("你好,我的手机屏幕碎了")]},
config
)
for msg in result['messages']:
msg.pretty_print()
# 轮次 2: 用户回应保修信息
print("\n=== 轮次 2: 保修回应 ===")
result = agent.invoke(
{"messages": [HumanMessage("是的,还在保修期内")]},
config
)
for msg in result['messages']:
msg.pretty_print()
print(f"当前步骤: {result.get('current_step')}")
# 轮次 3: 用户描述问题
print("\n=== 轮次 3: 问题描述 ===")
result = agent.invoke(
{"messages": [HumanMessage("屏幕因为摔落而物理性碎裂")]},
config
)
for msg in result['messages']:
msg.pretty_print()
print(f"当前步骤: {result.get('current_step')}")
# 轮次 4: 解决方案
print("\n=== 轮次 4: 解决方案 ===")
result = agent.invoke(
{"messages": [HumanMessage("我该怎么办?")]},
config
)
for msg in result['messages']:
msg.pretty_print()
- 保修验证步骤:询问保修状态
- 问题分类步骤:询问问题,确定为硬件问题
- 解决方案步骤:提供保修维修说明
7. 理解状态转换
让我们跟踪每轮发生的情况:轮次 1: 初始消息
{
"messages": [HumanMessage("你好,我的手机屏幕碎了")],
"current_step": "warranty_collector" # 默认值
}
- 系统提示词:
WARRANTY_COLLECTOR_PROMPT - 工具:
[record_warranty_status]
轮次 2: 记录保修状态后
工具调用:record_warranty_status("in_warranty") 返回:
Command(update={
"warranty_status": "in_warranty",
"current_step": "issue_classifier" # 状态转换!
})
- 系统提示词:
ISSUE_CLASSIFIER_PROMPT(使用warranty_status="in_warranty"格式化) - 工具:
[record_issue_type]
轮次 3: 分类问题后
工具调用:record_issue_type("hardware") 返回:
Command(update={
"issue_type": "hardware",
"current_step": "resolution_specialist" # 状态转换!
})
- 系统提示词:
RESOLUTION_SPECIALIST_PROMPT(使用warranty_status和issue_type格式化) - 工具:
[provide_solution, escalate_to_human]
current_step 来驱动工作流,而中间件在下一轮通过应用相应的配置来响应。
8. 管理消息历史
随着智能体推进步骤,消息历史会增长。使用摘要中间件在保留对话上下文的同时压缩较早的消息:from langchain.agents import create_agent
from langchain.agents.middleware import SummarizationMiddleware
from langgraph.checkpoint.memory import InMemorySaver
agent = create_agent(
model,
tools=all_tools,
state_schema=SupportState,
middleware=[
apply_step_config,
SummarizationMiddleware(
model="gpt-5.4-mini",
trigger=("tokens", 4000),
keep=("messages", 10)
)
],
checkpointer=InMemorySaver(),
)
9. 增加灵活性:返回
某些工作流需要允许用户返回到先前的步骤以更正信息(例如,更改保修状态或问题分类)。然而,并非所有转换都有意义——例如,一旦退款处理完成,通常就无法返回。对于此支持工作流,我们将添加工具以返回到保修验证和问题分类步骤。如果你的工作流需要在大多数步骤之间进行任意转换,请考虑是否真的需要结构化工作流。当步骤遵循清晰的顺序进展,并且偶尔需要向后转换以进行更正时,此模式效果最佳。
@tool
def go_back_to_warranty() -> Command:
"""返回保修验证步骤。"""
return Command(update={"current_step": "warranty_collector"})
@tool
def go_back_to_classification() -> Command:
"""返回问题分类步骤。"""
return Command(update={"current_step": "issue_classifier"})
# 更新 resolution_specialist 配置以包含这些工具
STEP_CONFIG["resolution_specialist"]["tools"].extend([
go_back_to_warranty,
go_back_to_classification
])
RESOLUTION_SPECIALIST_PROMPT = """你是一位帮助解决设备问题的客户支持代理。
当前阶段: 解决方案
客户信息: 保修状态为 {warranty_status},问题类型为 {issue_type}
在此步骤中,你需要:
1. 对于软件问题:使用 provide_solution 提供故障排除步骤
2. 对于硬件问题:
- 如果在保修期内:使用 provide_solution 解释保修维修流程
- 如果超出保修期:escalate_to_human 处理付费维修选项
如果客户表示任何信息有误,请使用:
- go_back_to_warranty 更正保修状态
- go_back_to_classification 更正问题类型
提供具体且有帮助的解决方案。"""
result = agent.invoke(
{"messages": [HumanMessage("实际上,我搞错了——我的设备超出保修期了")]},
config
)
# 智能体将调用 go_back_to_warranty 并重新开始保修验证步骤
完整示例
以下是所有内容整合到一个可运行脚本中的示例:Show 完整代码
Show 完整代码
"""
客户支持状态机示例
此示例演示了状态机模式。
单个智能体根据 current_step 状态动态改变其行为,
为顺序信息收集创建一个状态机。
"""
from langchain_core.utils.uuid import uuid7
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import Command
from typing import Callable, Literal
from typing_extensions import NotRequired
from langchain.agents import AgentState, create_agent
from langchain.agents.middleware import wrap_model_call, ModelRequest, ModelResponse, SummarizationMiddleware
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage, ToolMessage
from langchain.tools import tool, ToolRuntime
model = init_chat_model("google_genai:gemini-3.6-flash")
# 定义可能的流程步骤
SupportStep = Literal["warranty_collector", "issue_classifier", "resolution_specialist"]
class SupportState(AgentState):
"""客户支持工作流的状态。"""
current_step: NotRequired[SupportStep]
warranty_status: NotRequired[Literal["in_warranty", "out_of_warranty"]]
issue_type: NotRequired[Literal["hardware", "software"]]
@tool
def record_warranty_status(
status: Literal["in_warranty", "out_of_warranty"],
runtime: ToolRuntime[None, SupportState],
) -> Command:
"""记录客户的保修状态并过渡到问题分类。"""
return Command(
update={
"messages": [
ToolMessage(
content=f"保修状态已记录为: {status}",
tool_call_id=runtime.tool_call_id,
)
],
"warranty_status": status,
"current_step": "issue_classifier",
}
)
@tool
def record_issue_type(
issue_type: Literal["hardware", "software"],
runtime: ToolRuntime[None, SupportState],
) -> Command:
"""记录问题类型并过渡到解决方案专家。"""
return Command(
update={
"messages": [
ToolMessage(
content=f"问题类型已记录为: {issue_type}",
tool_call_id=runtime.tool_call_id,
)
],
"issue_type": issue_type,
"current_step": "resolution_specialist",
}
)
@tool
def escalate_to_human(reason: str) -> str:
"""将案例升级到人工支持专家。"""
# 在实际系统中,这将创建工单、通知员工等。
return f"正在升级到人工支持。原因: {reason}"
@tool
def provide_solution(solution: str) -> str:
"""为客户提供问题的解决方案。"""
return f"已提供解决方案: {solution}"
# 将提示词定义为常量
WARRANTY_COLLECTOR_PROMPT = """你是一位帮助解决设备问题的客户支持代理。
当前步骤: 保修验证
在此步骤中,你需要:
1. 热情地问候客户
2. 询问他们的设备是否在保修期内
3. 使用 record_warranty_status 记录他们的回答并移动到下一步
保持对话性和友好性。不要一次问多个问题。"""
ISSUE_CLASSIFIER_PROMPT = """你是一位帮助解决设备问题的客户支持代理。
当前步骤: 问题分类
客户信息: 保修状态为 {warranty_status}
在此步骤中,你需要:
1. 要求客户描述他们的问题
2. 确定是硬件问题(物理损坏、损坏的部件)还是软件问题(应用崩溃、性能问题)
3. 使用 record_issue_type 记录分类并移动到下一步
如果不清楚,在分类前先询问澄清问题。"""
RESOLUTION_SPECIALIST_PROMPT = """你是一位帮助解决设备问题的客户支持代理。
当前步骤: 解决方案
客户信息: 保修状态为 {warranty_status},问题类型为 {issue_type}
在此步骤中,你需要:
1. 对于软件问题:使用 provide_solution 提供故障排除步骤
2. 对于硬件问题:
- 如果在保修期内:使用 provide_solution 解释保修维修流程
- 如果超出保修期:escalate_to_human 处理付费维修选项
提供具体且有帮助的解决方案。"""
# 步骤配置:将步骤名称映射到(提示词、工具、必需状态)
STEP_CONFIG = {
"warranty_collector": {
"prompt": WARRANTY_COLLECTOR_PROMPT,
"tools": [record_warranty_status],
"requires": [],
},
"issue_classifier": {
"prompt": ISSUE_CLASSIFIER_PROMPT,
"tools": [record_issue_type],
"requires": ["warranty_status"],
},
"resolution_specialist": {
"prompt": RESOLUTION_SPECIALIST_PROMPT,
"tools": [provide_solution, escalate_to_human],
"requires": ["warranty_status", "issue_type"],
},
}
@wrap_model_call
def apply_step_config(
request: ModelRequest,
handler: Callable[[ModelRequest], ModelResponse],
) -> ModelResponse:
"""根据当前步骤配置智能体行为。"""
# 获取当前步骤(首次交互默认为 warranty_collector)
current_step = request.state.get("current_step", "warranty_collector")
# 查找步骤配置
step_config = STEP_CONFIG[current_step]
# 验证必需的状态是否存在
for key in step_config["requires"]:
if request.state.get(key) is None:
raise ValueError(f"在达到 {current_step} 之前必须设置 {key}")
# 用状态值格式化提示词
system_prompt = step_config["prompt"].format(**request.state)
# 注入系统提示词和特定于步骤的工具
request = request.override(
system_prompt=system_prompt,
tools=step_config["tools"],
)
return handler(request)
# 从所有步骤配置中收集所有工具
all_tools = [
record_warranty_status,
record_issue_type,
provide_solution,
escalate_to_human,
]
# 创建具有基于步骤配置和摘要功能的智能体
agent = create_agent(
model,
tools=all_tools,
state_schema=SupportState,
middleware=[
apply_step_config,
SummarizationMiddleware(
model="gpt-5.4-mini",
trigger=("tokens", 4000),
keep=("messages", 10)
)
],
checkpointer=InMemorySaver(),
)
# ============================================================================
# 测试工作流
# ============================================================================
if __name__ == "__main__":
thread_id = str(uuid7())
config = {"configurable": {"thread_id": thread_id}}
result = agent.invoke(
{"messages": [HumanMessage("你好,我的手机屏幕碎了")]},
config
)
result = agent.invoke(
{"messages": [HumanMessage("是的,还在保修期内")]},
config
)
result = agent.invoke(
{"messages": [HumanMessage("屏幕因为摔落而物理性碎裂")]},
config
)
result = agent.invoke(
{"messages": [HumanMessage("我该怎么办?")]},
config
)
for msg in result['messages']:
msg.pretty_print()
后续步骤
Connect these docs to Claude, VSCode, and more via MCP for real-time answers.

