Views
No views yet
Qwen/Qwen3.5-9B
(loaded as AutoModelForImageTextToText). Mathematical composition of:...-lora-v4-rl-step25 adapter (eval mean -1.59, max +0.91).<tool_call>{...}</tool_call> per turn.
A companion environment owns the JATS tree and applies actions.⚠️ Inference requires both the model and the JATS environment. The minimal inference-only package (env, tool schemas, serializer, runnable example) is at https://github.com/parthsarin/agentic-jats-annotation-inference. Full training source is at https://github.com/parthsarin/jats-annotation-via-agentic-scratchpad.
1from peft import PeftModel
2from transformers import AutoModelForImageTextToText, AutoTokenizer
3
4base = AutoModelForImageTextToText.from_pretrained(
5 "Qwen/Qwen3.5-9B",
6 torch_dtype="bfloat16", trust_remote_code=True, device_map="auto",
7)
8model = PeftModel.from_pretrained(
9 base,
10 "public-knowledge-project/agentic-jats-annotation-qwen3.5-9b-lora-v8-rl-step70",
11)
12tok = AutoTokenizer.from_pretrained("Qwen/Qwen3.5-9B")</tool_call>, enable_thinking=False,
max_new_tokens 160-256, temperature 0.7).</tool_call> — one tool call per turn.enable_thinking=False — the SFT teacher data emitted no thinking
content; leaving thinking on makes the model ramble. Always pass
enable_thinking=False to apply_chat_template.1You annotate documents with JATS XML by emitting one tool call per turn.
2The environment owns the XML tree; you only emit JSON describing the next
3edit. Use <think>...</think> for brief reasoning (<=200 tokens) and then
4emit exactly ONE <tool_call>{...}</tool_call> block. Generation stops at
5</tool_call>; the env resumes after parsing.
6
7# Tool-call JSON shape
8
9Each call is a SINGLE FLAT JSON object whose discriminator field is "name"
10and whose other fields are the call's arguments at the SAME nesting level
11(NOT nested under an "arguments" or "params" key). Line numbers are
12INTEGERS (e.g. 5), not strings (e.g. NOT "L0005").
13
14Three correct examples:
15
16 <tool_call>{"name": "set_article_title", "line": 1, "title": "German-Austrian Consensus on Charcot Neuroarthropathy"}</tool_call>
17
18 <tool_call>{"name": "mark_section_start", "line": 5, "depth": 1, "title": "Introduction"}</tool_call>
19
20 <tool_call>{"name": "mark_xref", "line": 7, "target": "1", "ref_type": "bibr", "rid": "cit0001", "head": "guidelines (", "tail": ")."}</tool_call>
21
22Common WRONG shapes the parser rejects:
23 {"command": "...", ...} -- key must be "name"
24 {"name": "...", "arguments": {...}} -- args are FLAT, not nested
25 {"name": "...", "line": "L0001"} -- "line" is int, not "L..."
26
27# Tools (signatures: required fields then [optional])
28
29Front-matter:
30 set_article_title line:int, title:str
31 add_contrib surname:str, given_names:str, [contrib_type, initials, email, aff_rids:list[str]]
32 add_affiliation aff_id:str, text:str
33 start_abstract / end_abstract (no args)
34 add_keyword text:str
35
36Body:
37 mark_section_start line:int, depth:int(1..4), title:str, [sec_type]
38 mark_section_end depth:int
39 mark_paragraph start_line:int, end_line:int
40 mark_xref line:int, target:str, ref_type:"bibr"|"table"|"fig"|"sec"|"aff"|"fn", rid:str, [head, tail]
41 mark_inline line:int, target:str, tag:"italic"|"bold"|"sup"|"sub"|"underline", [head, tail]
42 mark_list_start list_type:"bullet"|"order"|"simple"|"alpha-lower"|"alpha-upper"
43 mark_list_item start_line:int, end_line:int
44 mark_list_end (no args)
45 mark_table start_line:int, end_line:int, [label, caption]
46 mark_figure line:int, [label, caption, graphic_href]
47
48Back / ref-list:
49 add_ref rid:str, label:str, publication_type:"journal"|"book"|"chapter"|"conf-proc"|"thesis"|"webpage"|"other", fields:list[{field:str, value:str}]
50 Preferred: emits a whole <ref> in one turn instead of start_ref/ref_field*N/end_ref.
51 `field` values: surname|given-names|year|article-title|source|volume|issue|fpage|lpage|pub-id-doi|pub-id-pmid|ext-link-uri|...
52 start_ref rid:str, label:str, [publication_type] # alternative to add_ref, used with ref_field/end_ref
53 ref_field field:str, value:str # field: surname|given-names|year|article-title|source|volume|issue|fpage|lpage|pub-id-doi|...
54 end_ref (no args)
55
56Meta:
57 skip_lines start_line:int, end_line:int, [reason]
58 unassign_lines start_line:int, end_line:int
59 finish (no args)
60
61# Semantic rules
62
63- depth must equal (parent_depth + 1), or 1 at top level.
64- mark_xref / mark_inline require the line to already be inside a <p>.
65- mark_xref's `rid` must reference an entry in the rid_table.
66- finish() requires zero open sections and zero unassigned non-empty lines.Qwen/Qwen3.5-9B (9B, hybrid Gated DeltaNet + Sparse MoE, 262k ctx)(parent_tag, child_tag, depth, text_hash) tuples vs. gold JATS,
with a recall floor and anti-hack guards| Model | mean reward | max reward | positive | >+1.0 |
|---|---|---|---|---|
| 3-epoch SFT (no RL) | -1.65 | +0.70 | 3/20 | 0 |
| v4 RL step-25 | -1.59 | +0.91 | 4/20 | 0 |
| v8 RL step-40 | -1.48 | +0.52 | 4/20 | 0 |
| This (v8 RL step-70) | -1.26 | +1.29 | 3/20 | 1/20 |
finish() rarely successful — most rollouts end via turn cap or
consecutive-error limit; serialize partial state via
src/serialize.py:calls_to_xml.