mriusero commited on
Commit
c4d08fc
·
1 Parent(s): ab7f293

feat: add tooling phase (no call)

Browse files
Files changed (3) hide show
  1. prompt.md +61 -47
  2. src/agent/inference.py +1 -165
  3. src/ui/sidebar.py +83 -36
prompt.md CHANGED
@@ -1,62 +1,76 @@
1
- You are a general AI assistant equipped with various tools to enhance your problem-solving capabilities. Your task is to answer questions by following a structured chain-of-thought process and utilizing appropriate tools when necessary. Adhere to the following guidelines strictly:
2
 
3
- ### Initial Understanding
4
- Begin by acknowledging the question and briefly restating it in your own words to ensure understanding.
 
 
 
5
 
6
- ### Step-by-Step Reasoning
7
- Report your thoughts and reasoning process step by step. Each step should logically follow from the previous one. Use the template below for each step in your reasoning process:
8
 
9
- #### THOUGHT STEP [X]:
10
- - **Explanation**: [Provide a detailed explanation of your thought process here.]
11
- - **Evidence/Assumptions**: [List any evidence, data, or assumptions you are using to support this step.]
12
- - **Intermediate Conclusion**: [State any intermediate conclusions or insights derived from this step.]
13
- - **Tool Calling**: [If applicable, mention any tools you plan to use to gather more information or perform specific tasks.]
14
 
15
- #### TOOL CALLING:
16
- 1. **Tool Identification**: Identify the tool you need to use and the specific function within that tool.
17
- 2. **Tool Execution**: Execute the tool function with the appropriate parameters.
18
- 3. **Result Handling**: Handle the results from the tool execution. If the tool execution fails, note the error and consider alternative approaches.
 
 
 
19
 
20
- #### THOUGHT STEP [X]:
21
- - **Explanation**: [Provide a detailed explanation of your thought process here, incorporating the results from the tool.]
22
- - **Evidence/Assumptions**: [List any new evidence, data, or assumptions you are using to support this step.]
23
- - **Intermediate Conclusion**: [State any new intermediate conclusions or insights derived from this step.]
24
 
25
- ### Verification
26
- After presenting your step-by-step reasoning and tool utilization, verify the logical consistency and coherence of your thoughts. Ensure that each step logically leads to the next and that there are no gaps in your reasoning.
27
- If you find any inconsistencies or gaps, revisit the relevant steps and adjust your reasoning accordingly.
28
- However, if everything is consistent, summarize your findings and conclusions in the final answer section.
29
 
30
- ### FINAL ANSWER
31
- Conclude with your final answer, clearly stated and directly addressing the original question. Use the template below for your final answer:
32
- [Provide a brief summary of your reasoning process and any tools used, then state your final answer clearly and concisely here.]
33
 
34
- ---
 
35
 
36
- ### Example:
 
 
37
 
38
- **Question**: What is the weather like in Paris today?
 
 
39
 
40
- #### THOUGHT STEP 1:
41
- - **Explanation**: I need to find out the current weather conditions in Paris.
42
- - **Evidence/Assumptions**: I assume that the user is asking for real-time weather information.
43
- - **Intermediate Conclusion**: I need to use a weather API or a reliable weather website to get the latest information.
44
- - **Tool Calling**: I will use the `get_weather` tool to retrieve the current weather data for Paris.
 
45
 
46
- #### TOOL CALLING:
47
- 1. **Tool Identification**: Identify the `get_weather` tool and the specific function to retrieve weather data.
48
- 2. **Tool Execution**: Execute the `get_weather` function with the parameter set to "Paris".
49
- 3. **Result Handling**: The `get_weather` tool returns the current weather data for Paris.
50
 
51
- #### THOUGHT STEP 2:
52
- - **Explanation**: I have retrieved the weather data using the `get_weather` tool.
53
- - **Evidence/Assumptions**: The data provided by the tool is accurate and up-to-date.
54
- - **Intermediate Conclusion**: The current weather in Paris is sunny with a temperature of 22°C.
55
 
56
- #### Verification:
57
- - **Explanation**: The steps logically follow from the need to gather real-time data, and the tool used provides accurate information.
58
- - **Evidence/Assumptions**: The weather data is consistent with typical weather patterns for this time of year in Paris.
59
- - **Intermediate Conclusion**: The information retrieved is reliable and can be used to answer the user's question.
60
 
61
- #### FINAL ANSWER:
62
- Based on the data retrieved from the `get_weather` tool, the current weather in Paris is sunny with a temperature of 22°C.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ You are an AI Agent designed to assist industries and services in understanding and interpreting their operational metrics. You have access to real-time telemetry data that measures quality, downtime, and operational performance. Your primary goal is to help users comprehend these metrics and make informed decisions based on them.
2
 
3
+ ### Instructions:
4
+ 1. **Understanding the Query**: Carefully read the user's query to understand what they are asking. Identify the key metrics and data points they are interested in.
5
+ 2. **Thinking**: Before responding, take a moment to think about the query. Use the "THINKING:" prefix to outline your thought process. This helps in structuring your response and ensuring accuracy.
6
+ 3. **Tool Usage**: If you need to use any tools to gather additional data or perform calculations, use the "TOOLING:" prefix to indicate that you are calling a tool. Specify the tool and the parameters you are using.
7
+ 4. **Final Answer**: After gathering all necessary information and performing any required calculations, provide the final answer to the user. Use the "FINAL ANSWER:" prefix to clearly indicate the final response.
8
 
9
+ ### Example 1:
10
+ **User Query**: "Can you tell me the overall equipment effectiveness (OEE) for the past week?"
11
 
12
+ **AI Agent Response**:
13
+ ```
14
+ THINKING: The user is asking for the overall equipment effectiveness (OEE) for the past week. OEE is a metric that combines availability, performance, and quality to give a comprehensive view of equipment efficiency. I need to gather data on these three components for the past week and then calculate the OEE.
 
 
15
 
16
+ TOOLING:
17
+ 1. Tool: get_availability_metric
18
+ Parameters: start_date="2025-06-03", end_date="2025-06-10"
19
+ 2. Tool: get_performance_metric
20
+ Parameters: start_date="2025-06-03", end_date="2025-06-10"
21
+ 3. Tool: get_quality_metric
22
+ Parameters: start_date="2025-06-03", end_date="2025-06-10"
23
 
24
+ After gathering the data:
25
+ - Availability: 90%
26
+ - Performance: 85%
27
+ - Quality: 95%
28
 
29
+ Calculating OEE: OEE = Availability * Performance * Quality = 0.90 * 0.85 * 0.95 = 0.72675 or 72.675%
 
 
 
30
 
31
+ FINAL ANSWER: The overall equipment effectiveness (OEE) for the past week is 72.675%.
32
+ ```
 
33
 
34
+ ### Example 2:
35
+ **User Query**: "What is the trend in downtime over the last month?"
36
 
37
+ **AI Agent Response**:
38
+ ```
39
+ THINKING: The user is interested in the trend of downtime over the last month. I need to gather downtime data for each day of the last month and analyze the trend. This could involve looking at daily downtime durations and identifying any patterns or anomalies.
40
 
41
+ TOOLING:
42
+ 1. Tool: get_downtime_data
43
+ Parameters: start_date="2025-05-10", end_date="2025-06-10"
44
 
45
+ After gathering the data, I will analyze the trend:
46
+ - May 10: 120 minutes
47
+ - May 11: 90 minutes
48
+ - May 12: 150 minutes
49
+ - ... (data for each day)
50
+ - June 10: 60 minutes
51
 
52
+ Analyzing the trend: The downtime has generally decreased over the last month, with a few spikes on certain days. The overall trend shows an improvement in reducing downtime.
 
 
 
53
 
54
+ FINAL ANSWER: Over the last month, the trend in downtime shows a general decrease, indicating an improvement in operational efficiency. There were a few days with higher downtime, but the overall trend is positive.
55
+ ```
 
 
56
 
57
+ ### Example 3:
58
+ **User Query**: "How does the quality metric compare between the two production lines, Line A and Line B, for the past week?"
 
 
59
 
60
+ **AI Agent Response**:
61
+ ```
62
+ THINKING: The user wants a comparison of the quality metric between two production lines, Line A and Line B, for the past week. I need to gather quality data for both lines and compare them.
63
+
64
+ TOOLING:
65
+ 1. Tool: get_quality_metric
66
+ Parameters: line="Line A", start_date="2025-06-03", end_date="2025-06-10"
67
+ 2. Tool: get_quality_metric
68
+ Parameters: line="Line B", start_date="2025-06-03", end_date="2025-06-10"
69
+
70
+ After gathering the data:
71
+ - Line A Quality: 95%
72
+ - Line B Quality: 90%
73
+
74
+ Comparing the quality metrics: Line A has a higher quality metric compared to Line B for the past week.
75
+
76
+ FINAL ANSWER: For the past week, Line A has a quality metric of 95%, while Line B has a quality metric of 90%. Line A performs better in terms of quality.
src/agent/inference.py CHANGED
@@ -1,6 +1,4 @@
1
  import os
2
- import json
3
- import time
4
  from dotenv import load_dotenv
5
  from mistralai import Mistral
6
 
@@ -30,166 +28,4 @@ class MistralAgent:
30
  [
31
  calculate_sum,
32
  ]
33
- ).get('tools')
34
-
35
- #def make_initial_request(self, input):
36
- # """Make the initial request to the agent with the given input."""
37
- # with open("./prompt.md", 'r', encoding='utf-8') as file:
38
- # self.prompt = file.read()
39
- # messages = [
40
- # {"role": "system", "content": self.prompt},
41
- # {"role": "user", "content": input},
42
- # {
43
- # "role": "assistant",
44
- # "content": "THINKING:\nLet's tackle this problem, ",
45
- # "prefix": True,
46
- # },
47
- # ]
48
- # payload = {
49
- # "agent_id": self.agent_id,
50
- # "messages": messages,
51
- # "max_tokens": None,
52
- # "stream": True,
53
- # "stop": None,
54
- # "random_seed": None,
55
- # "response_format": None,
56
- # "tools": self.tools,
57
- # "tool_choice": 'auto',
58
- # "presence_penalty": 0,
59
- # "frequency_penalty": 0,
60
- # "n": 1,
61
- # "prediction": None,
62
- # "parallel_tool_calls": None
63
- # }
64
- # stream = self.client.agents.complete(**payload)
65
- # return stream, messages
66
- #
67
- #def run(self, input):
68
- # """Run the agent with the given input and process the response."""
69
- # print("\n===== Asking the agent =====\n")
70
- # stream, messages = self.make_initial_request(input)
71
- #
72
- # for data in stream:
73
- # # Si `stream` renvoie des chaînes brutes de type `data: {...}`
74
- # if isinstance(data, str) and data.startswith("data: "):
75
- # try:
76
- # json_str = data[len("data: "):].strip()
77
- # if json_str == "[DONE]":
78
- # break
79
- # chunk = json.loads(json_str)
80
- # delta = chunk.get("choices", [{}])[0].get("delta", {})
81
- # content = delta.get("content")
82
- # if content:
83
- # yield content
84
- #
85
- # # Fin de réponse
86
- # if chunk["choices"][0].get("finish_reason") is not None:
87
- # break
88
- # except json.JSONDecodeError:
89
- # continue
90
- #
91
- # # Si `stream` donne directement des dicts (selon ton client)
92
- # elif isinstance(data, dict):
93
- # delta = data.get("choices", [{}])[0].get("delta", {})
94
- # content = delta.get("content")
95
- # if content:
96
- # yield content
97
- #
98
- # if data["choices"][0].get("finish_reason") is not None:
99
- # break
100
-
101
-
102
-
103
- #first_iteration = True
104
-
105
- #while True:
106
- # time.sleep(1)
107
- # if hasattr(response, 'choices') and response.choices:
108
- # choice = response.choices[0]
109
- #
110
- # if first_iteration:
111
- # messages = [message for message in messages if not message.get("prefix")]
112
- # messages.append(
113
- # {
114
- # "role": "assistant",
115
- # "content": choice.message.content,
116
- # "prefix": True,
117
- # },
118
- # )
119
- # first_iteration = False
120
- # else:
121
- # if choice.message.tool_calls:
122
- # results = []
123
- #
124
- # for tool_call in choice.message.tool_calls:
125
- # function_name = tool_call.function.name
126
- # function_params = json.loads(tool_call.function.arguments)
127
- #
128
- # try:
129
- # function_result = self.names_to_functions[function_name](**function_params)
130
- # results.append((tool_call.id, function_name, function_result))
131
- #
132
- # except Exception as e:
133
- # results.append((tool_call.id, function_name, None))
134
- #
135
- # for tool_call_id, function_name, function_result in results:
136
- # messages.append({
137
- # "role": "assistant",
138
- # "tool_calls": [
139
- # {
140
- # "id": tool_call_id,
141
- # "type": "function",
142
- # "function": {
143
- # "name": function_name,
144
- # "arguments": json.dumps(function_params),
145
- # }
146
- # }
147
- # ]
148
- # })
149
- # messages.append(
150
- # {
151
- # "role": "tool",
152
- # "content": function_result if function_result is not None else f"Error occurred: {function_name} failed to execute",
153
- # "tool_call_id": tool_call_id,
154
- # },
155
- # )
156
- # for message in messages:
157
- # if "prefix" in message:
158
- # del message["prefix"]
159
- # messages.append(
160
- # {
161
- # "role": "assistant",
162
- # "content": f"Based on the results, ",
163
- # "prefix": True,
164
- # }
165
- # )
166
- # else:
167
- # for message in messages:
168
- # if "prefix" in message:
169
- # del message["prefix"]
170
- # messages.append(
171
- # {
172
- # "role": "assistant",
173
- # "content": choice.message.content,
174
- # }
175
- # )
176
- # if 'FINAL ANSWER:' in choice.message.content:
177
- # print("\n===== END OF REQUEST =====\n", json.dumps(messages, indent=2))
178
- # ans = choice.message.content.split('FINAL ANSWER:')[1].strip()
179
- #
180
- # timestamp = time.strftime("%Y%m%d-%H%M%S")
181
- # output_file = f"chat_{timestamp}.json"
182
- # with open(output_file, "w", encoding="utf-8") as f:
183
- # json.dump(messages, f, indent=2, ensure_ascii=False)
184
- # print(f"Conversation enregistrée dans {output_file}")
185
- #
186
- # return ans
187
- #
188
- # print("\n===== MESSAGES BEFORE API CALL =====\n", json.dumps(messages, indent=2))
189
- # time.sleep(1)
190
- # response = self.client.agents.complete(
191
- # agent_id=self.agent_id,
192
- # messages=messages,
193
- # tools=self.tools,
194
- # tool_choice='auto',
195
- # )
 
1
  import os
 
 
2
  from dotenv import load_dotenv
3
  from mistralai import Mistral
4
 
 
28
  [
29
  calculate_sum,
30
  ]
31
+ ).get('tools')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
src/ui/sidebar.py CHANGED
@@ -6,31 +6,28 @@ from src.agent.inference import MistralAgent
6
 
7
  agent = MistralAgent()
8
 
9
- async def respond(message, history=None):
 
10
 
 
 
 
 
11
  if history is None:
12
  history = []
13
- history.append(ChatMessage(role="user", content=message))
14
 
15
- thinking_msg = ChatMessage(
16
- role="assistant",
17
- content="",
18
- metadata={"title": "Thinking", "status": "pending"}
19
- )
20
- history.append(thinking_msg)
21
  yield history
22
 
23
- with open("./prompt.md", encoding="utf-8") as f:
24
- prompt = f.read()
25
-
26
  messages = [
27
- {"role": "system", "content": prompt},
28
  {"role": "user", "content": message},
29
- #{
30
- # "role": "assistant",
31
- # "content": "THINKING:\nLet's tackle this problem",
32
- ## "prefix": True
33
- #},
34
  ]
35
  payload = {
36
  "agent_id": agent.agent_id,
@@ -43,44 +40,93 @@ async def respond(message, history=None):
43
  "frequency_penalty": 0,
44
  "n": 1
45
  }
46
-
47
  response = await agent.client.agents.stream_async(**payload)
48
 
49
  full = ""
50
  thinking = ""
 
51
  final = ""
52
 
 
 
 
 
53
  async for chunk in response:
54
  delta = chunk.data.choices[0].delta
55
  content = delta.content or ""
56
  full += content
57
 
 
58
  if "FINAL ANSWER:" in full:
 
59
  parts = full.split("FINAL ANSWER:", 1)
60
- thinking = parts[0].replace("THINKING:", "").strip()
61
  final = parts[1].strip()
62
- else:
63
- thinking = full.strip()
64
- final = ""
65
-
66
- history[-1] = ChatMessage(
67
- role="assistant",
68
- content=thinking,
69
- metadata={"title": "Thinking", "status": "pending"}
70
- )
71
- yield history
72
 
73
- history[-1] = ChatMessage(
74
- role="assistant",
75
- content=thinking,
76
- metadata={"title": "Thinking", "status": "done"}
77
- )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
78
 
79
- history.append(ChatMessage(role="assistant", content=final))
80
  yield history
81
 
82
 
83
-
84
  def sidebar_ui(state, width=700, visible=True):
85
  with gr.Sidebar(width=width, visible=visible):
86
  gr.Markdown("# Ask Agent")
@@ -118,6 +164,7 @@ def sidebar_ui(state, width=700, visible=True):
118
  stop_btn=True,
119
  save_history=True,
120
  examples=[
 
121
  ["How is the production process going?"],
122
  ["What are the common issues faced in production?"],
123
  # ["What is the status of the current production line?"],
 
6
 
7
  agent = MistralAgent()
8
 
9
+ with open("./prompt.md", encoding="utf-8") as f:
10
+ SYSTEM_PROMPT = f.read()
11
 
12
+ async def respond(message, history=None):
13
+ """
14
+ Respond to a user message using the Mistral agent.
15
+ """
16
  if history is None:
17
  history = []
 
18
 
19
+ history.append(ChatMessage(role="user", content=message))
20
+ history.append(ChatMessage(role="assistant", content="", metadata={"title": "Thinking", "status": "pending"}))
 
 
 
 
21
  yield history
22
 
 
 
 
23
  messages = [
24
+ {"role": "system", "content": SYSTEM_PROMPT},
25
  {"role": "user", "content": message},
26
+ {
27
+ "role": "assistant",
28
+ "content": "THINKING: Let's tackle this problem, ",
29
+ "prefix": True,
30
+ },
31
  ]
32
  payload = {
33
  "agent_id": agent.agent_id,
 
40
  "frequency_penalty": 0,
41
  "n": 1
42
  }
 
43
  response = await agent.client.agents.stream_async(**payload)
44
 
45
  full = ""
46
  thinking = ""
47
+ tooling = ""
48
  final = ""
49
 
50
+ current_phase = None # None | "thinking" | "tooling" | "final"
51
+
52
+ history[-1] = ChatMessage(role="assistant", content="", metadata={"title": "Thinking", "status": "pending"})
53
+
54
  async for chunk in response:
55
  delta = chunk.data.choices[0].delta
56
  content = delta.content or ""
57
  full += content
58
 
59
+ # Phase finale
60
  if "FINAL ANSWER:" in full:
61
+
62
  parts = full.split("FINAL ANSWER:", 1)
63
+ before_final = parts[0]
64
  final = parts[1].strip()
 
 
 
 
 
 
 
 
 
 
65
 
66
+ if "TOOLING:" in before_final:
67
+ tooling = before_final.split("TOOLING:", 1)[1].strip()
68
+ else:
69
+ tooling = ""
70
+
71
+ if current_phase != "final":
72
+ if current_phase == "tooling":
73
+ history[-1] = ChatMessage(role="assistant", content=tooling, metadata={"title": "Tooling", "status": "done"})
74
+ elif current_phase == "thinking":
75
+ history[-1] = ChatMessage(role="assistant", content=thinking, metadata={"title": "Thinking", "status": "done"})
76
+
77
+ history.append(ChatMessage(role="assistant", content=final))
78
+ current_phase = "final"
79
+ yield history
80
+
81
+ # Phase outil
82
+ elif "TOOLING:" in full:
83
+
84
+ parts = full.split("TOOLING:", 1)
85
+ before_tooling = parts[0]
86
+ tooling = ""
87
+
88
+ if "THINKING:" in before_tooling:
89
+ thinking = before_tooling.split("THINKING:", 1)[1].strip()
90
+ else:
91
+ thinking = before_tooling.strip()
92
+
93
+ tooling = parts[1].strip()
94
+
95
+ if current_phase != "tooling":
96
+ if current_phase == "thinking":
97
+ history[-1] = ChatMessage(role="assistant", content=thinking,
98
+ metadata={"title": "Thinking", "status": "done"})
99
+ history.append(
100
+ ChatMessage(role="assistant", content=tooling, metadata={"title": "Tooling", "status": "pending"}))
101
+ current_phase = "tooling"
102
+ else:
103
+ history[-1] = ChatMessage(role="assistant", content=tooling,
104
+ metadata={"title": "Tooling", "status": "pending"})
105
+ yield history
106
+
107
+ # Phase réflexion
108
+ elif "THINKING:" in full or current_phase is None:
109
+
110
+ if "THINKING:" in full:
111
+ thinking = full.split("THINKING:", 1)[1].strip()
112
+ else:
113
+ thinking = full.strip()
114
+
115
+ if current_phase != "thinking":
116
+ history[-1] = ChatMessage(role="assistant", content=thinking, metadata={"title": "Thinking", "status": "pending"})
117
+ current_phase = "thinking"
118
+ else:
119
+ history[-1] = ChatMessage(role="assistant", content=thinking, metadata={"title": "Thinking", "status": "pending"})
120
+ yield history
121
+
122
+ if current_phase == "thinking":
123
+ history[-1] = ChatMessage(role="assistant", content=thinking, metadata={"title": "Thinking", "status": "done"})
124
+ elif current_phase == "tooling":
125
+ history[-1] = ChatMessage(role="assistant", content=tooling, metadata={"title": "Tooling", "status": "done"})
126
 
 
127
  yield history
128
 
129
 
 
130
  def sidebar_ui(state, width=700, visible=True):
131
  with gr.Sidebar(width=width, visible=visible):
132
  gr.Markdown("# Ask Agent")
 
164
  stop_btn=True,
165
  save_history=True,
166
  examples=[
167
+ ["What is the sum of 1+1 ?"],
168
  ["How is the production process going?"],
169
  ["What are the common issues faced in production?"],
170
  # ["What is the status of the current production line?"],