修复更新同一条记录触发智能体无限循环的问题

This commit is contained in:
jingrow 2025-11-01 03:32:45 +08:00
parent 20aedb7347
commit 92700c638a
3 changed files with 52 additions and 4 deletions

View File

@ -6,12 +6,17 @@ import functools
import inspect
import logging
import os
import threading
from jingrow.model.page import Page
from jingrow.config import Config
from jingrow.utils.jingrow_api import upload_file_to_jingrow
_local = {}
# 【通用执行上下文标记】用于标记当前调用链的来源,防止循环触发等场景
# 使用 thread-local 存储,轻量且精确(同一线程内有效)
_update_source_context = threading.local()
# 统一 Jingrow 日志记录器(仅为本模块及调用方提供最小可用输出,不修改全局 root logger
_root_logger = logging.getLogger("jingrow")
@ -62,6 +67,38 @@ def update_pg(pagetype: str, name: str, data: Dict[str, Any]):
return updated
def skip_hooks(source: str = "agent"):
"""
设置上下文标记表示当前调用链来自指定来源如智能体执行
用于跳过某些钩子防止循环触发等场景
"""
try:
_update_source_context.source = source
except Exception:
pass
def restore_hooks():
"""
清除上下文标记恢复正常的钩子执行
"""
try:
if hasattr(_update_source_context, 'source'):
delattr(_update_source_context, 'source')
except Exception:
pass
def get_hook_source() -> Optional[str]:
"""
获取当前调用链的来源标识用于判断是否跳过某些钩子
"""
try:
return getattr(_update_source_context, 'source', None)
except Exception:
return None
def delete_pg(pagetype: str, name: str) -> bool:
pg = Page(pagetype)
res = pg.delete(name)

View File

@ -160,7 +160,13 @@ def execute(context=None, inputs=None, config=None):
# 调用 Jingrow 更新记录(仅当有更新)
if updated:
server_record = jingrow.update_pg(record_type, record_name, mock_record)
# 【防无限循环】设置上下文标记,表示当前更新来自智能体执行
# 这样在 on_update 钩子中就不会再次触发智能体,防止循环
jingrow.skip_hooks("agent")
try:
server_record = jingrow.update_pg(record_type, record_name, mock_record)
finally:
jingrow.restore_hooks()
if server_record is False:
return {"success": False, "error": "更新记录失败"}
if server_record is True:

View File

@ -38,12 +38,17 @@ def run_agent(pg=None, method=None, event=None, page=None, **kwargs):
"""本地版 Local Ai Agent 事件驱动机制。
- 支持按 pagetype module 分组合并去重
- condition 支持 Jinja2 表达式
- 使用本地任务队列避免链式重复触发
- 使用上下文标记防止无限循环
"""
# 兼容多种调用方式
pg = pg or page
method = event or method or kwargs.get("event")
# 【防无限循环】检查上下文标记:如果当前调用来自智能体执行,跳过
# 使用轻量级 thread-local 上下文标记,防止循环触发
if jingrow.get_hook_source() == "agent":
return
# 支持的事件
event_list = [
"on_update",
@ -91,7 +96,6 @@ def run_agent(pg=None, method=None, event=None, page=None, **kwargs):
merged_agents = list({a.get("name"): a for a in agents_by_pagetype + agents_by_module}.values())
if not merged_agents:
jingrow.log_error("LocalAIAgent", "No Local Ai Agents matched for this page")
return
# 一次性准备渲染上下文(仅当至少一个 agent 有 condition 时才构建)
@ -112,6 +116,7 @@ def run_agent(pg=None, method=None, event=None, page=None, **kwargs):
for agent in merged_agents:
if agent.get("event_type") == method:
agent_name = agent.get("name")
trigger = False
if not agent.get("condition"):
@ -131,7 +136,7 @@ def run_agent(pg=None, method=None, event=None, page=None, **kwargs):
trigger = False
if trigger:
enqueue_local_ai_agent(pg, agent.get('name'))
enqueue_local_ai_agent(pg, agent_name)
def enqueue_local_ai_agent(pg, agent_name):
"""后台实际入队执行 Local Ai Agent。"""