# Architecting and Testing Controllable Agents

Lance Martin, LangChain | AI Engineer World's Fair 2024 | 2:21:54

Source: https://www.youtube.com/watch?v=ib-wTAvCZqg
Channel: AI Engineer (https://www.youtube.com/@aiDotEngineer). Summarised by AIE Talks.
Page: https://aietalks.com/talks/architecting-and-testing-controllable-agents
Published: 2024-10-11
Tags: evals, reliability, tool-use, workflows

## TL;DR
- An agent lets an LLM choose application control flow, which makes it flexible but can lead to repeated tools, incorrect arguments, and unreliable behavior.
- LangGraph constrains an agent's control flow with graphs, state, nodes, and edges, allowing developers to keep fixed steps while adding LLM-based routing or self-correction.
- Reliable agent development needs feedback at runtime, before production with evaluation sets, and in production through monitoring and failure collection.

## Summary
Lance Martin explains how to build agents that retain some flexibility without giving an LLM unrestricted control over every step. He contrasts fixed chains with open-ended ReAct agents, then presents LangGraph as a way to encode application flow as a graph with state, nodes, and edges. This structure supports corrective RAG, hallucination checks, code-generation retries, routing, and other self-correcting flows. Martin then shows how LangSmith can evaluate both final answers and tool-call trajectories. He recommends separate feedback loops for in-app error handling, pre-production tests, and production monitoring. The talk also covers practical evaluation without reference answers, synthetic question-answer sets, unit tests inside an application, long-context retrieval, tool selection, multi-turn state, and retrieval quality. His examples favor small, explicit checks and constrained flows when production reliability matters.

## Key ideas
### An agent is an LLM-controlled application flow
[02:28](https://www.youtube.com/watch?v=ib-wTAvCZqg&t=148s)
Martin defines a chain as control flow set by the developer. Retrieval-augmented generation is a typical chain: a vector store retrieves documents, an LLM receives them, and the application returns an answer. An agent changes this arrangement by putting an LLM inside the flow. The LLM examines the output of one step and decides whether to proceed, return to an earlier step, or choose another path. Function calling does not let an LLM magically execute code. The model produces a function name and structured arguments, and application code uses that output to call the tool. In a ReAct loop, the model chooses an action, observes the tool response, and repeats until it produces a normal text response instead of another tool call.

### Open-ended ReAct agents trade reliability for flexibility
[17:55](https://www.youtube.com/watch?v=ib-wTAvCZqg&t=1075s)
ReAct agents can choose many sequences of tool calls, such as running one tool, several tools, or returning to an earlier tool. That flexibility helps with open-ended tasks, but Martin says these agents can get stuck calling the same tool. LLM non-determinism contributes to the problem, as do errors in choosing a tool or producing its arguments. The problem becomes worse with longer dialogues and larger tool lists. He gives examples where the application exposes step two but the model selects step three, or where the expected input is three and the model supplies four. A fixed chain avoids these failures because it always runs its steps in order, though it cannot adapt its flow.

### LangGraph constrains only the parts of the flow that need flexibility
[27:38](https://www.youtube.com/watch?v=ib-wTAvCZqg&t=1658s)
Martin presents LangGraph as a graph-based way to express application control flow. Nodes perform operations and modify shared state. Edges decide which node runs next, with an LLM able to make decisions at selected points. State acts as short-term memory over the graph's lifetime. This lets a developer keep some steps fixed while adding routing or branching where it is useful. Martin describes this as a middle ground between a rigid chain and a fully open-ended ReAct agent. The resulting flow is less flexible than ReAct, but the constraints make it much more reliable. He says this pattern is sufficient for many production applications, where predictable behavior matters more than arbitrary tool sequences.

### Self-correction works when it is built into a bounded graph
[09:05](https://www.youtube.com/watch?v=ib-wTAvCZqg&t=545s)
Martin uses corrective RAG to show how a graph can inspect and repair its own intermediate results. The application retrieves documents, grades their relevance, and sends the question to web search when the retrieved material is insufficient. It then generates an answer, checks for hallucinations against the documents, and checks whether the answer addresses the question. A similar pattern appears in code generation through the AlphaCodium work: generate code, run unit tests, send failures back to the LLM, and try again. Martin describes a simple import check in an internal RAG application. The system extracts imports from generated code, tests whether they exist, and asks the model to correct invalid imports. He says this small check significantly improved performance.

### Evaluation should inspect both the answer and the tool trajectory
[16:19](https://www.youtube.com/watch?v=ib-wTAvCZqg&t=979s)
Martin divides agent evaluation into application outcomes and internal behavior. For end-to-end evaluation, a dataset can contain questions and reference answers, and an evaluator can compare the agent's response with the reference. An LLM can act as a judge, though the prompt needs care, or developers can write custom evaluators. Martin also evaluates the sequence of tools used. An agent can produce the right answer through an inefficient or strange trajectory, which an answer-only score would miss. In his example, a local eight-billion-parameter model reached 60% answer performance while maintaining a strong tool trajectory. A 70-billion-parameter model reached 80% answer performance and 100% on tool calling with LangGraph. The answer score depended more on model capacity, while the constrained reasoning flow stayed consistent.

### Trajectory tests need different rules for short and open-ended agents
[26:32](https://www.youtube.com/watch?v=ib-wTAvCZqg&t=1592s)
Martin says exact trajectory evaluation becomes difficult for long-running tasks that can be solved in many valid ways. For shorter agents, where a run might take around five to ten steps, developers can enumerate reasonable trajectories and compare actual tool calls with them. For more open-ended systems, he recommends checking for repeated tool calls, excessive tool use, and other clearly abnormal behavior. In LangGraph, each node can append its name to state, creating a record of the path through the graph. For a ReAct agent, the evaluator can inspect message history and extract tool calls. These evaluators are ordinary functions, so teams can define checks that match their application rather than relying on one universal trajectory metric.

### Production evaluation can grow from failures observed in use
[24:24](https://www.youtube.com/watch?v=ib-wTAvCZqg&t=1464s)
Martin describes three feedback loops. Runtime checks catch errors inside the application, such as irrelevant retrievals, hallucinations, invalid imports, and malformed structured output. Pre-production evaluation runs the application against a test set and measures answer quality and tool use. Production monitoring applies evaluators to live inputs and outputs, tags poor cases, and sends them back for review. The reviewed failures can become corrected question-answer examples in the offline test set. Martin recommends starting with a small evaluation set, using synthetic question-answer generation to bootstrap coverage when appropriate, and expanding the set with real failures. He compares this process with the data loop used in self-driving systems, where failures are collected, curated, and added back into testing or training.

### Retrieval quality often matters more than generation quality in RAG
[1:57:25](https://www.youtube.com/watch?v=ib-wTAvCZqg&t=7045s)
Martin says retrieval remains a difficult, domain-specific part of RAG. A system may return documents that are semantically related but less useful than a canonical guide or a carefully maintained overview. He suggests combining question routing with document importance or quality scores. For LangChain documentation, general questions might favor tutorials and conceptual guides, while integration-specific questions should favor the relevant integration page. He also recommends thinking about document precision and recall. Recall asks whether the needed answer appears anywhere in the retrieved material. Precision asks how much retrieved material is unrelated. Martin favors higher recall when larger context windows and cheaper tokens make extra context acceptable, though he warns that very large contexts can suffer from poor recall and recency bias.

### Explicit routing and state can handle multi-turn retrieval
[59:53](https://www.youtube.com/watch?v=ib-wTAvCZqg&t=3593s)
Martin prefers an explicit router node at the start of a LangGraph flow when the application must choose between sources such as a vector store and web search. The router always runs first and sends the question to a defined destination, avoiding the noisier choice among many tools inside a ReAct agent. The router can receive graph state, including message history and documents already retrieved, so it can decide whether a follow-up question needs new retrieval. For a deeper follow-up about a chapter, rewriting the question may still return the same chunks. Martin suggests increasing the retrieval count or using metadata filters to retrieve the whole relevant section. He describes state as a dictionary containing fields such as the question, generated answer, documents, search flag, and step list.

## Notable quotes
- "An agent is just one of the control flows set by an LLM." (02:27)
- "What they can do is produce the payload or arguments needed to run that function." (03:45)
- "LangGraph kind of sits in the middle where you can actually implement these user-defined LLM-gated control flows." (13:01)
- "The tool calling or reasoning is consistent whether you're using a local model or 70 billion parameter model with LangGraph." (20:44)
- "I think retrieval is very hard, in particular, looking at the LangChain docs in particular, the overlay of document importance on top of raw semantic similarity search." (2:06:26)

## Tools & references mentioned
- LangGraph
- LangSmith
- LangChain
- ReAct
- Corrective RAG
- Self-RAG
- Adaptive RAG
- AlphaCodium
- Llama 3
- Llama 3 8B
- Fireworks Function V2
- GPT-4o
- Claude
- Ollama
- Instructor
- Pydantic
- Grok
- RAFT
- STORM
- Devon
- OpenDevin
- Chat LangChain
- Google context caching
- Greg Kamradt
- Andrej Karpathy

## Who should watch
- You are deciding whether an open-ended tool-calling agent is reliable enough for a production application.
- You are building RAG or code-generation workflows that need retrieval checks, retries, routing, or answer validation.
- You need a practical way to evaluate both what an agent answers and the path it took to get there.

## Related talks

- [12-Factor Agents: Patterns of Reliable LLM Applications](https://aietalks.com/talks/12-factor-agents-patterns-of-reliable-llm-applications) (Dex Horthy, HumanLayer, 17:06)
- [Building Enterprise LLM Agents That Work](https://aietalks.com/talks/building-enterprise-llm-agents-that-work) (Shaan Desai, Cohere, 18:29)
- [Building Multi-agent Systems with Finite State Machines](https://aietalks.com/talks/building-multi-agent-systems-with-finite-state-machines) (Adam Terlson, 17:11)
- [Ship Real Agents: Hands-On Evals for Agentic Applications](https://aietalks.com/talks/ship-real-agents-hands-on-evals-for-agentic-applications) (Laurie Voss, Arize AI, 2:04:18)
- [Don't Let the LLM Drive](https://aietalks.com/talks/dont-let-the-llm-drive) (Ornella Bahidika, Microsoft & Joel Allou, 06:08)
