union-app-chat-stream 1.0.3

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.
Files changed (108) hide show
  1. package/.gitignore +16 -0
  2. package/PROJECT_OVERVIEW.md +187 -0
  3. package/app/.env +63 -0
  4. package/app/.env.dev +63 -0
  5. package/app/.env.prod.bj11 +63 -0
  6. package/app/.env.prod.sh20 +63 -0
  7. package/app/.env.prod.sz31 +63 -0
  8. package/app/.env.test.bj12 +63 -0
  9. package/app/__init__.py +42 -0
  10. package/app/__pycache__/__init__.cpython-312.pyc +0 -0
  11. package/app/__pycache__/authenticated_user.cpython-312.pyc +0 -0
  12. package/app/__pycache__/extensions.cpython-312.pyc +0 -0
  13. package/app/__pycache__/wsgi.cpython-312.pyc +0 -0
  14. package/app/authenticated_user.py +77 -0
  15. package/app/config/__pycache__/config_loader.cpython-312.pyc +0 -0
  16. package/app/config/__pycache__/env_config.cpython-312.pyc +0 -0
  17. package/app/config/__pycache__/logger_config.cpython-312.pyc +0 -0
  18. package/app/config/env_config.py +96 -0
  19. package/app/config/logger_config.py +46 -0
  20. package/app/manager/__init__.py +4 -0
  21. package/app/manager/__pycache__/__init__.cpython-312.pyc +0 -0
  22. package/app/manager/__pycache__/chatstream_manager.cpython-312.pyc +0 -0
  23. package/app/manager/__pycache__/prompts.cpython-312.pyc +0 -0
  24. package/app/manager/__pycache__/runtime_manager.cpython-312.pyc +0 -0
  25. package/app/manager/__pycache__/toolcall_manager.cpython-312.pyc +0 -0
  26. package/app/manager/chatstream_manager.py +90 -0
  27. package/app/manager/prompts.py +62 -0
  28. package/app/manager/runtime_manager.py +552 -0
  29. package/app/models/__pycache__/schemas.cpython-312.pyc +0 -0
  30. package/app/models/schemas.py +30 -0
  31. package/app/service/__init__.py +4 -0
  32. package/app/service/__pycache__/__init__.cpython-312.pyc +0 -0
  33. package/app/service/__pycache__/chat_service.cpython-312.pyc +0 -0
  34. package/app/service/__pycache__/llm_service.cpython-312.pyc +0 -0
  35. package/app/service/__pycache__/rag_service.cpython-312.pyc +0 -0
  36. package/app/service/__pycache__/tool_call_service.cpython-312.pyc +0 -0
  37. package/app/service/__pycache__/union_service.cpython-312.pyc +0 -0
  38. package/app/service/chat_service.py +228 -0
  39. package/app/service/llm_service.py +214 -0
  40. package/app/service/rag_service.py +866 -0
  41. package/app/service/union_service.py +201 -0
  42. package/app/utils/__init__.py +5 -0
  43. package/app/utils/__pycache__/__init__.cpython-312.pyc +0 -0
  44. package/app/utils/__pycache__/common_utils.cpython-312.pyc +0 -0
  45. package/app/utils/__pycache__/debug_context.cpython-312.pyc +0 -0
  46. package/app/utils/__pycache__/function_utils.cpython-312.pyc +0 -0
  47. package/app/utils/__pycache__/jwt_utils.cpython-312.pyc +0 -0
  48. package/app/utils/common_utils.py +169 -0
  49. package/app/utils/debug_context.py +16 -0
  50. package/app/utils/function_utils.py +274 -0
  51. package/app/utils/jwt_utils.py +39 -0
  52. package/app/views/__init__.py +6 -0
  53. package/app/views/__pycache__/__init__.cpython-312.pyc +0 -0
  54. package/app/views/__pycache__/view_chatstream.cpython-312.pyc +0 -0
  55. package/app/views/__pycache__/view_healthcheck.cpython-312.pyc +0 -0
  56. package/app/views/__pycache__/view_runtime.cpython-312.pyc +0 -0
  57. package/app/views/view_chatstream.py +53 -0
  58. package/app/views/view_healthcheck.py +14 -0
  59. package/app/views/view_runtime.py +72 -0
  60. package/app/wsgi.py +37 -0
  61. package/ci.yml +14 -0
  62. package/deploy/autoconf/templates/env.j2 +25 -0
  63. package/deploy/autoconf.yml +15 -0
  64. package/deploy/scripts/healthcheck.sh +0 -0
  65. package/deploy/scripts/requirements.txt +53 -0
  66. package/deploy/scripts/start.sh +75 -0
  67. package/deploy/scripts/stop.sh +31 -0
  68. package/knowledge/.gitkeep +0 -0
  69. package/knowledge/000001-biz-offline-85b99bd43b-v1.md +88 -0
  70. package/knowledge/000002-biz-offline-717e8d823e-v1.md +90 -0
  71. package/knowledge/000003-biz-offline-c963227cc8-v1.md +84 -0
  72. package/knowledge/000004-biz-offline-2a5868e7da-v1.md +92 -0
  73. package/knowledge/000005-biz-offline-f9d9cf1a88-v1.md +79 -0
  74. package/knowledge/000006-biz-offline-c4fa2df3bd-v1.md +77 -0
  75. package/knowledge/000007-biz-offline-78304b70ca-v1.md +76 -0
  76. package/knowledge/000008-biz-offline-987ae67b35-v1.md +75 -0
  77. package/knowledge/000009-biz-offline-4d656bcea3-v1.md +85 -0
  78. package/knowledge/000010-sop-offline-a9e1050719-v1.md +100 -0
  79. package/knowledge/000011-biz-offline-5de0624891-v1.md +86 -0
  80. package/knowledge/000012-biz-offline-7dfacccba3-v1.md +82 -0
  81. package/knowledge/000013-biz-offline-5e1d29d2ed-v1.md +81 -0
  82. package/knowledge/000014-biz-offline-1d0ed8b841-v1.md +68 -0
  83. package/knowledge/000015-biz-offline-8a1376ee3e-v1.md +78 -0
  84. package/knowledge/000016-biz-offline-c8bfc2aa08-v1.md +99 -0
  85. package/knowledge/000017-biz-offline-9dffb28032-v1.md +88 -0
  86. package/knowledge/000018-biz-offline-f935bc9a6a-v1.md +80 -0
  87. package/knowledge/000019-biz-offline-858b3ecd89-v1.md +86 -0
  88. package/knowledge/000020-biz-offline-65cb5c4f40-v1.md +113 -0
  89. package/knowledge/000021-biz-offline-1bf211639c-v1.md +148 -0
  90. package/knowledge/000022-biz-offline-8c5a637879-v1.md +140 -0
  91. package/knowledge/000023-biz-offline-fe872b8712-v1.md +188 -0
  92. package/knowledge/000024-biz-offline-a85010c500-v1.md +133 -0
  93. package/knowledge/000025-biz-offline-8af58a3638-v1.md +136 -0
  94. package/knowledge/000026-biz-offline-6754102e93-v1.md +142 -0
  95. package/knowledge/000027-biz-offline-ea2e5ca5f9-v1.md +150 -0
  96. package/knowledge/000028-scenario-offline-dab45cebb4-v1.md +136 -0
  97. package/knowledge/000029-scenario-offline-5b8ae5ea9f-v1.md +143 -0
  98. package/knowledge/000030-scenario-offline-9a82d42f3f-v1.md +136 -0
  99. package/knowledge/000031-scenario-offline-cc2edc0197-v1.md +122 -0
  100. package/knowledge/000032-scenario-offline-e5f6e5cbfa-v1.md +122 -0
  101. package/knowledge/000033-scenario-offline-e1955849aa-v1.md +135 -0
  102. package/knowledge/000034-scenario-offline-3a13d49a3a-v1.md +138 -0
  103. package/knowledge/000035-scenario-offline-fd5560211f-v1.md +147 -0
  104. package/knowledge/000036-scenario-offline-function-call-mock-v1.md +134 -0
  105. package/package.json +18 -0
  106. package/requirements.txt +53 -0
  107. package/tools/prompts.yaml +10 -0
  108. package/tools/tool_definitions.yaml +303 -0
@@ -0,0 +1,77 @@
1
+ from flask import Flask, request, jsonify, g, has_request_context
2
+ from werkzeug.exceptions import HTTPException
3
+ from loguru import logger
4
+ from app.utils import common_utils
5
+ from app.config.logger_config import setup_logger
6
+ from contextvars import ContextVar
7
+
8
+ _current_ip: ContextVar[str] = ContextVar("current_ip", default="unknown_ip")
9
+
10
+ logger = setup_logger()
11
+
12
+
13
+ class FlaskSessionClient:
14
+ def __init__(self, app):
15
+ self.auth_user_server = app.config['GET_USE_INFO_URL']
16
+ self.permissions = app.config['PERMISSIONS']
17
+ self.init_app(app)
18
+
19
+ def init_app(self, app: Flask):
20
+ def patcher(record):
21
+ record["extra"]["ip"] = _current_ip.get()
22
+
23
+ logger.configure(patcher=patcher)
24
+
25
+ @app.before_request
26
+ def require_auth():
27
+ try:
28
+ if has_request_context():
29
+ ip = common_utils.get_client_ip()
30
+ except LookupError:
31
+ ip = "unknown_context-lost"
32
+ _current_ip.set(ip)
33
+
34
+ if request.method == 'OPTIONS':
35
+ return
36
+
37
+ public_paths = [
38
+ '/healthcheck.html',
39
+ '/favicon.ico'
40
+ ]
41
+ if any(request.path == path or request.path.startswith(path) for path in public_paths):
42
+ return
43
+
44
+ g.current_user = {'jsessionid': 'test-jsessionid'}
45
+ return
46
+
47
+ jsessionid = request.headers.get('Cookie')
48
+
49
+ if not jsessionid:
50
+ logger.error("未登录")
51
+ return jsonify({"error": "auth error"}), 401
52
+
53
+ try:
54
+ response = common_utils.call_https_api(url=self.auth_user_server,
55
+ headers={'Cookie': 'CASSESSIONID=' + jsessionid},
56
+ method='GET', verify_ssl=False)
57
+ if response.get('status_code') != 200 or not response.get('data'):
58
+ logger.error("验证失败")
59
+ return jsonify({"error": "auth error"}), 401
60
+ user = response.get('data')
61
+ if user['loginName'] and self.permissions and self.permissions not in user['permissions']:
62
+ return jsonify({"error": "auth error"}), 401
63
+ g.current_user = response.get('data')
64
+ g.current_user['jsessionid'] = jsessionid
65
+
66
+ return
67
+ except Exception as e:
68
+ logger.error(f"auth 验证失败: {str(e)},路径: {request.path}")
69
+ return jsonify({"error": "auth error"}), 401
70
+
71
+ @app.errorhandler(Exception)
72
+ def handle_exception(e):
73
+ if isinstance(e, HTTPException):
74
+ return e
75
+
76
+ logger.error(f"未处理的异常: {str(e)}")
77
+ return jsonify({"error": "Internal Server Error"}), 500
@@ -0,0 +1,96 @@
1
+ import os
2
+
3
+
4
+ def _env_bool(name, default=False):
5
+ value = os.getenv(name)
6
+ if value is None:
7
+ return default
8
+ return value.lower() in {"1", "true", "yes", "on"}
9
+
10
+
11
+ def _env_int(name, default):
12
+ value = os.getenv(name)
13
+ if value is None:
14
+ return default
15
+ try:
16
+ return int(value)
17
+ except ValueError:
18
+ return default
19
+
20
+
21
+ def _env_float(name, default):
22
+ value = os.getenv(name)
23
+ if value is None:
24
+ return default
25
+ try:
26
+ return float(value)
27
+ except ValueError:
28
+ return default
29
+
30
+
31
+ def _env_list(name, default=None):
32
+ value = os.getenv(name)
33
+ if value is None:
34
+ return default or []
35
+ return [item.strip() for item in value.split(",") if item.strip()]
36
+
37
+
38
+ class Config:
39
+ SECRET_KEY = os.getenv('SECRET_KEY')
40
+ GET_USE_INFO_URL = os.getenv('GET_USE_INFO_URL')
41
+ GET_ORG_INFO_URL = os.getenv('GET_ORG_INFO_URL')
42
+ GET_JIRA_INFO_URL = os.getenv('GET_JIRA_INFO_URL')
43
+ GET_BIGDATA_URL = os.getenv('GET_BIGDATA_URL')
44
+ GET_UNION_BASE_URL = os.getenv('GET_UNION_BASE_URL')
45
+ GET_ORG_INFO_URL_TOKEN = os.getenv('GET_ORG_INFO_URL_TOKEN')
46
+ GET_JIRA_INFO_URL_TOKEN = os.getenv('GET_JIRA_INFO_URL_TOKEN')
47
+ PERMISSIONS = os.getenv('PERMISSIONS')
48
+ LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO")
49
+ CONSOLE_STDOUT = os.getenv("CONSOLE_STDOUT", "FALSE")
50
+ LOG_DIR = os.getenv("LOG_DIR", "/data/appLogs")
51
+ FLASK_ENV = os.getenv("FLASK_ENV", "prod")
52
+ JWT_SECRET_KEY = os.getenv("JWT_SECRET_KEY", f"union-fall-back-secret-for-{FLASK_ENV}")
53
+ JWT_EXPIRATION_SECOND = os.getenv("JWT_EXPIRATION_SECOND", 900)
54
+ JWT_RENEW_SECOND = os.getenv("JWT_RENEW_SECOND", 120)
55
+
56
+ # 大模型地址
57
+ LLM_URL = os.getenv('LLM_URL')
58
+ LLM_KEY = os.getenv('LLM_KEY')
59
+ LLM_MODEL = os.getenv('LLM_MODEL') # 默认模型名称
60
+ LLM_MAX_TOKENS = _env_int("LLM_MAX_TOKENS", 4096)
61
+ LLM_TEMPERATURE = _env_float("LLM_TEMPERATURE", 0.7)
62
+ LLM_TOP_P = _env_float("LLM_TOP_P", 0.9)
63
+
64
+ SYSTEM_PROMPT = os.getenv("SYSTEM_PROMPT", "")
65
+
66
+ FILTER_ENABLED = _env_bool("FILTER_ENABLED", False)
67
+ FILTER_ALLOWED_KEYWORDS = _env_list("FILTER_ALLOWED_KEYWORDS")
68
+ FILTER_REJECTION_MESSAGE = os.getenv(
69
+ "FILTER_REJECTION_MESSAGE",
70
+ "抱歉,我是联合运维智能客服,只能回答与联合运维相关的问题。",
71
+ )
72
+
73
+ TOOLS_MAX_ROUNDS = _env_int("TOOLS_MAX_ROUNDS", 5)
74
+
75
+ CONVERSATION_MAX_HISTORY = _env_int("CONVERSATION_MAX_HISTORY", 20)
76
+ CONVERSATION_TTL = _env_int("CONVERSATION_TTL", 3600)
77
+
78
+ RAG_ENABLED = _env_bool("RAG_ENABLED", True)
79
+ RAG_KNOWLEDGE_DIR = os.getenv("RAG_KNOWLEDGE_DIR", "knowledge")
80
+ RAG_PERSIST_DIR = os.getenv("RAG_PERSIST_DIR", ".chroma")
81
+ RAG_COLLECTION = os.getenv("RAG_COLLECTION", "ops_knowledge")
82
+ RAG_EMBEDDING_MODEL = os.getenv("RAG_EMBEDDING_MODEL", "embedding-3")
83
+ RAG_EMBEDDING_MAX_CHARS = _env_int("RAG_EMBEDDING_MAX_CHARS", 6000)
84
+ RAG_EMBEDDING_BATCH_SIZE = _env_int("RAG_EMBEDDING_BATCH_SIZE", 8)
85
+ RAG_TOP_K = _env_int("RAG_TOP_K", 5)
86
+ RAG_SEMANTIC_CANDIDATE_K = _env_int("RAG_SEMANTIC_CANDIDATE_K", 40)
87
+ RAG_CONTEXT_K = _env_int("RAG_CONTEXT_K", 8)
88
+ RAG_EXACT_CONTEXT_K = _env_int("RAG_EXACT_CONTEXT_K", 6)
89
+ RAG_EXACT_PER_FILE_CONTEXT_K = _env_int("RAG_EXACT_PER_FILE_CONTEXT_K", 1)
90
+ RAG_PER_FILE_CONTEXT_K = _env_int("RAG_PER_FILE_CONTEXT_K", 2)
91
+ RAG_CHUNK_SIZE = _env_int("RAG_CHUNK_SIZE", 1200)
92
+ RAG_REBUILD_ON_STARTUP = _env_bool("RAG_REBUILD_ON_STARTUP", False)
93
+
94
+ @classmethod
95
+ def init_app(cls, app):
96
+ pass
@@ -0,0 +1,46 @@
1
+ from loguru import logger
2
+ import os
3
+
4
+
5
+ def setup_logger():
6
+
7
+
8
+ env = os.getenv("FLASK_ENV", "prod")
9
+ log_level = os.getenv("LOG_LEVEL", "INFO")
10
+ console_stdout = os.getenv("CONSOLE_STDOUT", "FALSE")
11
+ log_dir = os.getenv("LOG_DIR", "/data/appLogs")
12
+ os.makedirs(log_dir, exist_ok=True)
13
+ app_log_path = os.path.join(log_dir, "union-py-app.log")
14
+ error_log_path = os.path.join(log_dir, "union-py-error.log")
15
+ logger.remove()
16
+
17
+ logger.configure(extra={"ip": "unknown_ip"})
18
+ log_format = "{time:YYYY-MM-DD HH:mm:ss}|{level:8}|{extra[ip]}|{name}:{function}:{line}|{message}"
19
+
20
+ logger.add(
21
+ app_log_path,
22
+ rotation="500 MB",
23
+ retention="30 days",
24
+ compression="gz",
25
+ level=log_level,
26
+ format=log_format,
27
+ enqueue=True,
28
+ encoding="utf=8"
29
+ )
30
+ logger.add(
31
+ error_log_path,
32
+ rotation="500 MB",
33
+ retention="30 days",
34
+ compression="gz",
35
+ level="ERROR",
36
+ encoding="utf=8"
37
+ )
38
+ if console_stdout:
39
+ logger.add(
40
+ sink=lambda msg: print(msg, end=""),
41
+ level=log_level,
42
+ format=log_format,
43
+ enqueue=True
44
+ )
45
+
46
+ return logger
@@ -0,0 +1,4 @@
1
+ from .chatstream_manager import ChatstreamManager
2
+ from .runtime_manager import RuntimeManager
3
+
4
+ __all__ = ["ChatstreamManager", "RuntimeManager"]
@@ -0,0 +1,90 @@
1
+ import threading
2
+ import time
3
+ from typing import Dict, Generator, List, Optional
4
+ from uuid import uuid4
5
+
6
+ from app.models.schemas import ChatResponse
7
+ from app.service.chat_service import ChatService
8
+ from app.service.rag_service import RagService
9
+ from app.utils.function_utils import tools
10
+
11
+
12
+ class ChatstreamManager:
13
+ def __init__(self, config, chat_service: ChatService, rag_service: RagService):
14
+ self._chat_service = chat_service
15
+ self._rag_service = rag_service
16
+ self._conversations: Dict[str, Dict] = {}
17
+ self._max_history = config["CONVERSATION_MAX_HISTORY"]
18
+ self._ttl = config["CONVERSATION_TTL"]
19
+ self._lock = threading.Lock()
20
+
21
+ @staticmethod
22
+ def normalize_conversation_id(conversation_id: Optional[str]) -> str:
23
+ normalized = (conversation_id or "").strip()
24
+ return normalized or f"conv-{uuid4().hex}"
25
+
26
+ def check_rag(self) -> Dict:
27
+ return self._rag_service.check()
28
+
29
+ def force_rebuild_rag(self) -> Dict:
30
+ return self._rag_service.force_rebuild()
31
+
32
+ def _cleanup_expired(self):
33
+ now = time.time()
34
+ expired = [cid for cid, c in self._conversations.items() if now - c["last_active"] > self._ttl]
35
+ for cid in expired:
36
+ del self._conversations[cid]
37
+
38
+ def _ensure_conversation(self, conversation_id: str):
39
+ if conversation_id not in self._conversations:
40
+ self._conversations[conversation_id] = {
41
+ "messages": [],
42
+ "created_at": time.time(),
43
+ "last_active": time.time(),
44
+ }
45
+
46
+ def _get_history(self, conversation_id: str) -> List[Dict[str, str]]:
47
+ with self._lock:
48
+ self._cleanup_expired()
49
+ self._ensure_conversation(conversation_id)
50
+ return list(self._conversations[conversation_id]["messages"])
51
+
52
+ def _append_exchange(self, conversation_id: str, user_question: str, assistant_answer: str):
53
+ with self._lock:
54
+ self._ensure_conversation(conversation_id)
55
+ conversation = self._conversations[conversation_id]
56
+ conversation["messages"].extend([
57
+ {"role": "user", "content": user_question},
58
+ {"role": "assistant", "content": assistant_answer},
59
+ ])
60
+ conversation["last_active"] = time.time()
61
+ max_messages = self._max_history * 2
62
+ if len(conversation["messages"]) > max_messages:
63
+ conversation["messages"] = conversation["messages"][-max_messages:]
64
+
65
+ def chat_stream(
66
+ self,
67
+ conversation_id: Optional[str],
68
+ question: str,
69
+ jsessionid: str,
70
+ ) -> Generator[ChatResponse, None, None]:
71
+ normalized_conversation_id = self.normalize_conversation_id(conversation_id)
72
+ history = self._get_history(normalized_conversation_id)
73
+ answer_parts: List[str] = []
74
+ stopped = False
75
+
76
+ for chunk in self._chat_service.tool_call_stream(
77
+ normalized_conversation_id,
78
+ question,
79
+ tools,
80
+ history,
81
+ jsessionid,
82
+ ):
83
+ if chunk.content:
84
+ answer_parts.append(chunk.content)
85
+ if chunk.finish_reason == "stop":
86
+ stopped = True
87
+ yield chunk
88
+
89
+ if stopped:
90
+ self._append_exchange(normalized_conversation_id, question, "".join(answer_parts))
@@ -0,0 +1,62 @@
1
+ """LLM提示词模板定义"""
2
+
3
+
4
+ # 提取时间范围的提示词
5
+ PROMPT_EXTRACT_TIME_RANGE_SYSTEM = """You are a helpful assistant tasked with extracting structured information based on specific criteria provided. Follow the guidelines below to ensure consistency and accuracy.
6
+ ### Task
7
+ Always call the `extract_parameters` function with the correct parameters. Ensure that the information extraction is contextual and aligns with the provided criteria.
8
+ ### Memory
9
+ Here is the chat history between the human and assistant, provided within <histories> tags:
10
+ <histories>
11
+
12
+ </histories>
13
+ ### Instructions:
14
+ Some additional information is provided below. Always adhere to these instructions as closely as possible:
15
+ <instruction>
16
+ 当前时间是{current_time}
17
+ </instruction>
18
+ Steps:
19
+ 1. Review the chat history provided within the <histories> tags.
20
+ 2. Extract the relevant information based on the criteria given, output multiple values if there is multiple relevant information that match the criteria in the given text.
21
+ 3. Generate a well-formatted output using the defined functions and arguments.
22
+ 4. Use the `extract_parameter` function to create structured outputs with appropriate parameters.
23
+ 5. Do not include any XML tags in your output.
24
+ ### Example
25
+ To illustrate, if the task involves extracting a user's name and their request, your function call might look like this: Ensure your output follows a similar structure to examples.
26
+ ### Final Output
27
+ Produce well-formatted function calls in json without XML tags, as shown in the example."""
28
+
29
+ PROMPT_EXTRACT_TIME_RANGE_USER = """### Structure
30
+ Here is the structure of the JSON object, you should always follow the structure.
31
+ <structure>
32
+ {"queryTimeBegin": {"description": "查询的开始时间,格式为yyyy-MM-dd,如果结果没有明确查询年份,则根据当前时间获取年份", "type": "string"}, "queryTimeEnd": {"description": "查询的结束时间,如果结果没有明确结束时间,则默认为当前时间,格式为yyyy-MM-dd", "type": "string"}, "queryContext": {"description": "用户原文", "type": "string"}}
33
+ </structure>
34
+
35
+ ### Text to be converted to JSON
36
+ Inside <text></text> XML tags, there is a text that you should convert to a JSON object.
37
+ <text>
38
+ {query_text}
39
+ </text>"""
40
+
41
+ # 质量下降月份分析的提示词
42
+ PROMPT_QUALITY_DECLINE_MONTHS = """根据输入的机构的运行质量情况,{data_json},回答问题{{answer}}。并提取出对比上一个月成功率下降的月份集合{{declineMonth}},注意,比较的精度是小数点后6位,月份的格式为yyyy-MM:。
43
+ 例子:{{\\"answer\\":\\"xxxx年xx月份以来,全链路系统成功率整体趋于下降,具体数据如下:- xxxx年x月:99.9989- xxxx年x月:99.9986- xxxx年x月:99.9985(有几个显示几个)。其中,xxxx年x月系统成功率最高,达到99.9990,最低为xxxx年x月的99.9985。\\",\\"declineMonth\\":\\"yyyy-mm,yyyy-mm(用逗号分隔,没有空格)\\"}}"""
44
+
45
+ # 机构维度故障详情的提示词
46
+ PROMPT_FAULT_DETAILS_BY_ORG = """根据输入的机构的运行质量情况,{data_json}。按以下为主要内容回答,可以使用markdown格式丰富展示:注意:faultCause属性里为固定名词,不要改变;影响笔数为整数,没有小数点。
47
+
48
+ <b>以成员机构为维度统计:</b>
49
+ xxx年x月:
50
+ 成员机构层面主要因为xx银行\\xx信用社\\xx公司(取前三)的系统失败导致。具体情况(取所有)如下:
51
+ 1)xx银行,影响笔数xxx,主要原因:faultCause"""
52
+
53
+ # 失败模式分析的提示词
54
+ PROMPT_FAILURE_PATTERNS_BY_ORG = """根据输入的机构的运行质量情况,{data_json}。按以下为主要内容回答。可以使用markdown格式丰富展示。注意:1.查出来的机构都是成功率低于全链路系统成功率的。2.分析内容不要输出属性值
55
+
56
+ 按以下进行分析:
57
+
58
+ xxx年x月
59
+ 1.找到交易量较大( scale值等于\"large\"),并且sysSuccessRate大于0.999955的银行单位。做出以下结论:
60
+ 1)成员单位xxx,xxx,xxx虽然造成系统失败交易量较大,但系统成功率已达到99.9955%,提升空间有限。
61
+ 2.排除提升有限的机构,统计下造成influence高的前3个机构,统计他们的totalCntFail之和。做出以下结论(不要把属性展示出来):
62
+ 2)成员机构xxx,xxx,xxx等合计造成系统失败量xxx(totalCntFail之和),同时其系统弄成功率相对较低,建议从xxx机构入手推动推动。"""