import os from config import OPENAI_API_KEY,LANGCHAIN_API_KEY from langchain_openai import ChatOpenAI from langchain.tools import tool from langchain_core.messages import HumanMessage from langgraph.graph import StateGraph, MessagesState, START, END from langgraph.prebuilt import ToolNode from langgraph.checkpoint.memory import MemorySaver # LangSmith调试 os.environ["LANGCHAIN_TRACING_V2"] = "true" # 总开关,决定启用追踪功能 os.environ["LANGCHAIN_PROJECT"] = "human_approval" # 自定义项目名 os.environ["LANGCHAIN_API_KEY"] = LANGCHAIN_API_KEY # llm配置 llm = ChatOpenAI( model="deepseek-chat", api_key=OPENAI_API_KEY, base_url="https://api.deepseek.com" ) # 定义一个敏感工具:发送邮件(模拟) @tool def send_email(to, content): """模拟发送邮件""" return f'邮件已发送至{to},内容为:{content}' # 工具绑定到llm tools = [send_email] llm_with_tools = llm.bind_tools(tools) # Node函数与Edge节点 tool_node = ToolNode(tools) def call_model(state: MessagesState): response = llm_with_tools.invoke(state['messages']) return {"messages":[response]} def should_continue(state: MessagesState): last_msg = state['messages'][-1] if hasattr(last_msg, "tool_calls") and last_msg.tool_calls: return "tools" return END # 构建基础ReAct图 workflow = StateGraph(MessagesState) workflow.add_node("agent", call_model) workflow.add_node("tools", tool_node) workflow.add_edge(START, "agent") workflow.add_conditional_edges( "agent", should_continue, { "tools": "tools", END: END } ) workflow.add_edge("tools", "agent") app = workflow.compile( # 在内存里做状态持久化 checkpointer=MemorySaver(), interrupt_before=["tools"] # 选择要人工审批的节点 -- 负责在哪里停,之后的代码负责停了之后怎么办 ) if __name__ == '__main__': config = { "configurable":{"thread_id":"user123"} } user_input = "请帮我给 boss@example.com 发一封邮件,内容是:会议推迟到明天下午3点。不要询问其他细节。" print("用户输入:",user_input) print("\nAgent正在思考...\n") # 初识输入 inputs = {"messages":[HumanMessage(content=user_input)]} while 1: # 触发工作流执行,推进到下一个中断点或自然结束 # inputs注入事件;config确定回话id;"values":完整记录每步结果 for _ in app.stream(inputs,config,stream_mode="values"): # 流式执行 pass # 必须迭代生成器,才能实际执行工作流 # 获取当前状态 snapshot = app.get_state(config) next_tasks = snapshot.next # 返回下一步要执行的节点名列表 # 如果没有下一步,说明工作流已结束 if not next_tasks: final_msg = snapshot.values['messages'][-1] print(f'\n最终回复:{final_msg.content}') break # 如果下一步是需要审批的节点 if "tools" in next_tasks: last_msg = snapshot.values['messages'][-1] tool_call = last_msg.tool_calls[0] print(f'\n⚠️ Agent准备执行操作:') print(f' 工具名称:{tool_call["name"]}') print(f' 参数:{tool_call["args"]}') approval = input("\n✅ 是否批准执行?(输入 'yes' 继续,其他取消): ").strip().lower() if approval == "yes": print('\n 继续执行...') inputs = None # 表示从断点继续,无新输入 else: print("\n❌ 操作已取消,流程终止") break