Also recently released is pydantic-ai, which is also based around pydantic / structured outputs, though works at level of "agents". https://github.com/pydantic/pydantic-ai
LLMs are hard to tame at scale, the focus is on tightly controlling the LLM inputs, making sure it has the information it needs to be accurate, and having detailed observability over outputs and costs. For that last part this new wave of AI observability tools can help (Helicone, Langsmith, W&B Weave...).
Frameworks like LangChain obscure the exact inputs and outputs and when the LLM is called. Fancy agentic patterns and one-size-fits-all RAG are expensive and their effectiveness in general is dubious. It's important to tightly engineer the prompt for every individual use-case and to think of it as a low-level input-output call, just like coding a good function, rather than a magical abstract intelligent being. In practice, I prefer to keep the control and simplicity of vanilla Python so I can focus on the actually difficult part of prompting the LLM well.
The reason why I keep procrastinating it is that, again, experience has shown me that LLMs are not really at a point where you can afford to abstract away the prompting. At least in the work I have been doing (large-scale unstructured data extraction and analysis), direct control over the actual input string is quite critical to getting good results. I also need fine-grained control over costs.
The DSPy pitch of automagically optimizing a pipeline of prompts sounds costly and hard to troubleshoot and iteratively improve by hand when it inevitably doesn't work as well as you need it to out-of-the-box, which is a constant with AI.
But don't get me wrong, I know I sound quite skeptical, but I intend to keep giving all these advancements a serious try, I'm sure one will actually be a big upgrade eventually.
I think we are at a stage where people are so eager to build something around LLMs to become the next shovel-maker, that a lot of what is being built doesn’t actually serve anyone’s needs.
LangChain never solved a real problem to begin with, so there's nothing that needs to be replaced.
Just write your own Python code that does the same thing that LangChain needs 10 layers of abstraction to do.