From 9194a02ae9508da3e087fa6b78b3ec7ef08a320a Mon Sep 17 00:00:00 2001 From: "2287551746@qq.com" <2287551746@example.com> Date: Wed, 12 Nov 2025 11:07:54 +0800 Subject: [PATCH] 2025.11.12 --- .env.example | 6 +- 08_langgraph_basics/01_state_node_edge.py | 42 +++++++ 08_langgraph_basics/01_workflow.png | Bin 0 -> 4879 bytes 08_langgraph_basics/02_langsmith_trace.py | 51 +++++++++ 08_langgraph_basics/03_conditional_router.py | 87 ++++++++++++++ 08_langgraph_basics/04_agent_with_memory.py | 113 +++++++++++++++++++ 08_langgraph_basics/README.md | 101 +++++++++++++++++ README.md | 19 +++- requirements.txt | 2 + 9 files changed, 414 insertions(+), 7 deletions(-) create mode 100644 08_langgraph_basics/01_state_node_edge.py create mode 100644 08_langgraph_basics/01_workflow.png create mode 100644 08_langgraph_basics/02_langsmith_trace.py create mode 100644 08_langgraph_basics/03_conditional_router.py create mode 100644 08_langgraph_basics/04_agent_with_memory.py create mode 100644 08_langgraph_basics/README.md diff --git a/.env.example b/.env.example index d9a9e7e..fedb5ec 100644 --- a/.env.example +++ b/.env.example @@ -1 +1,5 @@ -OPENAI_API_KEY=your_openai_api_key \ No newline at end of file +# LLM密钥 +OPENAI_API_KEY=your_openai_api_key + +# LangSmith 相关配置(用于调试/监控Langgraph流程) -- 未用到可暂时不更改 +LANGCHAIN_API_KEY=your_langsmith_api_key \ No newline at end of file diff --git a/08_langgraph_basics/01_state_node_edge.py b/08_langgraph_basics/01_state_node_edge.py new file mode 100644 index 0000000..73b6202 --- /dev/null +++ b/08_langgraph_basics/01_state_node_edge.py @@ -0,0 +1,42 @@ +from typing import TypedDict +from langgraph.graph import StateGraph,END,START + + +# 1. 定义State(状态) -- 白板上只有一个字段"count" +class State(TypedDict): + count:int + +# 2. 编写Node(节点) -- 两个"工人" +def node_a(state:State): + # 接收当前State状态,返回要更新的部分 + print(f'[Node A]收到状态:{state}') + return {"count":state["count"]+1} + +def node_b(state:State): + print(f'[Node B]收到状态:{state}') + return {"count":state["count"]+1} + + +# 3. 添加Node到图中 +workflow = StateGraph(State) # 创建画布 +workflow.add_node("A",node_a) # 添加节点A +workflow.add_node("B",node_b) # 添加节点B + +# 4. 用Edge连线 +workflow.add_edge(START,"A") # START -> A +workflow.add_edge("A","B") # A -> B +workflow.add_edge("B",END) # B -> END + +# 编译成可运行应用 +app = workflow.compile() + +# 传入初始状态,执行工作流 +print("---开始执行---") +result = app.invoke({"count":1}) +print("最终状态:",result) # 输出{'count':4} + + +# 保存可视化架构图 +with open('01_workflow.png', 'wb') as f: + f.write(app.get_graph().draw_mermaid_png()) +print("图表已保存为 01_workflow.png") \ No newline at end of file diff --git a/08_langgraph_basics/01_workflow.png b/08_langgraph_basics/01_workflow.png new file mode 100644 index 0000000000000000000000000000000000000000..5fc97208e6a4b64ee95906075e80632595b94ba7 GIT binary patch literal 4879 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 A +workflow.add_edge("A","B") # A -> B +workflow.add_edge("B",END) # B -> END + +# 编译成可运行应用 +app = workflow.compile() + +# 传入初始状态,执行工作流 +print("---开始执行---") +result = app.invoke({"count":1}) +print("最终状态:",result) # 输出{'count':4} + diff --git a/08_langgraph_basics/03_conditional_router.py b/08_langgraph_basics/03_conditional_router.py new file mode 100644 index 0000000..2e27044 --- /dev/null +++ b/08_langgraph_basics/03_conditional_router.py @@ -0,0 +1,87 @@ +from dotenv import load_dotenv +import os + + +load_dotenv() +api_key = os.getenv("OPENAI_API_KEY") +langchain_api_key = os.getenv("LANGCHAIN_API_KEY") + +from langchain.schema import HumanMessage +from langchain.tools import tool +from langchain_openai import ChatOpenAI +from langgraph.graph import StateGraph, MessagesState, END,START +from langgraph.prebuilt import ToolNode + +os.environ["LANGCHAIN_TRACING_V2"] = "true" # 总开关,决定启用追踪功能 +os.environ["LANGCHAIN_PROJECT"] = "demo01" # 自定义项目名 +os.environ["LANGCHAIN_API_KEY"] = langchain_api_key + +# LLM配置 +llm = ChatOpenAI( + model="deepseek-chat", + api_key=api_key, + base_url="https://api.deepseek.com" +) + +# 工具定义 +@tool +def get_weather(loaction): + """模拟获取天气""" + return f'{loaction}当前天气:23℃,晴,风力2级' + + +tools = [get_weather] +llm_with_tools = llm.bind_tools(tools) # 让llm学会调用工具节点 + + +# --- 核心组件:拆解AgentExecutor --- +# ReAct Step1:Thought(LLM决策) +def call_model(state:MessagesState): + response = llm_with_tools.invoke(state['messages']) + return {"messages":[response]} # 新消息追加到状态 + + +# ReAct Step2-3:Action + Observation +tool_node = ToolNode(tools) + +# ReAct Step4:Loop Controller(是否循环) +def should_continue(state:MessagesState): + last_msg = state["messages"][-1] + if hasattr(last_msg,"tool_calls") and len(last_msg.tool_calls) > 0: + return "tools" # 有工具调用 -> 执行工具 + return END # 无工具调用 -> 返回答案 + + +# --- 构建 ReAct 循环图--- +workflow = StateGraph(MessagesState) + +workflow.add_node("agent",call_model) # Thought +workflow.add_node("tools",tool_node) # Action + Observation + +workflow.add_edge(START,"agent") + +# 条件边:Thought -> 决定下一步 +workflow.add_conditional_edges( + "agent", # 从哪个节点出发 + should_continue, # 决定下一步去哪 + { + "tools":"tools", # 如果返回tools,去tools节点 + END:END # 如果返回END,直接结束工作流 + } +) + +workflow.add_edge("tools","agent") + +app = workflow.compile() + +if __name__ == '__main__': + # 触发工具 + result = app.invoke( + {"messages":[ + HumanMessage(content="北京天气如何?") + ]} + ) + print('工具调用结果:',result['messages'][-1].content) + # 不触发工具 + result = app.invoke({"messages":HumanMessage(content="你好")}) + print('直接回答:',result['messages'][-1].content) \ No newline at end of file diff --git a/08_langgraph_basics/04_agent_with_memory.py b/08_langgraph_basics/04_agent_with_memory.py new file mode 100644 index 0000000..309bdca --- /dev/null +++ b/08_langgraph_basics/04_agent_with_memory.py @@ -0,0 +1,113 @@ +from dotenv import load_dotenv +import os + +load_dotenv() +api_key = os.getenv("OPENAI_API_KEY") +langchain_api_key = os.getenv("LANGCHAIN_API_KEY") + +from langchain.schema import HumanMessage +from langchain.tools import tool +from langchain_openai import ChatOpenAI +from langgraph.graph import StateGraph, MessagesState, END,START +from langgraph.prebuilt import ToolNode +from langchain_core.messages import SystemMessage +from langgraph.checkpoint.memory import MemorySaver + +os.environ["LANGCHAIN_TRACING_V2"] = "true" # 总开关,决定启用追踪功能 +os.environ["LANGCHAIN_PROJECT"] = "demo02" # 自定义项目名 +os.environ["LANGCHAIN_API_KEY"] = langchain_api_key + +# LLM配置 +llm = ChatOpenAI( + model="deepseek-chat", + api_key=api_key, + base_url="https://api.deepseek.com" +) + +# Prompt配置 +sys_prompt = "你是一个强大的助手,能查天气,也能回答一般问题。请使用中文回答。" + +# 工具定义 +@tool +def get_weather(loaction): + """模拟获取天气""" + return f'{loaction}当前天气:23℃,晴,风力2级' + + +tools = [get_weather] +llm_with_tools = llm.bind_tools(tools) # 让llm学会调用工具节点 + + +# --- 核心组件:拆解AgentExecutor --- +# ReAct Step1:Thought(LLM决策) +def call_model(state:MessagesState): + # 构造带system prompt 的完整消息列表(仅用于本次LLM调用) + message_for_llm = [SystemMessage(content=sys_prompt)]+state["messages"] + response = llm_with_tools.invoke(message_for_llm) + # 此处只会返回新生成的消息,不包含prompt,防止污染历史 + return {"messages":[response]} # 新消息追加到状态 + + +# ReAct Step2-3:Action + Observation +tool_node = ToolNode(tools) + +# ReAct Step4:Loop Controller(是否循环) +def should_continue(state:MessagesState): + last_msg = state["messages"][-1] + if hasattr(last_msg,"tool_calls") and len(last_msg.tool_calls) > 0: + return "tools" # 有工具调用 -> 执行工具 + return END # 无工具调用 -> 返回答案 + + +# --- 构建 ReAct 循环图--- +workflow = StateGraph(MessagesState) + +workflow.add_node("agent",call_model) # Thought +workflow.add_node("tools",tool_node) # Action + Observation + +workflow.add_edge(START,"agent") + +# 条件边:Thought -> 决定下一步 +workflow.add_conditional_edges( + "agent", # 从哪个节点出发 + should_continue, # 决定下一步去哪 + { + "tools":"tools", # 如果返回tools,去tools节点 + END:END # 如果返回END,直接结束工作流 + } +) + +workflow.add_edge("tools","agent") + + + + + +# 编译时启用记忆 +app = workflow.compile(checkpointer=MemorySaver()) + + + +if __name__ == '__main__': + session_id = "user123" + config = { + "configurable":{"thread_id":session_id} + } + while 1: + user_input = input('\n你:') + if user_input.strip().lower() == 'quit': + break + + result = app.invoke( + {'messages':[HumanMessage(content=user_input)]}, + config=config + ) + + ai_msg = result["messages"][-1] + print(f'AI:{ai_msg.content}') + + + + + + diff --git a/08_langgraph_basics/README.md b/08_langgraph_basics/README.md new file mode 100644 index 0000000..835478a --- /dev/null +++ b/08_langgraph_basics/README.md @@ -0,0 +1,101 @@ +# 🧩 模块说明:LangGraph 基础篇 - 从状态机到智能 Agent + +> 📌 核心知识点:StateGraph 基础结构|MessagesState 对话状态|ToolNode 工具执行|条件路由|MemorySaver 记忆|System Prompt 无污染注入|LangSmith 追踪 + +--- + +### 1. `01_state_node_edge.py` (LangGraph 最小状态机) + +演示 LangGraph 最基础的三要素:State(状态)、Node(节点)、Edge(边)。 + +- ✅ 掌握点: + - 定义 `TypedDict` 作为状态(如 `{"count": int}`)。 + - 编写节点函数(`node_a`, `node_b`)处理状态并返回更新。 + - 使用 `add_edge(START, "A")`、`add_edge("A", "B")` 构建线性流程。 + - 调用 `app.get_graph().draw_mermaid_png()` 生成可视化流程图。 + +- 输出: + - 控制台打印状态变化过程。 + - 生成 `01_workflow.png` 流程图。 + +> 💡 此脚本**不涉及 LLM 或对话**,仅用于理解 LangGraph 底层机制。 + +--- + +### 2. `01_workflow.png` (状态机流程图) + +由 `01_state_node_edge.py` 自动生成的 Mermaid 可视化图。 + +- 内容: + - 展示 `START → A → B → END` 的线性执行流。 + - 节点 `A` 和 `B` 各将 `count` 加 1。 +- 作用: + - 直观理解 LangGraph 的“图”本质。 + - 为后续复杂控制流(如循环、分支)打下认知基础。 + +--- + +### 3. `02_langsmith_trace.py` (状态机 + LangSmith 追踪) + +在 `01` 的基础上启用 LangSmith,实现执行过程可视化追踪。 + +- ✅ 掌握点: + - 设置环境变量:`LANGCHAIN_TRACING_V2=true`、`LANGCHAIN_PROJECT="my_demo"`。 + - 无需修改节点逻辑,自动上报每一步状态变更。 + - 在 [LangSmith UI](https://smith.langchain.com) 查看执行轨迹。 + +- 注意: + - 仍是一个**纯状态机示例**(count +1 +1),**非对话 Agent**。 + - 用于验证 LangSmith 集成是否生效。 + +--- + +### 4. `03_conditional_router.py` (首个 ReAct Agent:无记忆) + +构建第一个真正意义上的 LangGraph Agent:支持工具调用与条件循环。 + +- ✅ 掌握点: + - 使用 `MessagesState` 管理对话历史。 + - 定义 `@tool def get_weather(location)` 并绑定到 LLM。 + - 实现 `should_continue` 函数判断是否需调用工具。 + - 构建 `agent → (条件) → tools → agent` 的 ReAct 循环。 + - 通过 `app.invoke({"messages": [...]})` 触发执行。 + +- 效果: + - 输入“北京天气如何?” → 调用工具 → 返回天气。 + - 输入“你好” → 直接回答,不触发工具。 +- 局限: + - **无记忆**:每次 `invoke` 都是独立会话。 + +--- + +### 5. `04_agent_with_memory.py` (完整 Agent:带记忆 + 系统提示) + +在 `03` 基础上升级为生产级 Agent 范式。 + +- ✅ 掌握点: + - 启用 `MemorySaver()` 实现跨轮次记忆(`checkpointer=MemorySaver()`)。 + - 通过 `config={"configurable": {"thread_id": "user123"}}` 绑定会话。 + - 在 `call_model` 中动态注入 `SystemMessage(content=sys_prompt)`,**但不写入 state**,避免污染历史。 + - 保留 LangSmith 追踪能力。 + +- 效果: + - 支持连续对话(如“查北京天气” → “那上海呢?”)。 + - 系统指令始终生效,但不会出现在消息历史中。 + - 全流程可追踪、可调试。 + +--- + +### 🔔 全局注意事项 + +- **学习路径建议**: + `01`(理解图) → `02`(理解追踪) → `03`(理解 ReAct) → `04`(理解记忆+prompt) +- 所有 `.py` 文件均依赖 `.env` 中的 `OPENAI_API_KEY` 和 `LANGCHAIN_API_KEY`。 +- 若想复用你的 RAG 工具,只需将 `get_weather` 替换为 `search_war_and_peace`,其余逻辑不变。 +- `01_workflow.png` 仅反映 `01_state_node_edge.py` 的简单线性流,**不代表 Agent 结构**。 + +--- + +### 💡 **建议** + +先运行 `01` 和 `02` 理解 LangGraph 底层机制,再重点掌握 `03` 和 `04` —— 它们构成了后续所有进阶 Agent(多工具、人工干预、自定义状态等)的**标准范式**。 \ No newline at end of file diff --git a/README.md b/README.md index d95dee7..c2e2382 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ ## 🧭 模块总览(16 模块) > 💡 每个模块对应独立目录(含代码、说明与示例),可独立运行与学习。 -> 🔥 已更新至 07 Rag 进阶篇,持续更新中! +> 🔥 已更新至 08 LangGraph 基础篇,持续更新中! | 章节 | 模块 | 博客 | 核心关键词 | 难度 | |:-----------:|:--------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------:|:----------------------------------------------------|:-----:| @@ -32,8 +32,8 @@ | | [05 LangChain 进阶篇](https://github.com/Annyfee/agent-craft/tree/main/05_langchain_advanced) | [🏠](https://blog.csdn.net/2401_87328929/article/details/154064397) | Agents · 缓存 · 流式输出 | ⭐⭐⭐ | | | [06 RAG 基础篇](https://github.com/Annyfee/agent-craft/tree/main/06_rag_basics) | [🏠](https://blog.csdn.net/2401_87328929/article/details/154230067) | RAG概念 · Split · Embedding · FAISS · RAG 链 | ⭐⭐ | | | [07 RAG 进阶篇](https://github.com/Annyfee/agent-craft/tree/main/07_rag_advanced) | [🏠](https://blog.csdn.net/2401_87328929/article/details/154408744) | Chroma · Reranker · RAG工具化 · 集成 | ⭐⭐⭐ | -| | 08 LangGraph 基础篇 | 🚧撰写中 | `State` · `Node` · `Conditional Edge` · RAG+反思 | ⭐⭐⭐ | -| | 09 LangGraph 进阶篇 | 🚧 | `Multi-Agent` · `Human-in-the-Loop` · “总控-员工”架构 | ⭐⭐⭐⭐ | +| | [08 LangGraph 基础篇]() | [🏠](https://blog.csdn.net/2401_87328929/article/details/154576812) | Langgraph三要素 · LangSmith · ReAct · 提示词安全注入 | ⭐⭐⭐ | +| | 09 LangGraph 进阶篇 | 🚧撰写中 | `Multi-Agent` · `Human-in-the-Loop` · “总控-员工”架构 | ⭐⭐⭐⭐ | | 🧠 **智能篇** | 10 MCP 基础 (Client) | 🚧 | `MCP` 协议 · `CherryStudio` · 消费公共 MCP | ⭐⭐⭐ | | | 11 MCP 进阶 (Server) | 🚧 | `Streamable HTTP` · `src layout` · 构建私有 MCP | ⭐⭐⭐⭐ | | | 12 Swarm & Agents SDK | 🚧 | `Swarm` · `Handoff` · “航空公司客服”项目 | ⭐⭐⭐⭐ | @@ -46,7 +46,7 @@ ## 🧩 当前学习建议(适用于已完成模块) -目前已开放模块:**01 ~ 07**。 +目前已开放模块:**01 ~ 08**。 建议按顺序学习,每一章都有完整代码示例与注释。 ### ✅ 模块 01 — Agent 入门 & 环境搭建 @@ -84,7 +84,12 @@ - **目标**:学会进阶的Chroma向量数据库,会Reranker精排序,最终将04到07所学的Langchain六大模块完整集成。 - **内容**:Chroma 持久化 | Reranker 精排 | RAG 工具化 | Langchain六大模块集成 -> 📌 后续模块将陆续开放(LangGraph、MCP、多智能体等) +### ✅ 模块 08 — LangGraph 基础篇 + +- **目标**:懂得Langgraph的三要素,会使用LangSmith调试当前agent,并能自己写一个简单的Langgraph流程。 +- **内容**:Langgraph核心三要素|ReAct循环白盒化实现 | LangSmith调试追踪 | 持久化记忆 | 提示词安全注入 + +> 📌 后续模块将陆续开放(MCP、多智能体、Streamlit等) --- @@ -129,9 +134,11 @@ cp .env.example .env ```env OPENAI_API_KEY=your_deepseek_api_key_here +LANGCHAIN_API_KEY=your_langsmith_api_key ``` -> 💡 **获取API Key**: 访问 [DeepSeek官网](https://platform.deepseek.com/) 注册并获取API Key +> 💡 **获取API Key**: 访问 [DeepSeek官网](https://platform.deepseek.com/)、[LangSmith官网](https://smith.langchain.com/) +> 注册并获取API Key ### 3️⃣ 运行示例 diff --git a/requirements.txt b/requirements.txt index c8e4201..9a3945f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -4,6 +4,8 @@ requests~=2.32.4 langchain~=0.2.16 langchain-community~=0.2.16 langchain-openai~=0.1.15 +langchain-core~=0.2.38 +langgraph~=0.2.0 langchain-huggingface==0.0.3 langchain-chroma==0.1.1 chromadb==0.4.22