Head to head: Z.ai: GLM 5.3 vs MoonshotAI: Kimi K3

Z.ai: GLM 5.3 vs MoonshotAI: Kimi K3

This matchup wasn’t close. Kimi K3 consistently beat GLM 5.3 on the kind of details that separate a usable model from one that keeps tripping over the prompt.

Kimi K3 takes this head-to-head outright: **116.0 to 104.3, with 100% confidence**, plus an **8-0 lead in task wins** with four ties. That is not a vibes-based edge or a judge-interpretation squeaker. It’s a decisive sweep built on repeatable advantages across extraction, localization, SQL, unit-aware math, and instruction-following. What stands out is *how* Kimi won. Again and again, both models knew roughly what to do, but GLM 5.3 lost points on avoidable compliance mistakes: exceeding a six-word reason limit in nuanced classification, wrapping strict-JSON and SQL answers in Markdown fences, adding notes outside required JSON, and being slightly sloppier on exact wording or rounding procedure. Kimi K3 kept hitting the brief cleanly while preserving correctness. That’s the difference between “basically right” and production-safe. The localization results are especially telling. Kimi was better in both Spanish and French because it preserved meaning more precisely while sounding more natural in product-facing copy. In SQL, it added a deterministic tie-breaker and cleaner Postgres handling. In math, it showed the rounding step the prompt explicitly asked for. None of these are flashy wins; they’re the kind that matter when you actually ship model output. GLM 5.3 wasn’t bad here. It tied on staffing math, support-ticket labeling, contradiction finding, and the Python CSV bugfix, and in a few of those ties it was arguably a touch cleaner stylistically. But it never converted that into a category win, and the pattern across the losses is hard to excuse: too many format violations, too many small instruction misses, too little precision when precision was the whole task. **Final call: MoonshotAI: Kimi K3 is the clear winner.** Not because it produced radically more brilliant answers, but because it was more disciplined, more exact, and far more reliable under constraint—the traits that usually decide real-world text-model evaluations.

Nuanced classification

Classify each review's sentiment as "positive", "negative", or "mixed", and give a 6-word-max reason. Return ONLY a JSON array of {"text","label","reason"} in input order. Reviews: ["Fast shipping but the fabric feels cheap.", "Absolutely love it, wearing it daily!", "It broke after a week. Refund was quick and painless though."]

Z.ai: GLM 5.3: ```json [ { "text": "Fast shipping but the fabric feels cheap.", "label": "mixed", "reason": "Fast shipping praised, cheap fabric criticized." }, { "text": "Absolutely love it, wearing it daily!", "label": "positive", "reason": "Enthusiastic daily use shows strong satisfaction." }, { "text": "It broke after a week. Refund was quick and painless though.", "label": "mixed", "reason": "Product broke, but refund experience positive." } ] ```
MoonshotAI: Kimi K3: ```json [ {"text": "Fast shipping but the fabric feels cheap.", "label": "mixed", "reason": "Fast shipping, but cheap fabric."}, {"text": "Absolutely love it, wearing it daily!", "label": "positive", "reason": "Loves it, wears daily."}, {"text": "It broke after a week. Refund was quick and painless though.", "label": "mixed", "reason": "Broke quickly; refund was painless."} ] ```

Model B matches the requested labels and keeps every reason within the 6-word maximum. Model A is otherwise correct, but two reasons exceed the word limit, so Model B follows instructions more precisely. (Second judge pass, order swapped — scores are the average of both: Model B and Model A both classify all three reviews correctly, but Model B follows the 6-word-max reason constraint on every item while Model A exceeds it for all three reasons. Model B is therefore better on instruction adherence while maintaining strong clarity.)

Strict JSON extraction

Extract every meeting from this text into a JSON array of {"title","day","start24","durationMinutes"}. Use 24-hour "HH:MM" for start24, integer minutes for duration, and title-case titles. Return ONLY valid JSON, no commentary. Text: "Standup is daily at 9am for a quarter hour. The design review runs thursday from 2:30-4pm. Payroll sync — first monday, 11:00 to noon."

Z.ai: GLM 5.3: ```json [ { "title": "Standup", "day": "Daily", "start24": "09:00", "durationMinutes": 15 }, { "title": "Design Review", "day": "Thursday", "start24": "14:30", "durationMinutes": 90 }, { "title": "Payroll Sync", "day": "First Monday", "start24": "11:00", "durationMinutes": 60 } ] ```
MoonshotAI: Kimi K3: [ {"title":"Standup","day":"Daily","start24":"09:00","durationMinutes":15}, {"title":"Design Review","day":"Thursday","start24":"14:30","durationMinutes":90}, {"title":"Payroll Sync","day":"First Monday","start24":"11:00","durationMinutes":60} ]

Model B is better because both outputs extract the meetings correctly, but Model B returns only valid JSON as requested. Model A includes Markdown code fences, which violates the instruction to return only JSON. (Second judge pass, order swapped — scores are the average of both: Model B is fully correct and follows the instruction to return only valid JSON. Model A has the same extracted content, but the surrounding Markdown code fences violate the strict output requirement.)

Localization with tone

Translate this app onboarding line into natural, friendly European Spanish suitable for a mobile toast (keep it under 60 characters, no exclamation marks): "You're all set — your first backup starts tonight." Return only the translation, then the character count in parentheses.

Z.ai: GLM 5.3: Todo listo: tu primera copia de seguridad será esta noche. (58)
MoonshotAI: Kimi K3: Listo: tu primera copia de seguridad empieza esta noche. (56)

Model B is more natural and concise for a friendly mobile toast while staying under 60 characters. Model A is understandable, but "será esta noche" sounds less natural for a backup starting, and its reported character count appears inaccurate. (Second judge pass, order swapped — scores are the average of both: Model B is more faithful to the source meaning because it preserves that the backup starts tonight, while Model A shifts the meaning to the backup simply being tonight. Both stay under 60 characters and avoid exclamation marks, but Model B sounds slightly more natural for a mobile toast in European Spanish.)

festival_staffing_math

Step-by-step reasoning — A neighborhood festival needs volunteer coverage for 3 booths: Tickets, Info, and Kids Zone. Rules: - Each 1-hour slot needs: Tickets 2 people, Info 1 person, Kids Zone 2 people. - There are 4 slots: 10–11, 11–12, 12–1, 1–2. - Volunteers and availability: - Nia: 10–11, 11–12, 12–1 - Omar: 10–11, 12–1, 1–2 - Priya: 11–12, 12–1 - Luca: 10–11, 11–12, 1–2 - Soren: 12–1, 1–2 - Mei: 10–11, 11–12, 12–1, 1–2 - Talia: 11–12, 1–2 - No person can work consecutive slots. - Everyone can work any booth. Question: What is the MINIMUM number of additional volunteer-hours needed to fully staff all booths across all slots? Give the number and a short explanation.

Z.ai: GLM 5.3: **Minimum additional volunteer-hours needed: 8** Step-by-step: 1. **Total staffing requirement** Each slot needs: - Tickets: 2 people - Info: 1 person - Kids Zone: 2 people Total per slot: **5 people** There are **4 slots**, so total need is: \[ 4 \times 5 = 20 \text{ volunteer-hours} \] 2. **Maximum possible hours from the listed volunteers** Because no one can work consecutive slots: - Nia: max 2 - Omar: max 2 - Priya: max 1 - Luca: max 2 - Soren: max 1 - Mei: max 2 - Talia: max 2 Total possible from listed volunteers: \[ 2+2+1+2+1+2+2 = 12 \] 3. **A schedule achieving 12 listed-volunteer-hours:** - 10–11: Nia, Omar, Mei - 11–12: Priya, Luca, Talia - 12–1: Nia, Omar - 1–2: Luca, Soren, Mei, Talia No one works consecutive slots, and all assignments respect availability. 4. **Shortfall** \[ 20 - 12 = 8 \] So the festival needs **8 additional volunteer-hours**.
MoonshotAI: Kimi K3: **Answer: 8 additional volunteer-hours.** - Total needed: (2 Tickets + 1 Info + 2 Kids) × 4 slots = 5 × 4 = **20 hours**. - Max each current volunteer can work without consecutive slots: - Nia 2 (10–11 & 12–1), Omar 2, Priya 1, Luca 2, Soren 1, Mei 2, Talia 2 → **12 hours max**. - This 12 is reachable, e.g.: - 10–11: Nia, Omar, Luca, Mei (4/5, short 1) - 11–12: Priya, Talia (2/5, short 3) - 12–1: Nia, Soren, Mei (3/5, short 2) - 1–2: Omar, Luca, Talia (3/5, short 2) Shortfall = 20 − 12 = 1+3+2+2 = **8 volunteer-hours**.

Model A and Model B both arrive at the correct minimum of 8 additional volunteer-hours by correctly computing the 20 total required hours and the 12 maximum usable hours from existing volunteers under the no-consecutive-slots rule. Model A is slightly cleaner because it explicitly states a feasible 12-hour schedule, while Model B is also valid but presents per-slot shortfalls in a way that is a bit less direct; overall, their quality is effectively equal. (Second judge pass, order swapped — scores are the average of both: Model B and Model A both reach the correct minimum of 8 additional volunteer-hours using the same valid upper-bound logic and each provides a feasible nonconsecutive schedule achieving 12 in-house volunteer-hours. Model A is slightly clearer and more polished, while Model B is a bit more concise; neither has a substantive correctness or instruction-following advantage.)

SQL window query

Given Postgres tables `orders(id, customer_id, created_at, total_cents)` and `customers(id, name)`, write ONE SQL query returning each customer's name and their SECOND-largest order total (in dollars, 2 decimals), excluding customers with fewer than two orders. Order by that value descending. Return ONLY the SQL.

Z.ai: GLM 5.3: ```sql SELECT c.name, ROUND(o.total_cents / 100.0, 2) AS second_largest_total FROM ( SELECT customer_id, total_cents, ROW_NUMBER() OVER (PARTITION BY customer_id ORDER BY total_cents DESC) AS rn FROM orders ) o JOIN customers c ON c.id = o.customer_id WHERE o.rn = 2 ORDER BY second_largest_total DESC; ```
MoonshotAI: Kimi K3: WITH ranked_orders AS ( SELECT customer_id, total_cents, ROW_NUMBER() OVER ( PARTITION BY customer_id ORDER BY total_cents DESC, id DESC ) AS rn FROM orders ) SELECT c.name, ROUND(ro.total_cents::numeric / 100, 2) AS second_largest_total FROM ranked_orders ro JOIN customers c ON c.id = ro.customer_id WHERE ro.rn = 2 ORDER BY second_largest_total DESC;

Model B is slightly better because it adds a deterministic tie-breaker in the window ordering and uses an explicit numeric cast before rounding, making the result more robust in Postgres. Model A is still largely correct, but its ranking among equal totals is less well-defined. (Second judge pass, order swapped — scores are the average of both: Model B is slightly better because it returns valid Postgres SQL with no extra formatting and correctly excludes customers with fewer than two orders via the row-number filter. Model A is also largely correct, but it violates the instruction to return only SQL by wrapping the query in a Markdown code fence.)

Unit-aware math

A pump moves 3.5 liters every 8 seconds. A tank holds 0.9 cubic meters. Starting empty, how long to fill it, in minutes and seconds (mm:ss), rounded to the nearest second? Show the key steps, then give the final answer on its own line.

Z.ai: GLM 5.3: - Tank volume: \(0.9\text{ m}^3 = 900\text{ L}\) - Pump rate: \(\frac{3.5\text{ L}}{8\text{ s}} = 0.4375\text{ L/s}\) - Fill time: \(\frac{900}{0.4375} = 2057.14\text{ s}\) - Convert: \(2057.14\text{ s} = 34\text{ min }17.14\text{ s}\) 34:17
MoonshotAI: Kimi K3: Convert tank volume: 0.9 m³ × 1000 = 900 L Pump rate: 3.5 L / 8 s = 0.4375 L/s Time: 900 L ÷ 0.4375 L/s = 2057.142857 s ≈ 2057 s Convert: 2057 s = 34 min 17 s 34:17

Model B is slightly better because it explicitly rounds the total seconds to the nearest second before converting to mm:ss, matching the instruction more directly. Model A’s math and final answer are still correct, but it leaves the intermediate time as 2057.14 s rather than clearly showing the rounding step. (Second judge pass, order swapped — scores are the average of both: Model B and Model A both compute the correct fill time and provide the required final answer format. Model B is slightly better because it explicitly rounds to the nearest second before converting to mm:ss, whereas Model A leaves the intermediate result as 17.14 seconds and then gives 34:17 without stating the rounding step as clearly.)

fr_localization_push_notice

Translation & localization — Translate this product notice into French for customers in France. Tone: warm and professional. Length constraint: max 38 words. Keep the meaning and nuance, including the soft apology and the action requested. "We’re sorry — yesterday’s warehouse scan missed a small batch of pre-orders. If your Rellan S2 hasn’t shipped yet, please confirm your delivery address in the app by 6 p.m. today."

Z.ai: GLM 5.3: **French translation (37 words):** > Toutes nos excuses : hier, notre scan d'entrepôt a laissé passer un petit lot de précommandes. Si votre Rellan S2 n'est pas encore en route, merci de confirmer votre adresse de livraison dans l'application avant 18 h aujourd'hui. **Localization notes:** - **« Merci de confirmer »** keeps the request warm rather than administrative (« veuillez » would feel colder). - **« 18 h »** uses the 24-hour format standard in France. - **« n'est pas encore en route »** deliberately avoids gendering the product name. If your French materials already establish *le/la Rellan S2*, you can swap in « n'a pas encore été expédié(e) » — same word count, same meaning. - The apology stays soft and brief (« Toutes nos excuses »), matching the original's light touch rather than a heavy formal apology.
MoonshotAI: Kimi K3: **French (France) — 37 words :** > Nous sommes vraiment désolés : le scan d'entrepôt d'hier a manqué un petit lot de précommandes. Si votre Rellan S2 n'a pas encore été expédié, merci de confirmer votre adresse de livraison dans l'application avant 18 h aujourd'hui. **Localization notes:** - **Soft apology preserved:** « Nous sommes vraiment désolés » mirrors the warm, direct tone of "We're sorry." - **Warm-professional register:** formal *vous* throughout, and « merci de confirmer » softens the request compared to the more directive « veuillez ». - **Time format adapted:** "6 p.m." → « 18 h », the standard 24-hour convention in France. - **« scan d'entrepôt »** is natural in French logistics contexts; « précommandes » is the standard term for pre-orders.

Model B is more faithful to the source: « n'a pas encore été expédié » matches “hasn’t shipped yet” better than Model A’s « n'est pas encore en route », and its apology reads warmer and more natural for the requested tone. Model A is strong and within the length limit, but it slightly shifts the meaning and sounds a bit less direct in the key shipping-status phrase. (Second judge pass, order swapped — scores are the average of both: Model B is more faithful to the source: it preserves the soft apology, clearly conveys that the pre-orders were missed in yesterday’s warehouse scan, and accurately renders “hasn’t shipped yet” as “n'a pas encore été expédié.” Model A is fluent and within length, but “n'est pas encore en route” shifts the meaning slightly and is less precise than the original shipping status.)

proofread_policy_update

Editing & proofreading — Rewrite the passage below to correct grammar, punctuation, and clarity WITHOUT changing meaning. Then add 2 brief bullet points noting the main changes. "Each team member need to submit their access request by Thursday, otherwise IT may not be able process it before the office move. The new badges works at both entrances, but only after security have activate them, which usually take 24 hours."

Z.ai: GLM 5.3: **Revised passage:** "Each team member needs to submit their access request by Thursday; otherwise, IT may not be able to process it before the office move. The new badges work at both entrances, but only after security has activated them, which usually takes 24 hours." **Main changes:** - Corrected subject–verb agreement and verb forms throughout ("member needs," "able **to** process," "badges work," "security has activated," "usually takes"). - Replaced the comma splice before "otherwise" with a semicolon and added a comma after it for proper punctuation.
MoonshotAI: Kimi K3: **Rewritten passage:** "Each team member needs to submit their access request by Thursday; otherwise, IT may not be able to process it before the office move. The new badges work at both entrances, but only after security has activated them, which usually takes 24 hours." **Main changes:** - Corrected subject-verb agreement throughout: "need" → "needs," "works" → "work," "have activate" → "has activated," and "take" → "takes." - Fixed punctuation and a missing word: replaced the comma before "otherwise" with a semicolon (it joins two independent clauses) and added "to" in "able to process."

Model A and Model B produce the same corrected passage, fully preserving meaning while fixing the grammar, punctuation, and clarity issues. Model A’s notes are slightly more concise, while Model B’s notes are slightly more explicit, but both follow the instructions equally well. (Second judge pass, order swapped — scores are the average of both: Model B and Model A produce the same strong revised passage, but Model B’s notes are fully accurate. Model A incorrectly claims it added a comma after “otherwise,” which does not appear in its revision, so Model B is better on correctness and instruction adherence.)

support_ticket_labeling

Classification & labeling — Classify each support message into exactly one category: Billing, Bug Report, Feature Request, Account Access, Shipping Return your answer in a 5-line table with columns: item | category | brief justification Items: A. "I was charged twice for order QN-4412 after I updated my card. Please reverse the extra payment." B. "Since the 4.3.1 update, exporting a chart as PNG produces a blank image on my Pixel 8." C. "Can you add an option to mute only calendar reminders but keep task reminders on?" D. "My reset link says expired immediately, and I still can’t sign in with the backup code." E. "Tracking for parcel HushCart 77 says delivered, but nothing was at reception or the mailroom."

Z.ai: GLM 5.3: | item | category | brief justification | |------|----------|----------------------| | A | Billing | Duplicate charge on an order with a request to reverse payment | | B | Bug Report | Software defect (blank PNG export) triggered by the 4.3.1 update | | C | Feature Request | Asking for new functionality — selective muting of calendar reminders | | D | Account Access | Broken password reset link and backup code preventing sign-in | | E | Shipping | Parcel marked "delivered" but not received — delivery discrepancy |
MoonshotAI: Kimi K3: | item | category | brief justification | |------|----------|---------------------| | A | Billing | Reports a duplicate charge and requests a payment reversal. | | B | Bug Report | Describes broken PNG export functionality after a software update. | | C | Feature Request | Asks for a new granular mute option for reminder types. | | D | Account Access | User cannot sign in due to an expired reset link and failing backup code. | | E | Shipping | Parcel marked as delivered but not received at any location. |

Model A and Model B both classify all five items correctly and follow the requested table format with concise justifications. Model B is slightly more polished stylistically, but the difference is negligible and does not create a meaningful quality gap. (Second judge pass, order swapped — scores are the average of both: Model B and Model A both classify all five items correctly and follow the requested table format with concise justifications. Model A is slightly more polished in phrasing, but the difference is negligible, so the outputs are effectively equal in quality.)

Find the contradiction

The following spec contains exactly one internal contradiction. Quote the two conflicting sentences verbatim and explain the conflict in one sentence. Do not fix it. Spec: "Free accounts may create up to three projects. Every account, regardless of tier, may archive unlimited projects. Archiving a project does not count against the project limit. Free accounts are limited to three projects total, including archived ones."

Z.ai: GLM 5.3: **Conflicting sentences:** 1. "Archiving a project does not count against the project limit." 2. "Free accounts are limited to three projects total, including archived ones." **Conflict:** The first sentence excludes archived projects from counting toward the limit, while the second sentence explicitly includes archived projects in the three-project limit, so they cannot both be true.
MoonshotAI: Kimi K3: “Archiving a project does not count against the project limit.” “Free accounts are limited to three projects total, including archived ones.” The first sentence excludes archived projects from the limit, while the second includes them in the same three-project limit.

Model A and Model B both identify the same two conflicting sentences verbatim and explain the contradiction accurately in one sentence without attempting to fix it. Model A is slightly more formatted, while Model B is slightly more concise, but neither is meaningfully better for this task. (Second judge pass, order swapped — scores are the average of both: Model B and Model A both identify the exact contradictory sentences verbatim and explain the conflict accurately in one sentence without attempting to fix it. Model A is slightly more formatted, but both fully satisfy the task equally well.)

extract_invoice_fields

Information extraction — From the messy note below, extract the requested fields and return them as valid JSON with exactly these keys: company, invoice_id, issue_date, due_date, currency, subtotal, tax, total, contact_email, line_items Where line_items is an array of objects with keys: description, qty, unit_price. Messy note: "For Willow Bend Studio LLC — INV# WB-2087-A (issued 2026/04/09). Bill to: Willow Bend Studio LLC, attn. Mara Voss. Items: 3 x 'On-site color calibration' @ 185.00; 1 x 'Rush edit fee' @ 75.50. Sub-total 630.50 USD. Sales tax (8.25%): 52.02. Grand Total: USD 682.52. Please remit within 21 days; due 30 Apr 2026. Questions? [email protected]"

Z.ai: GLM 5.3: ```json { "company": "Willow Bend Studio LLC", "invoice_id": "WB-2087-A", "issue_date": "2026-04-09", "due_date": "2026-04-30", "currency": "USD", "subtotal": 630.50, "tax": 52.02, "total": 682.52, "contact_email": "[email protected]", "line_items": [ { "description": "On-site color calibration", "qty": 3, "unit_price": 185.00 }, { "description": "Rush edit fee", "qty": 1, "unit_price": 75.50 } ] } ``` Notes on the extraction: - **Dates** were normalized to ISO 8601 format (YYYY-MM-DD); the due date came from "due 30 Apr 2026" (consistent with the "remit within 21 days" note from the 2026-04-09 issue date). - **Amounts** are numeric values; the math checks out: (3 × 185.00) + 75.50 = 630.50, plus 8.25% tax (52.02) = 682.52.
MoonshotAI: Kimi K3: ```json { "company": "Willow Bend Studio LLC", "invoice_id": "WB-2087-A", "issue_date": "2026-04-09", "due_date": "2026-04-30", "currency": "USD", "subtotal": 630.50, "tax": 52.02, "total": 682.52, "contact_email": "[email protected]", "line_items": [ { "description": "On-site color calibration", "qty": 3, "unit_price": 185.00 }, { "description": "Rush edit fee", "qty": 1, "unit_price": 75.50 } ] } ```

Model B exactly follows the instruction to return only valid JSON with the requested keys, and its extraction is correct. Model A’s JSON content is also correct, but it adds explanatory notes outside the JSON, so it does not fully comply with the output-format requirement. (Second judge pass, order swapped — scores are the average of both: Model B and Model A produce the same valid JSON with all requested keys, correctly extracted values, and properly structured line items. Both fully follow the instruction and are equally clear and accurate.)

python_csv_bugfix

Debugging & code review — Python The function below should return the email addresses for ACTIVE users only, preserving input order. It currently drops some valid rows and may crash on messy data. Find the bug(s), fix them, and return ONLY the corrected code. ```python def active_emails(csv_text): rows = csv_text.strip().split("\n") out = [] for row in rows[1:]: name, status, email = row.split(",") if status.lower().strip() == "active" and email: out.append(email.strip().lower) return list(set(out)) ``` Sample input it should handle: ```text name,status,email Ari, Active , [email protected] Bo,inactive,[email protected] Cia,ACTIVE, Dee,active, [email protected] Eli, active, [email protected] ```

Z.ai: GLM 5.3: ```python import csv def active_emails(csv_text): out = [] reader = csv.reader(csv_text.strip().splitlines()) # csv module: handles quoted commas, CRLF, stray columns next(reader, None) # skip the header row for row in reader: if len(row) < 3: # blank/malformed row: skip instead of crashing on unpack continue status, email = row[1], row[2] if status.strip().lower() == "active" and email.strip(): # test stripped email, not raw field out.append(email.strip().lower()) # actually CALL .lower(), don't reference the method return out # preserve input order; set() scrambled order and dropped duplicate emails ```
MoonshotAI: Kimi K3: ```python import csv import io def active_emails(csv_text): out = [] reader = csv.reader(io.StringIO(csv_text)) next(reader, None) # skip header row for row in reader: if len(row) < 3: continue # skip blank/malformed rows instead of crashing status = row[1].strip().lower() email = row[2].strip() if status == "active" and email: out.append(email.lower()) return out ```

Model B provides a correct, concise fix that preserves input order, avoids crashes on malformed rows, and properly normalizes emails. Model A is also mostly correct, but its comment about the csv module handling stray columns is misleading and it adds unnecessary commentary relative to the instruction to return only corrected code. (Second judge pass, order swapped — scores are the average of both: Model A is slightly better because it fixes all identified bugs while explicitly preserving input order and correctly calling .lower(); Model B is also correct on the sample and robust to malformed rows, but it is a bit less precise in addressing the original issues and includes an unnecessary io import.)

Matchup powered by OpenRouter.