DJAYADEV commited on
Commit
3358fd3
·
verified ·
1 Parent(s): bd468ee

Upload folder using huggingface_hub

Browse files
Files changed (3) hide show
  1. inference.py +118 -92
  2. openenv.yaml +26 -12
  3. server/grader.py +59 -0
inference.py CHANGED
@@ -35,6 +35,7 @@ MODEL_NAME = os.getenv("MODEL_NAME", "Qwen/Qwen2.5-72B-Instruct")
35
  HF_TOKEN = os.getenv("HF_TOKEN")
36
 
37
  MAX_STEPS = 30
 
38
 
39
  SYSTEM_PROMPT = """You are an automated Data Engineer managing an AI Knowledge Base.
40
  Your goal is to optimize the messy chunks of text in the database so that a TF-IDF Search Algorithm can find answers easily.
@@ -64,117 +65,142 @@ def format_action_str(action: RagOptimizerAction) -> str:
64
  return "submit()"
65
  return f"{action.action_type}()"
66
 
67
- def main():
68
- # Setup OpenAI Client
69
- client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
70
-
71
- # Track metrics for the final output
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  step_rewards = []
73
  success = False
74
  error_msg = "null"
75
- score = 0.0
76
-
77
- print(f"[START] task=rag_optimizer_env env=OpenEnv model={MODEL_NAME}")
78
-
 
79
  # We suppress any other custom prints to respect the STDOUT format strictly
80
  import contextlib
81
  import io
82
-
83
- with RagOptimizerEnvClient(base_url="http://localhost:8000").sync() as env:
84
- # Suppress prints from client or env reset
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
85
  with contextlib.redirect_stdout(io.StringIO()):
86
  try:
87
- result = env.reset()
88
  observation = result.observation
 
89
  except Exception as e:
90
  error_msg = str(e).replace('\n', ' ')
91
- print(f"[END] success=false steps=0 score=0.00 rewards=")
92
- return
 
93
 
94
- history = [{"role": "system", "content": SYSTEM_PROMPT}]
95
-
96
- init_obs = {
 
 
 
 
 
 
 
 
 
97
  "server_feedback": observation.message,
98
  "current_reward": observation.reward,
99
- "current_knowledge_base": observation.current_docs
100
  }
101
- history.append({"role": "user", "content": json.dumps(init_obs, indent=2)})
102
-
103
- step = 0
104
- for i in range(1, MAX_STEPS + 1):
105
- step = i
106
- messages = list(history)
107
-
108
- action_str = "unknown"
109
- error_msg = "null"
110
-
111
- try:
112
- completion = client.chat.completions.create(
113
- model=MODEL_NAME,
114
- messages=messages,
115
- response_format={"type": "json_object"},
116
- max_tokens=1000
117
- )
118
- response_text = completion.choices[0].message.content or ""
119
- action_data = json.loads(response_text)
120
-
121
- # Normalize fields if model returns lists instead of strings
122
- for field in ("doc_id", "text", "metadata_key", "metadata_value"):
123
- val = action_data.get(field)
124
- if isinstance(val, list):
125
- if val and isinstance(val[0], str):
126
- action_data[field] = " ".join(val)
127
- elif val and isinstance(val[0], dict):
128
- action_data[field] = json.dumps(val[0])
129
- else:
130
- action_data[field] = str(val[0]) if val else ""
131
-
132
- action = RagOptimizerAction(**action_data)
133
- action_str = format_action_str(action)
134
-
135
- except Exception as exc:
136
- error_msg = str(exc).replace('\n', ' ')
137
- action = RagOptimizerAction(action_type="submit")
138
- action_str = format_action_str(action)
139
-
140
- # Suppress normal prints during step
141
- with contextlib.redirect_stdout(io.StringIO()):
142
- try:
143
- result = env.step(action)
144
- observation = result.observation
145
- reward = result.reward
146
- except Exception as e:
147
- error_msg = str(e).replace('\n', ' ')
148
- reward = 0.0
149
- result = type('obj', (object,), {'done': True})()
150
- observation = type('obj', (object,), {'message': 'error', 'current_docs': {}})()
151
-
152
- step_rewards.append(reward)
153
- done = "true" if result.done else "false"
154
-
155
- print(f"[STEP] step={step} action={action_str} reward={reward:.2f} done={done} error={error_msg}")
156
-
157
- if result.done:
158
- success = True if reward > 0.5 else False # Or however you define success
159
- score = float(reward)
160
- break
161
-
162
- history.append({"role": "assistant", "content": json.dumps(action.model_dump(), default=str)})
163
- next_obs = {
164
- "server_feedback": observation.message,
165
- "current_reward": observation.reward,
166
- "current_knowledge_base": observation.current_docs
167
- }
168
- history.append({"role": "user", "content": json.dumps(next_obs, indent=2)})
169
-
170
- else:
171
- # Reached max steps
172
- success = False
173
- score = float(result.reward)
174
 
175
  rewards_str = ",".join([f"{r:.2f}" for r in step_rewards])
176
  done_str = "true" if success else "false"
177
  print(f"[END] success={done_str} steps={step} score={score:.2f} rewards={rewards_str}")
178
 
 
 
 
 
 
 
 
 
179
  if __name__ == "__main__":
180
  main()
 
35
  HF_TOKEN = os.getenv("HF_TOKEN")
36
 
37
  MAX_STEPS = 30
38
+ TASK_IDS = ["easy", "medium", "hard"]
39
 
40
  SYSTEM_PROMPT = """You are an automated Data Engineer managing an AI Knowledge Base.
41
  Your goal is to optimize the messy chunks of text in the database so that a TF-IDF Search Algorithm can find answers easily.
 
65
  return "submit()"
66
  return f"{action.action_type}()"
67
 
68
+
69
+ def _safe_reset(env: RagOptimizerEnvClient, task_id: str):
70
+ """Reset env for a specific task with compatibility fallbacks."""
71
+ try:
72
+ return env.reset(task_id=task_id)
73
+ except TypeError:
74
+ try:
75
+ return env.reset(task=task_id)
76
+ except TypeError:
77
+ return env.reset()
78
+
79
+
80
+ def _clamp_score(value: float) -> float:
81
+ if value < 0.01:
82
+ return 0.01
83
+ if value > 0.99:
84
+ return 0.99
85
+ return value
86
+
87
+
88
+ def run_task_episode(
89
+ env: RagOptimizerEnvClient,
90
+ llm_client: OpenAI,
91
+ task_id: str,
92
+ ) -> None:
93
  step_rewards = []
94
  success = False
95
  error_msg = "null"
96
+ score = 0.01
97
+ step = 0
98
+
99
+ print(f"[START] task={task_id} env=OpenEnv model={MODEL_NAME}")
100
+
101
  # We suppress any other custom prints to respect the STDOUT format strictly
102
  import contextlib
103
  import io
104
+
105
+ with contextlib.redirect_stdout(io.StringIO()):
106
+ try:
107
+ result = _safe_reset(env, task_id)
108
+ observation = result.observation
109
+ except Exception as e:
110
+ error_msg = str(e).replace('\n', ' ')
111
+ print(f"[END] success=false steps=0 score=0.01 rewards=")
112
+ return
113
+
114
+ history = [{"role": "system", "content": SYSTEM_PROMPT}]
115
+
116
+ init_obs = {
117
+ "server_feedback": observation.message,
118
+ "current_reward": observation.reward,
119
+ "current_knowledge_base": observation.current_docs,
120
+ }
121
+ history.append({"role": "user", "content": json.dumps(init_obs, indent=2)})
122
+
123
+ for i in range(1, MAX_STEPS + 1):
124
+ step = i
125
+ messages = list(history)
126
+
127
+ action_str = "unknown"
128
+ error_msg = "null"
129
+
130
+ try:
131
+ completion = llm_client.chat.completions.create(
132
+ model=MODEL_NAME,
133
+ messages=messages,
134
+ response_format={"type": "json_object"},
135
+ max_tokens=1000,
136
+ )
137
+ response_text = completion.choices[0].message.content or ""
138
+ action_data = json.loads(response_text)
139
+
140
+ # Normalize fields if model returns lists instead of strings
141
+ for field in ("doc_id", "text", "metadata_key", "metadata_value"):
142
+ val = action_data.get(field)
143
+ if isinstance(val, list):
144
+ if val and isinstance(val[0], str):
145
+ action_data[field] = " ".join(val)
146
+ elif val and isinstance(val[0], dict):
147
+ action_data[field] = json.dumps(val[0])
148
+ else:
149
+ action_data[field] = str(val[0]) if val else ""
150
+
151
+ action = RagOptimizerAction(**action_data)
152
+ action_str = format_action_str(action)
153
+
154
+ except Exception as exc:
155
+ error_msg = str(exc).replace('\n', ' ')
156
+ action = RagOptimizerAction(action_type="submit")
157
+ action_str = format_action_str(action)
158
+
159
+ # Suppress normal prints during step
160
  with contextlib.redirect_stdout(io.StringIO()):
161
  try:
162
+ result = env.step(action)
163
  observation = result.observation
164
+ reward = _clamp_score(float(result.reward))
165
  except Exception as e:
166
  error_msg = str(e).replace('\n', ' ')
167
+ reward = 0.01
168
+ result = type("obj", (object,), {"done": True})()
169
+ observation = type("obj", (object,), {"message": "error", "current_docs": {}})()
170
 
171
+ step_rewards.append(reward)
172
+ done = "true" if result.done else "false"
173
+
174
+ print(f"[STEP] step={step} action={action_str} reward={reward:.2f} done={done} error={error_msg}")
175
+
176
+ if result.done:
177
+ success = True if reward > 0.5 else False
178
+ score = _clamp_score(float(reward))
179
+ break
180
+
181
+ history.append({"role": "assistant", "content": json.dumps(action.model_dump(), default=str)})
182
+ next_obs = {
183
  "server_feedback": observation.message,
184
  "current_reward": observation.reward,
185
+ "current_knowledge_base": observation.current_docs,
186
  }
187
+ history.append({"role": "user", "content": json.dumps(next_obs, indent=2)})
188
+ else:
189
+ # Reached max steps
190
+ success = False
191
+ score = _clamp_score(float(result.reward))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
192
 
193
  rewards_str = ",".join([f"{r:.2f}" for r in step_rewards])
194
  done_str = "true" if success else "false"
195
  print(f"[END] success={done_str} steps={step} score={score:.2f} rewards={rewards_str}")
196
 
197
+ def main():
198
+ # Setup OpenAI Client
199
+ client = OpenAI(base_url=API_BASE_URL, api_key=HF_TOKEN)
200
+
201
+ with RagOptimizerEnvClient(base_url="http://localhost:8000").sync() as env:
202
+ for task_id in TASK_IDS:
203
+ run_task_episode(env=env, llm_client=client, task_id=task_id)
204
+
205
  if __name__ == "__main__":
206
  main()
openenv.yaml CHANGED
@@ -1,16 +1,30 @@
1
- spec_version: 1
2
- name: rag_optimizer
3
- type: space
4
- runtime: fastapi
5
- app: server.app:app
6
- port: 8000
 
 
 
 
 
7
  tasks:
8
  - id: easy
9
- steps: 10
10
- description: Conflict Resolution - Resolve overlapping pricing parameters by deleting the legacy pricing format.
 
 
11
  - id: medium
12
- steps: 10
13
- description: Ontological Tagging - Route exact programatic metadata tags to support tickets.
 
 
14
  - id: hard
15
- steps: 15
16
- description: Syntactic Splintering - Break down the monolithic onboarding blob into multiple granular chunks.
 
 
 
 
 
 
1
+ spec_version: "1.0"
2
+ name: "rag_optimizer"
3
+ environment:
4
+ name: "RAG Optimizer"
5
+ description: "RAG pipeline optimization benchmark. Agents resolve pricing conflicts, route metadata tags, and splinter monolithic content blobs."
6
+ version: "1.0.0"
7
+ dockerfile: "Dockerfile"
8
+ endpoints:
9
+ reset: "/reset"
10
+ step: "/step/{session_id}"
11
+ state: "/state/{session_id}"
12
  tasks:
13
  - id: easy
14
+ name: "Conflict Resolution"
15
+ description: "Resolve overlapping pricing parameters by deleting the legacy pricing format."
16
+ reward_range: [0.1, 0.99]
17
+ grader: "rag_optimizer.server.grader:grade_easy"
18
  - id: medium
19
+ name: "Ontological Tagging"
20
+ description: "Route exact programmatic metadata tags to support tickets."
21
+ reward_range: [0.1, 0.99]
22
+ grader: "rag_optimizer.server.grader:grade_medium"
23
  - id: hard
24
+ name: "Syntactic Splintering"
25
+ description: "Break down the monolithic onboarding blob into multiple granular chunks."
26
+ reward_range: [0.1, 0.99]
27
+ grader: "rag_optimizer.server.grader:grade_hard"
28
+ agent:
29
+ inference_entrypoint: "inference.py"
30
+ requirements: "requirements.txt"
server/grader.py ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from __future__ import annotations
2
+
3
+ from typing import Any
4
+
5
+
6
+ def _clamp_score(value: Any) -> float:
7
+ try:
8
+ score = float(value)
9
+ except (TypeError, ValueError):
10
+ return 0.01
11
+ if score < 0.01:
12
+ return 0.01
13
+ if score > 0.99:
14
+ return 0.99
15
+ return score
16
+
17
+
18
+ def _extract_score_from_trajectory(trajectory: Any) -> float:
19
+ if trajectory is None:
20
+ return 0.01
21
+
22
+ if isinstance(trajectory, (int, float)):
23
+ return _clamp_score(trajectory)
24
+
25
+ if isinstance(trajectory, dict):
26
+ for key in ("score", "reward", "final_score", "final_reward"):
27
+ if key in trajectory:
28
+ return _clamp_score(trajectory.get(key))
29
+
30
+ observation = trajectory.get("observation")
31
+ if isinstance(observation, dict):
32
+ for key in ("reward", "score"):
33
+ if key in observation:
34
+ return _clamp_score(observation.get(key))
35
+
36
+ steps = trajectory.get("steps")
37
+ if isinstance(steps, list) and steps:
38
+ last_step = steps[-1]
39
+ if isinstance(last_step, dict):
40
+ for key in ("reward", "score"):
41
+ if key in last_step:
42
+ return _clamp_score(last_step.get(key))
43
+
44
+ if isinstance(trajectory, (list, tuple)) and trajectory:
45
+ return _extract_score_from_trajectory(trajectory[-1])
46
+
47
+ return 0.01
48
+
49
+
50
+ def grade_easy(trajectory: Any = None) -> float:
51
+ return _extract_score_from_trajectory(trajectory)
52
+
53
+
54
+ def grade_medium(trajectory: Any = None) -> float:
55
+ return _extract_score_from_trajectory(trajectory)
56
+
57
+
58
+ def grade_hard(trajectory: Any = None) -> float:
59
+ return _extract_score_from_trajectory(trajectory)