Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 80 additions & 0 deletions openseek/competition/LongContext-ICL-Annotation/src/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
## 目录结构

- `src/`:源码目录,包含推理入口、任务策略、客户端配置和依赖清单
- `data/`:官方数据集
- `submission_results.zip`:已测试好的提交结果压缩包
- `README.md`:使用说明

## 运行环境

建议使用 Python 3.10 及以上版本。

安装依赖:

```bash
pip install -r src/requirements.txt
```

当前最小依赖仅包含:

- `requests`

## 模型与合规说明

本方案遵循赛事合规要求,核心逻辑均基于官方指定的 `Qwen3-4B` 模型进行设计与优化,未接入任何外部模型或非公开数据集。

在模型底层支撑方面,本方案依托于官方提供的 `FlagScale` 推理平台(或等效的 `FlagScale + Qwen3-4B` 算力环境)。模型的加载及服务端推理由 `FlagScale` 框架提供核心支持。

为保证工程复现的简洁性与跨平台一致性,本项目通过标准化 OpenAI 接口与 `FlagScale` 推理服务通信。代码专注于 ICL 标注策略、动态上下文组织及结果自修复逻辑的实现,模型的底层生命周期与服务化部署建议参考 `FlagScale` 官方文档与环境预设。

## 配置说明

模型服务接口配置位于 `src/llm_config.yaml`。

默认配置如下:

```yaml
api:
base_url: "http://localhost:30000/v1"
model: "Qwen3-4B"
api_key: ""
```

如果服务启用了鉴权,可通过 `api_key` 进行配置。

为确保方案成功复现,请在运行前确认已准备好提供以下标准化接口的 `FlagScale` 推理环境:

- `POST /completions`
- `POST /chat/completions`
- `GET /models`

## 快速开始

1. **环境准备**:
```bash
pip install -r src/requirements.txt
```

2. **配置服务**:
在 `src/llm_config.yaml` 中配置推理服务的 `base_url`;如果服务要求鉴权,同时填写 `api_key`。

3. **执行推理**:
```bash
cd src
# 默认运行 Task 1-8 全量任务
python main.py

# 单任务运行 (例如 Task 8)
python main.py --task_id 8

# 冒烟测试 (每任务仅运行前 5 条)
python main.py --limit 5
```

## 输出产物

本目录中已包含测试完成后的提交文件 `submission_results.zip`,可直接作为赛事平台提交结果使用。

如在复现环境中重新执行推理,程序会在 `submission_results/` 目录下生成:
- **JSONL 文件**:`openseek-1-v1.jsonl` 至 `openseek-8-v1.jsonl`
- **打包文件**:`result.zip`(由当前运行自动生成,包含本次推理得到的全部任务结果)
21 changes: 0 additions & 21 deletions openseek/competition/LongContext-ICL-Annotation/src/api_test.py

This file was deleted.

108 changes: 108 additions & 0 deletions openseek/competition/LongContext-ICL-Annotation/src/llm_client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
import requests
from pathlib import Path
from typing import List, Union, Optional

CONFIG_PATH = Path(__file__).resolve().parent / "llm_config.yaml"


def load_config(config_path: Path) -> dict[str, str]:
base_url = "http://localhost:8000/v1"
model = "Qwen3-4B"
api_key = "EMPTY"

for raw_line in config_path.read_text(encoding="utf-8").splitlines():
line = raw_line.strip()
if not line or line.startswith("#") or line == "api:":
continue
if line.startswith("base_url:"):
base_url = line.split(":", 1)[1].strip().strip('"').strip("'")
elif line.startswith("model:"):
model = line.split(":", 1)[1].strip().strip('"').strip("'")
elif line.startswith("api_key:"):
api_key = line.split(":", 1)[1].strip().strip('"').strip("'")

return {
"base_url": base_url,
"model": model,
"api_key": api_key,
}


config = load_config(CONFIG_PATH)
API_URL = config["base_url"]
MODEL_NAME = config["model"]
API_KEY = config["api_key"]

class LLMClient:
def __init__(self):
self.api_url = API_URL
self.model_name = MODEL_NAME
self.api_key = API_KEY
self.headers = {"Authorization": f"Bearer {self.api_key}"} if self.api_key else {}

def post_chat_completion(
self,
messages: List[dict],
max_tokens: int = 5000,
temperature: float = 0.0,
stop: Optional[List[str]] = None,
timeout: int = 600
) -> str:
data = {
"model": self.model_name,
"messages": messages,
"max_tokens": max_tokens,
"temperature": temperature,
}
if stop: data["stop"] = stop
try:
url = f"{self.api_url}/chat/completions"
response = requests.post(url, json=data, headers=self.headers, timeout=timeout)
response.raise_for_status()
res_json = response.json()
return str(res_json["choices"][0].get("message", {}).get("content", "")) if res_json.get("choices") else ""
except Exception as e:
print(f"LLM Chat API Error: {e}")
raise

def post_completion(
self,
prompt: Union[str, List[str]],
max_tokens: int = 5000,
temperature: float = 0.0,
stop: Optional[List[str]] = None,
timeout: int = 600
) -> str:
data = {
"model": self.model_name,
"prompt": prompt,
"max_tokens": max_tokens,
"temperature": temperature,
}
if stop: data["stop"] = stop
try:
url = f"{self.api_url}/completions"
response = requests.post(url, json=data, headers=self.headers, timeout=timeout)
response.raise_for_status()
res_json = response.json()
return str(res_json["choices"][0].get("text", "")) if res_json.get("choices") else ""
except Exception as e:
print(f"LLM API Error: {e}")
raise

def is_available(self) -> bool:
try:
response = requests.get(f"{self.api_url}/models", headers=self.headers, timeout=5)
return response.status_code == 200
except Exception: return False

client = LLMClient()

def post_completion(prompt, **kwargs) -> str:
return client.post_completion(prompt, **kwargs)

def post_chat(messages: List[dict], **kwargs) -> str:
return client.post_chat_completion(messages, **kwargs)

def is_completion_server_available() -> bool:
return client.is_available()
Original file line number Diff line number Diff line change
@@ -1,30 +1,4 @@
serve:
- serve_id: vllm_model
engine: vllm
engine_args:
model: ../Qwen3-4B
host: 0.0.0.0
uvicorn_log_level: warning
port: 2026
gpu_memory_utilization: 0.9
trust_remote_code: true
no_enable_prefix_caching: true

experiment:
exp_name: qwen3_4b
exp_dir: outputs/${experiment.exp_name}
task:
type: serve
runner:
hostfile: null
deploy:
use_fs_serve: false
envs:
CUDA_VISIBLE_DEVICES: 0
CUDA_DEVICE_MAX_CONNECTIONS: 1

action: run

hydra:
run:
dir: ${experiment.exp_dir}/hydra
api:
base_url: "http://localhost:30000/v1"
model: "Qwen3-4B"
api_key: "EMPTY"
Loading