| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214 |
- # -*- 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
|