Agentic AI Product × Engineering Workflows

Wenjie Luo

Wenjie Luo

罗文杰

NUS MSc Civil Engineering · AI Product Builder
Reliable agents: LLM orchestration × deterministic tools × HITL × eval

One-page PDF · Grad. Jan 2027 · Singapore

About

I am Wenjie Luo, an MSc student in Civil Engineering (Transport) at the National University of Singapore. Expected graduation: January 2027. I build agentic AI products for complex workflows: the model routes, tools compute, humans confirm, evals rerun.

I work as a project engineer at Far East Facade in Singapore: 15 façade material types and inbound plans, 5 suppliers for sampling and tests, transport and site progress. In the open-source repos, Civil Buddy packs with tools computing coordinates and counts, then a human yes; malaysia-auto-ask stops if wholesale TIV versus registrations is unclear, and answers carry metric text plus table-level lineage. Its note-for-colleagues view can only be copied after a human confirms it. Both are demoable and measurable — not a live production business.

At Chery I ran competitive win/loss and VOC; at CaiXun I wrote PRDs with acceptance. Months on site made one product rule clear: an agent people will actually use has its guardrails written into the spec, not bolted on afterwards.

📍Singapore
🎓NUS MSc · Jan 2027
🏗️Far East · project engineer
🧩Agents · HITL · Eval

How I judge

Four judgments from the work.

Education

2025.08 – 2027.01 In progress

National University of Singapore

MSc Civil Engineering · Transport

Transport engineering programme; the AI coursework was taken within it.

Transcript courses: CEE5901QA ML Foundations, CEE5901QB Advanced AI for CEE; plus traffic planning and ITS simulation.

CEE5901QA · ML Foundations CEE5901QB · Advanced AI for CEE Traffic flow & control ITS & simulation
2021.09 – 2025.06

Chang’an University

BEng Transportation · Outstanding Engineer class

GPA 3.16 / 5.0 · about top 15% in major

Courses: Calculus I 93, university computing 90, Python. Class Youth League secretary, Sep 2024 – Jun 2025.

Experience

Material lists, supplier tests, transport and site progress — the repetitive copying is scripted away.

2026.06 – Present Project engineer Singapore · on site

Far East Facade (Singapore) | Project engineer

Semiconductor fab façade project · also an LTA building

  • Material board: 15 façade material types and inbound plans; a board tracks status and milestones.
  • Suppliers: 5 vendors; sampling and third-party tests so material arrives on schedule.
  • Site progress: installation checks; 8 weekly project meetings to catch slippage early.
  • Mail tool: Python pulls shipment and test mail, extracts arrival and inspection fields, replaces hand copying.
Material boardSuppliersPython Weekly meetings

Internships

2026.05.04 – 2026.06.23 Product

Chery International | Product manager intern

  • Competitive & VOC: win/loss, styling comparison, complaint mining; 15 personas and 5 VOC reports for product definition and refresh.
  • Regional sales: bubble charts by length / price / registrations to track target-market trends.
  • KD localization: Gantt for production, logistics, and compliance nodes on the critical path.
2025.06.02 – 2025.07.31 Product

Colorful-Clouds (CaiXun) | Product manager intern

  • PRDs: 3 documents covering features, interaction, and acceptance in one spec.
  • Prototype & delivery: 5 Axure core pages that entered development; worked with FE / BE / QA.
2024.12 – 2025.05 Supply chain

Expeditors | Supply-chain assistant

  • Coordination: carriers, clients, and customs brokers; issued and reviewed declarations. English on site.
  • Process: tightened the spreadsheet flow; about 50 declarations per day.

Projects

Public repos can be cloned and rerun. Course work is labelled as such.

2026.09 Open source · Inference diagnosis

vllm-sm75-throughput — a 10× throughput collapse traced to one GEMM cliff

GTX 1650 (sm_75) · refutation experiment on a T4 · fp16 GEMM

vLLMcuBLASTensor CoresAttribution
  • Problem vLLM throughput collapses about 10× on a GTX 1650. On the surface anything could be the cause.
  • Attribution fp16 GEMM bandwidth falls from 99.5 to 4.3 GiB/s going from M=1 to M=2 (0.04×): with tensor cores removed from sm_75, the cuBLAS small-M path is pathological.
  • The experiment that could have refuted it Same script on a T4 — same sm_75, same Turing, tensor cores kept: 106.7 → 88.1 GiB/s (0.83×), consistent over three shapes. One variable, a 20× difference in the ratio; the attribution holds.
  • Reported upstream The root cause is filed against PyTorch (issue #195716) and the deployment trap, with a warning proposal, against vLLM (issue #54950: --dtype half is a performance trap on tensor-core-less Turing cards); both are open.
2026.09 Open source · Flow Q&A

EDA Copilot — OpenROAD flow Q&A that stops and asks when the metric is unclear

Ran RTL→GDSII myself · 1,215-chunk corpus with line-level provenance · stop-guard ablation

OpenROAD / ORFSRAGStop guardQoR
  • Corpus Ran the full nangate45/gcd back-end flow in the official image and cut the 46 reports/logs/stage metrics plus 31 script docs into 1,215 chunks, each cited to the line.
  • Stop guard Seven structured stop codes (ambiguous metric, setup/hold unspecified, out of scope, …): 12/12 should-stop questions stop with the right code. With the guard off, all 12 are answered anyway, each with a citation — the cited wrong answer is the dangerous kind.
  • Evaluation decides Hybrid retrieval showed no gain and was switched off; once run artifacts made the corpus heterogeneous it won (Hit@5 0.957 vs 0.913) and was switched back on. Both numbers stay in the README. From my own QoR report: TNS −7.18 vs WNS −0.16, timing buffers at 18.7% of standard-cell area with WNS still unconverged.
  • Scope Example-scale design, open 45 nm library, default parameters; a digital back-end QoR report, not fab yield data.
2026.09 TechJam Track 2 · Autonomous ML agent

RecAgent — an agent that runs its own MLE loop

KuaiRand-Pure · official scoring protocol · did not place

LightGBMAutoMLRanking0 manual edits
  • Problem The track does not ask for a high-scoring model. It asks for an agent that inspects, engineers features, trains, evaluates and reflects on its own.
  • Result Under the official protocol: test 0.6015 vs the FM baseline 0.5946, +0.0069 on the primary metric — in 23 scored iterations (cap 50), CPU-only, about 3.5 hours (cap 6 h).
  • The number I care about is the zero Zero manual code changes. Half the budget unused, and not a line of model code written by me — only five goal-level instructions — is what makes it an agent rather than me tuning parameters.
2026.09 TechJam Track 3 · GPU kernel

Transformer forward-pass GPU kernel

13/13 gradeable shapes PASS · free cloud GPUs · did not place

Fused SDPAtorch.compileNumerical parity
  • Problem The hardest shape, seq_len=100000, needs roughly 20.5 TB just for the baseline attention score matrix. Not a speed problem — it simply cannot run.
  • What it does Fused SDPA (the memory-efficient backend) replaces the O(S²) matrix with an O(S) kernel; the 100k shape is chunked into a preallocated output tensor. Every baseline submodule and parameter name is kept, so a strict weight copy still succeeds and the comparison stays apples-to-apples.
  • Result 13/13 gradeable shapes PASS at a worst absolute error of 9.5e-6 against a 2e-3 gate; median speedup 2.83× on a T4 (per-shape median of three independent runs, range 1.57×–5.22×) / 2.07× on a P100; the 100k shape completes inside 14.2 GB (184 s on the T4).
  • Where the speed comes from A hand-written fp16x3 linear layer: each operand is split into an fp16 hi + lo pair and fed to one cuBLAS tensor-core GEMM with K tripled — fp32-class accuracy on the fp16 tensor cores. The GEMM-bound shape goes 1.09× → 1.57×, the median 2.30× → 2.83×. Not accuracy traded for speed.
  • The trade-off fp16 storage autocast reaches 4.01×, but its worst absolute error of 2.04e-3 has crossed atol=0.002. Shipped off — half the speedup, in exchange for a number that is not sitting on the tolerance line.
  • Self-audit An adversarial audit of our own claims found five wrong ones, "FlashAttention" among them (a backend probe showed neither GPU could run it, and the probe is committed as evidence), including our own sweep script silently dropping torch.compile from the fifth shape on and under-reporting three shapes. Three hand-written kernel families were all measured; one ships: fp16x3. A fused add+LayerNorm matched Inductor without beating it, and a split-operand attention kernel reached fp32-class accuracy but lost on speed — both left off.
2026.09 TechJam Track 4 · Conversational search

ByteSize — recommend only once the evidence is enough

50,000-item catalog · 0 tokens / $0 · did not place

Value of informationLate fusionFully offline
  • Problem In multi-turn shopping dialogue the common failure is recommending as soon as the candidate pool gets small. A small pool does not mean the agent knows enough — it may just have guessed narrowly.
  • What it does Every turn asks one explicit question: is the evidence sufficient? If yes, recommend; if not, ask once more. The controller reads scenario, disclosed slots and pool size — it never inspects the remaining turn budget and never changes the ranking function.
  • Result On 800 ID-disjoint sessions it gains +60 rank-1 recommendations with zero Hit-rate loss and improves 8 of 8 shards; Hit@10 is 1.000 on the labelled public set. All of it at 0 tokens and $0.
  • Scope The holdout and the 800 sessions are my own ID-disjoint splits, not an official leaderboard.
2026.09 WebMCP Challenge · Open source

Counterask — when answering would be a guess, the tool asks back

9,901 real menswear products (Amazon Reviews 2023) · one page, no server · 0 tokens

WebMCPSentence parsingExpected-survivors stoppingCategory-tree questions
  • What A menswear storefront whose search_products tool returns a question instead of half a ranking whenever answering would be a guess; answer_question is registered only while a question is open and unregistered once it is answered; checkout is a declarative form an agent can fill but only a person can submit. One page, no server, no model call. Verified on Chrome 152 with the WebMCP flag, driving document.modelContext directly: all eleven imperative tools plus the checkout form show up in getTools(), answer_question comes and goes natively, and checkout stops in front of the Place-order button with nothing submitted.
  • Reading a whole sentence An agent relays "a leather belt, nothing with a snap, not over $50", not two search-box words. Budget, refusals, stated attributes and "any is fine" are parsed in a fixed order, each claimed span blanked so no word is read twice. On 800 sentences generated from real product records: Hit@10 0.793 with a keyword matcher → 0.999 with the parser (0.993 on the rebuilt index, 0.991 under phrasings it was never tuned on); refusals inverted into requirements 100% → 0, budget broken in the top 10 31% → 0. 61 hand-written cases and a 4,000-sentence fuzzer run in npm test.
  • When to ask Not entropy — with multi-valued attributes the shares are not a distribution — but expected candidates removed; missing data is not a mismatch, attributes recorded on under 45% of the pool are never asked about, and a question that clears fewer than 10 candidates is not worth a turn. A "clear leader, stop asking" rule was built twice and removed twice; one step of lookahead was built, measured and left off. Each time the measurement said no.
  • Scope and credit The simulated shopper answers instantly and only tells the truth, so neither benchmark prices a person's patience or a missing attribute; coverage is the ceiling — after the index rebuild, material is recorded on 69% of products (from 56%), fit still on 9%. Teammate Cui Zixuan built an independent implementation of the same design (the cuizi-rewrite branch of the counterask repo); five of its ideas were folded back into this one.
2026.08 – 2026.09 Open source · Image forensics

RepostGuard — detect AI-generated images on the repost, not the original

Frozen CLIP + DINOv2 + a 28-D forensic vector · ~110M, CPU-only · all 15 transforms

Image forensicsRobustnessBootstrap CIsLeakage control
  • Why framed this way What circulates on a platform is never the original: it has been JPEG-compressed, thumbnailed and noised. Most detectors report a clean-image number and lose it on the repost chain, so this one is scored on the transformed image.
  • Result On a held-out 1,400-image slice of SID-Set, across all 15 real repost transforms with bootstrap intervals: clean AUC 0.981, mean over 14 transforms 0.977, worst case (0.25x thumbnail) 0.968; on an unseen generator family (WildFake) 0.966 clean.
  • The finding worth reading The forensic branch is the entire cross-source generalisation — a CLIP-only probe scores 0.54 on thumbnails from an unseen generator, where chance is 0.50, and the branch lifts it to 0.79 — and it is also what collapses under noise (0.925 to 0.810 at sigma 0.10). Either half alone gives the wrong conclusion: the branch and a noise training view are worth -0.006 and +0.004 separately, and +0.014 together.
  • Showing it is not cheating Re-encoding both classes identically moves every head by at most +0.0009 AUC, and a bare blockiness scalar separates them at only 0.586 — so it is not reading JPEG history. Multi-crop TTA was implemented, measured at -0.0039 mean AUC over 15 conditions, and left off, reported as its own A/B.
  • Scope Built against the TikTok TechJam Track 5 brief and never submitted to Devpost — not a competition entry, no placement claimed. Trained on SID-Set only, so unknown commercial generators still shift the features; crop is the one scored family not yet a training view. About four days on a laptop with no GPU.
2026.09 Open source · Operations research

LP / MIP from scratch — the model matters more than the solver

Two-phase simplex + branch and bound + real Gomory cuts · cross-checked against HiGHS · 29 tests

Linear programmingInteger programmingSimplexCutting planes
  • The main result One problem — minimum fleet size for a fixed timetable — written two ways. The assignment formulation has a totally unimodular constraint matrix, so the LP relaxation is integral and branch and bound closes in a single node. The big-M formulation gives the identical answer but its bound collapses from 3.0 to 1.0 and it explores 21 to 31 nodes. An order of magnitude, decided at modelling time.
  • How big should big-M be A measurable decision, not a habit: tightening M from 10000 to each variable's own capacity moves the relaxation bound 1086.54 to 970.51 and the node count 19 to 5, with the optimum unchanged at 953.
  • The textbook warning is real On Beale's 1955 degenerate example, Dantzig pricing cycles and has not terminated after 203 iterations; Bland's rule converges in 9. The shipped default is Dantzig with an iteration cap that restarts under Bland, locked by a test. On the Klee-Minty cube, Dantzig takes exactly 2^n - 1 iterations (7 / 15 / 31 / 63 / 127 for n=3..7), to the step.
  • Two negative results carry it First, cuts are not free: three knapsacks go 17/27/35 nodes to 1, but n=12 is the counterexample — the bound does improve (163.44 to 160.33) and the tree still grows from 29 to 31. Second, cut validity is checked against the definition rather than by reading the code: enumerate all 5,376 integer points and assert none was cut off. An earlier fake cut failed exactly that test.
  • Scope Written on 2026-09-08; it corresponds to no past coursework or job. The largest instances are an 80x120 dense LP, 14 binaries and an 8-trip multi-depot problem, on a dense tableau simplex that does not scale; column generation is not implemented — I read about it, which is not the same as having done it. "Slower than HiGHS" is false on small instances and only reaches 32x at 80x120.
2026.09 Open source · Time-dependent routing

Campus shuttle routing — testing a claim that could not be falsified where it was made

23 nodes / 58 directed edges, time-dependent · four solvers cross-checked over 600 queries · 37 tests

Time-dependent shortest pathCross-validationTail latencyMap matching
  • Correctness does not rest on one solver A binary-heap Dijkstra, A*, a label-correcting reference and brute-force enumeration agree across 600 cross-checked queries; A* expands 42.48% fewer nodes and upper-bound pruning saves another 20.41%, staying optimal on 600/600. Brute force is the only independent oracle — the other two share an assumption and, on a constructed non-FIFO network, were wrong together by 38 minutes.
  • Isolate the variable before concluding "A binary heap brings this to O(|E| + |V| log |V|)" cannot be falsified on 23 nodes, where barely a dozen get expanded. So the heap was isolated on deterministically generated grid networks: its speedup grows from 1.56x at 100 nodes to 17.03x at 4,900, with A*'s saving rising from 20.0% to 38.3%. The claim has no support at the size it was made; it holds at ten thousand nodes.
  • "Under 50 ms" needs its method attached Same code: with connection reuse the p99 is 0.44 ms at concurrency 1 and 17.7 ms at 16; with a fresh TCP connection per request it becomes 515 ms — 29x worse, and all of it in connection setup, since solving itself has a p99 of 0.035 ms. The p50 lies: the fresh-connection row has the better p50 while its tail is already in seconds.
  • Fleet size is not continuous It is a ceiling function of cycle time over headway, so it drops in steps: a 26.81 min peak loop on a 4 min headway with a 3 min turnaround needs 8 vehicles, and removing one requires a 6.75% cut in cycle time — a 6% cut removes none. "Travel time down x%" and "n fewer vehicles" are separate claims.
  • Scope This is a September 2026 rebuild, not the original 2024 coursework. The original traces and code were never archived, so this repo deliberately does not reproduce the figures quoted from it. The network and the speed history are synthetic. What is rebuilt is the method and its checkability: when asked what the denominator of that 98.7% was, or how the 50 ms was measured, the answer is here.
2026 NUS · CE5203 group

AYE weaving: counts, simulation, ramp metering

Group 12 · public repo

AYE weaving simulation and ramp metering
YOLOv11SUMO
  • Situation: AYE westbound Exit 9→11 weaving jams at peak. Task: calibrate on counted traffic, then compare VSL, ramp metering, and both.
  • Action: 43 min peak and 60 min off-peak video at 4 stations; SUMO 7 nodes / 6 edges; 12 experiments. Weaving capacity ~5,060 veh/h.
  • Result: ramp metering cut peak network total time loss 22.7% and weaving delay 7.7% — more than speed limits alone.
2026 NUS · CE5212 course

Traffic coordination: approve / reject only

Course project · decision and grounding layers are open source

Three-layer LLM traffic coordination
LLMSUMO
  • Situation: letting the model rewrite the network produced state hallucination. Task: rules propose; the model only approves or rejects.
  • Action: SUMO net 1.4 km², calibrated on 2,874 measured speeds; 645 commuters (time-sensitive 35% / price-sensitive 40% / information-poor 25%).
  • Result: of 180 coordination ticks, 137 (76%) never reached the model; the 43 that did were all approved, none rejected — so the honest claim is “three quarters of the decisions do not need it”, not that the model caught anything. Direct invention hallucinated; sync calls slowed the sim — Bus 95 delay +2.2 min. Course lab, not a production KPI.

Coursework also includes SAP2000 frame analysis and ABAQUS seepage — part of my civil training, not the focus of this site.

Skills

Product

PRD / acceptance Axure VOC / personas Gates & eval

Agents

Tools compute / humans confirm Grok Build · Claude DeepSeek API Whitelisted SQL Metrics / table lineage

Site & supply chain

Material board / suppliers Outlook pull Customs coordination Rhino (basic)

Engineering background

SUMO / TraCI Python CEE5901 ML

Campus

🏛️

Class Youth League secretary

2024.09 – 2025.06

Ran class sessions and volunteering; helped peers with job resources. University “outstanding member” award. Other undergrad posts omitted.

Contact

📧
📞
📍
Location Singapore

The approach stays the same: tools compute, humans confirm, evals rerun.
Happy to talk about agents, evaluation and engineering workflows.
NUS · graduating Jan 2027 · based in Singapore