union-app-chat-stream 1.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/__init__.py +1 -0
- package/app/agent/__init__.py +1 -0
- package/app/agent/capabilities.py +388 -0
- package/app/agent/coordinator/__init__.py +1 -0
- package/app/agent/coordinator/definition.py +50 -0
- package/app/agent/coordinator/output_guard.py +29 -0
- package/app/agent/graph.py +95 -0
- package/app/agent/guardrails.py +30 -0
- package/app/agent/routing.py +81 -0
- package/app/agent/runtime/__init__.py +1 -0
- package/app/agent/runtime/activity.py +393 -0
- package/app/agent/runtime/delegation.py +80 -0
- package/app/agent/runtime/deps.py +34 -0
- package/app/agent/runtime/execution.py +368 -0
- package/app/agent/runtime/model.py +47 -0
- package/app/agent/runtime/model_errors.py +24 -0
- package/app/agent/runtime/session.py +154 -0
- package/app/agent/specialists/__init__.py +1 -0
- package/app/agent/specialists/behavior_risk/__init__.py +1 -0
- package/app/agent/specialists/behavior_risk/definition.py +54 -0
- package/app/agent/specialists/build.py +94 -0
- package/app/agent/specialists/knowledge/__init__.py +1 -0
- package/app/agent/specialists/knowledge/definition.py +38 -0
- package/app/agent/specialists/personal_memory/__init__.py +1 -0
- package/app/agent/specialists/personal_memory/definition.py +35 -0
- package/app/agent/specialists/personal_memory/output_guard.py +55 -0
- package/app/agent/specialists/running_analysis/__init__.py +1 -0
- package/app/agent/specialists/running_analysis/definition.py +46 -0
- package/app/agent/specialists/running_analysis/output_guard.py +38 -0
- package/app/agent/specialists/scheduled_task_draft/__init__.py +8 -0
- package/app/agent/specialists/scheduled_task_draft/definition.py +142 -0
- package/app/agent/specialists/scheduled_task_draft/output_guard.py +81 -0
- package/app/asgi.py +139 -0
- package/app/config/__init__.py +1 -0
- package/app/config/settings.py +67 -0
- package/app/memory/__init__.py +1 -0
- package/app/memory/store.py +154 -0
- package/app/service/rag_service.py +364 -0
- package/app/skills/full-chain-quality-analysis/SKILL.md +22 -0
- package/app/tools/__init__.py +1 -0
- package/app/tools/business.py +183 -0
- package/app/utils/__init__.py +1 -0
- package/app/utils/api_client.py +76 -0
- package/app/utils/control_auth.py +35 -0
- package/app/utils/state_client.py +60 -0
- package/app/views/__init__.py +1 -0
- package/app/views/auth.py +189 -0
- package/app/views/errors.py +19 -0
- package/app/views/routes.py +25 -0
- package/app/views/run_context.py +33 -0
- package/app/views/streaming_runs.py +340 -0
- package/app/views/sync_runs.py +152 -0
- package/deploy/autoconf/templates/env.j2 +23 -0
- package/deploy/autoconf.yml +15 -0
- package/deploy/scripts/healthcheck.sh +12 -0
- package/deploy/scripts/start.sh +80 -0
- package/deploy/scripts/stop.sh +35 -0
- package/knowledge/000036-scenario-offline-function-call-mock-v1.md +134 -0
- package/package.json +21 -0
- package/requirements.txt +10 -0
- package/scripts/healthcheck.sh +4 -0
- package/scripts/start-BJ11.sh +1 -0
- package/scripts/start-BJ12.sh +1 -0
- package/scripts/start-SH20.sh +1 -0
- package/scripts/start-SZ31.sh +1 -0
- package/scripts/stop.sh +4 -0
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
"""处理 CAS 同步运行与定时任务同步适配入口。"""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
import logging
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Any
|
|
9
|
+
from zoneinfo import ZoneInfo
|
|
10
|
+
|
|
11
|
+
from pydantic import BaseModel
|
|
12
|
+
from pydantic_ai.exceptions import ModelHTTPError
|
|
13
|
+
from starlette.requests import Request
|
|
14
|
+
from starlette.responses import JSONResponse
|
|
15
|
+
|
|
16
|
+
from app.agent.runtime.model_errors import model_http_error_details
|
|
17
|
+
from app.utils.control_auth import ControlAuth
|
|
18
|
+
from app.views.auth import (
|
|
19
|
+
authenticate_scheduled_run,
|
|
20
|
+
authenticate_user,
|
|
21
|
+
reject_scheduled_on_cas_endpoint,
|
|
22
|
+
scheduled_token,
|
|
23
|
+
strict_scheduled_body,
|
|
24
|
+
)
|
|
25
|
+
from app.views.errors import RouteError
|
|
26
|
+
from app.views.run_context import build_run_deps, build_state_client
|
|
27
|
+
|
|
28
|
+
logger = logging.getLogger(__name__)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
async def sync_run(request: Request):
|
|
32
|
+
runtime = request.app.state.runtime
|
|
33
|
+
reject_scheduled_on_cas_endpoint(request)
|
|
34
|
+
user = await authenticate_user(request, runtime)
|
|
35
|
+
try:
|
|
36
|
+
payload = await request.json()
|
|
37
|
+
question = str(payload["question"]).strip()
|
|
38
|
+
input_data = payload["input"]
|
|
39
|
+
except (KeyError, TypeError, ValueError, json.JSONDecodeError):
|
|
40
|
+
return JSONResponse({"error": "invalid sync request"}, status_code=422)
|
|
41
|
+
if not question or not isinstance(input_data, dict):
|
|
42
|
+
return JSONResponse({"error": "invalid sync request"}, status_code=422)
|
|
43
|
+
return await _sync_response(
|
|
44
|
+
runtime,
|
|
45
|
+
user,
|
|
46
|
+
question,
|
|
47
|
+
input_data,
|
|
48
|
+
effective_context=_effective_time_context(request),
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
async def scheduled_run(request: Request):
|
|
53
|
+
runtime = request.app.state.runtime
|
|
54
|
+
token = scheduled_token(request)
|
|
55
|
+
await strict_scheduled_body(request)
|
|
56
|
+
identity = await authenticate_scheduled_run(runtime, token)
|
|
57
|
+
input_data = {
|
|
58
|
+
"scheduledTaskId": identity.task_id,
|
|
59
|
+
"scheduledRunId": identity.run_id,
|
|
60
|
+
"scheduledAt": identity.scheduled_at.isoformat().replace("+00:00", "Z"),
|
|
61
|
+
"timezone": identity.timezone,
|
|
62
|
+
}
|
|
63
|
+
return await _sync_response(
|
|
64
|
+
runtime,
|
|
65
|
+
{
|
|
66
|
+
"authentication_type": "SCHEDULED",
|
|
67
|
+
"user_id": identity.user_id,
|
|
68
|
+
"org_code": identity.org_code,
|
|
69
|
+
"scheduled_run_id": identity.run_id,
|
|
70
|
+
"control_auth": ControlAuth.scheduled(token),
|
|
71
|
+
},
|
|
72
|
+
identity.prompt,
|
|
73
|
+
input_data,
|
|
74
|
+
effective_context=(input_data["scheduledAt"], identity.timezone),
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
async def _sync_response(
|
|
79
|
+
runtime,
|
|
80
|
+
user: dict[str, Any],
|
|
81
|
+
question: str,
|
|
82
|
+
input_data: dict[str, Any],
|
|
83
|
+
*,
|
|
84
|
+
effective_context: tuple[str, str] | None = None,
|
|
85
|
+
) -> JSONResponse:
|
|
86
|
+
try:
|
|
87
|
+
content = await _run_sync(
|
|
88
|
+
runtime,
|
|
89
|
+
user,
|
|
90
|
+
question,
|
|
91
|
+
input_data,
|
|
92
|
+
effective_context=effective_context,
|
|
93
|
+
)
|
|
94
|
+
except ModelHTTPError as exc:
|
|
95
|
+
status, code, message, model_name = model_http_error_details(exc)
|
|
96
|
+
logger.error(
|
|
97
|
+
"Sync model request failed status=%s model=%s code=%s message=%s",
|
|
98
|
+
status,
|
|
99
|
+
model_name,
|
|
100
|
+
code,
|
|
101
|
+
message,
|
|
102
|
+
)
|
|
103
|
+
return JSONResponse(
|
|
104
|
+
{"error": message, "code": code, "model": model_name},
|
|
105
|
+
status_code=status,
|
|
106
|
+
)
|
|
107
|
+
return JSONResponse({"content": content})
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
async def _run_sync(
|
|
111
|
+
runtime,
|
|
112
|
+
user: dict[str, Any],
|
|
113
|
+
question: str,
|
|
114
|
+
input_data: Any,
|
|
115
|
+
*,
|
|
116
|
+
effective_context: tuple[str, str] | None = None,
|
|
117
|
+
):
|
|
118
|
+
state_client = build_state_client(runtime, user)
|
|
119
|
+
deps = build_run_deps(runtime, user, state_client)
|
|
120
|
+
if effective_context is not None:
|
|
121
|
+
deps.effective_at, deps.effective_timezone = effective_context
|
|
122
|
+
prompt = f"{question}\n\n输入数据:{json.dumps(input_data, ensure_ascii=False)}"
|
|
123
|
+
decision = await runtime.graph.router.run(
|
|
124
|
+
prompt,
|
|
125
|
+
deps=deps,
|
|
126
|
+
usage_limits=runtime.graph.usage_limits,
|
|
127
|
+
)
|
|
128
|
+
agent = runtime.graph.resolve_root(decision.output)
|
|
129
|
+
result = await agent.run(
|
|
130
|
+
prompt,
|
|
131
|
+
deps=deps,
|
|
132
|
+
usage_limits=runtime.graph.usage_limits,
|
|
133
|
+
)
|
|
134
|
+
output = result.output
|
|
135
|
+
return output.model_dump(by_alias=True) if isinstance(output, BaseModel) else output
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
def _effective_time_context(request: Request) -> tuple[str, str] | None:
|
|
139
|
+
effective_at = request.headers.get("x-agent-effective-at")
|
|
140
|
+
timezone = request.headers.get("x-agent-effective-timezone")
|
|
141
|
+
if effective_at is None and timezone is None:
|
|
142
|
+
return None
|
|
143
|
+
if not effective_at or not timezone:
|
|
144
|
+
raise RouteError(422, "invalid effective time context")
|
|
145
|
+
try:
|
|
146
|
+
parsed = datetime.fromisoformat(effective_at.replace("Z", "+00:00"))
|
|
147
|
+
if parsed.tzinfo is None:
|
|
148
|
+
raise ValueError
|
|
149
|
+
ZoneInfo(timezone)
|
|
150
|
+
except (KeyError, ValueError):
|
|
151
|
+
raise RouteError(422, "invalid effective time context")
|
|
152
|
+
return effective_at, timezone
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
APP_ENV={{APP_ENV}}
|
|
2
|
+
CONSOLE_STDOUT={{CONSOLE_STDOUT}}
|
|
3
|
+
LOG_LEVEL={{LOG_LEVEL}}
|
|
4
|
+
LOG_DIR={{LOG_DIR}}
|
|
5
|
+
# 联合运维服务
|
|
6
|
+
UNION_BASE_URL={{UNION_BASE_URL}}
|
|
7
|
+
PERMISSIONS={{PERMISSIONS}}
|
|
8
|
+
|
|
9
|
+
# 大模型地址
|
|
10
|
+
LLM_URL={{LLM_URL}}
|
|
11
|
+
LLM_KEY={{LLM_KEY}}
|
|
12
|
+
LLM_MODEL={{LLM_MODEL}}
|
|
13
|
+
LLM_CONTEXT_WINDOW={{LLM_CONTEXT_WINDOW}}
|
|
14
|
+
AGENT_MAX_RUN_SECONDS={{AGENT_MAX_RUN_SECONDS | default('900')}}
|
|
15
|
+
SUBAGENT_TIMEOUT_SECONDS={{SUBAGENT_TIMEOUT_SECONDS | default('900')}}
|
|
16
|
+
|
|
17
|
+
# 向量模型地址(OpenAI-compatible embeddings API)
|
|
18
|
+
RAG_ENABLED=true
|
|
19
|
+
RAG_KNOWLEDGE_DIR=knowledge
|
|
20
|
+
RAG_COLLECTION=ops_knowledge
|
|
21
|
+
RAG_EMBEDDING_MODEL={{RAG_EMBEDDING_MODEL}}
|
|
22
|
+
RAG_TOP_K=5
|
|
23
|
+
RAG_CHUNK_SIZE=1200
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
union-py-app:
|
|
2
|
+
test:
|
|
3
|
+
test:
|
|
4
|
+
- template: deploy/autoconf/templates/env.j2
|
|
5
|
+
dest: app/config/env/.env.test.bj12
|
|
6
|
+
prod:
|
|
7
|
+
bj11:
|
|
8
|
+
- template: deploy/autoconf/templates/env.j2
|
|
9
|
+
dest: app/config/env/.env.prod.bj11
|
|
10
|
+
sh20:
|
|
11
|
+
- template: deploy/autoconf/templates/env.j2
|
|
12
|
+
dest: app/config/env/.env.prod.sh20
|
|
13
|
+
sz31:
|
|
14
|
+
- template: deploy/autoconf/templates/env.j2
|
|
15
|
+
dest: app/config/env/.env.prod.sz31
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
set -u
|
|
4
|
+
|
|
5
|
+
TIMEOUT_SECONDS="${HEALTHCHECK_TIMEOUT_SECONDS:-5}"
|
|
6
|
+
|
|
7
|
+
probe_http() {
|
|
8
|
+
local url="$1"
|
|
9
|
+
curl --fail --silent --show-error --max-time "$TIMEOUT_SECONDS" "$url" >/dev/null
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
probe_http "${APP_HEALTHCHECK_URL:-http://127.0.0.1:${APP_PORT:-8080}/healthcheck.html}" || exit 1
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# 脚本:启动 ASGI 应用
|
|
3
|
+
# 功能:
|
|
4
|
+
# 1.删除旧的union-py虚拟环境
|
|
5
|
+
# 2.创建新venv环境并安装依赖
|
|
6
|
+
# 3.启动ASGI服务
|
|
7
|
+
ASGI_APP="app.asgi:app"
|
|
8
|
+
PYTHON="python"
|
|
9
|
+
LOG_ACCESS_FILE="/data/dataLogs/hypercorn_$(date '+%Y-%m-%d_%H_%M_%S').log"
|
|
10
|
+
|
|
11
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
12
|
+
VENV_DIR="$ROOT_DIR/union_py"
|
|
13
|
+
REQUIREMENTS="$ROOT_DIR/requirements.txt"
|
|
14
|
+
OFFLINK_PKGS="$ROOT_DIR/deploy/offline-packages"
|
|
15
|
+
PID_FILE="$ROOT_DIR/deploy/scripts/pid"
|
|
16
|
+
STARTUP_TIMEOUT_SECONDS="${APP_STARTUP_TIMEOUT_SECONDS:-300}"
|
|
17
|
+
export PYTHONUNBUFFERED=1
|
|
18
|
+
export APP_ENV="${APP_ENV:-dev}"
|
|
19
|
+
mkdir -p "$(dirname "$LOG_ACCESS_FILE")"
|
|
20
|
+
echo "切换到项目目录$ROOT_DIR 并设置APP_ENV环境变量:$APP_ENV" >> "$LOG_ACCESS_FILE"
|
|
21
|
+
BIND_HOST="127.0.0.1"
|
|
22
|
+
if [[ "$APP_ENV" == *test* ]]; then
|
|
23
|
+
BIND_HOST="0.0.0.0"
|
|
24
|
+
fi
|
|
25
|
+
echo "开始启动,当前目录:$(pwd)...." >> "$LOG_ACCESS_FILE"
|
|
26
|
+
if [ -d "$VENV_DIR" ]; then
|
|
27
|
+
echo "删除现有环境:$VENV_DIR" >> "$LOG_ACCESS_FILE"
|
|
28
|
+
rm -rf "$VENV_DIR"
|
|
29
|
+
else
|
|
30
|
+
echo "虚拟环境$VENV_DIR 不存在,跳过删除" >> "$LOG_ACCESS_FILE"
|
|
31
|
+
fi
|
|
32
|
+
echo "开始创建虚拟环境$VENV_DIR " >> "$LOG_ACCESS_FILE"
|
|
33
|
+
$PYTHON -m venv "$VENV_DIR"
|
|
34
|
+
if [ $? -ne 0 ]; then
|
|
35
|
+
echo "创建虚拟环境$VENV_DIR 失败,请检查python3 和venv命令是否可用" >> "$LOG_ACCESS_FILE"
|
|
36
|
+
exit 1
|
|
37
|
+
fi
|
|
38
|
+
source "$VENV_DIR/bin/activate"
|
|
39
|
+
echo "虚拟环境$VENV_DIR 创建成功.并已激活虚拟环境$VENV_DIR" >> "$LOG_ACCESS_FILE"
|
|
40
|
+
|
|
41
|
+
echo "安装依赖 from $REQUIREMENTS 文件" >> "$LOG_ACCESS_FILE"
|
|
42
|
+
if [ ! -f "$REQUIREMENTS" ]; then
|
|
43
|
+
echo "$REQUIREMENTS 文件不存在,退出" >> "$LOG_ACCESS_FILE"
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
pip install \
|
|
47
|
+
--no-index \
|
|
48
|
+
--find-links "$OFFLINK_PKGS" \
|
|
49
|
+
--no-cache-dir \
|
|
50
|
+
-r "$REQUIREMENTS" || { echo "依赖安装失败,请检查离线包是否完整" >> "$LOG_ACCESS_FILE"; exit 1 ;}
|
|
51
|
+
|
|
52
|
+
echo "安装依赖完成。启动ASGI应用:$ASGI_APP" >> "$LOG_ACCESS_FILE"
|
|
53
|
+
cd "$ROOT_DIR"
|
|
54
|
+
hypercorn \
|
|
55
|
+
--workers 1 \
|
|
56
|
+
--bind "$BIND_HOST":8080 \
|
|
57
|
+
--keep-alive 2 \
|
|
58
|
+
--pid "$PID_FILE" \
|
|
59
|
+
"$ASGI_APP" \
|
|
60
|
+
>> "$LOG_ACCESS_FILE" 2>&1 &
|
|
61
|
+
echo $! >> "$LOG_ACCESS_FILE"
|
|
62
|
+
|
|
63
|
+
for i in $(seq 1 "$STARTUP_TIMEOUT_SECONDS");do
|
|
64
|
+
if [ -f "$PID_FILE" ] ;then
|
|
65
|
+
PID=$(cat "$PID_FILE" 2>/dev/null)
|
|
66
|
+
if [ -n "$PID" ] && kill -0 "$PID" 2>/dev/null ; then
|
|
67
|
+
if HEALTHCHECK_TIMEOUT_SECONDS=1 bash "$ROOT_DIR/deploy/scripts/healthcheck.sh"; then
|
|
68
|
+
echo "hypercorn 已就绪(PID:$PID)"
|
|
69
|
+
exit 0
|
|
70
|
+
fi
|
|
71
|
+
else
|
|
72
|
+
break
|
|
73
|
+
fi
|
|
74
|
+
fi
|
|
75
|
+
sleep 1
|
|
76
|
+
done
|
|
77
|
+
|
|
78
|
+
echo "hypercorn 未在 ${STARTUP_TIMEOUT_SECONDS}s 内就绪" >> "$LOG_ACCESS_FILE"
|
|
79
|
+
bash "$ROOT_DIR/deploy/scripts/stop.sh"
|
|
80
|
+
exit 1
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
4
|
+
|
|
5
|
+
PID_FILE="$ROOT_DIR/deploy/scripts/pid"
|
|
6
|
+
|
|
7
|
+
quiet_stop(){
|
|
8
|
+
local pid_file="$1"
|
|
9
|
+
local name="$2"
|
|
10
|
+
if [ ! -f "$pid_file" ];then
|
|
11
|
+
return 0
|
|
12
|
+
fi
|
|
13
|
+
PID=$(cat "$pid_file" 2>/dev/null)
|
|
14
|
+
if [ -z "$PID" ];then
|
|
15
|
+
rm -f "$pid_file"
|
|
16
|
+
return 0
|
|
17
|
+
fi
|
|
18
|
+
if kill -0 "$PID" 2>/dev/null; then
|
|
19
|
+
echo "正在停止 $name(PID:$PID)..."
|
|
20
|
+
kill "$PID" >/dev/null 2>&1
|
|
21
|
+
for i in {1..5}; do
|
|
22
|
+
if ! kill -0 "$PID" 2>/dev/null; then
|
|
23
|
+
echo "$name(PID:$PID) 已停止"
|
|
24
|
+
rm -f "$pid_file"
|
|
25
|
+
return 0
|
|
26
|
+
fi
|
|
27
|
+
sleep 1
|
|
28
|
+
done
|
|
29
|
+
echo "兜底,强制停止"
|
|
30
|
+
kill -9 "$PID" 2>/dev/null
|
|
31
|
+
fi
|
|
32
|
+
rm -f "$pid_file"
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
quiet_stop "$PID_FILE" "hypercorn"
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
---
|
|
2
|
+
kb_id: scenario-offline-function-call-mock-v1
|
|
3
|
+
title: 成员机构运行质量分析场景指南
|
|
4
|
+
doc_type: scenario
|
|
5
|
+
domain: 联合运维
|
|
6
|
+
category: 运行质量分析
|
|
7
|
+
category_description: 指导模型在联合运维场景中围绕成员机构运行质量调用工具、组织证据并形成分析结论。
|
|
8
|
+
category_keywords:
|
|
9
|
+
- 运行质量
|
|
10
|
+
- 成员机构
|
|
11
|
+
- 系统成功率
|
|
12
|
+
- 平均耗时
|
|
13
|
+
- 交易量
|
|
14
|
+
- 失败率
|
|
15
|
+
- 变更报备
|
|
16
|
+
- Jira故障
|
|
17
|
+
- 根因辅助分析
|
|
18
|
+
status: active
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
# 成员机构运行质量分析场景指南
|
|
22
|
+
|
|
23
|
+
当用户询问某家成员机构“近期运行质量如何”“过去一段时间运行表现怎样”“有没有影响运行质量的因素”时,应把问题识别为成员机构运行质量分析场景。
|
|
24
|
+
|
|
25
|
+
运行质量不是单一系统成功率指标。系统成功率是核心指标,但平均耗时、交易量、失败笔数、失败率、同期变更、同期故障都会影响对运行质量的判断。
|
|
26
|
+
|
|
27
|
+
## 默认时间范围
|
|
28
|
+
|
|
29
|
+
用户没有明确时间范围时,使用近 30 天作为默认分析窗口,并在回答中说明“按近 30 天分析”。
|
|
30
|
+
|
|
31
|
+
常见时间表达处理规则:
|
|
32
|
+
|
|
33
|
+
- “近期”“最近”“过去一段时间”:近 30 天。
|
|
34
|
+
- “本月”:当前自然月开始日至当前日期。
|
|
35
|
+
- “上月”:上一自然月。
|
|
36
|
+
- “过去 N 天”:按用户给出的 N 天。
|
|
37
|
+
- “过去 N 个月”:按用户给出的 N 个月。
|
|
38
|
+
- 如果用户给出明确日期,以用户日期为准。
|
|
39
|
+
|
|
40
|
+
工具入参中的日期优先使用 `yyyyMMdd` 格式,例如 `20260513`。
|
|
41
|
+
|
|
42
|
+
## 推荐工具调用顺序
|
|
43
|
+
|
|
44
|
+
分析某家机构时,优先按以下顺序调用工具:
|
|
45
|
+
|
|
46
|
+
1. `runningAnalysis.resolve_member_org`
|
|
47
|
+
|
|
48
|
+
根据用户输入的机构名称、简称或别名识别标准机构和 `orgCode`。例如用户说“中国银行”“中行”“BOC”,不要直接猜测机构编码。
|
|
49
|
+
|
|
50
|
+
2. `runningAnalysis.query_member_metrics`
|
|
51
|
+
|
|
52
|
+
使用 `orgCodeList + startDate + endDate` 查询一个或多个机构每日运行指标;单机构也传数组,例如 `["C100000000"]`。重点关注系统成功率、平均耗时、交易笔数、失败笔数、失败率。
|
|
53
|
+
|
|
54
|
+
3. `runningAnalysis.query_changes`
|
|
55
|
+
|
|
56
|
+
使用同一机构和同一时间窗口查询变更报备。重点关注计划开始时间、计划结束时间、变更状态、执行评价、影响范围。
|
|
57
|
+
|
|
58
|
+
4. `runningAnalysis.query_faults`
|
|
59
|
+
|
|
60
|
+
使用同一机构和同一时间窗口查询 Jira 故障工单。重点关注故障时间、恢复时间、故障等级、影响范围、影响描述、故障原因。
|
|
61
|
+
|
|
62
|
+
5. `runningAnalysis.query_chain_metrics`
|
|
63
|
+
|
|
64
|
+
当需要判断某机构异常是否具有全局背景时,可查询同一时间窗口的全链路指标作为对照。如果全链路整体稳定而单机构异常,更偏向机构侧因素;如果全链路同时波动,更偏向平台或公共链路因素。
|
|
65
|
+
|
|
66
|
+
## 运行指标分析方法
|
|
67
|
+
|
|
68
|
+
应综合判断以下指标:
|
|
69
|
+
|
|
70
|
+
- 系统成功率:核心稳定性指标。下降代表交易成功能力变弱。
|
|
71
|
+
- 失败率和失败笔数:用于判断成功率变化背后的实际影响。低交易量下成功率波动可能被放大,高交易量下少量成功率下降也可能代表大量失败交易。
|
|
72
|
+
- 平均耗时:核心性能指标。成功率稳定但耗时明显上升,说明用户体验和处理性能可能劣化。
|
|
73
|
+
- 交易笔数:核心业务流量指标。成功率稳定但交易量异常下降,可能代表业务流量、接入、路由或前置系统存在问题。
|
|
74
|
+
- 连续性:单日尖峰和连续多日劣化含义不同。连续多日成功率下降、耗时上升或失败率升高,风险更高。
|
|
75
|
+
|
|
76
|
+
分析时不要只看单个日期,也要观察趋势:
|
|
77
|
+
|
|
78
|
+
- 成功率是否低于近期均值。
|
|
79
|
+
- 平均耗时是否持续升高。
|
|
80
|
+
- 失败笔数是否集中在某几天。
|
|
81
|
+
- 交易笔数是否突然下降或突然放大。
|
|
82
|
+
- 成员机构指标是否明显偏离全链路指标。
|
|
83
|
+
|
|
84
|
+
## 变更关联分析方法
|
|
85
|
+
|
|
86
|
+
变更可能影响运行质量,但不能仅凭时间接近就断言变更导致异常。应做相关性判断:
|
|
87
|
+
|
|
88
|
+
- 如果运行指标劣化时间与变更计划开始时间、执行时间高度重合,标记为“变更相关性较高”。
|
|
89
|
+
- 如果变更执行评价为异常、失败、回退、部分成功,且同日或次日运行指标劣化,标记为重点关注。
|
|
90
|
+
- 如果变更影响范围包含核心支付链路、前置系统、网络策略、清算链路、接入链路,相关性高于普通配置或低风险变更。
|
|
91
|
+
- 如果变更时间远离指标波动时间,或变更执行评价正常且影响范围较小,应降低变更相关性。
|
|
92
|
+
|
|
93
|
+
回答时使用“可能相关”“相关性较高”“需要进一步核实”,不要直接说“由该变更导致”。
|
|
94
|
+
|
|
95
|
+
## 故障关联分析方法
|
|
96
|
+
|
|
97
|
+
Jira 故障是解释运行质量波动的重要证据:
|
|
98
|
+
|
|
99
|
+
- 如果故障发生时间与成功率下降、失败率升高、耗时上升时间重合,故障相关性较高。
|
|
100
|
+
- 高等级故障、影响范围涉及该成员机构核心交易链路时,应提高风险判断。
|
|
101
|
+
- 故障恢复时间之后指标恢复,说明故障与运行质量波动可能存在较强关联。
|
|
102
|
+
- 故障原因如果指向网络、前置系统、核心支付链路、数据库、中间件、限流、超时,与耗时和失败率变化更相关。
|
|
103
|
+
- 多个低等级故障集中发生,也可能形成累计影响。
|
|
104
|
+
|
|
105
|
+
同样不能直接断言因果。应说明证据链:故障时间、故障等级、影响范围、指标变化之间是否吻合。
|
|
106
|
+
|
|
107
|
+
## 总体运行质量判断
|
|
108
|
+
|
|
109
|
+
可以使用以下分层:
|
|
110
|
+
|
|
111
|
+
- 良好:成功率稳定,耗时稳定,交易量无异常,失败笔数和失败率低,未发现相关变更或故障影响。
|
|
112
|
+
- 基本稳定但需关注:核心指标总体正常,但存在单日波动、耗时上升、交易量异常、轻微故障或近期变更。
|
|
113
|
+
- 有波动:成功率或失败率出现明显波动,或耗时/交易量有异常,同时存在同期变更或故障。
|
|
114
|
+
- 明显异常:成功率下降、失败率上升、耗时明显恶化或交易量异常,并且故障或异常变更与波动时间高度重合。
|
|
115
|
+
|
|
116
|
+
## 输出建议结构
|
|
117
|
+
|
|
118
|
+
回答运行质量分析问题时,建议使用以下结构:
|
|
119
|
+
|
|
120
|
+
1. 总体判断:一句话说明运行质量是良好、基本稳定、有波动还是明显异常。
|
|
121
|
+
2. 运行指标表现:说明成功率、平均耗时、交易量、失败笔数、失败率的主要变化。
|
|
122
|
+
3. 变更关联分析:列出同期变更及其计划时间、状态、执行评价、影响范围,并判断相关性。
|
|
123
|
+
4. 故障关联分析:列出同期故障及故障时间、等级、影响范围、原因、恢复情况,并判断相关性。
|
|
124
|
+
5. 可能影响因素排序:按证据强弱排序,例如故障影响、变更影响、交易量变化、全链路背景等。
|
|
125
|
+
6. 不确定性:说明哪些结论只是相关性判断,哪些需要进一步查看日志、监控或工单详情。
|
|
126
|
+
7. 建议动作:例如关注后续指标、复核变更执行记录、跟进未关闭故障、对异常日期做链路排查。
|
|
127
|
+
|
|
128
|
+
## 重要约束
|
|
129
|
+
|
|
130
|
+
- 不要编造机构编码。缺少 `orgCode` 时先调用 `runningAnalysis.resolve_member_org`。
|
|
131
|
+
- 不要只基于系统成功率下结论。
|
|
132
|
+
- 不要把变更或故障直接断定为根因,除非工具返回中已有明确结论。
|
|
133
|
+
- 如果工具数据为空,应明确说明“未查询到相关数据”,不要补造。
|
|
134
|
+
- 如果运行指标、变更、故障之间结论冲突,应分别说明证据,并给出保守判断。
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "union-app-chat-stream",
|
|
3
|
+
"version": "1.1.6",
|
|
4
|
+
"description": "Union operations PydanticAI ASGI service package.",
|
|
5
|
+
"license": "UNLICENSED",
|
|
6
|
+
"files": [
|
|
7
|
+
"app",
|
|
8
|
+
"!app/config/env/.env",
|
|
9
|
+
"!app/config/env/.env.*",
|
|
10
|
+
"!app/**/__pycache__",
|
|
11
|
+
"!app/**/*.pyc",
|
|
12
|
+
"deploy",
|
|
13
|
+
"!deploy/**/__pycache__",
|
|
14
|
+
"!deploy/**/*.pyc",
|
|
15
|
+
"!deploy/offline-packages",
|
|
16
|
+
"!deploy/offline-packages/**",
|
|
17
|
+
"scripts",
|
|
18
|
+
"knowledge",
|
|
19
|
+
"requirements.txt"
|
|
20
|
+
]
|
|
21
|
+
}
|
package/requirements.txt
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
prod.bj11
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
test.bj12
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
prod.sh20
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
prod.sz31
|
package/scripts/stop.sh
ADDED