LangGraph.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110
  1. from langchain.chat_models import init_chat_model
  2. from langchain.tools import tool
  3. from langchain.agents import create_agent
  4. from langchain.agents.middleware import before_model, wrap_tool_call, AgentState
  5. # 使用 DeepSeek 模型,通过阿里云百炼平台接入
  6. # init_chat_model 会自动适配 OpenAI 兼容接口
  7. model = init_chat_model(
  8. model="deepseek-v4-flash",
  9. model_provider="openai",
  10. base_url="https://api.deepseek.com",
  11. api_key="sk-80a123483afb480285c6452985eea18e",
  12. )
  13. # ---- 模拟数据 ----
  14. # 实际项目中,这些数据来自数据库或 API
  15. EXPORT_RIGHTS = {
  16. "zhangsan": {"role": "finance", "region": "all"},
  17. "lisi": {"role": "operation", "region": "east"},
  18. }
  19. @tool
  20. def check_export_permission(username: str) -> dict:
  21. """查询用户是否有报表导出权限。
  22. 参数 username 为员工账号(英文名)。
  23. """
  24. user_info = EXPORT_RIGHTS.get(username)
  25. if not user_info:
  26. return {"username": username, "can_export": False, "reason": "用户不存在"}
  27. return {
  28. "username": username,
  29. "role": user_info["role"],
  30. "region": user_info["region"],
  31. "can_export": user_info["role"] in ("finance", "ops_manager"),
  32. }
  33. @tool
  34. def create_export_task(
  35. report_name: str, file_format: str, estimated_rows: int, reason: str
  36. ) -> dict:
  37. """创建报表导出任务。
  38. report_name: 报表名称
  39. file_format: 导出格式 (xlsx / csv)
  40. estimated_rows: 预计导出行数
  41. reason: 导出原因
  42. """
  43. return {
  44. "task_id": "EXPORT-20260706-001",
  45. "report_name": report_name,
  46. "file_format": file_format,
  47. "estimated_rows": estimated_rows,
  48. "reason": reason,
  49. "status": "queued",
  50. }
  51. tools = [check_export_permission, create_export_task]
  52. @before_model
  53. def log_before_model(state: AgentState, runtime):
  54. """模型调用前执行:看一眼当前上下文里有多少条消息。"""
  55. # state["messages"] 是 Agent 当前累积的全部对话历史
  56. # runtime 携带运行时环境信息(后面会详细讲)
  57. print(f"[审计] 准备调用模型,当前上下文消息数:{len(state['messages'])}")
  58. return None # 返回 None 表示不做任何修改
  59. @wrap_tool_call
  60. def log_tool_call(request, handler):
  61. """工具调用前后各打一条日志,并记录耗时。"""
  62. tool_name = request.tool_call["name"]
  63. print(f"[审计] 开始执行工具:{tool_name}")
  64. # handler(request) 是"真正执行工具"的入口
  65. # 不调用它,工具就不会执行
  66. result = handler(request)
  67. print(f"[审计] 工具执行完毕:{tool_name}")
  68. return result
  69. # 组装 Agent,把 Middleware 列表传进去
  70. agent = create_agent(
  71. model=model,
  72. tools=tools,
  73. middleware=[
  74. log_before_model, # 排在前面:先记录状态
  75. log_tool_call, # 排在后面:包裹工具调用
  76. ],
  77. system_prompt=(
  78. "你是报表导出平台的智能助手。"
  79. "用户询问导出相关问题前,先调用 check_export_permission 确认权限。"
  80. "只有在用户明确提出导出需求时,才调用 create_export_task 创建任务。"
  81. ),
  82. )
  83. # 跑一次看看
  84. response = agent.invoke({
  85. "messages": [
  86. {
  87. "role": "user",
  88. "content": "我是 zhangsan,需要导出本月 east 区域的订单报表,大约 5000 行,xlsx 格式。",
  89. }
  90. ]
  91. })
  92. print(response["messages"][-1].content)