Skip to content

Brazil (GMT-3) · Remote-ready, any time zone · Open to relocation

Lucas Gonçalves

AI Engineer

AI Engineer | LLM Agents · RAG · AI Guardrails & Evaluation

3rd of 1,300+
A soil-reading app I built placed 3rd at the 16th FETEPS 2025, a state science fair; its paper was accepted and presented as a poster at the ICPA/ConBAP 2026 precision-agriculture conference.
+51.9%
Macro-F1 gain after a fine-tuning run that came out worse than its baseline, once error analysis traced the failure to the wrong starting model rather than the wrong settings.
370 tests
Line coverage of 90% across the measured modules of a FAPESP-funded question-answering agent that scores its own confidence in every answer.

Work

The records, and what each one cost to get right

Open any record below for the details. Each one carries the problem, what constrained it, the decision I made, what I rejected, the measured result with its methodology, and where it still falls short.

  1. SmartB100: A RAG Agent for Agronomy That Knows When to Doubt ItselfA research assistant for agronomy that scores how much to trust each answer, runs on self-hosted models, and works with no connection.370 testsLLM Agents & RAG · research

    Problem

    Field technicians and farmers need answers buried in dense technical manuals. A chatbot will sometimes invent one and state it as confidently as a correct one, which is the worst failure when someone is about to act on it in the field. This system answers only from a fixed set of trusted manuals, through retrieval-augmented generation, built inside a FAPESP-funded research project where I worked as a volunteer researcher.

    Constraints

    No budget for paid AI services, so retrieval and answering had to run on self-hosted models. It had to work without reliable internet, since that is where it is used. And every answer needed a trust signal a non-expert could read at a glance.

    Decision

    Rather than a right or wrong flag, I built a confidence detector on semantic entropy (Farquhar et al.): ask the model the same question several times, group the answers that mean the same thing, and turn the disagreement into one score from 0 to 1, with a similarity cache cutting that pass from quadratic to one embedding call per sample. Answers adapt to beginner or specialist readers, over FastAPI, Qdrant and Ollama. I then replaced the agent's three guessed safety limits with measured ones: a sweep over 120 labeled questions set the topic filter at 96.7 percent true positives against 3.3 percent false positives, and twelve instrumented runs set the step and token ceilings.

    Rejected

    A binary hallucination flag was quicker, but it tells the reader nothing about how unsure the system is, so a shaky answer looks identical to a solid one. A paid hosted model with its own guardrails broke both the self-hosting and the offline requirement, and would have tied a public research project to a recurring bill it cannot guarantee paying.

    Result

    The confidence layer is implemented and calibrated rather than running in production: it ships disabled by default. With it on, every answer carries a 0 to 1 score, and embedding, retrieval and answering all run on local open-weight models. Around it sit 370 automated tests at 90 percent line coverage of the measured modules, strict type checking and linting in the build, and fifteen written architecture decisions. The calibration evidence is committed as a fixture, so three tests fail the build if a safety default drifts.

    How it was measured

    The headline measures the test suite, not the answers. The 90 percent is line coverage of the modules listed for measurement; the CI gate itself sits at 23 percent, with the evaluation, UI and database packages outside the measured scope. No answer-quality score appears anywhere in this record, because the evaluation harness has never been run. What is measured against data is the calibration: 120 labeled questions, twelve instrumented runs.

    Known limits

    The confidence check generates several answers per question, so accuracy and speed pull against each other. It sits behind a clean boundary so it can be split off and scaled later, but heavy traffic would need a rethink. The scoring step still defaults to a hosted verifier, so a fully local run means switching that provider explicitly. The evaluation harness, five stages and 60 tests, has never been run end to end.

    Period

    2025-2026

    Stack

    • Python 3.12
    • FastAPI
    • Qdrant
    • Ollama
    • LangGraph
    • Docker
    • GitHub Actions
    • pytest / mypy --strict
  2. VisioSoil: Reading Soil Texture From a Photo, OfflineReads soil texture from a photo on the phone itself, tagged with its location, with no signal needed. Placed 3rd of more than 1,300 entries at a state science fair.3rd / 1,300+Computer Vision · research

    Problem

    Soil texture, the mix of sand, silt and clay, drives real decisions about irrigation and planting. Reading it normally means a lab sample or a specialist, and on a large farm with no signal neither happens, so most fields are never assessed. VisioSoil classifies soil texture from a single photo, on the phone.

    Constraints

    It had to work with no internet whatsoever, because that is exactly where it is needed. It had to run on an ordinary phone rather than a server. And the reading had to be trustworthy, since a soil measurement is only useful if you also know where it was taken and whether the photo was good enough to judge.

    Decision

    The v2.0.0 classifier uses 26 descriptors computed on the device, with image resampling byte-for-byte identical to Pillow so the Dart and Python implementations process the same input consistently. Classification runs offline on the phone, and readings are stored locally with their GPS location.

    Rejected

    A cloud service classifying on a server was simpler, but it fails the moment the signal drops, which is most of the time in the field. A storage abstraction in between means adding optional sync later does not mean rewriting the app. The photo-quality check could have lived only in the app, but the same rule governs which photos enter the dataset, so I wrote it in both languages and locked them to a shared reference file that fails both test suites if they ever disagree.

    Result

    The project placed 3rd out of more than 1,300 entries at the 16th FETEPS 2025, the Centro Paula Souza technology fair, and the paper was accepted and presented as a poster at the 17th ICPA and 11th ConBAP in Porto Alegre, July 2026. Version v2.0.0 ships the offline capture, classify and store workflow, backed by 992 Dart tests, 810 Python tests, an 8-job CI pipeline and 28 architecture decision records (ADRs).

    How it was measured

    Verification covers the current descriptor-based classifier with 992 Dart tests and 810 Python tests, including image resampling that is byte-for-byte identical to Pillow. An 8-job CI pipeline checks the implementation, and 28 ADRs document engineering decisions. These are engineering checks, while the competition placement and conference poster are external recognition; none is a measure of classifier accuracy.

    Known limits

    The app expects a different number of categories than the next model will produce, so wiring a trained model in and letting it read its own labels at startup is the main open thread. I also audited the delivered photo archive and found it was not shot on a fixed rig as assumed, with scale varying by a factor of 2.6 across images, which retired an earlier design decision outright.

    Period

    2025-2026

    Stack

    • Flutter
    • Dart
    • scikit-learn
    • Riverpod
    • Drift/SQLite
  3. When Fine-Tuning Made It Worse: Diagnosing a Failed Training RunA fine-tuning run that came out worse than its starting point, the error analysis that explained why, and the pivot that turned it into a 51.9% gain.+51.9% macro F1NLP & LLMs · personal

    Problem

    Most ready-made sentiment tools are trained on clean, formal writing and quietly fall apart on tweets, where slang, mentions, hashtags and emojis break the assumptions they were built on. I set out to fine-tune a language model for exactly that noisy text, and the first attempt failed in an interesting way.

    Constraints

    Any claim of improvement needed a measured starting point that was actually fair, not a number borrowed from someone else's published results. The cleaning had to be correct down to individual emojis, which are easy to corrupt when a program splits text the wrong way. And it had to be fast enough for a million tweets, not a sample.

    Decision

    I started from RoBERTa in a version already specialized for Twitter and fine-tuned it. It came out 2.72 percent worse than the baseline. Rather than tuning settings until the number moved, I ran a per-class error analysis and found the cause: the starting model had already been trained on this exact task, so training it again on the same data only overfit it. I wrote that up as a decision record weighing five alternatives, then switched to a task-agnostic starting model and a different classification task. Separately, I rebuilt the Python cleaning step, the bottleneck at volume, in Rust and proved output parity.

    Rejected

    The tempting move after a bad result is to keep adjusting the learning rate and batch size, but that treats a structural problem as a tuning problem and would have burned days. Comparing against the starting model's own published score was the other shortcut, and a score published by a model's authors is not a baseline you earned; the honest comparison is a classifier trained on the frozen model's features, which is what I used.

    Result

    After the pivot, the fine-tuned model reaches 0.887 macro F1 against a frozen-features baseline at 0.584 on the 2,000-row dair-ai/emotion test split, a 51.9 percent relative gain concentrated in the rarest categories. The effect of balancing those categories was reported as a controlled with-and-without ablation, not assumed. The Rust cleaning tool runs 4.1 times faster than the Python version at a million tweets, 2.832 seconds down to 0.694, with output parity checked at three sizes. The failed run is kept under a release tag rather than deleted.

    How it was measured

    Macro F1 weights every category equally regardless of frequency, which is why the gain concentrates in the rarest ones. One preprocessing contract is shared by the training tokenizer, the baseline, batch inference and the Rust tool, with byte-identical fixtures in both languages, so none of the four can drift apart unnoticed.

    Known limits

    The first attempt is the most useful part of this project, and I left it visible on purpose. I also retired the older speed figures once a change to the cleaning contract made them no longer apply, rather than leaving a flattering number the code no longer earned. The training outputs are not committed, so the reported scores rest on the recorded runs rather than on artifacts a reader can re-open.

    Period

    2025

    Stack

    • Python
    • Rust
    • HuggingFace Transformers
    • RoBERTa
    • Polars
    • Rayon
    • scikit-learn
    • PyTorch
  4. Weather Forecasting, and the Leak I Found in My Own ResultsA forecasting pipeline whose headline numbers I withdrew after finding the evaluation had been scoring itself, plus a scikit-learn model ported to the browser and proven equivalent to within 1e-6.1e-6Data Engineering & MLOps · personal

    Problem

    Frost warnings, irrigation timing and energy demand all hang on short-term temperature forecasts. I built a pipeline over more than 151,000 raw readings from 211 countries, aggregated into one global daily-mean series, and first reported an accuracy figure that turned out to be wrong. How I found out is the useful part of this record.

    Constraints

    The dashboard had to be a static site with no server behind it, yet a visitor still had to run the project's real anomaly model on their own inputs. Any accuracy claim had to survive someone checking it. And the data is one aggregated global daily-mean signal, which caps what can honestly be claimed from it.

    Decision

    I exported the fitted Isolation Forest from Python as a versioned artifact of flat arrays, then reimplemented its scoring in TypeScript over a serialized 200-tree, 23,528-node forest. The proof that the two agree is generated from the exact same fitted model the browser downloads, not a fresh retraining, so the test cannot pass by comparing two coincidentally similar models. On the forecasting side, I audited the evaluation and found two leaks: the held-out test set was serving as the early-stopping signal, so the model chose its own size against the data it would be graded on, and the ensemble weights came from that same window.

    Rejected

    ONNX was the obvious route for in-browser inference, and I rejected it because Isolation Forest conversion is not reliably supported and it ships a multi-megabyte runtime for a model I can serialize and walk directly. Calling the existing Python API fails the static-site constraint outright. On the evaluation, the tempting move after a leak is to quietly fix it and republish a slightly worse number as if nothing happened. I withdrew the affected figures explicitly instead.

    Result

    The three leak-inflated metrics were struck from the README and replaced with the word withdrawn, and the retraction is enforced in code: the dashboard export emits a pending status with empty numeric fields, and a CI gate fails the build if retracted copy reaches the rendered HTML. The leak-free rerun reaches 0.27°C RMSE against 0.73 for ARIMA on a 30-day holdout over 151K+ rows from 211 countries. The browser anomaly checker ships entirely client-side, matched within 1e-6 on standardization and scoring.

    How it was measured

    Two measurements sit in this record and should not be read as one. The 1e-6 is parity between two implementations of the same fitted model, an anomaly score rather than a temperature, and says nothing about forecast accuracy. The forecast numbers come from one leakage-free evaluation over more than 151,000 raw readings from 211 countries: the final 30 days are held out and scored once, and GradientBoosting reaches 0.27°C RMSE against 0.73 for ARIMA. The withdrawn figures came from a split that was also its own early-stopping signal.

    Known limits

    The series is one global daily mean, not a per-country forecast, so sub-degree error says less than it seems, and the 0.27°C figure comes from a single 30-day holdout whose variance nobody has quantified. The Prophet comparison was a separate run with different inputs, so it does not rank against the others. The open work is a multi-step recursive evaluation where every model forecasts the same way. The dashboard is deployed and runs the anomaly check client-side, so the parity claim is one a reader can exercise.

    Period

    2025

    Stack

    • Python
    • TypeScript
    • LightGBM
    • scikit-learn
    • statsmodels
    • SHAP
    • Next.js
    • FastAPI
    • Docker
  5. my-framework: Development Standards a Binary EnforcesA single Go binary that checks AI coding agents against written development standards, with seven deterministic gates that call no model.7 gatesAI Guardrails & Evaluation · personal

    Problem

    Written standards are easy. Standards an AI coding agent actually reads, follows, and is checked against are not.

    Decision

    I built mf, a single Go binary, plus versioned Markdown standards. The binary reads the standards, runs three review roles (internal, cross-provider and pull request), each a chain of backends chosen in configuration and bound to no vendor, and enforces everything enforceable without a model through seven deterministic gates: spec, commit, branch, docs, records, agents and design. The gates run in CI, in a pre-push hook and in a commit-msg hook, and all three fail closed: a gate that cannot find its runner says so and stops instead of exiting zero in silence.

    Result

    v0.8.0 is the current release, published as stamped binaries for five platforms (Linux, macOS and Windows) under one SHA256SUMS. On a fresh clone, mf check runs the seven gates against the repository itself. The suite covers 21 packages with tests that build real repositories on disk and run real git rather than mocking it, on GitHub Actions across Linux, macOS and Windows.

    How it was measured

    The gates judge artifacts, not processes, because only the first is reliable without a model. Reviewer provenance is recorded per branch, so the cross-provider claim resolves to verified, declared or unknown rather than being assumed.

    Known limits

    The project is still in development. mf init adopts the harness, not the forge: it does not write .github templates or workflows, and those are still copied by hand.

    Stack

    • Go 1.26
    • TOML
    • Markdown
    • GitHub Actions

Experience

Where the work happened

  1. Sep 2026 to PresentPompeia, BrazilWork

    Data & AI Assistant · Unipac (Grupo Jacto)

    Packaging and polymers manufacturer of Grupo Jacto. Built and hardened an internal multi-agent AI platform that generates software, currently in pre-production validation.

    • Built a deterministic security gate (Semgrep with 20 rules, plus Trivy) in a network-less sandbox with SHA-256 snapshots, covered by 154 tests; it blocked 21/21 severe findings across a 22-project pilot.
    • Re-architected the multi-agent platform into a deterministic 4-wave scheduler orchestrating up to 12 agent phases (LangGraph, LangChain, deepagents, FastAPI, GCP Cloud Run); 12 of 14 E2E runs were approved.
    • Engineered auto-remediation that resolved 14 of 21 gate failures across 13 runs with no human input.
    • Mitigated runaway agent behavior with a 9-layer guardrail stack, after a single response issued 2,179 identical tool calls.
    • Instrumented per-run cost metering across 13 E2E runs (US$1.01 to 6.96, median US$2.63, median 17 min), cutting idea-validation cost from ~R$200K/~6 months to ~R$3K/<2 weeks (~66x).
    • Contributed to data quality and standardization on a ~3.8 TB / ~25B-row BigQuery medallion lakehouse (288 bronze tables, 31 gold tables with ~30M rows), documenting metadata for 15+ previously undocumented tables so downstream AI agents get richer context.
  2. Jun 2026 to Aug 2026Miami, United States (remote)Work

    AI Engineer · PM Accelerator

    U.S. AI product accelerator. Selected for Cohort 9 of its AI Engineer Internship Program, building an AI college-admissions advisor in an 8-contributor international team.

    • Led the launch of the advisor as the backend AI engineer, owning the advisor's answer pipeline end to end: retrieval, prompt assembly, token-budgeted memory, two-tier model routing, a 90s turn ceiling and persistence (Python, FastAPI, PostgreSQL).
    • Designed hybrid retrieval that ranks exact name/alias matches ahead of pgvector HNSW similarity over ~1,800 U.S. institutions, returning an explicit "not enough data" signal instead of a nearest-neighbor guess.
    • Enforced factual grounding in code with a refuse-before-call gate (no model call or quota spent on unanswerable questions) and a post-generation verifier that flags unsupported rates, costs and GPAs.
    • Secured per-student data isolation with explicit owner predicates on every query and a CLI harness that exits non-zero on any cross-student leak.
    • Cut CI install footprint from ~800MB to ~90MB by moving embeddings from torch to fastembed/ONNX.
    • Expanded the backend test suite to 561 passing tests (from 539) in the final contract week, closing grounding and ordering edge cases.
  3. Nov 2024 to Jun 2026Pompeia, BrazilWork

    After-Sales – Data & Automation · Jacto

    Global agricultural machinery manufacturer with 5,000+ employees and presence in 100+ countries.

    • Co-led the fix of wrong-part returns: ~20% (2025) → <5% (2026) → 0% in 06/2026, against a 6% Six Sigma target, with the manual approved across 150+ dealers; avoided ~R$100 to 135K in freight in 1H/2026.
    • Automated data collection across 99 regional pages (Python, Selenium, pandas, RU→EN translation, Salesforce-ready output), saving up to 5 h/day (~25 to 100 h per collection).
    • Audited a 13,000+ part flow (~R$6.5M/semester); the resulting manual corrected >50% of discrepancies.
    • Reduced pending returns to ~R$120 to 250K/month (2025) and ~R$540K (1H/2026), down from millions before.
    • Synchronized 4 systems (physical count, SAP, Salesforce, platform), cutting load time from 5 to 10 min to <1 min across 20+ validated improvements.
    • Interpreted English-Portuguese at up to 3 international live events.
  4. Feb 2024 to Oct 2024Pompeia, BrazilWork

    Software Engineer – Synapse Program · CIAg (Grupo Jacto)

    Agro-innovation center of Grupo Jacto; Synapse is its applied-AI program for faculty and students.

    • Led a 2 to 3 developer team building an LLM assistant with contextual RAG for faculty and students (Python, FastAPI, OpenAI API).
    • Built the REST layer between the app and the model.
  5. 2024 to Nov 2026Pompeia, BrazilEducation

    Technology degree (CST) in Big Data for Agribusiness · Fatec Shunji Nishimura, Pompeia, São Paulo

    A public applied-technology degree. Coursework covers machine learning, artificial intelligence, data structures, databases (SQL and NoSQL), APIs and microservices, cloud architecture, and statistics.

    • Co-authored a paper accepted and presented as a poster at the 17th International Conference on Precision Agriculture and the 11th ConBAP, Porto Alegre, July 2026 (abstract #14064).
    • Volunteer researcher on a FAPESP-funded research project (grant 2024/00985-1), the state research foundation of São Paulo.
    • Placed 3rd out of more than 1,300 entries at the 16th FETEPS 2025, a large state science and technology fair.
    • Languages: Portuguese (native) · English (professional working proficiency).

About

Background

I came to AI through agriculture. In 2024, at CIAg, the Jacto Group's agro-innovation center, I led a small team building an LLM assistant that answered faculty and students from agronomic documents. It worked well enough to be convincing, and that bothered me: when it was wrong, it sounded exactly as sure as when it was right.

I learned what that kind of mistake costs when I moved to after-sales at Jacto. For about twenty months I worked on wrong-part returns, where every wrong answer came back as a returned part and a freight bill. I wrote the returns manual the dealer network adopted, and together with the team we brought the rate down to zero by mid-2026.

When I went back to building with models, that experience decided where I spent my time. At PM Accelerator, I made an AI advisor refuse a question before calling the model whenever it had no data to answer it. As a volunteer researcher on a FAPESP-funded project, from March to June 2026, I calibrated the domain gate of a soil-fertility RAG agent from 120 labeled questions. Today at Unipac I work on an internal platform where AI agents generate whole applications, and I wrote the security gate each one has to pass before a developer approves it.

That gate is also where my curiosity widened. After an agent fired 2,179 identical tool calls in a single response, I added layers of guardrails and started reading about AI security engineering as a field of its own, which led me to a cybersecurity course this year. AR and digital twins pull me the other way, back to machines and fields. I want to know what checking an answer looks like when the model reasons about a physical system. I haven't built anything there yet.

That's the work I want to keep doing: building AI systems people can actually rely on.

Lucas Gonçalves, AI Engineer
Based in
Brazil (GMT-3) · remote-ready, any time zone · open to relocation
Education
Technology degree (CST) in Big Data for Agribusiness, Fatec Shunji Nishimura (expected Nov 2026)
Focus
LLM agents · RAG · AI guardrails & evaluation
Languages
Portuguese (native) · English (professional working proficiency)
Email
lucassg2015@gmail.com

Stack

Languages
  • Python
  • SQL
  • TypeScript
  • Rust
LLM, RAG & agents
  • RAG
  • LangGraph
  • Agent orchestration
  • LLM-as-judge evaluation
  • Semantic entropy
  • Anthropic API
  • OpenAI API
ML
  • PyTorch
  • HuggingFace Transformers
  • scikit-learn
  • Fine-tuning
Backend & data
  • FastAPI
  • PostgreSQL
  • pgvector
  • Qdrant
Cloud & practices
  • Docker
  • Google Cloud (Cloud Run, BigQuery, Dataflow)
  • GitHub Actions
  • pytest
  • Test-driven development

Contact

Get in touch

I read everything that arrives here. If you are hiring for an AI or ML engineering role, tell me what the team is working on and what would make the first ninety days a success.

Elsewhere

Your message goes straight to my inbox. No newsletter, no tracking.

Open to remote and international roles, and to a short call about either.