修复斗鱼日报Dify 400请求并增强错误诊断
变更项:\n1. 在斗鱼插件新增 daily_report_include_structured_inputs 配置(默认 false),Dify 入参默认改为精简字段(task_type/query/system_prompt/user_prompt/room_id 等),避免复杂对象输入触发 400。\n2. 调整 _build_dify_daily_report_inputs:仅在 include_structured_inputs=true 时才附带 report_payload_json,大幅降低 Workflow 入参类型不匹配风险。\n3. 在初始化流程中读取 report_api.include_structured_inputs,支持按环境开关结构化入参。\n4. 在 UnifiedLLMClient 的 Dify 调用中新增 HTTPError 细粒度处理,last_error 与日志会追加 response_body 片段,便于快速定位 Dify 侧具体报错原因。\n5. 更新 douyu 配置模板注释,明确复杂输入导致 400 的风险与开关用途,方便后续维护。
This commit is contained in:
@@ -29,3 +29,6 @@ audience_stats_sample_interval_seconds = 0
|
|||||||
[Douyu.report_api]
|
[Douyu.report_api]
|
||||||
# 切换到 Dify 斗鱼日报专用工作流;对应配置位于根目录 config.yaml 的 llm.backends。
|
# 切换到 Dify 斗鱼日报专用工作流;对应配置位于根目录 config.yaml 的 llm.backends。
|
||||||
backend = "dify_workflow_douyu_daily_report"
|
backend = "dify_workflow_douyu_daily_report"
|
||||||
|
# 是否把完整结构化 payload(JSON 大对象)作为输入传给 Dify。
|
||||||
|
# 某些 Workflow 对复杂输入类型校验严格,会导致 400,默认关闭以保证可用性。
|
||||||
|
include_structured_inputs = false
|
||||||
|
|||||||
@@ -523,6 +523,10 @@ class DouyuPlugin(MessagePluginInterface):
|
|||||||
self._daily_report_max_sessions = 4
|
self._daily_report_max_sessions = 4
|
||||||
self._daily_report_max_length = 1800
|
self._daily_report_max_length = 1800
|
||||||
self._daily_report_send_image = True
|
self._daily_report_send_image = True
|
||||||
|
# Dify 入参策略:
|
||||||
|
# 默认发送精简字段,避免某些 Workflow 对复杂对象输入校验严格导致 400。
|
||||||
|
# 如需在工作流中使用完整结构化 payload,可在 report_api 显式开启。
|
||||||
|
self._daily_report_include_structured_inputs = False
|
||||||
self._audience_stats_sample_interval_seconds = 60
|
self._audience_stats_sample_interval_seconds = 60
|
||||||
self._status_check_retry_count = 3
|
self._status_check_retry_count = 3
|
||||||
self._status_check_retry_delay_seconds = 1
|
self._status_check_retry_delay_seconds = 1
|
||||||
@@ -613,6 +617,12 @@ class DouyuPlugin(MessagePluginInterface):
|
|||||||
)
|
)
|
||||||
|
|
||||||
report_api_cfg = cfg.get("report_api", {}) or {}
|
report_api_cfg = cfg.get("report_api", {}) or {}
|
||||||
|
self._daily_report_include_structured_inputs = bool(
|
||||||
|
report_api_cfg.get(
|
||||||
|
"include_structured_inputs",
|
||||||
|
self._daily_report_include_structured_inputs,
|
||||||
|
)
|
||||||
|
)
|
||||||
if report_api_cfg:
|
if report_api_cfg:
|
||||||
self._daily_report_llm_client = UnifiedLLMClient(report_api_cfg)
|
self._daily_report_llm_client = UnifiedLLMClient(report_api_cfg)
|
||||||
return True
|
return True
|
||||||
@@ -1857,8 +1867,11 @@ class DouyuPlugin(MessagePluginInterface):
|
|||||||
room_id = str(meta.get("room_id") or "").strip()
|
room_id = str(meta.get("room_id") or "").strip()
|
||||||
anchor_day = str(meta.get("anchor_day") or "").strip()
|
anchor_day = str(meta.get("anchor_day") or "").strip()
|
||||||
nickname = str(meta.get("nickname") or meta.get("room_name") or "").strip()
|
nickname = str(meta.get("nickname") or meta.get("room_name") or "").strip()
|
||||||
payload_json = json.dumps(payload, ensure_ascii=False)
|
# 说明:
|
||||||
return {
|
# 1. 部分 Dify Workflow 对输入变量类型校验较严格,复杂对象(dict/list)容易触发 400;
|
||||||
|
# 2. 默认只提交精简字符串字段,优先保证链路可用;
|
||||||
|
# 3. 如需在工作流内使用完整载荷,可通过 include_structured_inputs 开关启用。
|
||||||
|
inputs = {
|
||||||
# 任务路由字段:在 Dify 条件分支里用于区分日报正文/弹幕摘要。
|
# 任务路由字段:在 Dify 条件分支里用于区分日报正文/弹幕摘要。
|
||||||
"task_type": task_type,
|
"task_type": task_type,
|
||||||
# 兼容 Workflow 中直接读取 query 的场景。
|
# 兼容 Workflow 中直接读取 query 的场景。
|
||||||
@@ -1866,9 +1879,6 @@ class DouyuPlugin(MessagePluginInterface):
|
|||||||
# 保留原有两段提示词,便于工作流内部二次拼装或调试。
|
# 保留原有两段提示词,便于工作流内部二次拼装或调试。
|
||||||
"system_prompt": system_prompt,
|
"system_prompt": system_prompt,
|
||||||
"user_prompt": user_prompt,
|
"user_prompt": user_prompt,
|
||||||
# 结构化报告载荷:既提供对象,也提供 JSON 文本,适配不同节点处理能力。
|
|
||||||
"report_payload": payload,
|
|
||||||
"report_payload_json": payload_json,
|
|
||||||
# 关键元信息:用于日志、标题拼接、数据看板或异常追踪。
|
# 关键元信息:用于日志、标题拼接、数据看板或异常追踪。
|
||||||
"room_id": room_id,
|
"room_id": room_id,
|
||||||
"anchor_day": anchor_day,
|
"anchor_day": anchor_day,
|
||||||
@@ -1876,6 +1886,9 @@ class DouyuPlugin(MessagePluginInterface):
|
|||||||
# 控制输出长度:避免 Dify 侧生成超长内容后再被本地硬截断。
|
# 控制输出长度:避免 Dify 侧生成超长内容后再被本地硬截断。
|
||||||
"max_length": int(self._daily_report_max_length or 1800),
|
"max_length": int(self._daily_report_max_length or 1800),
|
||||||
}
|
}
|
||||||
|
if self._daily_report_include_structured_inputs:
|
||||||
|
inputs["report_payload_json"] = json.dumps(payload, ensure_ascii=False)
|
||||||
|
return inputs
|
||||||
|
|
||||||
def _call_daily_report_llm(
|
def _call_daily_report_llm(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ from typing import Any, Dict, List, Optional, Tuple
|
|||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
|
from requests import HTTPError
|
||||||
from loguru import logger
|
from loguru import logger
|
||||||
|
|
||||||
from utils.ai.llm_registry import LLMRegistry
|
from utils.ai.llm_registry import LLMRegistry
|
||||||
@@ -282,6 +283,23 @@ class UnifiedLLMClient:
|
|||||||
if parsed and parsed.get("text"):
|
if parsed and parsed.get("text"):
|
||||||
return parsed
|
return parsed
|
||||||
self.last_error = f"empty_model_output:{self.mode}"
|
self.last_error = f"empty_model_output:{self.mode}"
|
||||||
|
except HTTPError as exc:
|
||||||
|
# 诊断增强:
|
||||||
|
# 1. Dify 返回 400 时,异常信息默认只包含状态码和 URL,不含具体原因;
|
||||||
|
# 2. 这里把响应体片段追加到 last_error,便于快速定位“入参字段/类型”问题。
|
||||||
|
response_text = ""
|
||||||
|
response_obj = getattr(exc, "response", None)
|
||||||
|
if response_obj is not None:
|
||||||
|
try:
|
||||||
|
response_text = str(response_obj.text or "").strip()
|
||||||
|
except Exception:
|
||||||
|
response_text = ""
|
||||||
|
response_text = response_text[:500] if response_text else ""
|
||||||
|
self.last_error = (
|
||||||
|
f"request_failed:attempt_{attempt}:{exc}"
|
||||||
|
+ (f" | response_body={response_text}" if response_text else "")
|
||||||
|
)
|
||||||
|
self.LOG.warning(f"[UnifiedLLMClient] Dify 请求失败: tag={tag}, attempt={attempt}, error={self.last_error}")
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
self.last_error = f"request_failed:attempt_{attempt}:{exc}"
|
self.last_error = f"request_failed:attempt_{attempt}:{exc}"
|
||||||
self.LOG.warning(f"[UnifiedLLMClient] Dify 请求失败: tag={tag}, attempt={attempt}, error={exc}")
|
self.LOG.warning(f"[UnifiedLLMClient] Dify 请求失败: tag={tag}, attempt={attempt}, error={exc}")
|
||||||
|
|||||||
Reference in New Issue
Block a user