# -*- coding: utf-8 -*- """ 需风量计算 Agent 创建与配置模块 核心功能: - 创建需风量计算 DeepAgent(整合 Skills + 计算工具 + MCP 数据) - 配置流式输出 - 管理 Agent 实例生命周期 架构: - 模型: 通过 vent_agent._get_model() 获取 - Skills: needq-calc(需风量计算技能) - Tools: 14个 calc_tools 计算函数 + write_todos + get_needq_all_data - Backend: FilesystemBackend(virtual_mode) - 系统提示词仅包含通用行为准则,具体计算规则在各技能的 SKILL.md 中 """ import os from pathlib import Path from typing import Optional from dotenv import load_dotenv load_dotenv() SKILLS_ROOT = str((Path(__file__).parent.parent / "skills").resolve()) # 复用现有项目的模型加载 from agents.vent_agent import _get_model # 导入 write_todos from langchain.agents.middleware.todo import write_todos from langgraph.checkpoint.memory import MemorySaver # 导入全部计算工具 from tools.calc_tools import ( calc_face_by_gas, calc_face_by_workers, calc_face_by_wind_speed, calc_face_air_volume_max, calc_tunnel_by_gas, calc_tunnel_by_explosives, calc_tunnel_by_workers, calc_tunnel_by_wind_speed, calc_tunnel_air_volume_max, calc_chamber_by_equipment, calc_chamber_by_wind_speed, calc_other_by_wind_speed, calc_effective_area, calc_total_air_volume, ) # 导入 MCP 工具 from tools.vent_tools import get_needq_all_data # ============================================================ # 系统提示词(仅通用行为准则,不写计算规则) # ============================================================ NEEDQ_CALC_SYSTEM_PROMPT = """你是一名煤矿通风需风量计算专家,帮助用户交互式计算各用风地点的需风量。 ## 全局通用行为准则 1. **必须调用工具计算**:所有需风量计算必须通过调用 calc_tools 中的工具函数完成,绝对禁止凭 LLM 知识直接给出计算结果。此条为红线。 2. **参数缺失要追问**:若用户未提供必要计算参数,明确列出所需参数并引导用户补充,绝不编造参数值。 3. **列式计算**:展示每个计算过程的公式 → 代入数值 → 计算结果,不能只给结果。 4. **多轮对话承接**:记住当前会话中的用风地点类型和已有参数,用户补充参数或要求调整时自动衔接。 5. **全程简体中文输出**。 6. **禁止输出 ANSI 转义序列、内部工具名、函数名、技能标识**。 7. **全流程使用 write_todos 工具**实时更新任务进度。 8. 所有数据来源于工具调用结果,绝不编造数据。 9. 引用规程时附上具体条款来源(《煤矿安全规程》2025版、AQ 1056-2008)。 10. 无法判断时诚实说明原因,不臆测。 ## 支持的用风地点类型 - 采煤工作面(含备用工作面) - 掘进工作面 - 机电硐室 - 其他用风地点(主要进回风巷、采区进回风巷、其他通风人行巷道等) - 多地点汇总 - 通防管控平台数据查询 ## 工作模式 严格按照技能(skill: needq-calc)中定义的流程执行任务: 1. 识别用风地点类型 2. 收集/提取计算参数 3. 调用计算工具 4. 格式化输出结果 5. 支持参数调整重算 """ # ============================================================ # Agent 工厂函数 # ============================================================ def create_needq_calc_agent(): """创建「需风量计算」Agent。 该 Agent 专门处理各用风地点的需风量交互式计算,具备: - 14个计算工具(覆盖采煤面/掘进面/硐室/其他巷道) - MCP 远程数据查询能力(get_needq_all_data) - 多轮对话参数承接能力 - 结构化计算报告输出能力 - 使用运行时模型配置(支持前端动态切换) Returns: CompiledStateGraph: 编译后的 LangGraph 状态图,支持 .invoke() 和 .stream() """ from deepagents import create_deep_agent from deepagents.backends import FilesystemBackend from deepagents import FilesystemPermission from api.model_config import get_model_instance from tools.context_tracker import init_system_components, _tool_to_text _project_root = str(Path(__file__).parent.parent) skills = ["skills/needq-calc"] print(f"[skills] Agent=needq-calc-agent skills={skills}") agent = create_deep_agent( model=get_model_instance(), tools=[ # 基础工具 write_todos, # 辅助工具 calc_effective_area, calc_total_air_volume, # 采煤工作面计算 calc_face_by_gas, calc_face_by_workers, calc_face_by_wind_speed, calc_face_air_volume_max, # 掘进工作面计算 calc_tunnel_by_gas, calc_tunnel_by_explosives, calc_tunnel_by_workers, calc_tunnel_by_wind_speed, calc_tunnel_air_volume_max, # 硐室计算 calc_chamber_by_equipment, calc_chamber_by_wind_speed, # 其他巷道计算 calc_other_by_wind_speed, # MCP 远程数据查询 get_needq_all_data, ], skills=skills, system_prompt=NEEDQ_CALC_SYSTEM_PROMPT, backend=FilesystemBackend(root_dir=_project_root, virtual_mode=True), permissions=[ FilesystemPermission(operations=["write"], paths=["/**"], mode="deny"), ], middleware=[], name="needq-calc-agent", checkpointer=MemorySaver(), ) # ── 初始化上下文用量追踪 ── _all_tools = [ write_todos, calc_effective_area, calc_total_air_volume, calc_face_by_gas, calc_face_by_workers, calc_face_by_wind_speed, calc_face_air_volume_max, calc_tunnel_by_gas, calc_tunnel_by_explosives, calc_tunnel_by_workers, calc_tunnel_by_wind_speed, calc_tunnel_air_volume_max, calc_chamber_by_equipment, calc_chamber_by_wind_speed, calc_other_by_wind_speed, ] tool_texts = [_tool_to_text(t) for t in _all_tools] skill_contents = [] for s in skills: sf = Path(__file__).parent.parent / s / "SKILL.md" if sf.exists(): skill_contents.append(sf.read_text(encoding="utf-8")) # MCP 工具:单独归入 mcp 类别 mcp_text = _tool_to_text(get_needq_all_data) init_system_components( system_prompt=NEEDQ_CALC_SYSTEM_PROMPT, tool_defs=tool_texts, skill_contents=skill_contents, mcp_defs=[mcp_text], ) return agent # ============================================================ # 单例缓存 # ============================================================ _needq_calc_agent: Optional[object] = None def invalidate_cache(): """失效需风量计算 Agent 缓存(模型切换时调用)。""" global _needq_calc_agent _needq_calc_agent = None print("[模型切换] needq-calc-agent 缓存已失效") def get_needq_calc_agent(): """获取需风量计算 Agent 单例""" global _needq_calc_agent if _needq_calc_agent is None: _needq_calc_agent = create_needq_calc_agent() return _needq_calc_agent