-
Notifications
You must be signed in to change notification settings - Fork 42
Expand file tree
/
Copy pathcontroller.py
More file actions
179 lines (153 loc) · 9.82 KB
/
controller.py
File metadata and controls
179 lines (153 loc) · 9.82 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
import json
import re
from IPython.terminal.embed import InteractiveShellEmbed
from rca.baseline.rca_agent.executor import execute_act
from rca.api_router import get_chat_completion
system = """You are the Administrator of a DevOps Assistant system for failure diagnosis. To solve each given issue, you should iteratively instruct an Executor to write and execute Python code for data analysis on telemetry files of target system. By analyzing the execution results, you should approximate the answer step-by-step.
There is some domain knowledge for you:
{background}
{agent}
The issue you are going to solve is:
{objective}
Solve the issue step-by-step. In each step, your response should follow the JSON format below:
{format}
Let's begin."""
format = """{
"analysis": (Your analysis of the code execution result from Executor in the last step, with detailed reasoning of 'what have been done' and 'what can be derived'. Respond 'None' if it is the first step.),
"completed": ("True" if you believe the issue is resolved, and an answer can be derived in the 'instruction' field. Otherwise "False"),
"instruction": (Your instruction for the Executor to perform via code execution in the next step. Do not involve complex multi-step instruction. Keep your instruction atomic, with clear request of 'what to do' and 'how to do'. Respond a summary by yourself if you believe the issue is resolved. Respond a summary by yourself if you believe the issue is resolved. Respond a summary by yourself if you believe the issue is resolved.)
}
(DO NOT contain "```json" and "```" tags. DO contain the JSON object with the brackets "{}" only. Use '\\n' instead of an actual newline character to ensure JSON compatibility when you want to insert a line break within a string.)"""
summary = """Now, you have decided to finish your reasoning process. You should now provide the final answer to the issue. The candidates of possible root cause components and reasons are provided to you. The root cause components and reasons must be selected from the provided candidates.
{cand}
Recall the issue is: {objective}
Please first review your previous reasoning process to infer an exact answer of the issue. Then, summarize your final answer of the root causes using the following JSON format at the end of your response:
```json
{{
"1": {{
"root cause occurrence datetime": (if asked by the issue, format: '%Y-%m-%d %H:%M:%S', otherwise ommited),
"root cause component": (if asked by the issue, one selected from the possible root cause component list, otherwise ommited),
"root cause reason": (if asked by the issue, one selected from the possible root cause reason list, otherwise ommited),
}}, (mandatory)
"2": {{
"root cause occurrence datetime": (if asked by the issue, format: '%Y-%m-%d %H:%M:%S', otherwise ommited),
"root cause component": (if asked by the issue, one selected from the possible root cause component list, otherwise ommited),
"root cause reason": (if asked by the issue, one selected from the possible root cause reason list, otherwise ommited),
}}, (only if the failure number is "unknown" or "more than one" in the issue)
... (only if the failure number is "unknown" or "more than one" in the issue)
}}
```
(Please use "```json" and "```" tags to wrap the JSON object. You only need to provide the elements asked by the issue, and ommited the other fields in the JSON.)
Note that all the root cause components and reasons must be selected from the provided candidates. Do not reply 'unknown' or 'null' or 'not found' in the JSON. Do not be too conservative in selecting the root cause components and reasons. Be decisive to infer a possible answer based on your current observation."""
def control_loop(objective:str, plan:str, ap, bp, logger, max_step = 15, max_turn = 3) -> str:
prompt = [
{'role': 'system', 'content': system.format(objective=objective,
format=format,
agent=ap.rules,
background=bp.schema)},
{'role': 'user', 'content': "Let's begin."}
]
history = []
trajectory = []
observation = "Let's begin."
status = False
kernel = InteractiveShellEmbed()
init_code = "import pandas as pd\n"+ \
"pd.set_option('display.width', 427)\n"+ \
"pd.set_option('display.max_columns', 10)\n"
kernel.run_cell(init_code)
for step in range(max_step):
note = [{'role': 'user', 'content': f"Continue your reasoning process for the target issue:\n\n{objective}\n\nFollow the rules during issue solving:\n\n{ap.rules}.\n\nResponse format:\n\n{format}"}]
attempt_actor = []
response_raw = ""
try:
response_raw = get_chat_completion(
messages=prompt + note,
)
if response_raw is None:
logger.error("API returned None response")
prompt.append({'role': 'user', 'content': "The API request failed. Please provide your analysis in requested JSON format."})
continue
if "```json" in response_raw:
m = re.search(r"```json\s*\n(.*?)\n\s*```", response_raw, re.S)
if m:
response_raw = m.group(1).strip()
else:
m2 = re.search(r"```json\s*(.*?)```", response_raw, re.S)
if m2:
response_raw = m2.group(1).strip()
logger.debug(f"Raw Response:\n{response_raw}")
if '"analysis":' not in response_raw or '"instruction":' not in response_raw or '"completed":' not in response_raw:
logger.warning("Invalid response format. Please provide a valid JSON response.")
prompt.append({'role': 'assistant', 'content': response_raw})
prompt.append({'role': 'user', 'content': "Please provide your analysis in requested JSON format."})
continue
response = json.loads(response_raw)
analysis = response['analysis']
instruction = response['instruction']
completed = response['completed']
logger.info('-'*80 + '\n' + f"### Step[{step+1}]\nAnalysis: {analysis}\nInstruction: {instruction}" + '\n' + '-'*80)
if completed == "True":
kernel.reset()
prompt.append({'role': 'assistant', 'content': response_raw})
prompt.append({'role': 'user', 'content': summary.format(objective=objective,
cand=bp.cand)})
answer = get_chat_completion(
messages=prompt,
)
if answer is None:
answer = "API request failed. No root cause found."
logger.debug(f"Raw Final Answer:\n{answer}")
prompt.append({'role': 'assistant', 'content': answer})
if "```json" in answer:
m = re.search(r"```json\s*\n(.*?)\n\s*```", answer, re.S)
if m:
answer = m.group(1).strip()
else:
m2 = re.search(r"```json\s*(.*?)```", answer, re.S)
if m2:
answer = m2.group(1).strip()
return answer, trajectory, prompt
code, result, status, new_history = execute_act(instruction, bp.schema, history, attempt_actor, kernel, logger)
if not status:
logger.warn(f'Self-Correction failed.')
observation = "The Executor failed to execute the instruction. Please provide a new instruction."
observation = f"{result}"
history = new_history
trajectory.append({'code': f"# In[{step+1}]:\n\n{code}", 'result': f"Out[{step+1}]:\n```\n{result}```"})
logger.info('-'*80 + '\n' + f"Step[{step+1}]\n### Observation:\n{result}" + '\n' + '-'*80)
prompt.append({'role': 'assistant', 'content': response_raw})
prompt.append({'role': 'user', 'content': observation})
except Exception as e:
logger.error(e)
prompt.append({'role': 'assistant', 'content': response_raw})
prompt.append({'role': 'user', 'content': f"{str(e)}\nPlease provide your analysis in requested JSON format."})
if 'context_length_exceeded' in str(e):
logger.warning("Token length exceeds the limit.")
kernel.reset()
return "Token length exceeds. No root cause found.", trajectory, prompt
logger.warning("Max steps reached. Please check the history.")
kernel.reset()
final_prompt = {'role': 'user', 'content': summary.format(objective=objective,
cand=bp.cand).replace('Now, you have decided to finish your reasoning process. ', 'Now, the maximum steps of your reasoning have been reached. ')}
if prompt[-1]['role'] == 'user':
prompt[-1]['content'] = final_prompt['content']
else:
prompt.append({'role': 'user', 'content': final_prompt['content']})
answer = get_chat_completion(
messages=prompt,
)
if answer is None:
answer = "API request failed. No root cause found."
logger.debug(f"Raw Final Answer:\n{answer}")
prompt.append({'role': 'assistant', 'content': answer})
if "```json" in answer:
m = re.search(r"```json\s*\n(.*?)\n\s*```", answer, re.S)
if m:
answer = m.group(1).strip()
else:
# Fallback: try to extract JSON object directly after ```json
m2 = re.search(r"```json\s*(.*?)```", answer, re.S)
if m2:
answer = m2.group(1).strip()
return answer, trajectory, prompt