Spaces:
Running
Running
File size: 3,552 Bytes
9d0d4e9 | 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 | #!/usr/bin/env python3
"""opencode-only teacher label generation - runs in background."""
import json, subprocess, time, sys
from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed
ARTIFACTS = Path(__file__).resolve().parents[2] / "artifacts" / "tiny_nla"
RECORDS_FILE = ARTIFACTS / "records_v2.jsonl"
OUTPUT_JSONL = ARTIFACTS / "teacher_labels_v2.jsonl"
PROMPT = """\
你是语言模型内部机制分析专家。用1-2句简洁中文描述Qwen3-0.6B在处理下面这个token时,该位置residual stream激活值编码的语义信息。
上下文:{context}
当前token:「{token}」(位置{pos}/{seq_len})
模型预测下一个词的候选:{top_tokens}
要求:简洁具体,联系token在句中的实际句法/语义角色,联系预测候选推断编码内容,不超过55字。只输出解释本身。"""
def make_prompt(r):
return PROMPT.format(context=r["text"], token=r["token_text"],
pos=r["pos"], seq_len=r["seq_len"],
top_tokens="、".join(r["top_tokens"][:5]))
def strip_think(t):
return t.split("</think>")[-1].strip() if "</think>" in t else t.strip()
def call_opencode(r):
res = subprocess.run(
["opencode", "run", "--model", "opencode/deepseek-v4-flash-free", make_prompt(r)],
capture_output=True, text=True, timeout=240,
)
lines = [l.strip() for l in res.stdout.splitlines()
if l.strip() and not l.startswith("\x1b") and "orchestrator" not in l
and not l.startswith("{") and not l.startswith('"')]
return strip_think("\n".join(lines))
def load_done():
done = set()
try:
for r in json.load(open(ARTIFACTS / "teacher_labels_v2.json")):
done.add((r["text_idx"], r["pos"]))
except Exception:
pass
if OUTPUT_JSONL.exists():
for line in open(OUTPUT_JSONL):
try:
r = json.loads(line)
done.add((r["text_idx"], r["pos"]))
except Exception:
pass
return done
def process(idx_rec):
idx, rec = idx_rec
try:
expl = call_opencode(rec)
if expl and len(expl) >= 5:
return {**rec, "teacher_explanation": expl, "teacher_source": "opencode"}
except Exception as e:
print(f" err [{idx}]: {e}", flush=True)
return None
def main():
workers = int(sys.argv[1]) if len(sys.argv) > 1 else 3
records = [json.loads(l) for l in open(RECORDS_FILE)]
done = load_done()
todo = [(i, r) for i, r in enumerate(records)
if (r["text_idx"], r["pos"]) not in done]
print(f"Remaining: {len(todo)}/9810, workers: {workers}", flush=True)
completed = 0
t0 = time.time()
out_f = open(OUTPUT_JSONL, "a", encoding="utf-8", buffering=1)
with ThreadPoolExecutor(max_workers=workers) as pool:
futures = {pool.submit(process, item): item for item in todo}
for fut in as_completed(futures):
result = fut.result()
if result:
out_f.write(json.dumps(result, ensure_ascii=False) + "\n")
completed += 1
if completed % 20 == 0:
rate = completed / (time.time() - t0) * 60
eta_h = (len(todo) - completed) / (rate / 60) / 3600
print(f" [{len(done)+completed}/{9810}] {rate:.0f}/min ETA={eta_h:.1f}h", flush=True)
out_f.close()
print(f"Done: {completed} new labels written", flush=True)
if __name__ == "__main__":
main()
|