Download main.py from datadb/Telco-Troubleshooting-Agentic-Challenge-Track-A: direct link, hf CLI and curl.
- Browser
- Download file 15.6 kB
-
https://huggingface.co/datadb/Telco-Troubleshooting-Agentic-Challenge-Track-A/resolve/main/main.py
- Command line
-
hf download hf://datadb/Telco-Troubleshooting-Agentic-Challenge-Track-A/main.py
-
curl -L -o main.py https://huggingface.co/datadb/Telco-Troubleshooting-Agentic-Challenge-Track-A/resolve/main/main.py
15.6 kB
| #!/usr/bin/env python | |
| # -*- coding: utf-8 -*- | |
| """ | |
| Inference entry point for Track A. | |
| This script owns the executable prediction flow: | |
| 1. Load test scenarios. | |
| 2. Hydrate placeholder telemetry from the competition server when needed. | |
| 3. Load the trained model bundle produced by train.py. | |
| 4. Ask the Qwen/OpenRouter assistant to call the trained-model tool. | |
| 5. Checkpoint and finally write results/result.csv, debug JSON, and traces JSON. | |
| Reusable feature extraction, prediction helpers, server utilities, and file writers | |
| live in src/model_core.py. Training and cross-validation live in train.py. | |
| python main.py \ | |
| --test_path "data/Phase_2/test.json" \ | |
| --model_bundle "results/model_v4_bundle.pkl" \ | |
| --out "results/result.csv" \ | |
| --debug_out "results/debug_phase2_v4.json" \ | |
| --traces_out "results/traces.json" \ | |
| --checkpoint_every 1 \ | |
| --max_steps 4 \ | |
| --max_tool_calls 8 \ | |
| --concurrency 1 \ | |
| --question_timeout 180 | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import os | |
| import re | |
| import time | |
| from concurrent.futures import ThreadPoolExecutor, as_completed | |
| from typing import List, Optional | |
| import httpx | |
| from openai import OpenAI | |
| from tqdm import tqdm | |
| from src.model_core import ( | |
| build_question_text, | |
| get_env_value, | |
| get_options, | |
| hydrate_scenario_from_server, | |
| load_env_file, | |
| load_json, | |
| load_model_bundle, | |
| result_csv_path, | |
| run_agent_with_trained_model, | |
| scenario_needs_server_data, | |
| write_debug, | |
| write_json, | |
| write_submission, | |
| ) | |
| DEFAULT_TRACK_B_TEST = os.path.join("..", "Track B", "data", "Phase_2", "test.json") | |
| def normalize_track_a_answer(answer: object) -> str: | |
| text = str(answer or "").strip() | |
| if not text: | |
| return "" | |
| labels = re.findall(r"C\d+", text) | |
| if not labels: | |
| return text | |
| labels = sorted(dict.fromkeys(labels), key=lambda label: int(label[1:])) | |
| return "|".join(labels) | |
| def normalize_submission_rows(rows: list[dict[str, str]]) -> list[dict[str, str]]: | |
| out = [] | |
| for row in rows: | |
| out.append( | |
| { | |
| "ID": row.get("ID", ""), | |
| "Track A": normalize_track_a_answer(row.get("Track A", "")), | |
| "Track B": str(row.get("Track B", "") or ""), | |
| } | |
| ) | |
| return out | |
| def write_result(path: str, rows: list[dict[str, str]]) -> None: | |
| write_submission(path, normalize_submission_rows(rows)) | |
| def append_track_b_blank_rows( | |
| rows: list[dict[str, str]], track_b_test_path: str | |
| ) -> int: | |
| if not track_b_test_path or not os.path.exists(track_b_test_path): | |
| return 0 | |
| track_b = load_json(track_b_test_path) | |
| existing = {str(row.get("ID", "")) for row in rows} | |
| added = 0 | |
| for i, s in enumerate(track_b, start=1): | |
| sid = str(s.get("scenario_id") or s.get("ID") or "").strip() | |
| if not sid: | |
| task_id = s.get("task", {}).get("id", i) | |
| raise ValueError(f"Missing scenario_id for Track B task id {task_id}") | |
| if sid in existing: | |
| raise ValueError(f"Track B ID already exists in output rows: {sid}") | |
| rows.append({"ID": sid, "Track A": "", "Track B": ""}) | |
| existing.add(sid) | |
| added += 1 | |
| return added | |
| def main() -> None: | |
| load_env_file() | |
| parser = argparse.ArgumentParser() | |
| parser.add_argument("--test_path", default="data/Phase_1/test.json") | |
| parser.add_argument("--model_bundle", default="results/model_v4_bundle.pkl") | |
| parser.add_argument("--track_b_test", default=DEFAULT_TRACK_B_TEST) | |
| parser.add_argument("--out", default="results/result.csv") | |
| parser.add_argument("--debug_out", default="results/debug_v4.json") | |
| parser.add_argument("--traces_out", default="results/traces.json") | |
| parser.add_argument("--max_samples", type=int, default=None) | |
| parser.add_argument("--use_server_data", action="store_true") | |
| parser.add_argument("--no_auto_server_data", action="store_true") | |
| parser.add_argument("--server_url", default="https://124.71.227.61/no") | |
| parser.add_argument("--env_path", default=None) | |
| parser.add_argument("--auth_token_env", default="AUTH_TOKEN") | |
| parser.add_argument("--timeout", type=float, default=30.0) | |
| parser.add_argument("--verify_ssl", action="store_true") | |
| parser.add_argument("--try_scenario_endpoint", action="store_true") | |
| parser.add_argument("--checkpoint_every", type=int, default=1) | |
| parser.add_argument("--no_progress", action="store_true") | |
| parser.add_argument("--no_agent", action="store_true") | |
| parser.add_argument("--max_steps", type=int, default=4) | |
| parser.add_argument("--max_tool_calls", type=int, default=8) | |
| parser.add_argument("--concurrency", type=int, default=1) | |
| parser.add_argument( | |
| "--model_url", | |
| default=os.getenv("OPENROUTER_URL") | |
| or os.getenv("OPENAI_BASE_URL") | |
| or "https://openrouter.ai/api/v1", | |
| ) | |
| parser.add_argument( | |
| "--model_name", | |
| default=os.getenv("OPENROUTER_MODEL") | |
| or os.getenv("OPENAI_MODEL") | |
| or "qwen/qwen3.5-35b-a3b", | |
| ) | |
| parser.add_argument( | |
| "--api_key_env", | |
| default="OPENROUTER_API_KEY,AGENT_API_KEY,OPENAI_API_KEY", | |
| ) | |
| parser.add_argument("--agent_timeout", type=float, default=60.0) | |
| parser.add_argument("--llm_timeout", type=float, default=None) | |
| parser.add_argument("--question_timeout", type=float, default=180.0) | |
| parser.add_argument("--max_output_tokens", type=int, default=900) | |
| parser.add_argument("--history_chars", type=int, default=24000) | |
| parser.add_argument("--observation_chars", type=int, default=20000) | |
| parser.add_argument("--temperature", type=float, default=0.0) | |
| args = parser.parse_args() | |
| args.out = result_csv_path(args.out) | |
| llm_timeout = args.llm_timeout if args.llm_timeout is not None else args.agent_timeout | |
| test = load_json(args.test_path) | |
| if args.max_samples is not None: | |
| test = test[: max(0, args.max_samples)] | |
| print(f"Loaded test={len(test)}") | |
| loaded_env = load_env_file(args.env_path) | |
| auto_server_data = not args.no_auto_server_data and any( | |
| scenario_needs_server_data(s) for s in test | |
| ) | |
| use_server_data = args.use_server_data or auto_server_data | |
| if use_server_data: | |
| print( | |
| f"Server data mode enabled: {args.server_url}" | |
| + (f" (env: {loaded_env})" if loaded_env else "") | |
| ) | |
| if not os.path.exists(args.model_bundle): | |
| raise FileNotFoundError( | |
| f"Model bundle not found: {args.model_bundle}. Run train.py first." | |
| ) | |
| print(f"Loading trained model bundle: {args.model_bundle}") | |
| tmodel, smodel, model_metadata = load_model_bundle(args.model_bundle) | |
| if model_metadata: | |
| print(f"Model metadata: {model_metadata}") | |
| use_agent = not args.no_agent | |
| llm_client: Optional[OpenAI] = None | |
| if use_agent: | |
| api_key = get_env_value(args.api_key_env) | |
| if api_key: | |
| llm_client = OpenAI( | |
| base_url=args.model_url, | |
| api_key=api_key, | |
| http_client=httpx.Client(verify=args.verify_ssl), | |
| timeout=llm_timeout, | |
| ) | |
| print(f"Agent mode enabled: {args.model_name}") | |
| else: | |
| print( | |
| f"Warning: {args.api_key_env} is not set; using direct trained-model fallback." | |
| ) | |
| row_entries, debug_entries, trace_entries = [], [], [] | |
| print("Predicting Track A test...") | |
| headers = {"Content-Type": "application/json"} | |
| token = os.environ.get(args.auth_token_env, "").strip() | |
| if token: | |
| headers["Authorization"] = f"Bearer {token}" | |
| headers["X-API-Token"] = token | |
| if use_server_data and not token: | |
| print(f"Warning: {args.auth_token_env} is not set; server may reject requests.") | |
| def ordered_rows() -> list[dict[str, str]]: | |
| return [row for _, row in sorted(row_entries, key=lambda x: x[0])] | |
| def ordered_debug() -> list[dict]: | |
| return [row for _, row in sorted(debug_entries, key=lambda x: x[0])] | |
| def ordered_traces() -> list[dict]: | |
| return [row for _, row in sorted(trace_entries, key=lambda x: x[0])] | |
| def checkpoint() -> None: | |
| write_result(args.out, ordered_rows()) | |
| write_debug(args.debug_out, ordered_debug()) | |
| write_json(args.traces_out, ordered_traces()) | |
| def solve_one(i: int, s: dict) -> tuple[int, dict, dict, dict, str]: | |
| sid = s.get("scenario_id") or s.get("ID") or f"test_{i}" | |
| start_time = time.perf_counter() | |
| tool_calls: List[str] = [] | |
| pred_s = s | |
| used_server_data = False | |
| try: | |
| if use_server_data and ( | |
| args.use_server_data or scenario_needs_server_data(s) | |
| ): | |
| with httpx.Client( | |
| headers=headers, | |
| timeout=args.timeout, | |
| verify=args.verify_ssl, | |
| follow_redirects=True, | |
| ) as client_ctx: | |
| pred_s, tool_calls = hydrate_scenario_from_server( | |
| s, | |
| client_ctx, | |
| args.server_url, | |
| try_scenario_endpoint=args.try_scenario_endpoint, | |
| ) | |
| used_server_data = bool(tool_calls) | |
| labels, dbg, completion, agent_tool_calls, agent_used = ( | |
| run_agent_with_trained_model( | |
| llm_client, | |
| args.model_name, | |
| tmodel, | |
| smodel, | |
| pred_s, | |
| timeout=llm_timeout, | |
| max_steps=args.max_steps, | |
| max_tool_calls=args.max_tool_calls, | |
| temperature=args.temperature, | |
| max_output_tokens=args.max_output_tokens, | |
| history_chars=args.history_chars, | |
| observation_chars=args.observation_chars, | |
| question_timeout=args.question_timeout, | |
| ) | |
| ) | |
| tool_calls.extend(agent_tool_calls) | |
| pred = "|".join(labels) | |
| elapsed = round(time.perf_counter() - start_time, 3) | |
| row = {"ID": sid, "Track A": pred, "Track B": ""} | |
| debug_row = { | |
| "scenario_id": sid, | |
| "prediction": pred, | |
| "debug": dbg, | |
| "options": get_options(pred_s), | |
| "used_server_data": used_server_data, | |
| "still_needs_server_data": scenario_needs_server_data(pred_s), | |
| "agent_used": agent_used, | |
| } | |
| trace_row = { | |
| "scenario_id": sid, | |
| "question": build_question_text(pred_s), | |
| "completion": completion, | |
| "prediction": labels, | |
| "ground_truth": pred_s.get("answer", "To be determined"), | |
| "score": 0.0, | |
| "execution_time_seconds": elapsed, | |
| "tool_calls": "\n".join(tool_calls), | |
| "boxed": f"\\boxed{{{pred}}}", | |
| } | |
| prob = dbg.get("template_prob", 0.0) | |
| try: | |
| prob_text = f"{float(prob):.3f}" | |
| except Exception: | |
| prob_text = "nan" | |
| msg = ( | |
| f"[A {i}/{len(test)}] {sid} -> {pred} " | |
| f"({dbg.get('template')} {prob_text})" | |
| ) | |
| return i, row, debug_row, trace_row, msg | |
| except Exception as exc: | |
| elapsed = round(time.perf_counter() - start_time, 3) | |
| row = {"ID": sid, "Track A": "", "Track B": ""} | |
| debug_row = { | |
| "scenario_id": sid, | |
| "prediction": "", | |
| "debug": { | |
| "runner_exception": f"{type(exc).__name__}: {exc}", | |
| "agent_used": False, | |
| }, | |
| "options": get_options(pred_s), | |
| "used_server_data": used_server_data, | |
| "still_needs_server_data": scenario_needs_server_data(pred_s), | |
| "agent_used": False, | |
| } | |
| trace_row = { | |
| "scenario_id": sid, | |
| "question": build_question_text(pred_s), | |
| "completion": "", | |
| "prediction": [], | |
| "ground_truth": pred_s.get("answer", "To be determined"), | |
| "score": 0.0, | |
| "execution_time_seconds": elapsed, | |
| "tool_calls": "\n".join(tool_calls), | |
| "boxed": "\\boxed{}", | |
| "messages": [ | |
| { | |
| "action": "runner_exception", | |
| "observation": f"{type(exc).__name__}: {exc}", | |
| } | |
| ], | |
| } | |
| return i, row, debug_row, trace_row, f"[A {i}/{len(test)}] {sid} -> ERROR: {exc}" | |
| max_workers = max(1, int(args.concurrency)) | |
| if max_workers == 1: | |
| iterator = enumerate(test, start=1) | |
| if not args.no_progress: | |
| iterator = tqdm(iterator, total=len(test), desc="Predicting Track A") | |
| for i, s in iterator: | |
| result_i, row, debug_row, trace_row, msg = solve_one(i, s) | |
| row_entries.append((result_i, row)) | |
| debug_entries.append((result_i, debug_row)) | |
| trace_entries.append((result_i, trace_row)) | |
| if args.checkpoint_every and result_i % args.checkpoint_every == 0: | |
| checkpoint() | |
| if result_i <= 5 or result_i % 50 == 0: | |
| if args.no_progress: | |
| print(msg) | |
| else: | |
| tqdm.write(msg) | |
| else: | |
| with ThreadPoolExecutor(max_workers=max_workers) as executor: | |
| future_to_index = { | |
| executor.submit(solve_one, i, s): i for i, s in enumerate(test, start=1) | |
| } | |
| iterator = as_completed(future_to_index) | |
| if not args.no_progress: | |
| iterator = tqdm(iterator, total=len(test), desc="Predicting Track A") | |
| completed = 0 | |
| for future in iterator: | |
| completed += 1 | |
| result_i, row, debug_row, trace_row, msg = future.result() | |
| row_entries.append((result_i, row)) | |
| debug_entries.append((result_i, debug_row)) | |
| trace_entries.append((result_i, trace_row)) | |
| if args.checkpoint_every and completed % args.checkpoint_every == 0: | |
| checkpoint() | |
| if args.no_progress: | |
| print(f"[{completed}/{len(test)}] {msg}") | |
| else: | |
| tqdm.write(f"[{completed}/{len(test)}] {msg}") | |
| rows = ordered_rows() | |
| added_track_b = append_track_b_blank_rows(rows, args.track_b_test) | |
| if added_track_b: | |
| print(f"Added Track B blank ID rows: {added_track_b}") | |
| write_result(args.out, rows) | |
| write_debug(args.debug_out, ordered_debug()) | |
| write_json(args.traces_out, ordered_traces()) | |
| print(f"Saved result: {args.out}") | |
| print(f"Saved debug: {args.debug_out}") | |
| print(f"Saved traces: {args.traces_out}") | |
| if __name__ == "__main__": | |
| main() | |