Files
iot-device-management-service/app/services/agent/tools/alarm_action.py
16337 8156f54004 重构 Agent:引入 LangGraph StateGraph 替代手写 FC 循环
架构变更:
- 新增 app/services/agent/ 模块(state/prompts/graph/tools)
- 7 个工具从 _tool_xxx 方法提取为 @tool 装饰器函数
- 构建 assistant + ToolNode 的 ReAct 图
- agent_dispatcher.py 改为薄壳入口,支持 USE_LANGGRAPH 开关
- MemorySaver checkpoint 持久化对话(thread_id=wechat-{user_id})
- 新增依赖:langchain-core, langchain-openai, langgraph

向后兼容:
- USE_LANGGRAPH=false 可切回旧版 FC 循环
- LangGraph 初始化失败自动降级到 Legacy 模式
- 企微图片处理/VLM分析逻辑不变
2026-03-25 13:52:55 +08:00

126 lines
4.2 KiB
Python

"""
告警操作工具:确认接单、忽略、完成、误报
"""
import json
from langchain_core.tools import tool
from langchain_core.runnables import RunnableConfig
from app.utils.logger import logger
def _get_order_id_for_alarm(alarm_id: str) -> str:
"""从 alarm_event_ext 中获取关联的工单ID"""
from app.models import get_session, AlarmEventExt
db = get_session()
try:
ext = db.query(AlarmEventExt).filter(
AlarmEventExt.alarm_id == alarm_id,
AlarmEventExt.ext_type == "WORK_ORDER",
).first()
if ext and ext.ext_data:
return ext.ext_data.get("order_id", "")
return ""
except Exception as e:
logger.error(f"查询工单ID失败: alarm={alarm_id}, error={e}")
return ""
finally:
db.close()
async def _update_wechat_card(alarm_id: str, user_id: str, action: str):
"""更新企微卡片状态"""
try:
from app.services.wechat_service import get_wechat_service
wechat = get_wechat_service()
response_code = wechat.get_response_code(alarm_id)
if not response_code:
return
if action == "confirm":
await wechat.update_alarm_card_step2(
response_code=response_code, user_ids=[user_id],
alarm_id=alarm_id, operator_name=user_id,
)
else:
await wechat.update_alarm_card_terminal(
response_code=response_code, user_ids=[user_id],
alarm_id=alarm_id, action=action, operator_name=user_id,
)
except Exception as e:
logger.error(f"更新企微卡片失败: alarm={alarm_id}, error={e}")
@tool
async def update_alarm_status(alarm_id: str, action: str, config: RunnableConfig) -> str:
"""更新告警状态:确认接单(confirm)、忽略(ignore)、处理完成(complete)、标记误报(false)
Args:
alarm_id: 告警ID
action: 操作类型 confirm=确认接单 ignore=忽略 complete=处理完成 false=标记误报
"""
from app.services.alarm_event_service import get_alarm_event_service
user_id = config.get("configurable", {}).get("user_id", "")
svc = get_alarm_event_service()
# 查告警是否存在
detail = svc.get_alarm(alarm_id)
if not detail:
return json.dumps({"error": f"未找到告警: {alarm_id}"}, ensure_ascii=False)
# 获取关联工单ID
order_id = _get_order_id_for_alarm(alarm_id)
from app.services.work_order_client import get_work_order_client
wo_client = get_work_order_client()
# 操作映射
action_map = {
"confirm": ("CONFIRMED", "HANDLING", "企微Agent确认接单"),
"ignore": ("FALSE", "IGNORED", "企微Agent忽略"),
"complete": ("CLOSED", "DONE", "企微Agent已处理"),
"false": ("FALSE", "IGNORED", "企微Agent标记误报"),
}
if action not in action_map:
return json.dumps({"error": f"未知操作: {action}"}, ensure_ascii=False)
alarm_status, handle_status, remark = action_map[action]
# IoT 工单操作
if order_id and wo_client.enabled:
iot_success = False
if action == "confirm":
iot_success = await wo_client.confirm_order(order_id)
elif action in ("ignore", "false"):
iot_success = await wo_client.false_alarm(order_id)
elif action == "complete":
iot_success = await wo_client.submit_order(order_id, result=f"已处理 by {user_id}")
if not iot_success:
remark += "(IoT降级)"
# 本地状态更新(不管 IoT 成功与否)
svc.handle_alarm(
alarm_id=alarm_id,
alarm_status=alarm_status,
handle_status=handle_status,
handler=user_id,
remark=remark,
)
# 更新企微卡片
card_action = action if action != "confirm" else "confirm"
await _update_wechat_card(alarm_id, user_id, card_action)
action_labels = {
"confirm": "已确认接单",
"ignore": "已忽略",
"complete": "已处理完成",
"false": "已标记误报",
}
return json.dumps(
{"success": True, "message": f"{action_labels[action]}: {alarm_id}"},
ensure_ascii=False,
)