惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
P
Palo Alto Networks Blog
月光博客
月光博客
H
Hackread – Cybersecurity News, Data Breaches, AI and More
I
InfoQ
aimingoo的专栏
aimingoo的专栏
腾讯CDC
T
Threatpost
D
DataBreaches.Net
Vercel News
Vercel News
F
Fortinet All Blogs
Engineering at Meta
Engineering at Meta
C
Cybersecurity and Infrastructure Security Agency CISA
Forbes - Security
Forbes - Security
U
Unit 42
C
Check Point Blog
Blog — PlanetScale
Blog — PlanetScale
O
OpenAI News
量子位
TaoSecurity Blog
TaoSecurity Blog
Microsoft Azure Blog
Microsoft Azure Blog
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
V
Visual Studio Blog
Recorded Future
Recorded Future
云风的 BLOG
云风的 BLOG
Security Archives - TechRepublic
Security Archives - TechRepublic
The Last Watchdog
The Last Watchdog
S
Security Affairs
Attack and Defense Labs
Attack and Defense Labs
罗磊的独立博客
Stack Overflow Blog
Stack Overflow Blog
Microsoft Security Blog
Microsoft Security Blog
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
V
V2EX
小众软件
小众软件
S
SegmentFault 最新的问题
www.infosecurity-magazine.com
www.infosecurity-magazine.com
W
WeLiveSecurity
AI
AI
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
博客园 - 聂微东
I
Intezer
Know Your Adversary
Know Your Adversary
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
P
Proofpoint News Feed
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
The Cloudflare Blog
博客园_首页
NISL@THU
NISL@THU
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

Pierce Freeman

A browser for agents | Pierce Freeman The grey market of podcast appearances The way I travel | Pierce Freeman Fixing slow AWS uploads | Pierce Freeman Local tools should still use vaults We solved scratch content first Starting a podcast in 2025 Being late but still being early Automating our home video imports Adding my parents to tailscale A deep dive on agent sandboxes Language servers for AI | Pierce Freeman My simple home podcast studio We need centralized infrastructure | Pierce Freeman My unified theory of social selling My personal backup strategy | Pierce Freeman July updates to the homelab How the KV Cache works httpx is the right way to do web requests in Python Reputation is becoming everything | Pierce Freeman Building a (kind of) invisible mac app Updated knowledge in language models Making an ascii animation | Pierce Freeman How speculative decoding works | Pierce Freeman Under the hood of Claude Code Doing things because they're easy, not hard Speeding up sideeffects with JIT in mountaineer Firehot for hot reloading in Python Misadventures in Python hot reloading How text diffusion works | Pierce Freeman The tenacity of modern LLMs The ergonomics of rails | Pierce Freeman How language servers work | Pierce Freeman Just add eggs | Pierce Freeman Unfortunately SEO still matters | Pierce Freeman The futility of human-only web requirements Setting up Input Leap | Pierce Freeman Checking in on Waymo | Pierce Freeman The react revolution | Pierce Freeman Speeding up many small transfers to a unifi nas Quick notes on swift libraries AI engineering is a different animal San Francisco | Pierce Freeman Debugging a mountaineer rendering segfault Local network config on macOS Building our home network | Pierce Freeman Introducing Envelope.dev | Pierce Freeman Legacy code and AI copilots Typehinting from day-zero | Pierce Freeman Generating database migrations with acyclic graphs Lofoten | Pierce Freeman Mountaineer v0.1: Webapps in Python and React Constraining LLM Outputs | Pierce Freeman Passthrough above all | Pierce Freeman Accuracy in kudos | Pierce Freeman How quick we are to adapt The curious case of LM repetition Costa Rica | Pierce Freeman Debugging chrome extensions with system-level logging Speeding up runpod | Pierce Freeman Inline footnotes with html templates Parsing Common Crawl in a day for $60 An era of rich CLI All or nothing with remote work The Next 10 Years | Pierce Freeman Adding wheels to flash-attention | Pierce Freeman LLMs as interdisciplinary agents | Pierce Freeman New Zealand | Pierce Freeman Representations in autoregressive models | Pierce Freeman Let's talk about Siri | Pierce Freeman Minimum viable public infrastructure | Pierce Freeman Reasoning vs. Memorization in LLMs Automatically migrate enums in alembic Greater sequence lengths will set us free On learning to ski | Pierce Freeman Dolomites | Pierce Freeman Using grpc with node and typescript Opportunity years | Pierce Freeman Buzzword peaks and valleys | Pierce Freeman Buenos Aires | Pierce Freeman Network routing interaction on MacOS Independent work: November recap | Pierce Freeman Debugging slow pytorch training performance The provenance of copy and paste Debugging tips for neural network training Patagonia | Pierce Freeman Santiago | Pierce Freeman My 2022 digital travel kit AWS vs GCP - GPU Availability V2 Independent work: October recap | Pierce Freeman Planning Patagonia | Pierce Freeman Relationship modeling | Pierce Freeman The power of status updates A new chapter | Pierce Freeman Give my library a coffee shop AWS vs GCP - GPU Availability V1 Switzerland | Pierce Freeman Headfull browsers beat headless | Pierce Freeman Webcrawling tradeoffs | Pierce Freeman Copenhagen | Pierce Freeman
Coercing agents to follow conventions using AST validation
2025-08-11 · via Pierce Freeman

Coding agents are getting really good. You're hard pressed to find a professional engineer these days that doesn't use Cursor or Claude Code for at least some part of their workflow.

LLMs are structurally advantaged to write code: there's a huge training dataset online and code is immediately validatable. Few other domains have a reinforcement learning environment where you can do as clean of a loop as that. Try compiling legal docs and getting a binary outcome.

My pipeline for making agents work as reliably as possible is:

  1. Scope out some clear functionality of the feature and the testing scope1
  2. Implement the initial feature
  3. Add associated tests for the new feature
  4. Request the model iterates until the new tests are all passing
  5. Request that the model iterates until all old tests are still passing and lints pass

This loop ends up taking the majority of time in steps 4-5. We can one-shot the first draft but then refining it over time requires a lot of trial and error. The reason why models can be tenacious now on coding tasks is because they can accept more context/knowledge from the environment and make adjustments. Simply asking the model to fix itself isn't injecting any more knowledge into the system and won't lead to much improvements. The more context you can feed forward into the model the better that the results will get.

Bad LLM Code

Usually the code that comes out of this iteration isn't wrong (ie. it technically compiles and passes tests) but it's messy. Or simply against my own coding conventions. Here are some things that I've seen2:

  • When in a long running loop to try and fix some tests, models will sometimes wrap test logic in a try/except in order to get it to pass
  • Models will use patch() to monkeypatch by default over testing the underlying end to end logic
  • They'll use bare assert statements over more detailed ValueError exception subclasses
  • time.sleep() in tests to stopgap investigating race conditions, or just littered excessively
  • Using List[] and Optional[] on Python 3.12 instead of the modern list[] and A | None.

All these happen regardless of how strongly I try to coerce the system prompt. We've managed to successfully make models pretty tenacious in problem solving, but that doesn't help much if they're able to cheat on the given problems while convincing themselves3 that they succeeded.

Determystic

Static analysis is a pretty good antidote to this behavior. At its simplest that feedback loop are just tests (pytest) and some linter (ruff). I put these checks by default in a Makefile and then instruct my system prompt to run every time.

I'm very bullish about the long term opportunity of static analysis to improve agents. But that goes beyond flagging things that are technically incorrect. We need to move into flagging things that aren't quite the behavior that we want.

What we ideally want is to specify our own rules. And it makes sense to specify these rules in code and not LLMs - since we need some determinism in these lints to return the same results after every pass. Thankfully LLMs are able to generate AST parsing code pretty accurately.

Could we just use LLMs to create deterministic guardrails for themselves? Determystic is a proof of concept to answer that question.

Let's say we want to ensure that our models always use modern Python typehinting and don't use Optional types. Let's say your LLM generated some code that we don't like:

from typing import Optional
from pydantic import BaseModel


class MyModel(BaseModel):
    name: Optional[str] = None
    age: int


def main():
    model = MyModel(name="John", age=30)
    print(model)

if __name__ == "__main__":
    main()

We can describe this explicitly by referencing bad code that the agent just wrote.4

uvx determystic new-validator

1. Enter the bad Python code that your Agent generated: var: Optional[int] = None

2. Describe the issues Don't use Optional - use A | None

3. Name your validator Modern typehinting

After this you can run uvx determystic validate and get a full validation of your project based on your new rule:

Custom Validator main.py:6: Use 'T | None' instead of 'Optional[T]' for type hints
     4 |
     5 | class MyModel(BaseModel):
>>>  6 |     name: Optional[str] = None
     7 |     age: int
     8 |

How it works

Determystic creates validators for your coding conventions, using the AST of your programming language. Running the new-validator CLI will kick off a Claude job to draft an AST validator. The validator will look for this Optional[] pattern and flag an error when it finds one.

To make sure that our AST parser does what we intend it to do, we also have the internal determystic Agent write a series of test cases that will test good and bad behavior. We will iterate on this until our parser passes so we know we'll get better code that you don't have to internally check yourself. All this is stored in a local .determystic hidden folder in your current project that you can introspect.

If this approach catches on, you can also share these validators across projects or across team members. In a pipeline like this I think the shareability of the validators is mission critical.

To make determystic a bit more convenient for all my projects, I also bundled in some default validators that I install on every project these days. ruff for code formatting and ty for type checking. ty is still an an early beta but moving quickly. I imagine once it's released as a stable beta a lot of people are going to move over from pyright and mypy5.

The future

As LLMs get better and we put more compute behind RL environments, I think a lot of this will be solved at the model layer. But even then the system prompt makes us rely on natural language to describe what is otherwise a more precise problem.

In the future we might not even look at our code. In these situations it doesn't really matter what your code looks like. But for as long as we need humans interacting with the code that we write - and therefore have opinions about coding style and library utilization - it's still very helpful. I've found it can also result in better code by enforcing some ways of implementing library subclasses that I know will lead to a more efficient end draft.

I'm still in the very early days on this approach. But I'd love some feedback about ergonomics and the unusual coding conventions I'm sure people are going to throw at it. Raise an issue if you have examples of things that aren't working and I'll try to get them fixed.

  1. There are more guides than I can read on how exactly to do this, so I won't spend much time on that here. ↩

  2. These are based on pretty extensive use of Claude lately but similar other things crop up when I'm using the GPT family of models. ↩

  3. And, sometimes, us. ↩

  4. uvx is just a runner here to execute the determystic package from pypi. ↩

  5. These are more comprehensive typechecking solutions but can be meaningfully slower for large projects. ↩