day17-LangGraph之智能导游案例-本地服务等
今日内容
1 LangGraph 介绍
1.1 LangGraph是什么
# 1 LangGraph = 用「流程图 / 状态机」的方式,搭建可控、可循环、可回溯的 LLM 应用。
-如果有同学用过Coze
-使用代码编写出 类 Coze拖拖拽拽出来的智能体
-智能导游
-AI医生
-。。。。
# 2 它是 LangChain 官方推出的新一代框架,专门解决:
复杂多步骤 AI
多轮对话
智能体(Agent)
带判断、循环、重试的工作流
# 3 总结 :【流程图】 编程框架
-流程图:如下图

1.2 LangGraph核心作用
# 1 LangGraph 能让我们做到 LangChain 很难做到、甚至做不到的事:
## 1.1 流程完全可控
能精确控制:先做什么、再做什么、满足什么条件走哪条路。
## 1.2 支持条件分支
检索不到内容 → 直接回答
检索到内容 → 走 RAG 回答
回答不满意 → 重新检索 / 重新生成
## 1.3 支持循环、重试、反思
比如:思考 → 工具调用 → 观察结果 → 再思考 → 再调用
这是真正智能体的基础。
之前langChain: 用户问题---》大模型--》调工具--》大模型--》返回给用户
## 1.4 内置状态管理(State)
所有数据(问题、历史、上下文、结果)统一管理,不用自己写一堆变量。
## 1.5 可回溯、可调试、可恢复
每一步都存状态,崩溃了能恢复,能看到每一步做了什么。
## 1.6 天然适合做 Agent
多智能体协作,LangGraph 是目前最舒服的方案。

1.3 LangGraph VS LangChain
# 1 LangChain = 链条(Chain)
## 1.1 线性执行
A → B → C → D
走完就结束,不能回头、不能判断、不能循环。
## 1.2 适合
简单 RAG
单轮问答
固定步骤的小应用
# 2 LangGraph = 图(Graph) 流程图
## 2.1 流程图执行
可以:
分支
循环
跳转
重试
多节点并行
## 2.2 适合
复杂智能体(Agent)
多轮对话
带思考、工具调用的系统
企业级工作流
# 3 总结:LangChain 是 “流水线”,LangGraph 是 “可控制、可循环、可判断的智能流程图”。
# 4 例子:
1 LangChain:自动售货机
投币---》选择商品---》出货
流程固定,不能改,不能回头,不能判断
2 LangGraph:去餐厅点菜
1 我们问有什么特色菜
2 服务员推荐菜
3 查询是否还有 菜
4 有--》厨师炒菜
5 没有--》告诉客户--》重新点别的
6 上菜后--》不好吃
7 重做、退钱
8 满意--》结账
整个流程,就是 LangGraph
1.4 LangGraph能做什么
#LangChain能做的,LangGraph都能做,但是LangGraph 比 LangChain 强 多 倍的智能体项目:
带思考的智能客服
能反思、能纠错的 RAG 系统
自主调用工具的 AI 助手(查资料、查天气、算数据)
多轮对话 + 记忆 + 状态管理
多智能体协作系统(研究员 + 分析师 + 文案 + 审稿)
企业级 LLM 工作流
1.5 LangGraph知识点
# 1 安装
# 2 快速开始:图api和函数api
-6步
# 3 项目级开发:应用程序结构
# 4 LangSmith部署和调用
# 5 本地运行 LangGraph项目
# 6 工作流和智能体
-LangGraph 不同工作模式
-LangGraph 能够做的案例
# 7 持久化
# 8 持久执行
# 9 流式处理
# 10 中断
# 11 时间旅行
# 12 内存
# 13 子图
1.6 快速案例【只需要了解】
了解LangGraph的核心功能和执行流程----》完全学完--》再回来看这个项目
1.6.1 智能导游-日志版
# 1 功能:
用户输入:城市,预算,旅行天数,用户偏好
推荐出旅行计划:先 生成计划后--》判断--》如果预算超了--》重新生成--》最终给用户
# 2 使用 LangGraph 最新:1.1.2
# 3 安装模块:
pip install langgraph langchain-openai python-dotenv
import os
import re
import logging
from dotenv import load_dotenv
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from typing import TypedDict, List
from langchain_core.messages import HumanMessage
##### 1 看到 图的执行流程【流程图执行流程】---》日志方式看
#######通过日志方式记录执行流程##########
# 配置全局日志格式和级别
logging.basicConfig(
level=logging.DEBUG, # 开启DEBUG级别,打印所有关键日志
format="%(asctime)s - %(name)s - %(levelname)s - %(message)s", # 日志格式(时间-模块-级别-内容)
handlers=[logging.StreamHandler()] # 输出到控制台,不输出到文件中
)
# 1.1 开启langgraph核心模块的日志(执行流程、节点调用、状态变化)
logging.getLogger("langgraph").setLevel(logging.DEBUG)
logging.getLogger("langgraph.executor").setLevel(logging.DEBUG)
logging.getLogger("langgraph.graph").setLevel(logging.INFO) # 图结构日志设为INFO,避免冗余
############## 2 导入环境变量##########
load_dotenv()
########## 3 Graph 核心:全局状态管理,存储数据:旅行计划状态##############
class TravelPlanState(TypedDict): # 整个图运行过程中,所需要的所有变量都放在类中
city: str # 城市
days: int # 天数
budget: float
user_preference: str # 偏好
attraction_plan: str
food_plan: str
total_cost: float
is_budget_ok: bool # 预算是否足够
final_plan: str # 最终方案
conversation_history: list
############### 4 初始化大模型##########
llm = ChatOpenAI(
model=os.getenv("MODEL_NAME"),
api_key=os.getenv("API_KEY"),
base_url=os.getenv("BASE_URL"),
)
###### 4 编辑工具函数 一 处理数据格式--》大模型生成的方案中会有金额
## 解析数字函数
def extract_numeric_value(s: str) -> float | None:
"""从字符串中提取最后一个数字(处理运算式/文字干扰)"""
numbers = re.findall(r'\d+\.?\d*', s)
if not numbers:
return None
last_num = numbers[-1]
try:
return float(last_num)
except ValueError:
return None
## 校验数字函数
def validate_numeric_input(input_str: str, input_type: str) -> int | float | None:
"""校验天数/预算输入合法性"""
try:
if input_type == "days":
num = int(input_str)
if num < 1 or num > 30:
print("❌ 天数需在1-30之间,请重新输入!")
return None
return num
elif input_type == "budget":
num = float(input_str)
if num < 100:
print("❌ 预算需≥100元,请重新输入!")
return None
return num
except ValueError:
print(f"❌ 请输入合法的{input_type}数字!")
return None
##### 5 核心函数:放在图的节点上
# 5.1 获取用户偏好:网红,特种兵,穷游,打开。。。
def get_user_preference(state: TravelPlanState) -> TravelPlanState:
"""获取用户真实偏好输入"""
if state.get("user_preference") and state["user_preference"].strip():
return state
print("\n📋 请补充你的旅行偏好(帮助我们生成更贴合的规划)")
print("示例:亲子友好、偏爱本地小吃、性价比高、喜欢自然风光、网红打卡等")
while True:
preference = input("请输入你的旅行偏好(不能为空):").strip()
if preference:
break
print("❌ 偏好不能为空,请重新输入!")
state["conversation_history"].append(f"用户输入偏好:{preference}")
return {"user_preference": preference, "conversation_history": state["conversation_history"]}
# 5.2 景点推荐师
def plan_attractions(state: TravelPlanState) -> TravelPlanState:
"""景点规划师"""
prompt = f"""
请为用户规划{state['city']} {state['days']}天的景点行程,要求:
1. 贴合用户偏好:{state['user_preference']}
2. 行程合理,不赶时间
3. 给出每个景点的预估门票费用
4. 最后汇总景点相关总费用(仅输出数字,单位元,不要加任何符号/文字)
格式:
行程:[详细行程描述]
景点总费用:[纯数字]
"""
response = llm.invoke([HumanMessage(content=prompt)])
content = response.content
plan_part = content.split("景点总费用:")[0].replace("行程:", "").strip()
cost_part = content.split("景点总费用:")[1].strip()
attraction_cost = extract_numeric_value(cost_part)
if attraction_cost is None:
attraction_cost = 0.0
print(f"⚠️ 景点费用提取失败,默认赋值0元(原始字符串:{cost_part})")
state["conversation_history"].append(f"生成景点规划:{plan_part[:50]}...")
return {
"attraction_plan": plan_part,
"total_cost": attraction_cost,
"conversation_history": state["conversation_history"]
}
## 5.2 食物推荐师
def plan_food(state: TravelPlanState) -> TravelPlanState:
"""美食推荐师"""
prompt = f"""
请为用户规划{state['city']} {state['days']}天的美食行程,要求:
1. 贴合用户偏好:{state['user_preference']}
2. 推荐本地特色小吃/餐厅,标注人均消费
3. 最后汇总美食相关总费用(仅输出数字,单位元,不要加任何符号/文字)
格式:
美食规划:[详细美食推荐]
美食总费用:[纯数字]
"""
response = llm.invoke([HumanMessage(content=prompt)])
content = response.content
food_plan_part = content.split("美食总费用:")[0].replace("美食规划:", "").strip()
food_cost_part = content.split("美食总费用:")[1].strip()
food_cost = extract_numeric_value(food_cost_part)
if food_cost is None:
food_cost = 0.0
print(f"⚠️ 美食费用提取失败,默认赋值0元(原始字符串:{food_cost_part})")
total_cost = state["total_cost"] + food_cost
state["conversation_history"].append(f"生成美食规划:{food_plan_part[:50]}...")
return {
"food_plan": food_plan_part,
"total_cost": total_cost,
"conversation_history": state["conversation_history"]
}
## 5.3 预算审核师:检查预算是否超了
def check_budget(state: TravelPlanState) -> TravelPlanState:
"""预算审核师"""
budget = state["budget"]
total_cost = state["total_cost"]
is_budget_ok = total_cost <= budget
reflection = f"预算{'达标' if is_budget_ok else '超支'}:预估{total_cost}元 {'≤' if is_budget_ok else '>'} 预算{budget}元"
state["conversation_history"].append(f"预算审核:{reflection}")
print(f"【预算审核】{reflection}")
return {"is_budget_ok": is_budget_ok, "conversation_history": state["conversation_history"]}
## 5.4 重新规划
def re_plan(state: TravelPlanState) -> TravelPlanState:
"""重新规划(预算超支时)"""
prompt = f"""
用户去{state['city']}旅行{state['days']}天,预算{state['budget']}元,当前预估{state['total_cost']}元(超支)。
请优化景点+美食规划,降低成本至预算内,保留核心体验,贴合偏好:{state['user_preference']}。
格式:
优化后景点行程:[内容]
优化后美食规划:[内容]
优化后总费用:[纯数字]
"""
response = llm.invoke([HumanMessage(content=prompt)])
content = response.content
attraction_plan = content.split("优化后景点行程:")[1].split("优化后美食规划:")[0].strip()
food_plan = content.split("优化后美食规划:")[1].split("优化后总费用:")[0].strip()
total_cost_part = content.split("优化后总费用:")[1].strip()
total_cost = extract_numeric_value(total_cost_part)
if total_cost is None:
total_cost = 0.0
print(f"⚠️ 优化后费用提取失败,默认赋值0元(原始字符串:{total_cost_part})")
state["conversation_history"].append(f"重新规划:优化后总费用{total_cost}元")
return {
"attraction_plan": attraction_plan,
"food_plan": food_plan,
"total_cost": total_cost,
"is_budget_ok": total_cost <= state["budget"],
"conversation_history": state["conversation_history"]
}
## 5.5 生成最终方案
def generate_final_plan(state: TravelPlanState) -> TravelPlanState:
"""生成最终旅行方案"""
prompt = f"""
请整合以下信息,生成一份完整、美观的{state['city']} {state['days']}天旅行方案:
用户偏好:{state['user_preference']}
预算:{state['budget']}元(实际预估:{state['total_cost']}元)
景点行程:{state['attraction_plan']}
美食规划:{state['food_plan']}
要求:结构清晰,语言亲切,分模块展示(行程概览、每日安排、美食推荐、费用明细)。
"""
final_plan = llm.invoke([HumanMessage(content=prompt)]).content
state["conversation_history"].append("生成最终旅行方案")
return {"final_plan": final_plan, "conversation_history": state["conversation_history"]}
## 5.6 分支判断函数:预算审核分支判断
def budget_check_branch(state: TravelPlanState) -> str:
"""预算审核分支判断"""
return "generate_final_plan" if state["is_budget_ok"] else "re_plan"
############6 构建LangGraph##########
def build_travel_graph():
"""构建旅行规划图"""
# 6.1 构建graph:构建有状态的图,把TravelPlanState传入
graph = StateGraph(TravelPlanState)
# 6.2 添加节点
graph.add_node("get_user_preference", get_user_preference)
graph.add_node("plan_attractions", plan_attractions)
graph.add_node("plan_food", plan_food)
graph.add_node("check_budget", check_budget)
graph.add_node("re_plan", re_plan)
graph.add_node("generate_final_plan", generate_final_plan)
# 6.3 设置入口点和边:连线
graph.set_entry_point("get_user_preference")
graph.add_edge("get_user_preference", "plan_attractions")
graph.add_edge("plan_attractions", "plan_food")
graph.add_edge("plan_food", "check_budget")
graph.add_conditional_edges("check_budget", budget_check_branch)
graph.add_edge("re_plan", "check_budget")
graph.add_edge("generate_final_plan", END)
# 6.4 添加了节点--》节点连线完成--》编译--》构建好了有状态的图
return graph.compile()
######## 7 交互逻辑--》纯python逻辑###
def interactive_travel_planner():
"""交互式旅行规划系统"""
print("=" * 60)
print("🎫 AI 旅行规划师 - 支持日志查看执行过程")
print("=" * 60)
# 1 初始化状态
current_state = {
"city": "",
"days": 0,
"budget": 0.0,
"user_preference": "",
"attraction_plan": "",
"food_plan": "",
"total_cost": 0.0,
"is_budget_ok": False,
"final_plan": "",
"conversation_history": []
}
# 2 构建图
travel_graph = build_travel_graph()
# 3 交互循环
while True:
print("\n📌 请选择操作:")
print("1. 输入/修改旅行城市")
print("2. 输入/修改旅行天数")
print("3. 输入/修改旅行预算")
print("4. 生成旅行规划(会输出详细日志)")
print("5. 查看对话记录")
print("6. 退出系统")
choice = input("请输入操作编号(1-6):").strip()
if choice == "1":
city = input("请输入旅行城市:").strip()
if not city:
print("❌ 城市不能为空!")
continue
current_state["city"] = city
current_state["conversation_history"].append(f"设置城市:{city}")
print(f"✅ 已设置旅行城市:{city}")
elif choice == "2":
days_str = input("请输入旅行天数:").strip()
days = validate_numeric_input(days_str, "days")
if days:
current_state["days"] = days
current_state["conversation_history"].append(f"设置天数:{days}天")
print(f"✅ 已设置旅行天数:{days}天")
elif choice == "3":
budget_str = input("请输入旅行预算(元):").strip()
budget = validate_numeric_input(budget_str, "budget")
if budget:
current_state["budget"] = budget
current_state["conversation_history"].append(f"设置预算:{budget}元")
print(f"✅ 已设置旅行预算:{budget}元")
elif choice == "4":
# 校验基础信息
if not current_state["city"] or current_state["days"] == 0 or current_state["budget"] == 0.0:
print("❌ 请先完善城市、天数、预算信息!")
continue
print("\n🔄 正在生成旅行规划(控制台会输出详细日志)...")
# 执行图并获取结果(日志会自动输出)
result = travel_graph.invoke(current_state)
current_state = result
# 展示最终结果
print("\n" + "=" * 50)
print("🎯 最终旅行规划方案")
print("=" * 50)
print(result["final_plan"])
print("\n💰 费用明细:")
print(f"预算:{current_state['budget']} 元 | 实际预估:{result['total_cost']} 元")
print(f"预算是否达标:{'✅ 是' if result['is_budget_ok'] else '❌ 否'}")
elif choice == "5":
print("\n📝 对话记录:")
if not current_state["conversation_history"]:
print("暂无对话记录")
else:
for i, record in enumerate(current_state["conversation_history"], 1):
print(f"{i}. {record}")
elif choice == "6":
print("\n👋 感谢使用AI旅行规划师,再见!")
break
else:
print("❌ 输入无效,请选择1-6的操作编号!")
######### 8 启动############
if __name__ == "__main__":
interactive_travel_planner()
1.6.1 智能导游-生成流程图
# 1 LangGraph 是状态图
-最好:能看到图的样子--》当前项目生成状态图【我们写项目】
-LangGraph支持:需要借助于graphviz
-更好:当前项目图每一步的执行流程【演示】
-LangSmith支持
# 2 安装一个软件:graphviz---》生成有向图的软件--》使用它把LangGraph的流程图生成
# 2.1 彩色的--》第三方--》写的代码多【自己代码画】
# 2.1 黑白的--》LangGraph官方支持--》几行代码【根据LangGraph节点和连线生成】
# 1 下载软件: https://graphviz.org/download/
-安装版,点选加入环境变量
-解压版:手动配置环境变量
# 2 打开cmd:输入
dot --version
# 输出:dot - graphviz version 14.1.3 (20260303.0454)
# 3 python快速使用
# pip install graphviz
from graphviz import Graph
# 1 创建有向图
dot = Graph()
# 2 添加节点和边
dot.node('A', 'Node A')
dot.node('B', 'Node B')
dot.edge('A', 'B')
# 渲染和显示图形
dot.render('graph', format='png', view=True)
# 4 就会生成有向图



import os
import re
import logging
from dotenv import load_dotenv
from langgraph.graph import StateGraph, END
from langchain_openai import ChatOpenAI
from typing import TypedDict, List
from langchain_core.messages import HumanMessage
from graphviz import Digraph # 安装:pip install graphviz
##### 1 看到 图的执行流程【流程图执行流程】---》生成流程图
################ 扩展:生成流程图片的代码###############
def generate_travel_graphviz():
"""生成旅行规划流程图(graphviz)"""
# 初始化有向图
dot = Digraph(
name="TravelPlanner",
format="png", # 输出格式:png/svg/pdf均可
encoding="utf-8",
graph_attr={"rankdir": "TD", "fontname": "SimHei", "fontsize": "12"}, # 从上到下布局、支持中文
node_attr={"fontname": "SimHei", "fontsize": "10", "style": "filled"},
edge_attr={"fontname": "SimHei", "fontsize": "9"}
)
# 添加节点(自定义样式)
dot.node("get_user_preference", "获取用户偏好", shape="ellipse", fillcolor="#e6f7ff")
dot.node("plan_attractions", "景点规划", shape="box", fillcolor="#b3e0ff")
dot.node("plan_food", "美食规划", shape="box", fillcolor="#b3e0ff")
dot.node("check_budget", "预算审核", shape="diamond", fillcolor="#fff3cd")
dot.node("re_plan", "重新规划", shape="box", fillcolor="#ffd966")
dot.node("generate_final_plan", "生成最终方案", shape="box", fillcolor="#c1e1c1")
dot.node("end", "结束", shape="ellipse", fillcolor="#f8f9fa")
# 添加边(含条件分支标签)
dot.edge("get_user_preference", "plan_attractions")
dot.edge("plan_attractions", "plan_food")
dot.edge("plan_food", "check_budget")
dot.edge("check_budget", "generate_final_plan", label="预算达标")
dot.edge("check_budget", "re_plan", label="预算超支")
dot.edge("re_plan", "check_budget")
dot.edge("generate_final_plan", "end")
# 保存并渲染
dot.save("travel_planner.dot") # 保存DOT源文件
dot.render("travel_planner") # 生成PNG图片
print("✅ 流程图已生成:travel_planner.png(当前目录)")
############## 2 导入环境变量##########
load_dotenv()
########## 3 Graph 核心:全局状态管理,存储数据:旅行计划状态##############
class TravelPlanState(TypedDict): # 整个图运行过程中,所需要的所有变量都放在类中
city: str # 城市
days: int # 天数
budget: float
user_preference: str # 偏好
attraction_plan: str
food_plan: str
total_cost: float
is_budget_ok: bool # 预算是否足够
final_plan: str # 最终方案
conversation_history: list
############### 4 初始化大模型##########
llm = ChatOpenAI(
model=os.getenv("MODEL_NAME"),
api_key=os.getenv("API_KEY"),
base_url=os.getenv("BASE_URL"),
)
###### 4 编辑工具函数 一 处理数据格式--》大模型生成的方案中会有金额
## 解析数字函数
def extract_numeric_value(s: str) -> float | None:
"""从字符串中提取最后一个数字(处理运算式/文字干扰)"""
numbers = re.findall(r'\d+\.?\d*', s)
if not numbers:
return None
last_num = numbers[-1]
try:
return float(last_num)
except ValueError:
return None
## 校验数字函数
def validate_numeric_input(input_str: str, input_type: str) -> int | float | None:
"""校验天数/预算输入合法性"""
try:
if input_type == "days":
num = int(input_str)
if num < 1 or num > 30:
print("❌ 天数需在1-30之间,请重新输入!")
return None
return num
elif input_type == "budget":
num = float(input_str)
if num < 100:
print("❌ 预算需≥100元,请重新输入!")
return None
return num
except ValueError:
print(f"❌ 请输入合法的{input_type}数字!")
return None
##### 5 核心函数:放在图的节点上
# 5.1 获取用户偏好:网红,特种兵,穷游,打开。。。
def get_user_preference(state: TravelPlanState) -> TravelPlanState:
"""获取用户真实偏好输入"""
if state.get("user_preference") and state["user_preference"].strip():
return state
print("\n📋 请补充你的旅行偏好(帮助我们生成更贴合的规划)")
print("示例:亲子友好、偏爱本地小吃、性价比高、喜欢自然风光、网红打卡等")
while True:
preference = input("请输入你的旅行偏好(不能为空):").strip()
if preference:
break
print("❌ 偏好不能为空,请重新输入!")
state["conversation_history"].append(f"用户输入偏好:{preference}")
return {"user_preference": preference, "conversation_history": state["conversation_history"]}
# 5.2 景点推荐师
def plan_attractions(state: TravelPlanState) -> TravelPlanState:
"""景点规划师"""
prompt = f"""
请为用户规划{state['city']} {state['days']}天的景点行程,要求:
1. 贴合用户偏好:{state['user_preference']}
2. 行程合理,不赶时间
3. 给出每个景点的预估门票费用
4. 最后汇总景点相关总费用(仅输出数字,单位元,不要加任何符号/文字)
格式:
行程:[详细行程描述]
景点总费用:[纯数字]
"""
response = llm.invoke([HumanMessage(content=prompt)])
content = response.content
plan_part = content.split("景点总费用:")[0].replace("行程:", "").strip()
cost_part = content.split("景点总费用:")[1].strip()
attraction_cost = extract_numeric_value(cost_part)
if attraction_cost is None:
attraction_cost = 0.0
print(f"⚠️ 景点费用提取失败,默认赋值0元(原始字符串:{cost_part})")
state["conversation_history"].append(f"生成景点规划:{plan_part[:50]}...")
return {
"attraction_plan": plan_part,
"total_cost": attraction_cost,
"conversation_history": state["conversation_history"]
}
## 5.2 食物推荐师
def plan_food(state: TravelPlanState) -> TravelPlanState:
"""美食推荐师"""
prompt = f"""
请为用户规划{state['city']} {state['days']}天的美食行程,要求:
1. 贴合用户偏好:{state['user_preference']}
2. 推荐本地特色小吃/餐厅,标注人均消费
3. 最后汇总美食相关总费用(仅输出数字,单位元,不要加任何符号/文字)
格式:
美食规划:[详细美食推荐]
美食总费用:[纯数字]
"""
response = llm.invoke([HumanMessage(content=prompt)])
content = response.content
food_plan_part = content.split("美食总费用:")[0].replace("美食规划:", "").strip()
food_cost_part = content.split("美食总费用:")[1].strip()
food_cost = extract_numeric_value(food_cost_part)
if food_cost is None:
food_cost = 0.0
print(f"⚠️ 美食费用提取失败,默认赋值0元(原始字符串:{food_cost_part})")
total_cost = state["total_cost"] + food_cost
state["conversation_history"].append(f"生成美食规划:{food_plan_part[:50]}...")
return {
"food_plan": food_plan_part,
"total_cost": total_cost,
"conversation_history": state["conversation_history"]
}
## 5.3 预算审核师:检查预算是否超了
def check_budget(state: TravelPlanState) -> TravelPlanState:
"""预算审核师"""
budget = state["budget"]
total_cost = state["total_cost"]
is_budget_ok = total_cost <= budget
reflection = f"预算{'达标' if is_budget_ok else '超支'}:预估{total_cost}元 {'≤' if is_budget_ok else '>'} 预算{budget}元"
state["conversation_history"].append(f"预算审核:{reflection}")
print(f"【预算审核】{reflection}")
return {"is_budget_ok": is_budget_ok, "conversation_history": state["conversation_history"]}
## 5.4 重新规划
def re_plan(state: TravelPlanState) -> TravelPlanState:
"""重新规划(预算超支时)"""
prompt = f"""
用户去{state['city']}旅行{state['days']}天,预算{state['budget']}元,当前预估{state['total_cost']}元(超支)。
请优化景点+美食规划,降低成本至预算内,保留核心体验,贴合偏好:{state['user_preference']}。
格式:
优化后景点行程:[内容]
优化后美食规划:[内容]
优化后总费用:[纯数字]
"""
response = llm.invoke([HumanMessage(content=prompt)])
content = response.content
attraction_plan = content.split("优化后景点行程:")[1].split("优化后美食规划:")[0].strip()
food_plan = content.split("优化后美食规划:")[1].split("优化后总费用:")[0].strip()
total_cost_part = content.split("优化后总费用:")[1].strip()
total_cost = extract_numeric_value(total_cost_part)
if total_cost is None:
total_cost = 0.0
print(f"⚠️ 优化后费用提取失败,默认赋值0元(原始字符串:{total_cost_part})")
state["conversation_history"].append(f"重新规划:优化后总费用{total_cost}元")
return {
"attraction_plan": attraction_plan,
"food_plan": food_plan,
"total_cost": total_cost,
"is_budget_ok": total_cost <= state["budget"],
"conversation_history": state["conversation_history"]
}
## 5.5 生成最终方案
def generate_final_plan(state: TravelPlanState) -> TravelPlanState:
"""生成最终旅行方案"""
prompt = f"""
请整合以下信息,生成一份完整、美观的{state['city']} {state['days']}天旅行方案:
用户偏好:{state['user_preference']}
预算:{state['budget']}元(实际预估:{state['total_cost']}元)
景点行程:{state['attraction_plan']}
美食规划:{state['food_plan']}
要求:结构清晰,语言亲切,分模块展示(行程概览、每日安排、美食推荐、费用明细)。
"""
final_plan = llm.invoke([HumanMessage(content=prompt)]).content
state["conversation_history"].append("生成最终旅行方案")
return {"final_plan": final_plan, "conversation_history": state["conversation_history"]}
## 5.6 分支判断函数:预算审核分支判断
def budget_check_branch(state: TravelPlanState) -> str:
"""预算审核分支判断"""
return "generate_final_plan" if state["is_budget_ok"] else "re_plan"
############6 构建LangGraph##########
def build_travel_graph():
"""构建旅行规划图"""
###### 添加代码,画流程图#########
generate_travel_graphviz()
# 6.1 构建graph:构建有状态的图,把TravelPlanState传入
graph = StateGraph(TravelPlanState)
# 6.2 添加节点
graph.add_node("get_user_preference", get_user_preference)
graph.add_node("plan_attractions", plan_attractions)
graph.add_node("plan_food", plan_food)
graph.add_node("check_budget", check_budget)
graph.add_node("re_plan", re_plan)
graph.add_node("generate_final_plan", generate_final_plan)
# 6.3 设置入口点和边:连线
graph.set_entry_point("get_user_preference")
graph.add_edge("get_user_preference", "plan_attractions")
graph.add_edge("plan_attractions", "plan_food")
graph.add_edge("plan_food", "check_budget")
graph.add_conditional_edges("check_budget", budget_check_branch)
graph.add_edge("re_plan", "check_budget")
graph.add_edge("generate_final_plan", END)
# 6.4 添加了节点--》节点连线完成--》编译--》构建好了有状态的图
return graph.compile()
######## 7 交互逻辑--》纯python逻辑###
def interactive_travel_planner():
"""交互式旅行规划系统"""
print("=" * 60)
print("🎫 AI 旅行规划师 - 生成流程图")
print("=" * 60)
# 1 初始化状态
current_state = {
"city": "",
"days": 0,
"budget": 0.0,
"user_preference": "",
"attraction_plan": "",
"food_plan": "",
"total_cost": 0.0,
"is_budget_ok": False,
"final_plan": "",
"conversation_history": []
}
# 2 构建图
travel_graph = build_travel_graph()
# 3 交互循环
while True:
print("\n📌 请选择操作:")
print("1. 输入/修改旅行城市")
print("2. 输入/修改旅行天数")
print("3. 输入/修改旅行预算")
print("4. 生成旅行规划(会输出详细日志)")
print("5. 查看对话记录")
print("6. 退出系统")
choice = input("请输入操作编号(1-6):").strip()
if choice == "1":
city = input("请输入旅行城市:").strip()
if not city:
print("❌ 城市不能为空!")
continue
current_state["city"] = city
current_state["conversation_history"].append(f"设置城市:{city}")
print(f"✅ 已设置旅行城市:{city}")
elif choice == "2":
days_str = input("请输入旅行天数:").strip()
days = validate_numeric_input(days_str, "days")
if days:
current_state["days"] = days
current_state["conversation_history"].append(f"设置天数:{days}天")
print(f"✅ 已设置旅行天数:{days}天")
elif choice == "3":
budget_str = input("请输入旅行预算(元):").strip()
budget = validate_numeric_input(budget_str, "budget")
if budget:
current_state["budget"] = budget
current_state["conversation_history"].append(f"设置预算:{budget}元")
print(f"✅ 已设置旅行预算:{budget}元")
elif choice == "4":
# 校验基础信息
if not current_state["city"] or current_state["days"] == 0 or current_state["budget"] == 0.0:
print("❌ 请先完善城市、天数、预算信息!")
continue
print("\n🔄 正在生成旅行规划(控制台会输出详细日志)...")
# 执行图并获取结果(日志会自动输出)
result = travel_graph.invoke(current_state)
current_state = result
# 展示最终结果
print("\n" + "=" * 50)
print("🎯 最终旅行规划方案")
print("=" * 50)
print(result["final_plan"])
print("\n💰 费用明细:")
print(f"预算:{current_state['budget']} 元 | 实际预估:{result['total_cost']} 元")
print(f"预算是否达标:{'✅ 是' if result['is_budget_ok'] else '❌ 否'}")
elif choice == "5":
print("\n📝 对话记录:")
if not current_state["conversation_history"]:
print("暂无对话记录")
else:
for i, record in enumerate(current_state["conversation_history"], 1):
print(f"{i}. {record}")
elif choice == "6":
print("\n👋 感谢使用AI旅行规划师,再见!")
break
else:
print("❌ 输入无效,请选择1-6的操作编号!")
######### 8 启动############
if __name__ == "__main__":
interactive_travel_planner()

2 LangGraph核心
使用LangGraph创建状态图的步骤
图api:需要6步
函数api:需要4步
2.1 Graph API
# 1 定义模型和工具
# 2 定义状态
# 3 定义模型节点
# 4 定义工具节点
# 5 定义结束逻辑
# 6 构建并编译代理
# pip install langchain
from langchain.tools import tool
from langchain.chat_models import init_chat_model
from langchain_openai import ChatOpenAI
####################### 1 定义模型和工具#######
## 1.1 连接模型---》讲过--》底层使用 langchain-deepseek 如果没装会报错
# model=init_chat_model(
# model="deepseek-chat",
# api_key="sk-d7835fa8f2cd4908a284ebf48818581b",
# base_url="https://api.deepseek.com",
# )
## 1.1 连接模型---》讲过--》使用ChatOpenAI 通用接口,需要装langchain_openai
model = ChatOpenAI(
model="deepseek-chat",
api_key="sk-d7835fa8f2cd4908a284ebf48818581b",
base_url="https://api.deepseek.com",
)
## 1.2 定义工具 :乘 加 除 --》3个工具
@tool
def multiply(a: int, b: int) -> int:
"""将`a`和`b`相乘。
参数:
a: 第一个整数
b: 第二个整数
"""
return a * b
@tool
def add(a: int, b: int) -> int:
"""将`a`和`b`相加。
参数:
a: 第一个整数
b: 第二个整数
"""
return a + b
@tool
def divide(a: int, b: int) -> float:
"""将`a`除以`b`。
参数:
a: 第一个整数
b: 第二个整数
"""
return a / b
## 1.3 把工具绑定给模型--》学过
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)
######################## 2 定义状态-LangGraph的核心,定义 整个工作流中传递数据的结构:要用哪个变量,提前定义好,放在状态类中#########
from langchain.messages import AnyMessage
from typing_extensions import TypedDict, Annotated
import operator
class MessagesState(TypedDict):
messages: Annotated[list[AnyMessage], operator.add] # 存跟模型交互的消息
llm_calls: int # 记录模型被调用了多少次
######################### 3 定义模型节点--》传入当前state:修改 state中的字段:message和llm_calls
from langchain.messages import SystemMessage
def llm_call(state: dict):
"""LLM decides whether to call a tool or not"""
return {
"messages": [
model_with_tools.invoke(
[
SystemMessage(
content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
)
]
+ state["messages"]
)
], # 记录了所有交互的消息
"llm_calls": state.get('llm_calls', 0) + 1
}
######################### 4 定义工具节点:LLM在决定调用工具时触发
from langchain.messages import ToolMessage
def tool_node(state: dict):
"""Performs the tool call"""
result = []
for tool_call in state["messages"][-1].tool_calls:
tool = tools_by_name[tool_call["name"]]
observation = tool.invoke(tool_call["args"])
result.append(ToolMessage(content=observation, tool_call_id=tool_call["id"]))
return {"messages": result} # 把最新的消息加入到状态中
######################### 5 定义结束逻辑:边条件函数:检查最后一条消息
# 如果用户输入的 提示词,要调用工具--》走向调用工具
# 如果用户 提示词,不需要调用工具--》直接返回答案,走向end
from typing import Literal
from langgraph.graph import StateGraph, START, END
def should_continue(state: MessagesState) -> Literal["tool_node", END]:
"""Decide if we should continue the loop or stop based upon whether the LLM made a tool call"""
messages = state["messages"]
last_message = messages[-1]
# If the LLM makes a tool call, then perform an action
if last_message.tool_calls:
return "tool_node"
# Otherwise, we stop (reply to the user)
return END
######################### 6 构建并编译代理
# 6.1 实例化得到StateGraph,传入状态
agent_builder = StateGraph(MessagesState)
# 6.2 初始化图,添加节点
agent_builder.add_node("llm_call", llm_call)
agent_builder.add_node("tool_node", tool_node)
# 6.3 连线
agent_builder.add_edge(START, "llm_call")
# 条件分支:从llm出来后,执行 should_continue函数
# 如果返回 tool_node---》调用工具节点
# 如果饭盒 end --》直接结束
agent_builder.add_conditional_edges(
"llm_call",
should_continue,
["tool_node", END]
)
# 6.4 循环
agent_builder.add_edge("tool_node", "llm_call")
# 6.5 编译
agent = agent_builder.compile()
##### 7 生成状态图图片--》内置自动生成:根据节点和连线生成,步需要我们写太多代码--》直接生成:黑白的
png_data = agent.get_graph(xray=True).draw_mermaid_png()
with open('demo.png', "wb") as f:
f.write(png_data)
print('该项目状态图已经保存:demo.png')
###### 8 交互,调用
from langchain.messages import HumanMessage
messages = [HumanMessage(content="Add 3 and 4.")]
messages = agent.invoke({"messages": messages})
for m in messages["messages"]:
m.pretty_print()
'''经典的模式:ReAct模式:(Reason + Act)
1 开始:用户输入:Add 3 and 4
2 LLM call:思考,需要工具吗?需要
3 tool node节点:执行加法运算
4 LLM call:计算结果给了 llm,思考,现在可以给用户了吗?
5 输出给用户
'''

2.2 Functional API
# 1 定义工具和模型
# 2 定义模型节点
# 3 定义工具节点
# 4 定义智能体
################ 1 定义工具和模型
from langchain.tools import tool
from langchain_openai import ChatOpenAI
## 1.1 连接模型
model= ChatOpenAI(
model="deepseek-chat",
api_key="sk-d7835fa8f2cd4908a284ebf48818581b",
base_url="https://api.deepseek.com",
)
# 1.2 定义工具
@tool
def multiply(a: int, b: int) -> int:
"""Multiply `a` and `b`.
Args:
a: First int
b: Second int
"""
return a * b
@tool
def add(a: int, b: int) -> int:
"""Adds `a` and `b`.
Args:
a: First int
b: Second int
"""
return a + b
@tool
def divide(a: int, b: int) -> float:
"""Divide `a` and `b`.
Args:
a: First int
b: Second int
"""
return a / b
## 1.3 模型跟工具绑定
tools = [add, multiply, divide]
tools_by_name = {tool.name: tool for tool in tools}
model_with_tools = model.bind_tools(tools)
################# 2 定义模型节点####
from langgraph.graph import add_messages
from langchain.messages import (
SystemMessage,
HumanMessage,
ToolCall,
)
from langchain_core.messages import BaseMessage
from langgraph.func import entrypoint, task
@task # 等同于:add_node
def call_llm(messages: list[BaseMessage]):
"""LLM decides whether to call a tool or not"""
return model_with_tools.invoke(
[
SystemMessage(
content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
)
]
+ messages
)
################# 3 定义工具节点 ####
@task # 等同于:add_node
def call_tool(tool_call: ToolCall):
"""Performs the tool call"""
tool = tools_by_name[tool_call["name"]]
return tool.invoke(tool_call)
################# 4 定义智能体
@entrypoint()
def agent(messages: list[BaseMessage]):
model_response = call_llm(messages).result()
while True:
if not model_response.tool_calls:
break
tool_result_futures = [
call_tool(tool_call) for tool_call in model_response.tool_calls
]
# 收集结果: 等待所有工具任务完成,获取计算结果列表。
tool_results = [fut.result() for fut in tool_result_futures]
messages = add_messages(messages, [model_response, *tool_results])
model_response = call_llm(messages).result()
# 循环结束后,将最后一次 LLM 的最终回复(纯文本)加入消息列表。 return messages: 返回完整的对话历史记录
messages = add_messages(messages, model_response)
return messages
# 5 交互,调用--》计算3 + 4--》流式输出
messages = [HumanMessage(content="Add 3 and 4.")]
# 流式输出
for chunk in agent.stream(messages, stream_mode="updates"):
print(chunk)
print("\n")

2.3 生成可视化
# 1 langgraph中,如果定义好了节点,连好了线,可以一键生成流程图
graph = StateGraph(MessagesState)
# add nod 添加节点
# add_edge 连线
# 编译
agent = graph.compile()
png_data = agent.get_graph(xray=True).draw_mermaid_png()
with open('demo.png', "wb") as f:
f.write(png_data)
3 运行本地服务器
上述案例,放在一个py文件中--》不适合工程化
工程化:复杂的目录结构---》官方有规范
3.1 程序结构
3.1.1 两种目录结构
pyproject.toml 和 requirements.txt 都是用来放当前项目依赖的
pyproject.toml 使用vu管理:pip install -e .
requirements.txt 使用pip管理:pip install -r requirements.txt
项目名/
├── my_agent # 代码都写在这里面
│ ├── utils # 节点,状态,工具--》放在这个文件夹中
│ │ ├── __init__.py
│ │ ├── tools.py # 工具:LangGraph或LangChain中学的
│ │ ├── nodes.py # 节点:大模型节点,工具节点,判断节点,重新规划节点,食物推荐节点。。
│ │ └── state.py # 状态:LangGraph的核心,定义 整个工作流中传递数据的结构
│ ├── __init__.py
│ └── agent.py # agent = graph.compile() 放在这里
├── .env # 环境变量
├── requirements.txt # 依赖
└── langgraph.json # 配置文件
项目名/
├── my_agent # 代码都写在这里面
│ ├── utils # 节点,状态,工具--》放在这个文件夹中
│ │ ├── __init__.py
│ │ ├── tools.py # 工具:LangGraph或LangChain中学的
│ │ ├── nodes.py # 节点:大模型节点,工具节点,判断节点,重新规划节点,食物推荐节点。。
│ │ └── state.py # 状态:LangGraph的核心,定义 整个工作流中传递数据的结构
│ ├── __init__.py
│ └── agent.py # agent = graph.compile() 放在这里
├── .env # 环境变量
├── langgraph.json # 配置文件
└── pyproject.toml # 依赖
3.1.2 解释
##### 1 配置文件-->一会有这个文件,我们看一下即可############
langgraph.json 文件是一个 JSON 文件,用于指定部署 LangGraph 应用程序所需的依赖项、图、环境变量和其他设置。
## 示例
1 依赖项包括一个自定义本地包和 langchain_openai 包。
2 将从文件 ./your_package/your_file.py 加载一个图,变量为 variable。
3 环境变量从 .env 文件加载。
{
"dependencies": ["langchain_openai", "./your_package"],
"graphs": {
"my_agent": "./your_package/your_file.py:agent"
},
"env": "./.env"
}
###### 2 依赖项
LangGraph 应用程序可能依赖于其他 Python 包。通常,您需要指定以下信息才能正确设置依赖项:
目录中的一个文件,用于指定依赖项:requirements.txt或pyproject.toml
####### 3 环境变量
如果您在本地使用已部署的 LangGraph 应用程序,可以在 LangGraph 配置文件 的 env 键中配置环境变量。
对于生产部署,通常希望在部署环境中配置环境变量
3.2 创建项目:命令创建项目
上述目录结构可以自己创建
但是:LangGraph 提供了命令,可以直接通过命令创建项目[工程],创建完的工程,就是上述目录结构--》我们再做微调即可
并且,可以通过LangGraph 提供的命令直接运行
运行后,可以在LangSmith 查看【演示--》实际项目中,只运行即可,不注册到LangSmith 中】
LangSmith要注册账号,个人单个智能体使用免费;多个智能体或企业使用收费
# 1 安装 LangGraph 脚手架:pip install "langgraph-cli[inmem]"
# Python >= 3.11 is required.
-创建 LangGraph 项目
-运行 LangGraph 项目
# 我装在虚拟环境里了
# 2 使用命令创建项目【我:必须在虚拟环境中才能创建】
# 从 new-langgraph-project-python 模板 创建一个新的应用程序。
# 此模板演示了一个可以扩展为包含您自己逻辑的单节点应用程序。:https://github.com/langchain-ai/new-langgraph-project
# 在创建的项目基础上继续开发即可
# 命令:
langgraph new path/to/your/app --template new-langgraph-project-python
langgraph new 路径和项目名 --template 基于哪个模板创建项目
# 我们的命令:在当前目录下创建项目:langgraph_demo001,没有指定模板,我们自选
langgraph new langgraph_demo001
# 有的同学可能会失败;原因是去github下载,国内有的地方访问不到
-1 重试
-2 FQ
-3 把老师创建好的空的,打开,继续开发即可
-等同于自己创建了文件夹和文件
# 3 使用pycharm打开:目录如下图
# 4 创建.env文件
-有一个 .env.example ,复制改名字即可
# 5 目前我们有解释器环境吗? 没有--》需要创建虚拟环境--》没有LangGraph脚手架的,我们需要手动装上---》因为项目运行,需要
pip install "langgraph-cli[inmem]"
# 6 安装依赖[虚拟环境中还没装:[LangGraph,python-dotenv]
pip install -e .
# 7 本地启动Agent服务器
langgraph dev








3.3 修改代码
把上面讲的Graph api的案例,修改成项目形式

########## graph.py
from typing import Literal
from langgraph.graph import StateGraph, START, END
from agent.state import MessagesState
from agent.nodes import llm_call, tool_node
def should_continue(state: MessagesState) -> Literal["tool_node", END]:
"""Routing logic: Check if the last message contains tool calls."""
last_message = state["messages"][-1]
if hasattr(last_message, "tool_calls") and last_message.tool_calls:
return "tool_node"
return END
def build_graph() -> StateGraph:
"""Builds and compiles the agent graph."""
builder = StateGraph(MessagesState)
# Add nodes
builder.add_node("llm_call", llm_call)
builder.add_node("tool_node", tool_node)
# Add edges
builder.add_edge(START, "llm_call")
# Conditional edges based on tool usage
builder.add_conditional_edges(
source="llm_call",
path=should_continue,
path_map=["tool_node", END]
)
# Loop back from tool to LLM
builder.add_edge("tool_node", "llm_call")
return builder.compile()
# Required export for langgraph dev
graph = build_graph()
########nodes.py
import os
from langchain_core.messages import SystemMessage, ToolMessage
from langchain.chat_models import init_chat_model
from agent.state import MessagesState
from agent.tools import tools_list, tools_by_name
from langchain_openai import ChatOpenAI
# 初始化模型 (读取环境变量)
model_name = os.getenv("MODEL_NAME")
api_key = os.getenv("API_KEY")
base_url = os.getenv("BASE_URL")
model= ChatOpenAI(
model=model_name,
api_key=api_key,
base_url=base_url,
)
model_with_tools = model.bind_tools(tools_list)
# 节点一
def llm_call(state: MessagesState) -> dict:
"""LLM Node: Decides whether to call a tool or answer directly."""
if model_with_tools is None:
raise RuntimeError("Model not initialized. Check ANTHROPIC_API_KEY in .env")
system_prompt = SystemMessage(
content="You are a helpful assistant tasked with performing arithmetic on a set of inputs."
)
# Construct full message history
messages_to_send = [system_prompt] + state["messages"]
response = model_with_tools.invoke(messages_to_send)
return {
"messages": [response],
"llm_calls": state.get("llm_calls", 0) + 1
}
# 节点二
def tool_node(state: MessagesState) -> dict:
"""Tool Node: Executes tools requested by the LLM."""
last_message = state["messages"][-1]
if not hasattr(last_message, "tool_calls") or not last_message.tool_calls:
return {"messages": []}
results = []
for tc in last_message.tool_calls:
tool_func = tools_by_name.get(tc["name"])
if not tool_func:
obs = f"Error: Tool '{tc['name']}' not found."
else:
try:
obs = tool_func.invoke(tc["args"])
except Exception as e:
obs = f"Error: {str(e)}"
results.append(
ToolMessage(content=str(obs), tool_call_id=tc["id"])
)
return {"messages": results}
#########state.py
from typing import Annotated, List
from typing_extensions import TypedDict
import operator
from langchain_core.messages import AnyMessage
class MessagesState(TypedDict):
"""
State schema for the math agent.
- messages: Accumulates conversation history using operator.add
- llm_calls: Tracks number of LLM invocations
"""
messages: Annotated[List[AnyMessage], operator.add]
llm_calls: int
####### tools.py
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiply `a` and `b`."""
return a * b
@tool
def add(a: int, b: int) -> int:
"""Adds `a` and `b`."""
return a + b
@tool
def divide(a: int, b: int) -> float:
"""Divide `a` by `b`."""
if b == 0:
raise ValueError("Cannot divide by zero")
return a / b
# 导出供其他模块使用
tools_list = [add, multiply, divide]
tools_by_name = {t.name: t for t in tools_list}


启动项目
langgraph dev

3.4 客户端调用

启动项目后,提供了api接口---》客户端可以调用

3.4.1 python同步调用
# 同步 pip install langgraph-sdk
# pip install langgraph-sdk
from langgraph_sdk import get_sync_client
client = get_sync_client(url="http://localhost:2024")
for chunk in client.runs.stream(
None, # 无线程运行
"agent", # 助手名称。在langgraph.json中定义。
input={
"messages": [{
"role": "human",
"content": "add 4 and 4 ",
}],
},
stream_mode="messages-tuple",
):
print(f"接收类型为: {chunk.event} 的新事件...")
print(chunk.data)
print("\n\n")
3.4.2 python异步调用
from langgraph_sdk import get_client
import asyncio
client = get_client(url="http://localhost:2024")
async def main():
async for chunk in client.runs.stream(
None, # Threadless run
"agent", # Name of assistant. Defined in langgraph.json.
input={
"messages": [{
"role": "human",
"content": "你是谁?",
}],
},
):
print(f"Receiving new event of type: {chunk.event}...")
print(chunk.data)
print("\n\n")
asyncio.run(main())
补充:导入包报错
# 本质没错--》只是pycharm在报错
# 要把src目录作为source root

3.5 LangSmith部署和调用
# 1 LangSmith 提供了一套完整的监控和部署流程
# 2 如果我们要上线,可以使用 langsmith提供的服务--》部署在它上面
-企业中,都部署在自己服务器上
###################### 步骤-不合适##################
# 1 先决条件 在开始之前,请确保您已具备以下条件
GitHub 帐户
LangSmith 帐户(免费注册)
# 2 部署代理
## 2.1. 在 GitHub 上创建存储库
您的应用程序的代码必须位于 GitHub 仓库中才能在 LangSmith 上部署。支持公共和私有仓库。对于此快速入门,首先确保您的应用程序与 LangGraph 兼容,方法是按照 本地服务器设置指南进行操作。然后,将您的代码推送到仓库。
## 2.2 部署到 LangSmith
1 导航到 LangSmith 部署
登录到 LangSmith。在左侧边栏中,选择 部署。
2 创建新部署
点击 + New Deployment(+ 新建部署)按钮。将打开一个面板,您可以在其中填写所需字段。
3 链接仓库
如果你是第一次用户,或者正在添加以前未连接的私有仓库,请点击 添加新账户 按钮并按照说明连接你的 GitHub 账户。
4 部署仓库
选择你的应用程序的仓库。点击 提交 进行部署。这可能需要大约 15 分钟才能完成。你可以在 部署详情 视图中检查状态。
## 2.3 在 Studio 中测试您的应用程序
应用程序部署后
选择您刚刚创建的部署以查看更多详细信息。
点击右上角的 Studio 按钮。Studio 将打开以显示你的图表。
## 2.4 获取部署的 API URL
在 LangGraph 的 部署详情 视图中,点击 API URL 将其复制到剪贴板。
点击 URL 将其复制到剪贴板。
########### 我们#########
把项目部署在有公网的云服务器上---》通过api调用即可
4 工作流和智能体

# 1 LLM应用【LangChain 或LangGraph都可以写】:从[确定工作流]到[自主代理]的三种模式
-核心区别:LLM在代码执行过程中有多少控制权
# 2 openclaw:龙虾
-部署完后---》给个任务:帮我赚钱
-如何干?什么流程? 通通是由 LLM 大模型决定的
-收到赚钱任务:大模型分析--》调用工具--》再分析--》再调工具--》返回循环--》最终输出结果--》转了
# 3 智能导游
-启动后:用户输入城市,预算,天数--》按照一个流程--》生成景点,生成食物,判断是否超预算--》工作流执行
# 4 最开始的 :工作流
# 5 到:高级工作流,高级编排
# 6 到:智能体
-----------第三种是最好的吗?--------------
根据场景来的
# 7 实际工程中,不要盲目追求 Agent

浙公网安备 33010602011771号