qwen3-event-extraction-exp5.1

Attribute-extraction model for NGEC (Next Generation Event Coder), the pipeline behind the POLECAT political event dataset. Given a document and a PLOVER event type definition, it extracts the actor, recipient, date, location, and an anchor quote for every instance of that event type in the text, as JSON.

This is a 2026 retraining (internally: exp5.1) of ahalt/event-attribute-extractor and supersedes it โ€” position-corrected LLM-judge evaluation against ECAV gold labels shows +4pp actor accuracy and +1pp joint (actor+recipient) accuracy, and a +4pp joint win rate against gold. See "Evaluation" below.

This model was trained on a different prompt format than the original event-attribute-extractor. Prompting it in the old format does not raise an error, but will return somewhatworse spans. If you use this model through the NGEC package, ngec.attribute_model.AttributeModel handles this automatically by keying the prompt format off the model name (see KNOWN_PROMPT_FORMATS). If you use it standalone, use the format below, not the one on the old model card.

Example usage with vLLM

Load the model and tokenizer

from vllm import LLM, SamplingParams
from transformers import AutoTokenizer

model = LLM(model="ahalt/qwen3-event-extraction-exp5.1",
            enable_prefix_caching=True,
            max_model_len=8000,
            gpu_memory_utilization=0.80)

tokenizer = AutoTokenizer.from_pretrained("ahalt/qwen3-event-extraction-exp5.1")

sampling_params = SamplingParams(
    temperature=0.5,       # Greedy decoding breaks Qwen
    top_p=0.8,             # Qwen3 non-thinking recommendation
    top_k=20,              # Qwen3 recommendation
    presence_penalty=1.5,  # Recommended for quantized models
    min_p=0.0,
    max_tokens=2048,       # this model runs longer than the old one's 1024
)

Prompt setup

The system prompt states the output format and the extraction rules. The user message puts the whole event-type definition โ€” main definition, sub-event (mode), and any special instructions โ€” inline after ## Event Type:, as a single string; there is no closing "extract the attributes" instruction, because the system prompt already carries it.

system_content = """Given the event type definition below, find all instances of that event in the document and extract their attributes as JSON.

OUTPUT FORMAT:
[
  {
    "event_type": "EVENT_TYPE",
    "anchor_quote": "exact 5-15 word quote from text",
    "actor": "who performed action OR N/A",
    "recipient": "who was targeted OR N/A",
    "date": "when occurred OR N/A",
    "location": "where occurred OR N/A"
  }
]

RULES:
- All values must be exact spans copied from the text. Do not rephrase.
- ACTOR: The person, group, or entity who performed the action. Use N/A only if truly unknown/unstated. Descriptions like "gunman" or "suicide bomber" ARE valid actors.
- LOCATION: Use the most specific named place (city > region > country).
- Use short, concise spans. Omit articles (a/an/the) and unnecessary context.
- Multiple values: separate with semicolons.
- Return [] if no events of the specified type are present.
- Follow any Special Instructions provided with the event type definition."""


def make_prompt(doc, event_type, event_def, tokenizer, mode_def=None, extraction_notes=None):
    definition = f"## Event: **{event_type}**: {event_def}"
    if mode_def:
        definition += f" ## Specific Sub-Event: {mode_def}"
    if extraction_notes:
        definition += f" ## Special Instructions: {extraction_notes}"
    user_content = f"## Document: {doc}\n\n## Event Type: {definition}"

    messages = [
        {"role": "system", "content": system_content},
        {"role": "user", "content": user_content},
    ]
    return tokenizer.apply_chat_template(
        messages,
        tokenize=False,
        add_generation_prompt=True,
        enable_thinking=False,
    )

Event type definitions come from the PLOVER codebook (PLOVER_structured_codebook_updated.csv in the NGEC package) โ€” this model was trained to expect the definition text, not just the bare type name, after ## Event Type:.

Example

text = """KYIV, Ukraine (AP) โ€” Ukraine's anti-corruption agencies said they had uncovered a major graft scheme involving inflated military procurement contracts, just two days after Ukraine's parliament voted to restore the agencies' independence.

In a joint statement published Saturday on social media, the National Anti-Corruption Bureau (NABU) and the Specialized Anti-Corruption Prosecutor's Office (SAPO) said the suspects had taken bribes in a scheme that used state funds to buy drones and other military equipment at inflated prices.

"The essence of the scheme was to conclude state contracts with supplier companies at deliberately inflated prices," the statement said, adding that offenders had received kickbacks of up to 30% of the contracts' value."""

event_type = "INVESTIGATE"
event_def = ("Investigate, charge, or prosecute a person or organization for "
             "wrongdoing, corruption, or crime.")

prompt = make_prompt(text, event_type, event_def, tokenizer)
output = model.generate(prompt, sampling_params=sampling_params)
response = output[0].outputs[0].text.strip()

# [{"event_type": "INVESTIGATE",
#   "anchor_quote": "uncovered a major graft scheme involving inflated military procurement contracts",
#   "actor": "National Anti-Corruption Bureau (NABU); Specialized Anti-Corruption Prosecutor's Office (SAPO)",
#   "recipient": "suspects",
#   "date": "Saturday",
#   "location": "Ukraine"}]

Training

Fine-tuned from Qwen/Qwen3-0.6B for 1 epoch on a synthetic attribute-extraction dataset built from PLOVER-coded news documents, using the prompt format shown above. See the paper for the full data-generation and training methodology.

Caveats

  • Recipient extraction is harder than actor extraction across both this model and its predecessor โ€” see the per-event-type breakdown in the paper.
  • Bilateral events (e.g. Clash) confuse actor/recipient roles more often than unilateral ones: the model has no training signal for which side is "the" actor when the codebook forces an asymmetric label onto a symmetric event.
  • Sample at temperature=0.5. Greedy decoding degrades this model, consistent with Qwen3's own recommendation against greedy decoding for non-thinking mode.
Downloads last month
-
Safetensors
Model size
0.6B params
Tensor type
BF16
ยท
Inference Providers NEW
This model isn't deployed by any Inference Provider. ๐Ÿ™‹ Ask for provider support

Model tree for ahalt/qwen3-event-extraction-exp5.1

Finetuned
Qwen/Qwen3-0.6B
Finetuned
(1140)
this model
Quantizations
1 model