Team: GenuineKnowledge_KEOL Challenge variant: LLMs4OL-2026
This package contains the TaskA, TaskB, and TaskC pipelines, flattened into a single directory:
- TaskA files are prefixed
taska_(plusmain1.pyas the orchestrator). - TaskB files are prefixed
taskb_(plusmain2.pyas the orchestrator). - TaskC ships as per-domain entry points (
archeon_main.py,hylex_main.py,biora_main.py,phyra_main.py) plus shared modules (llm_client.py,postprocess.py,edge_verifier.py,opus_extractor.py,pattern_inducer.py,rule_engine.py, and the per-domain*_opus_taxonomy.pyfiles). Its dependency list lives in the top-levelrequirements.txt, and its runtime configuration template lives in.taskc_env.example.
TaskA/TaskB outputs are written under outputs/taska/ and outputs/taskb/
respectively; TaskC writes each domain's submission.txt to the current
working directory.
Each task ships its own env template alongside the code:
.taska_env.example, .taskb_env.example, .taskc_env.example.
python3 -m venv .venv_taska && .venv_taska/bin/pip install -r taska_requirements.txt && cp -n .taska_env.example .taska_envFill in OPENAI_API_KEY, OPENAI_BASE_URL, and OPENAI_MODEL in .taska_env, then run:
.venv_taska/bin/python main1.py path/to/test_task_a_input.json --train path/to/train_task_a.jsonThe retrieval stage uses a Qwen3 embedding model (auto-downloaded from Hugging Face on first run, or pass a local directory via --embed-model-path / EMBED_MODEL_PATH). The final submission is written to outputs/taska/submission/<split-name>/submission_taska.json.
Useful checks:
python main1.py path/to/test_task_a_input.json --train path/to/train_task_a.json --dry-run
python taska_unittest.pyinput(positional): test input JSON.--train: train JSON file.--output-dir: output root (default:./outputs/taska).--model: optional model override applied to all LLM steps (pre-RAG generation, and the non-taxonomy postprocess fallback when--non-taxonomy-modelis unset). Either a plain model name, or a JSON object{"name": "...", "extra_kwargs": {...}}whereextra_kwargsis merged verbatim into the chat-completions request to enable provider-specific thinking-mode parameters (e.g. Claude'sthinking, Qwen/DeepSeek'sextra_body, OpenAI'sreasoning_effort) — field names are passed through as-is, never inferred.--domain-label-model/--non-taxonomy-model: same plain-name-or-JSON form, scoped to the domain classification and non-taxonomy LLM steps respectively.--embed-model-path: Qwen3 embedding model local directory or Hugging Face repo id.--limit: cap the number of items processed, for smoke testing.--keep-intermediate: keep per-stage intermediate dirs and the run manifest instead of deleting them after the run.--no-resume: force a full rerun instead of skipping ids already present in an existing submission file.
Run python main1.py --help for the full argument list.
main1.py: primary end-to-end TaskA pipeline orchestrator; runs pre-RAG graph generation, term-typing postprocessing, taxonomy export, non-taxonomy postprocessing, and final merge.taska_pre_rag.py: domain-aware RAG, retrieval, prompt building, domain classification, and initial term-typing confusion repair.taska_retriever.py: builds/caches the Qwen3 embedding index and does cosine-similarity top-k retrieval.taska_domain_classifier.py: LLM-based classification into the 13 fixed domain anchors, with on-disk caching.taska_prompt_builder.py: builds the structured few-shot prompt for pre-RAG generation.taska_surface_postprocess.py: rewrites predicted triple surfaces to unambiguous train-set surfaces.taska_nontax.py: non-taxonomy relation postprocess._taska_common.py: shared LLM-call helpers (env config,parse_model_specfor the plain-name-or-JSON--modelform).taska_unittest.py: lightweight tests for stage..taska_env.example: placeholder runtime configuration template; real API keys should be supplied separately.taska_requirements.txt: Python dependency list.
python3 -m venv .venv_taskb && .venv_taskb/bin/pip install -r taskb_requirements.txt && cp -n .taskb_env.example .taskb_envFill in OPENAI_API_KEY, OPENAI_BASE_URL, and OPENAI_MODEL in .taskb_env, then run:
.venv_taskb/bin/python main2.py --train-path path/to/train_task_b.json --test-path path/to/test_task_b_input.jsonThe term/tax retrieval stage needs a local Qwen3 embedding model directory, passed via --embed-model-path or EMBED_MODEL_PATH in .taskb_env. The final submission is written to outputs/taskb/submission/<run-name>/submission_taskb.json.
By default the term/tax stage runs three generator models (GEN1/2/3_*) plus a debate merge (DEBATE_A/B/C_* and DEBATE_ARBITER_*); each of these roles falls back to OPENAI_API_KEY/OPENAI_BASE_URL/OPENAI_MODEL if left blank in .taskb_env, but set them individually to actually use different models per role.
Useful checks:
python main2.py --train-path path/to/train_task_b.json --test-path path/to/test_task_b_input.json --dry-run
python taskb_unittest.py--train-path/--test-path(required): TaskB train/test JSON paths.--run-name: output run name (default:taskb-run).--model: term/tax generation model override (single-model mode; ignored when the three-model + debate merge runs). Either a plain model name, or a JSON object{"name": "...", "extra_kwargs": {...}}whereextra_kwargsis merged verbatim into the chat-completions request to enable provider-specific thinking-mode parameters (e.g. Claude'sthinking, Qwen/DeepSeek'sextra_body, OpenAI'sreasoning_effort) — field names are passed through as-is, never inferred.--domain-label-model/--nontax-model: same plain-name-or-JSON form, scoped to the domain-classification and non-taxonomy LLM steps respectively (defaults to--model/OPENAI_MODELif unset).--debate-model-a/--debate-model-b/--debate-model-c/--debate-arbiter-model: same plain-name-or-JSON form, overriding theDEBATE_A/B/C_MODELandDEBATE_ARBITER_MODELenv vars for the debate-merge stage.--embed-model-path: Qwen3 embedding model local directory.--limit: cap the number of items processed, for smoke testing.--no-gen-models: use a single term/tax generator run instead of the default three-model + debate merge.--dry-run: print the commands each stage would run, without executing them.--keep-intermediate: keep per-stage intermediate run dirs instead of deleting them after the run.--skip-term-tax/--skip-non-tax: rerun only part of the pipeline when the other stage's run already exists.
Run python main2.py --help for the full argument list.
main2.py: primary end-to-end TaskB pipeline orchestrator; runs term/tax RAG, postprocess, non-tax prediction, and final merge in order.taskb_term_tax_run_rag.py: predicts missingis-a(taxonomy) andinstance-of(term typing) triples with domain-aware few-shot RAG.taskb_domain_classifier.py: assigns each item a domain label via LLM classification over a fixed set of predefined domain anchors, used to select same-domain few-shot examples.taskb_term_tax_prompt.py: builds the term/tax prompt text and candidate relation lists.taskb_term_tax_retriever.py: builds cached Qwen3 embeddings and retrieves few-shot training examples for term/tax.taskb_debate_merge_term_tax.py: merges term/tax runs from three different models via a debater + arbiter debate; runs by default (skip with--no-gen-modelsto fall back to a single-model run).taskb_postprocess_term_tax.py: cleans up raw term/tax predictions (deduplication, surface canonicalization) and writes the post-processed run.taskb_non_tax_run_rag.py: predicts non-taxonomic relation triples in a single pass using deterministic rules plus LLM assistance.taskb_combine_taskb_runs.py: merges the postprocessed term/tax run and the non-tax run into the final TaskB submission JSON._taskb_common.py: sharedparse_model_spechelper for the plain-name-or-JSON--modelform.taskb_unittest.py: lightweight unit tests for prompt building, postprocess, combine, and non-tax rules..taskb_env.example: template for required environment variables (API keys, model names, tuning knobs).taskb_requirements.txt: Python dependency list.
Task C (Taxonomy Discovery) targets four unseen domains — archeon, hylex,
biora, phyra — and induces a hierarchical taxonomy over a supplied term
list. Every stage targets Claude Opus 4.7 (claude-opus-4-7) via an
OpenAI-compatible Chat Completions endpoint (proxy or gateway of your
choice), through the openai Python SDK.
Unlike TaskA/TaskB, TaskC ships one entry point per domain rather than a
single orchestrator — each of the four domains is its own end-to-end script
with its own input file (<Domain>_test_input.txt) and output
(submission.txt):
| Domain | Entry point | Pipeline variant |
|---|---|---|
| Archeon | archeon_main.py |
Single-shot Opus induction |
| Hylex | hylex_main.py |
Single-shot Opus induction |
| Biora | biora_main.py |
Five-stage rule + LLM hybrid |
| Phyra | phyra_main.py |
Five-stage rule + LLM hybrid |
python3 -m venv .venv_taskc && .venv_taskc/bin/pip install -r requirements.txt && cp -n .taskc_env.example .taskc_envFill in OPENAI_API_KEY, OPENAI_BASE_URL, and OPENAI_MODEL in
.taskc_env (OPENAI_MODEL defaults to claude-opus-4-7 if unset), then
export those variables (or source .taskc_env) before running — the
TaskC entry points read them via os.getenv and do not auto-load a dotenv
file. Place the domain's term list (<Domain>_test_input.txt) next to the
entry point, then run one of:
# Single-shot induction
.venv_taskc/bin/python archeon_main.py # or hylex_main.py
# Five-stage hybrid
.venv_taskc/bin/python biora_main.py # or phyra_main.pyEach entry point writes submission.txt in
[{"parent": "...", "child": "..."}] format (JSON body with a .txt
extension per submission spec).
Useful checks:
python unit_test_archeon.py
python unit_test_hylex.py
python unit_test_biora.py
python unit_test_phyra.pySingle-shot induction (Archeon, Hylex).
The full term list is placed in a cache-controlled system block, and one
Opus call returns a JSON array of {parent, child} edges. Results are
cached to induced_edges.txt so re-runs skip the API call.
Five-stage hybrid rule + LLM (Biora, Phyra).
Stage 0 pattern_inducer.induce_patterns Opus → pattern schema (cached)
Stage 1 rule_engine.generate_candidates F1-F8 surface rules
Stage 2 opus_extractor.induce_edges batched Opus over MiniLM+KMeans
Stage 3 edge_verifier.verify_edges per-edge yes/no Opus adjudication
Stage 4 postprocess.finalize dedup, cycle removal
Stage 1 is the recall engine (eight deterministic head-noun/surface rules). Stage 2 is the complement recall engine (embedding-clustered batches let Opus propose edges that don't fit any surface pattern). Stage 3 is the strict precision filter that adjudicates the union of Stage 1 and Stage 2.
--term-list <path>— override the default<Domain>_test_input.txt.--output <path>— override the defaultsubmission.txt.--cache <path>— override the defaultinduced_edges.txtcache location.
--term-list <path>— override the default<Domain>_test_input.txt.--output <path>— override the defaultsubmission.txt.--pattern-cache <path>— overrideinduced_patterns.json.--verify-cache <path>— overrideedge_verify.jsonl.--batches-dir <dir>— override the batched-extraction cache directory.--max-workers <n>— thread-pool size for per-edge verification.
Shared across all four domains:
llm_client.py: thin OpenAI-compatible Chat Completions wrapper used by every TaskC LLM stage. ReadsOPENAI_API_KEY,OPENAI_BASE_URL,OPENAI_MODELfrom the environment.postprocess.py: deduplicates edges, removes cycles, optionally applies transitive reduction, serialises to JSON.edge_verifier.py: Stage 3 (Biora/Phyra) — thread-pooled per-edge yes/no Opus adjudicator with JSONL cache.opus_extractor.py: Stage 2 (Biora/Phyra) — MiniLM + KMeans clusterer and per-batch Opus edge extractor. Caches per-batch JSON underbatches/.pattern_inducer.py: Stage 0 (Biora/Phyra) — Opus-based pattern schema induction (three passes: full schema, last-word substitutions, qualifier phrases). Caches toinduced_patterns.json.rule_engine.py: Stage 1 (Biora/Phyra) — head-noun-indexed candidate iterator plus eight surface rules (F1_head_noun,F2_modifier_drop,F3_single_token_anchor,F4_shared_head,F5_suffix_class,F6_token_substitution,F7_hierarchy_seed,F8_qualifier_phrase).requirements.txt: TaskC Python dependencies (union of both variants)..taskc_env.example: TaskC endpoint credential template.
Per-domain files:
archeon_main.py,hylex_main.py: single-shot Opus induction drivers.archeon_opus_taxonomy.py,hylex_opus_taxonomy.py: domain-specific Opus prompt + edge parser (differ in domain description and target edge counts).biora_main.py,phyra_main.py: five-stage orchestrators for the hybrid pipeline domains.unit_test_archeon.py,unit_test_hylex.py,unit_test_biora.py,unit_test_phyra.py: per-domain unit tests (import surface, model identity, edge parser, mocked verifier yes/no + cache, post-processor).