架构变更:
- 新增 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分析逻辑不变
126 lines
4.2 KiB
Python
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,
|
|
)
|