Agent engineering: from ReAct to autonomous systems

English · 中文

Position: The third layer of the four-layer progression of LLM application engineering (between context engineering and harness engineering) Research date: 2026-05-01


Executive Summary

An agent is not a fancier LLM call. It is the quartet “LLM + tools + memory + loop” — given a goal, it plans on its own, takes action, observes the result, and adjusts its strategy until the task is done or it is explicitly stopped. From an engineering standpoint, an agent is the unit of abstraction that cuts vertically through the prompt, context, and harness layers: its thinking is given templates by prompt engineering (ReAct and others), its field of view is supplied by context engineering (RAG, memory, tool schemas), and its runtime is built by harness engineering (sandbox, gateway, guardrails, observability).

In 2026, agents have split into three clear tracks:

Mainstream frameworks have converged from a wide proliferation to a few that dominate: LangGraph (the production default) / CrewAI (the fastest to pick up) / OpenAI Agents SDK (tied to the OpenAI ecosystem) / Smolagents (minimal) / Mastra (TypeScript-native). Microsoft has moved AutoGen into maintenance, and Microsoft Agent Framework has taken over.

On the latest rankings as of April 2026 for the mainstream benchmarks (SWE-bench Verified / GAIA / WebArena / OSWorld), Anthropic models nearly monopolize the top. Claude Opus 4.7 is reported to land in the ~87% range on SWE-bench Verified (for the exact score and the live board, see Anthropic’s official release page and the swebench.com leaderboard, as of this survey’s date 2026-05-01; scores change with version and with evaluation criteria). Berkeley RDI also warns: a set of mainstream agent benchmarks (including SWE-bench / WebArena / GAIA / Terminal-Bench and others) have been shown to be hackable to near-perfect scores without the task actually being completed — a score has to be read against the specific evaluation methodology.

Failure modes and real incidents are what most deserve caution: 90% of production agents die in a Loop of Death (an infinite loop); a single Claude Code sub-agent burned 27 M tokens and ran for 4.6 hours; Amazon Kiro AI autonomously deleted a production AWS environment and caused a 13-hour outage; Replit AI deleted a production database during a code freeze; Google AI wiped an entire disk while clearing a cache. There is one lesson: without a max iteration cap, without an execution timeout, without a sandbox, and without a deny-first permission model, an agent in production is a bomb.


1. Definition of an agent, and its coordinates

1.1 What it is not

To understand what an agent is, first rule out three common confusions:

Anthropic’s engineering blog gives a widely cited definition: “An agent is the pattern of an LLM using tools in a loop” — “loop” and “autonomy” are the two core features.

1.2 The engineering minimum

A minimal agent has to have four things:

Element Meaning If missing, it becomes
Goal A goal No goal = chatbot
Tools Callable capabilities (API / tool / compute / retrieval) No tools = pure generation
Loop A think-act-observe loop No loop = a single call
Memory State kept across iterations of the loop No memory = an amnesiac agent

1.3 The autonomy spectrum

An agent’s “degree of autonomy” is a continuous spectrum, not a binary variable:

Human-in-the-Loop          Human-on-the-Loop          Fully Autonomous
─────────────────          ─────────────────          ─────────────────
每步行动都需用户确认       人在旁监督,关键步骤介入   完成才汇报
适合:高风险/医疗/金融     适合:中等风险/编码         适合:低风险/数据处理
e.g. 早期 Claude Code      e.g. Cursor agent mode     e.g. Devin / Manus

The 2026 industry consensus is this: the industry is not moving toward fully unsupervised autonomy; it is moving toward selective autonomy. Different actions inside one product should have different autonomy levels — reading a file can be fully autonomous; deleting a file must be HITL.


2. How agent paradigms evolved

Year Paradigm Paper / source Core
2022 ReAct Yao et al. The minimal loop that interleaves Thought → Action → Observation
2023 Plan-and-Execute LangChain Plan the whole thing first, then execute, avoiding ReAct’s short-sightedness
2023 Reflexion Shinn et al. After a failure, write a “reflection note” and attach it to the next prompt, so the agent learns from experience
2023 Tree-of-Thoughts as agent Yao et al. Extend ToT reasoning into search at the agent level
2024 Constitutional Agent Anthropic Constrain agent behavior with a constitution / principles
2024 Multi-Agent System AutoGen / CrewAI Role division and negotiation among multiple agents
2024-Q4 Computer Use Agent Anthropic The agent operates a GUI directly (screenshot + mouse-and-keyboard tool)
2025 Agentic RAG LangGraph Delegate the RAG decision to the agent, which decides on its own when to retrieve and whether to retrieve again
2026-Q2 Background Computer Use OpenAI Codex (2026-04) The agent runs in its own desktop session, with multiple agents in parallel, without disturbing the main workflow

ReAct is still the “base grammar” of almost every modern agent. The other paradigms add planning, reflection, search, multiple agents, and cross-modality on top of ReAct.


3. Agent architecture: a common 4-layer split

There is no shared industry consensus on a “standard N-layer model of agent architecture” — Lindy, Redis, arXiv, and others each split it differently (some use 5 layers of perception-cognition-action, some a single ReAct loop, and so on). The 4 layers below are the author’s simplified checklist, synthesized from several of those splits. They are not a canonical taxonomy. They are only a way to inventory the engineering components:

3.1 Four-layer structure (a synthesized split)

┌─────────────────────────────────────────────┐
│ Reasoning Layer(推理层)                   │
│   LLM 解读输入、规划行动序列、决定下一步    │
└────────────────────┬────────────────────────┘
                     │
┌────────────────────▼────────────────────────┐
│ Orchestration Layer(编排层)               │
│   控制流、任务序列、重试、错误处理、状态机  │
│   e.g. LangGraph state graph                │
└────────────────────┬────────────────────────┘
                     │
        ┌────────────┴────────────┐
        ▼                         ▼
┌──────────────┐         ┌────────────────┐
│ Memory & Data│         │ Tool Integration│
│   短期对话   │         │   API / Function │
│   长期记忆   │         │   Calling / MCP  │
│   RAG        │         │   Sandbox 执行   │
└──────────────┘         └────────────────┘

3.2 The classic control loop

   ┌─→ Goal ──→ Perception ──→ Reasoning ──→ Planning
   │                                              │
   │                                              ▼
   │                                          Action
   │                                              │
   └─── Memory Update ←── Observation ←──────────┘

The loop continues until: (a) the goal is reached; (b) a stop condition fires (max iterations, timeout, user interrupt); (c) the agent itself judges “I cannot finish this; a human needs to step in.”

3.3 Key design decisions at each layer

See chapter 02 (context engineering) for the RAG and memory sections, and chapter 04 (harness engineering) for tool integration and orchestration.

3.4 Anthropic’s 6 composable agent patterns (required foundational reading)

Building Effective AI Agents, published by Anthropic in December 2024, is one of the most cited essays on productionizing agents in 2025-2026. It splits “agent” systems into two kinds:

“Workflows are great when tasks are well-defined; agents shine when flexibility is required. Often the best solution starts with a workflow and only adds agentic dynamism where it’s truly needed.”

It also proposes 6 composable building blocks — the base primitives for building any agentic system.

3.4.1 Building Block 0: Augmented LLM (the base LLM)

The most atomic “agent”: an LLM plus three augmentations (retrieval / tools / memory). Every pattern above it is stacked on top of this one.

            ┌──────────┐
   Input ───▶│   LLM    │───▶ Output
            │  + tools  │
            │  + memory │
            │  + retrieval│
            └──────────┘

3.4.2 Pattern 1: Prompt Chaining (a chain of prompts)

Split the task into a sequence of steps. Each step’s LLM processes the previous step’s output. A gate (a program that decides whether to continue) can sit between steps.

Input → LLM 1 → [Gate]? → LLM 2 → [Gate]? → LLM 3 → Output

Typical setting: generate an outline → check that the outline matches the format → generate the body from the outline → check the length → translate.

Strength: each step can be optimized and tested on its own, and the process can be traced. Weakness: more steps means higher latency; information can be lost between steps. When to use: the task decomposes cleanly into linear steps, and each step has a clear quality gate.

3.4.3 Pattern 2: Routing (dispatch)

One LLM looks at the input and decides which specialized path to take. Each path is optimized with its own prompt / tools / model.

                  ┌─→ Specialist LLM A (用 prompt_A, tools_A)
Input → Router LLM┤
                  ├─→ Specialist LLM B (用 prompt_B, tools_B)
                  └─→ Specialist LLM C (用 prompt_C, tools_C)

Typical setting: customer-support triage (a refund → a refund-specialist prompt; a technical issue → a technical prompt; chitchat → a general prompt); route by difficulty (a cheap model for an easy question, Opus for a hard one).

Strength: it makes “which prompt for which question” explicit, so each path can be optimized on purpose. Weakness: if the router is wrong, everything downstream is wrong. When to use: an input space with obvious categories.

3.4.4 Pattern 3: Parallelization (parallel execution)

Two variants:

              ┌─→ LLM 1 ─┐
Input ───────┼─→ LLM 2 ─┼──▶ Aggregator LLM ──▶ Output
              └─→ LLM 3 ─┘

Typical settings: - Sectioning: split a long document into sections and summarize them in parallel; split a safety review across dimensions and check them in parallel (toxicity / PII / bias / injection) - Voting: multi-model voting on a code review; multi-prompt voting on content moderation, to cut false positives

Strength: latency is low and reliability is high (voting resists a single failure). Weakness: the cost is N times a single run. When to use: the subtasks are truly independent, or you need redundant reliability.

3.4.5 Pattern 4: Orchestrator-Workers (conductor and workers)

A central LLM dynamically decides the subtasks (they are not predefined), dispatches them to worker LLMs, and synthesizes the result at the end.

                    ┌─→ Worker 1 (动态决定的子任务)
Input → Orchestrator┤
       LLM (动态规划)├─→ Worker 2
                    └─→ Worker 3
                          ↓
                    Synthesizer LLM ──▶ Output

The key difference from Parallelization: the subtasks cannot be defined in advance. The orchestrator sees the concrete input, and only then decides which subtasks to split it into.

Typical settings: - A code change across several files (only after reading the issue does the agent know which files to change) - A complex research task (it first has to decide which angles to look up before it can answer)

Strength: it handles complex tasks that are not known in advance. Weakness: cost and latency are high, and debugging is harder. When to use: a standard workflow cannot solve it, and the input is highly complex.

3.4.6 Pattern 5: Evaluator-Optimizer (an evaluate-and-optimize loop)

One LLM generates a response. Another LLM evaluates it and gives feedback. The first revises from that feedback. The loop continues until the response passes, or a cap is hit.

              Input
                │
                ▼
   ┌─→ Generator LLM ──▶ Response
   │         │                │
   │         │                ▼
   │         │       Evaluator LLM (judge)
   │         │                │
   │         │       PASS ──→ Output
   │         │       FAIL ──→ Feedback
   └─────────┴────────────────┘

Typical settings: - Literary translation (the generator translates; the evaluator checks faithfulness, expressiveness, and elegance, and feeds back “too literal” and the like) - Complex search (the generator writes an answer; the evaluator checks coverage and feeds back “the X angle is still missing”) - Code generation (the generator writes code; the evaluator runs the tests and feeds back the failing cases)

Strength: a high ceiling on quality (iterative quality close to a human review). Weakness: the iteration count is not controllable, it can loop forever, and the cost is high. When to use: the evaluation criteria are clear, and the first draft is clearly worse than the result after iteration.

3.4.7 Pattern 6: Agents (autonomous agents)

The previous five are workflows (the process is predefined). Agents are genuinely autonomous — inside the loop, the LLM decides for itself what to do next, which tool to use, and when to stop.

        Input + Goal
              │
              ▼
   ┌─→ LLM (think + act)
   │         │
   │         ▼
   │   Tool / Action
   │         │
   │         ▼
   │   Environment / Feedback
   │         │
   │         ▼
   └─── Update Context
        (until done or stopped)

When to upgrade to a real agent:

When not to use an agent (continue using workflow):

3.4.8 Decision tree for choosing among the 6 patterns

你的任务是?
│
├─ 单步即可解决 → 用 Augmented LLM
│
├─ 多步固定流程
│   ├─ 线性顺序 → Prompt Chaining
│   ├─ 按类型分流 → Routing
│   └─ 子任务独立 + 并行/冗余 → Parallelization
│
├─ 子任务无法预定义 → Orchestrator-Workers
│
├─ 需要质量迭代 + 评估清晰 → Evaluator-Optimizer
│
└─ 流程完全无法预定义 + 需要自主性 → Agent

Anthropic’s core advice: stay with a workflow (patterns 1-5) for as long as you can, and upgrade to an agent only when you truly need one. In production, 95% of “agentic systems” are served well enough by a workflow. Using an agent blindly brings in behavior that is hard to debug, unpredictable, and prone to runaway cost (see §9, failure modes).


4. A taxonomy of agent types

4.1 Classified by interaction mode

Type Examples Traits
Conversational Agent ChatGPT / Claude.ai with tools Conversation first; agent capability is supplementary
Task Agent Zapier AI Actions / Make AI After a trigger, it runs one process and stops
Coding Agent Claude Code / Cursor / Devin Long-running; edits files, runs tests, opens PRs
Browser Agent Multi-On / Browser Use / Skyvern Clicks, fills forms, and scrapes on web pages
Computer Use Agent Anthropic Computer Use / OpenAI Operator Operates mouse and keyboard across applications; reads the screen
Background Agent OpenAI Codex Background Computer Use (2026-04) Runs in its own session; multiple agents in parallel
Multi-Agent System CrewAI / AutoGen applications Several agents collaborate to finish a task

4.2 Classified by deployment form

4.3 Classified by degree of autonomy (see 1.3)

4.4 Browser agents: AI applied to web automation

The browser agent is the third-largest agent track of 2025-2026 (behind only coding and computer use). Benchmarks such as WebArena and WebVoyager have pushed this track to the SOTA.

Mainstream frameworks (2026)

Framework Language Paradigm Strength ⭐ / status
Browser Use Python Fully autonomous AI (agent loop) 91k ⭐, 89.1% success rate on WebVoyager Current SOTA
Stagehand (Browserbase) TypeScript AI primitives on top of Playwright 4 primitives: act / extract / observe / agent; readable and controllable Rising strongly
Playwright Multi-language Deterministic automation No AI; pure scripts; the fallback Testing baseline
Skyvern Python LLM + computer vision Visual understanding of pages it has not seen before A startup product
Browserbase (SaaS) API Cloud stealth browser Strongest against anti-bot defenses The most commercially mature
from browser_use import Agent
from langchain_anthropic import ChatAnthropic

agent = Agent(
    task="在 Hacker News 上找今天 #1 的帖子,把标题和评论数告诉我",
    llm=ChatAnthropic(model="claude-sonnet-4-6"),
)
result = await agent.run()
print(result)
# Browser Use 自动开 chromium、截图、决定点哪、抓 HTML、做循环直到任务完成

Stagehand (TypeScript, the most readable)

import { Stagehand } from "@browserbasehq/stagehand";
const stagehand = new Stagehand({ env: "LOCAL" });

await stagehand.page.goto("https://news.ycombinator.com");

// AI primitive: act(自然语言操作)
await stagehand.page.act("点击第一个帖子");

// AI primitive: extract(结构化抽数据)
const data = await stagehand.page.extract({
  instruction: "提取帖子标题和评论数",
  schema: z.object({ title: z.string(), comments: z.number() }),
});

// AI primitive: observe(让 AI 描述当前页面)
const observation = await stagehand.page.observe();

// AI primitive: agent(多步任务,自主完成)
await stagehand.page.agent({
  task: "找到登录按钮,用 user@x.com 登录",
});

Stagehand’s design philosophy: the AI writes the selectors; the human writes the control flow. Brittle CSS selectors are replaced by natural-language act, while Playwright’s deterministic control of the flow stays. The industry consensus: Stagehand’s hybrid architecture will be the template.

How to choose

你的任务是?
│
├─ 完全未知网站、AI 决定流程 → Browser Use(自主性最强)
├─ 流程基本已知、要稳定 → Stagehand(AI 局部 + 流程可控)
├─ 流程完全确定 → Playwright(不要用 AI)
├─ 视觉为主、HTML 不可靠 → Skyvern
└─ 需要反反爬云服务 → Browserbase(SaaS)+ Stagehand

Common pitfalls of browser agents

4.5 Voice / Realtime Agent

In the second half of 2024, the OpenAI Realtime API opened the era of realtime voice agents. The 2026 mainstream:

Approach Mode Latency Fit
OpenAI Realtime API (GPT-4o / GPT-5) Bidirectional audio streaming (WebSocket) < 500ms Customer support / personal assistant
Anthropic Voice (Claude) Text + TTS (asynchronous) 2-5s Content-generation settings
Gemini Live API Bidirectional multimodal (including video) < 1s Meeting assistant
Pipecat / LiveKit Agents Open-source frameworks that orchestrate STT + LLM + TTS 1-3s Self-hosted; flexible
Vapi / Retell SaaS; a hosted full stack for voice agents < 1s Startup MVP

Minimal Realtime API code

import asyncio, websockets, json, base64

async def voice_agent():
    async with websockets.connect(
        "wss://api.openai.com/v1/realtime?model=gpt-4o-realtime-preview-2026",
        extra_headers={"Authorization": f"Bearer {API_KEY}"},
    ) as ws:
        # 配置 session(音色、tools、instructions)
        await ws.send(json.dumps({
            "type": "session.update",
            "session": {
                "voice": "alloy",
                "instructions": "你是 ACME 客服。简短礼貌。",
                "tools": [...],   # 普通 function calling
                "input_audio_transcription": {"model": "whisper-1"},
                "turn_detection": {"type": "server_vad"},  # 服务器侧 VAD
            },
        }))

        # 用户麦克风音频流(PCM16)持续 push 进去
        async def push_mic():
            while audio_chunk := mic.read():
                await ws.send(json.dumps({
                    "type": "input_audio_buffer.append",
                    "audio": base64.b64encode(audio_chunk).decode(),
                }))

        # 模型音频回流,喂给扬声器
        async def play_audio():
            async for msg in ws:
                event = json.loads(msg)
                if event["type"] == "response.audio.delta":
                    speaker.play(base64.b64decode(event["delta"]))

        await asyncio.gather(push_mic(), play_audio())

Engineering points for voice agents


5. Mainstream agent frameworks compared (2026)

After the two-year Cambrian explosion of 2024-2025, the 2026 agent-framework landscape has clear leaders:

Framework Paradigm Model support Learning curve Production readiness Fit
LangGraph Explicit state machine / graph Any Medium Highest (LangSmith integration, checkpoint, time-travel debug, HITL) Complex production agents; explainable flows
CrewAI Role + task DSL Any Lowest (starts at 20 lines) Medium Fast business prototypes; multi-agent role collaboration
AutoGen Multi-agent conversational negotiation Any Medium In maintenance (Microsoft has shifted to Microsoft Agent Framework) Maintaining legacy projects
OpenAI Agents SDK Imperative handoff chain OpenAI only Extremely low (minimal mental model + first-class tracing) Medium OpenAI-ecosystem first
Anthropic Agent Skills Skill packages (released in 2026) Claude only Low Medium The Claude ecosystem; reusable capabilities
Smolagents Minimal (a core of a few hundred lines) Any Low Low (mainly teaching / research) Learning; the HuggingFace ecosystem
Mastra TypeScript-native Any Low Medium (growing fast) JS/TS projects; Vercel / Next.js
Pydantic AI Strongly typed Python Any Medium Medium Python projects where type safety matters
Google ADK / Gemini-first Medium Medium The Gemini / Vertex AI ecosystem
LlamaIndex Agent RAG-first Any Medium Medium RAG-heavy settings

5.1 The three frameworks compared most often

LangGraph vs CrewAI vs OpenAI Agents SDK is the three-way comparison discussed most in 2026:

5.2 How to choose a framework

5.3 “Hello World” compared across the three mainstream frameworks

The same task: “a ReAct agent that can answer questions with a web-search tool”. Watch how the three code philosophies differ.

LangGraph (state machine / graph)

from langgraph.graph import StateGraph, END
from langgraph.prebuilt import create_react_agent
from langchain_anthropic import ChatAnthropic
from langchain_community.tools.tavily_search import TavilySearchResults

llm = ChatAnthropic(model="claude-sonnet-4-6")
tools = [TavilySearchResults(max_results=3)]

# 一行创建预制 ReAct agent
agent = create_react_agent(llm, tools)

# 调用(自带 streaming + checkpoint)
for chunk in agent.stream({"messages": [("user", "2026 年 SWE-bench 头部模型是?")]}):
    print(chunk)

# 自定义复杂图
class State(TypedDict):
    messages: list
    iterations: int

def should_continue(state):
    if state["iterations"] >= 10: return END  # max iter cap
    return "agent"

graph = StateGraph(State)
graph.add_node("agent", agent)
graph.add_conditional_edges("agent", should_continue)
graph.set_entry_point("agent")
app = graph.compile(checkpointer=MemorySaver())  # checkpoint = HITL & resume 一等公民

Traits: defined as a graph, state explicit, checkpoint built in, time-travel debug.

CrewAI (role + task DSL)

from crewai import Agent, Task, Crew
from crewai_tools import SerperDevTool

researcher = Agent(
    role="2026 AI 趋势分析师",
    goal="找到关于 SWE-bench 头部模型的可靠信息",
    backstory="你是科技新闻深度分析专家",
    tools=[SerperDevTool()],
    verbose=True,
)

writer = Agent(
    role="技术博主",
    goal="把分析结果写成简洁清晰的总结",
    backstory="你擅长把技术细节翻译成易读文字",
    verbose=True,
)

task1 = Task(description="调查 2026 年 SWE-bench 头部模型", agent=researcher)
task2 = Task(description="把调查写成 200 字总结", agent=writer)

crew = Crew(agents=[researcher, writer], tasks=[task1, task2])
result = crew.kickoff()

Traits: a three-layer DSL of role + task + crew; starts at 20 lines; the fastest to pick up.

OpenAI Agents SDK (imperative handoff)

from agents import Agent, Runner, function_tool

@function_tool
def web_search(query: str) -> str:
    """搜索网页"""
    # ... 实现略
    return search_results

researcher = Agent(
    name="researcher",
    instructions="你是研究员,用 web_search 找资料",
    tools=[web_search],
)

writer = Agent(
    name="writer",
    instructions="把研究结果写成 200 字总结",
    handoffs=[researcher],  # writer 可以把任务 handoff 回 researcher 继续查
)

result = Runner.run_sync(writer, "2026 年 SWE-bench 头部模型是?")
print(result.final_output)

Traits: handoff is the SDK’s core abstraction; tracing is first-class; the mental model is minimal.

How the three philosophies compare

Dimension LangGraph CrewAI OpenAI Agents SDK
Abstraction State + Graph Role + Task + Crew Agent + Tools + Handoff
Mental model State-machine programmer Team manager Function calls
Control-flow visibility Very high (the graph) Medium (the task flow) Low (imperative)
Debugging tools LangSmith time-travel Default logs OpenAI tracing
Extensibility Very strong (custom nodes) Medium (custom tasks) Medium (custom tools)
Model support Any Any OpenAI only
Day-1 ramp-up Requires understanding graphs 30 minutes 5 minutes
Production deployment Strongest Medium Medium

5.4 Anthropic Agent Skills: a second standards path, beside MCP

In 2026 Anthropic introduced Agent Skills — packaging the procedural knowledge of “how an agent completes a class of task” into a reusable unit. This is Anthropic’s second attempt at an open standard, after MCP.

How Skills, MCP, and Tools differ

Abstraction What it solves Form Analogy
Tools (function calling) One atomic operation A function signature + a JSON schema One shell command
MCP Connect external tools and data to an LLM A server exposes tools / resources / prompts An OS device driver
Agent Skills A complete procedure for finishing a class of task A folder (instructions + templates + scripts + checklist items) A shell script / playbook

The key insight: MCP connects tools to the agent; Skills teach the agent how to use those tools to finish a concrete task. In Anthropic’s words: “MCP is plumbing, Skills is procedural knowledge.”

Standard layout of a skill

A skill is a folder:

my-skill/
├── SKILL.md              # 入口:何时用、做什么、怎么做
├── templates/            # 输出模板
│   └── report.md
├── scripts/              # 可执行辅助脚本
│   └── analyze.py
├── examples/             # 示范 input/output
│   └── case1.md
└── resources/            # 静态资源
    └── compliance.json

SKILL.md is a manual for the LLM to read:

# Skill: PR Review

## When to use
当用户请求"review my PR" / "code review" 时

## What it does
检查 diff 的:
- 安全问题(SQL injection / XSS / hardcoded secret)
- 测试覆盖
- 文档同步

## How to do
1. 用 `gh pr diff` 读 diff
2. 跑 `scripts/scan_security.py` 找 secret
3. 检查每个改动的函数是否有对应 test
4. 用 `templates/review.md` 输出

## Definition of done
- 输出包含 3 个 section(必读)
- 每个发现都引用 file:line
- 严重度按 critical / major / minor 分类

While it is carrying out a task, the LLM reads SKILL.md on its own and follows the steps in it.

Integration with Claude Code

Claude Code supports a skills directory natively. Create .claude/skills/ at the project root:

my-project/
├── .claude/
│   └── skills/
│       ├── pr-review/SKILL.md
│       ├── deploy/SKILL.md
│       └── investigate-bug/SKILL.md

Claude Code scans it at startup. When the user says “review the pr”, it matches the pr-review skill and runs it.

What Skills mean for the industry

Skills are the standardized unit of reusable agentic capability — a team can share them, an organization can govern them, and the community can publish them. Anthropic open-sourced the spec, the same strategy as with MCP: build the ecosystem first, then unify the standard.

For community skills, see skillmatic-ai/awesome-agent-skills.

5.5 Advanced LangGraph features a production agent must know

The state machine of basic LangGraph was covered in §5.3. Below are five advanced features that production agents actually use:

5.5.1 Checkpointer: pause the agent, resume it, and travel in time

LangGraph has a built-in checkpointer. After each node runs, state is saved automatically:

from langgraph.checkpoint.postgres import PostgresSaver

# 生产用 Postgres checkpointer(持久化跨进程)
checkpointer = PostgresSaver.from_conn_string("postgresql://...")
checkpointer.setup()

app = graph.compile(checkpointer=checkpointer)

# 每次调用带 thread_id
config = {"configurable": {"thread_id": "session_42"}}
result = app.invoke({"messages": [...]}, config=config)

# 服务器重启后用同一 thread_id 继续,状态自动恢复
result = app.invoke({"messages": [new_message]}, config=config)

Time-travel: you can roll back to any historical checkpoint and fork a new branch from there:

# 列出当前 thread 的所有历史 checkpoint
history = list(app.get_state_history(config))
# 选某个历史点
old_state = history[3]
# 从那里继续(fork 一条新分支)
result = app.invoke(None, config=old_state.config)

Uses: during debugging, go back to the step before the error; A/B-test two tool-call results; let the user undo an action.

5.5.2 Interrupt: human-in-the-loop as a first-class citizen

from langgraph.types import interrupt, Command

def risky_action(state):
    # 高风险操作前暂停等用户
    user_response = interrupt({
        "question": f"即将执行: DELETE FROM users WHERE id={state['user_id']}",
        "type": "approval_required",
    })
    if user_response.get("approved"):
        # 执行
        db.execute(...)
        return {"status": "executed"}
    return {"status": "cancelled"}

# 调用时碰到 interrupt 会停下,等用户响应
result = app.invoke({"user_id": 123}, config)
# result 里有 __interrupt__ 字段表示卡在某 node
# 用户在 UI 点 approve / reject
app.invoke(Command(resume={"approved": True}), config)  # 继续

5.5.3 Subgraph: turn a team into an embeddable subgraph

Split a complex agent into subgraphs. Each team develops, tests, and deploys on its own:

# Research team 是个子图
def build_research_team():
    g = StateGraph(ResearchState)
    g.add_node("planner", planner)
    g.add_node("searcher", searcher)
    g.add_node("synthesizer", synthesizer)
    # ... edges
    return g.compile()

# Engineering team 同理
def build_eng_team():
    ...

# 顶层把两个团队当 node 嵌入
top = StateGraph(GlobalState)
top.add_node("research", build_research_team())  # ★ 子图作为 node
top.add_node("eng", build_eng_team())
top.add_node("manager", top_manager)
top.set_entry_point("manager")
# ... edges 串起来

5.5.4 Streaming: let the user see the agent “thinking”

async for event in app.astream_events({"messages": [...]}, config, version="v2"):
    if event["event"] == "on_chat_model_stream":
        # LLM 流式输出 token
        chunk = event["data"]["chunk"].content
        yield chunk
    elif event["event"] == "on_tool_start":
        yield f"[正在调用 {event['name']}...]\n"
    elif event["event"] == "on_tool_end":
        yield f"[完成 {event['name']}]\n"

Render it live on the front end over SSE or WebSocket. The user experience improves 10×.

5.5.5 Time-travel debug, integrated with LangSmith

LangSmith records every checkpoint automatically. In the dashboard, click any step and you can:

This is the core reason LangGraph pulls ahead of CrewAI and AutoGen on production maturity.


6. Multi-agent collaboration patterns

The 4 + 1 mainstream patterns for putting several agents together:

6.1 Supervisor / Conductor

            ┌───────────────┐
            │   Supervisor  │
            └───┬───┬───┬───┘
                │   │   │
        ┌───────▼┐ ┌▼─┐ ┌▼──────┐
        │ Agent A│ │B │ │ Agent C│
        └────────┘ └──┘ └────────┘

A central supervisor agent receives the goal → splits it into subtasks → routes them to specialist worker agents → synthesizes the result. Easy to reason about, easy to trace, and the control flow is clear — one routing node, and every decision is visible. The mainstream production architecture.

6.2 Pipeline

Agent A → Agent B → Agent C → Output

Agents run in order. The output of one is the input of the next. In essence this is like a traditional ETL workflow. The “agent” abstraction is a bit redundant in this pattern; the benefit is that it integrates smoothly with traditional systems.

6.3 Swarm

   Agent A ←──→ Agent B
       ↓ ↘    ↗ ↑
       ↑   ╲╱    ↓
   Agent C ←──→ Agent D

Decentralized: agents hand off directly to one another. No intermediary, fewer calls, faster — but hard to debug, and easy to fall into a loop of passing the buck. LangGraph makes both supervisor and swarm first-class, so you choose by scenario.

6.4 Hierarchical (multi-level delegation)

Top Manager
├── Mid Supervisor 1
│   ├── Worker A
│   └── Worker B
└── Mid Supervisor 2
    ├── Worker C
    └── Worker D

Tree-shaped, multi-level delegation: the top handles strategy, the middle handles tactics, and the leaves execute. With shared state management, conflicts drop by a large margin (how large varies widely by team and by task; precise figures of the “80%” kind have no credible basis in public sources). It fits complex business, and the latency is high.

6.5 Hybrid (a mix)

In practice it is often a hybrid: one layer of a hierarchy uses a swarm for parallel exploration, and another layer uses a supervisor to converge. Devin’s internals, for example, are hierarchical (planner → coder → reviewer, three layers) plus a local swarm (the reviewer spawns several critics).

6.6 How to choose

6.7 LangGraph code samples for the five patterns

Each of the five code samples below runs on its own (you need pip install langgraph langchain-anthropic) and covers one of the five collaboration patterns.

Pattern 1: Supervisor / Conductor

from langgraph.graph import StateGraph, END
from typing import TypedDict, Literal
from langchain_anthropic import ChatAnthropic

class State(TypedDict):
    task: str
    next_worker: str
    results: dict

llm = ChatAnthropic(model="claude-sonnet-4-6")

def supervisor(state: State):
    """中央 supervisor 决定派给哪个 worker"""
    decision = llm.invoke(f"""任务:{state["task"]}
路由到下面哪个专家?只回答名字:
- researcher(找资料)
- writer(写文章)
- coder(写代码)
- DONE(已完成)""")
    return {"next_worker": decision.content.strip()}

def researcher(state: State):
    result = llm.invoke(f"找资料:{state['task']}")
    return {"results": {**state["results"], "research": result.content}}

def writer(state: State):
    result = llm.invoke(f"写文章基于:{state['results']}")
    return {"results": {**state["results"], "draft": result.content}}

def coder(state: State):
    result = llm.invoke(f"写代码:{state['task']}")
    return {"results": {**state["results"], "code": result.content}}

def route(state: State) -> Literal["researcher", "writer", "coder", END]:
    return END if state["next_worker"] == "DONE" else state["next_worker"]

g = StateGraph(State)
g.add_node("supervisor", supervisor)
g.add_node("researcher", researcher)
g.add_node("writer", writer)
g.add_node("coder", coder)
g.set_entry_point("supervisor")
g.add_conditional_edges("supervisor", route)
for w in ["researcher", "writer", "coder"]:
    g.add_edge(w, "supervisor")  # worker 完成后回 supervisor

app = g.compile()
result = app.invoke({"task": "调查 2026 RAG 现状并写一段总结", "results": {}})

Pattern 2: Pipeline (a sequential pipeline)

class PipelineState(TypedDict):
    raw_data: str
    cleaned: str
    analyzed: str
    summary: str

def clean(state):
    return {"cleaned": llm.invoke(f"清洗:{state['raw_data']}").content}

def analyze(state):
    return {"analyzed": llm.invoke(f"分析:{state['cleaned']}").content}

def summarize(state):
    return {"summary": llm.invoke(f"摘要:{state['analyzed']}").content}

g = StateGraph(PipelineState)
g.add_node("clean", clean)
g.add_node("analyze", analyze)
g.add_node("summarize", summarize)
g.set_entry_point("clean")
g.add_edge("clean", "analyze")
g.add_edge("analyze", "summarize")
g.add_edge("summarize", END)
app = g.compile()

Pattern 3: Swarm (decentralized handoff)

from langgraph.graph import MessagesState
from langgraph.prebuilt import create_react_agent
from langchain_core.tools import tool

@tool
def transfer_to_researcher():
    """需要查资料时调用"""
    return "Transferring to researcher"

@tool
def transfer_to_writer():
    """需要润色时调用"""
    return "Transferring to writer"

researcher = create_react_agent(llm, tools=[search_tool, transfer_to_writer])
writer     = create_react_agent(llm, tools=[transfer_to_researcher])

def router(state: MessagesState) -> Literal["researcher", "writer", END]:
    last = state["messages"][-1]
    if hasattr(last, "tool_calls") and last.tool_calls:
        name = last.tool_calls[0]["name"]
        if "researcher" in name: return "researcher"
        if "writer" in name: return "writer"
    return END

g = StateGraph(MessagesState)
g.add_node("researcher", researcher)
g.add_node("writer", writer)
g.set_entry_point("researcher")
g.add_conditional_edges("researcher", router)
g.add_conditional_edges("writer", router)
app = g.compile()

Each agent decides for itself whom to hand off to. There is no central supervisor.

Pattern 4: Hierarchical (multi-level delegation)

# 顶层 manager
def top_manager(state):
    decision = llm.invoke(f"任务:{state['task']}\n路由:team_research / team_eng / DONE")
    return {"next_team": decision.content.strip()}

# 中层 team supervisor
def research_team_supervisor(state):
    sub = llm.invoke("派给 worker:searcher / analyst / DONE")
    return {"next_research_worker": sub.content.strip()}

def eng_team_supervisor(state):
    sub = llm.invoke("派给 worker:coder / reviewer / DONE")
    return {"next_eng_worker": sub.content.strip()}

# 底层 worker(略)

# 编排:顶层 → 中层 supervisor → 底层 worker → 中层 supervisor → 顶层
g = StateGraph(...)
g.add_node("top", top_manager)
g.add_node("research_team", build_research_subgraph())  # 子图嵌入
g.add_node("eng_team", build_eng_subgraph())
g.set_entry_point("top")
g.add_conditional_edges("top", route_top)
# 子图返回 → 顶层
g.add_edge("research_team", "top")
g.add_edge("eng_team", "top")

LangGraph’s subgraph (subgraph) feature lets each layer be tested on its own and deployed on its own.

Pattern 5: Hybrid (common in production-grade systems)

# 顶层 hierarchical → 中层用 supervisor → 个别节点用 swarm 做并行探索
g = StateGraph(...)

# 顶层 hierarchical
g.add_node("strategist", strategist)
g.add_node("execution_layer", execution_supervisor_subgraph)

# 中层 supervisor
def execution_supervisor_subgraph():
    sub = StateGraph(...)
    sub.add_node("supervisor", supervisor)
    sub.add_node("planner", planner)
    sub.add_node("explorer_swarm", swarm_subgraph)  # 嵌入 swarm
    sub.add_node("validator", validator)
    return sub.compile()

# 底层 swarm 做并行假设探索
def swarm_subgraph():
    sub = StateGraph(...)
    for agent_id in ["explorer_a", "explorer_b", "explorer_c"]:
        sub.add_node(agent_id, build_explorer(agent_id))
    sub.add_node("synthesizer", synthesizer)
    # 三个 explorer 并行,结果汇到 synthesizer
    return sub.compile()

In practice, the sub-agent systems of Devin, Manus, and Claude Code are all close to this hybrid topology: strategy at the top, a tactical supervisor in the middle, and parallel exploration at the bottom.


7. Agent evaluation benchmarks

7.1 Six core agent benchmarks

Benchmark What it evaluates Task scale Scoring Head of the 2026-04 ranking
SWE-bench Verified Repairing real GitHub issues 500 human-verified issues from Python projects Programmatic (run the tests) Claude Opus 4.7 ~ 87% (Anthropic’s announced figure; the latest numbers are on the swebench.com leaderboard)
GAIA (Princeton HAL) Multi-step reasoning for a general assistant 466 questions, three difficulty tiers Programmatic + LLM judge Claude Sonnet 4.5 = 74.6%; Anthropic swept the top 6
TAU-bench Tool use + dialogue with a real user Multiple domains Simulated multi-turn interaction —
AgentBench 8 environment classes (OS / DB / KG / card games / lateral thinking / household chores / online shopping / web) Cross-environment Scored per environment —
WebArena (CMU) Web-navigation agents 812 tasks / 5 websites + a map Programmatic —
OSWorld Real operation across operating systems and applications 369 tasks / Ubuntu + Windows + macOS Verified by execution —

7.2 SWE-bench: the benchmark people cite most

SWE-bench Verified is the coding-agent signal most trusted in 2026: 500 human-verified issues from real GitHub Python projects. The agent has to read the code, edit files, and make the tests pass.

Claude Opus 4.7 is reported as one of the current leaders on SWE-bench Verified (the latest score is on swebench.com). OpenAI o3 / the Codex series and Google Gemini Code follow. The strongest open-source models currently sit in the 60%+ band.

7.3 A hard warning: every benchmark can be hacked

Berkeley RDI’s How We Broke Top AI Agent Benchmarks systematically audited 8 mainstream benchmarks (SWE-bench, WebArena, OSWorld, GAIA, Terminal-Bench, FieldWorkArena, CAR-bench, and others). The conclusion: every one of them can be exploited to a near-perfect score without actually completing the task. Common hack paths:

What this means in practice:

  1. Read the evaluation methodology before you read the score
  2. Do not trust a public benchmark ranking for your own business. Re-test on your own ground truth
  3. A composite of several benchmarks is more reliable than a single benchmark ranking

7.4 Running SWE-bench on your own machine (the full procedure)

If you want to run SWE-bench Verified yourself, and not only read the leaderboard number, the full procedure is below.

7.4.1 Hardware floor

7.4.2 Three-stage procedure

阶段 A: 安装 + 准备
  pip install swebench
  docker pull princeton-nlp/swebench-eval:latest

阶段 B: 跑你的 agent,把结果生成为 predictions JSON
  你的 agent → 输入:每个 task 的 problem_statement
            → 输出:patch 文件(diff 格式)
            → 保存为 predictions.jsonl

阶段 C: 用 SWE-bench harness 评估
  python -m swebench.harness.run_evaluation \
    --dataset_name princeton-nlp/SWE-bench_Lite \
    --predictions_path ./predictions.jsonl \
    --max_workers 8 \
    --run_id my_agent_v1

7.4.3 Full predictions format

{"instance_id": "django__django-11099", "model_name_or_path": "my_agent_v1",
 "model_patch": "diff --git a/django/...\n--- a/django/...\n+++ b/django/...\n@@ -100,3 +100,5 @@\n+    # fix: ...\n"}
{"instance_id": "django__django-11133", "model_name_or_path": "my_agent_v1",
 "model_patch": "..."}

Each line is one task. model_patch is a unified diff. The harness applies the diff, runs the tests, and compares the result with what was expected.

7.4.4 A wrapper that plugs in your own agent

import json
from datasets import load_dataset

def run_my_agent_on_swe_bench():
    dataset = load_dataset("princeton-nlp/SWE-bench_Lite", split="test")
    predictions = []

    for task in dataset:
        # 准备 agent 上下文
        context = {
            "repo": task["repo"],                    # e.g., "django/django"
            "base_commit": task["base_commit"],
            "problem_statement": task["problem_statement"],
            "hints_text": task["hints_text"],        # ★ 注意:避免泄露 ground truth
        }

        # 跑你的 agent(带 max_iterations / cost_cap 等护栏)
        try:
            patch = my_agent.solve(context, max_iter=30, max_cost_usd=2.0)
        except Exception as e:
            patch = ""  # 失败也要交白卷

        predictions.append({
            "instance_id": task["instance_id"],
            "model_name_or_path": "my_agent_v1",
            "model_patch": patch,
        })

    with open("predictions.jsonl", "w") as f:
        for p in predictions:
            f.write(json.dumps(p) + "\n")

if __name__ == "__main__":
    run_my_agent_on_swe_bench()

7.4.5 mini-swe-agent: the official baseline

The SWE-bench team’s mini-swe-agent is a minimal agent harness whose only tool is bash, about 500 lines of Python, meant as a baseline to compare against:

pip install mini-swe-agent
mini-swe-agent run --model claude-sonnet-4-6 --dataset princeton-nlp/SWE-bench_Lite

If your agent cannot beat the mini-swe-agent baseline on SWE-bench Lite, suspect the harness implementation before you suspect the model.

7.4.6 Choosing among the three SWE-bench variants

Variant Tasks Estimated cost to finish (Claude Sonnet 4.6) Use
SWE-bench Lite 300 ~$30, ~4 hours Fast iteration / day-to-day
SWE-bench Verified 500 ~$60, ~8 hours Papers / leaderboard submission
SWE-bench full 2,294 ~$300, ~36 hours Rarely used

In practice: use Lite day to day, and run Verified before a formal release.

7.5 A custom benchmark: turn your own business into an eval set

A public benchmark does not necessarily fit your business. The eval you can actually trust is ground truth from your own business. The minimum viable procedure:

7.5.1 Build a golden set of 100 cases

Collect 100 real business scenarios:

Store them with the schema below:

[
    {
        "id": "case_001",
        "category": "refund_query",
        "difficulty": "easy",
        "input": {"messages": [{"role": "user", "content": "我要退订单 #12345"}]},
        "expected_behavior": [
            "调用 lookup_order(12345)",
            "调用 process_refund(...)",
            "回复用户告知预计 3-5 工作日",
        ],
        "forbidden_behavior": [
            "不能在没有 lookup 的情况下直接 refund",
            "不能透露其他用户订单信息",
        ],
        "ground_truth_answer": "您的订单 #12345 退款已发起...",
    },
    ...
]

7.5.2 Code that runs the eval

def evaluate_agent(agent_fn, golden_set):
    results = []
    for case in golden_set:
        # 跑 agent 收集 trace
        with TraceCapture() as trace:
            answer = agent_fn(case["input"])

        # 三层评估
        scores = {
            # 层 1:tool call 顺序对不对
            "tool_correctness": check_tool_calls(trace, case["expected_behavior"]),
            # 层 2:是否触发禁止行为
            "safety": not any(matches(trace, fb) for fb in case["forbidden_behavior"]),
            # 层 3:答案质量(LLM-as-judge)
            "answer_quality": llm_judge(case["input"], answer, case["ground_truth_answer"]),
        }
        results.append({"case_id": case["id"], **scores})
    return results

7.5.3 Wire the eval into CI

# .github/workflows/eval.yml
name: Agent Eval Gate
on: pull_request
jobs:
  eval:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: pip install -e .
      - run: python -m my_agent.eval --golden-set ./eval/golden.jsonl --output report.json
      - run: |
          python -c "
          import json
          r = json.load(open('report.json'))
          tc = sum(x['tool_correctness'] for x in r) / len(r)
          sf = sum(x['safety'] for x in r) / len(r)
          aq = sum(x['answer_quality'] for x in r) / len(r)
          print(f'tool_correctness={tc:.2f}, safety={sf:.2f}, answer_quality={aq:.2f}')
          assert tc >= 0.85, 'tool_correctness regression'
          assert sf >= 0.99, 'safety regression'
          assert aq >= 0.75, 'quality regression'
          "

Every pull request runs the suite. A regression on any metric blocks the merge.

7.6 Beyond the score: seven disciplines of evaluation

A public leaderboard number is only the surface. What a production agent evaluation should actually look at:

  1. The distribution across failure modes (what share is Loop of Death / hallucination / tool misuse)
  2. The cost distribution (p50 / p95 / p99 cost per task)
  3. The latency distribution (the same)
  4. The safety-violation rate (computed on its own; it must not be folded into quality)
  5. Cross-model consistency (run the same case set on another model; high agreement is what shows that the eval itself is reliable)
  6. Human-calibration kappa (have people re-grade the golden set every month, and watch whether the LLM judge drifts)
  7. Correlation with real business KPIs (what you eventually need is NPS / conversion / support cost; the eval score is only a proxy)

8. Real product cases

8.1 The big three coding agents

If you are writing code in 2026, you are almost certainly using one of these three: Claude Code, GitHub Copilot, Cursor. The most common two-tool stack is Cursor for daily editing + Claude Code for hard tasks, or Copilot in the IDE + Claude Code in the terminal.

Claude Code (Anthropic) — the most representative CLI agent of 2026

Cursor

GitHub Copilot Workspace

8.2 Cloud agent platforms

Devin (Cognition)

Manus

8.3 Computer-use agents

Anthropic Claude Computer Use

OpenAI Codex Background Computer Use

Operator (OpenAI’s earlier computer-use product)

How computer use works (one shared architecture)

Anthropic Computer Use, Operator, OpenAI CUA, and Manus all run the same perceive–decide–act loop:

┌─────────────────────────────────────────────────────────┐
│  ① 截图(screenshot tool)                              │
│     resolution: 1280x800(Anthropic 推荐)              │
│     格式: PNG → base64 → vision LLM input                │
└─────────────────────────────┬───────────────────────────┘
                              ▼
┌─────────────────────────────────────────────────────────┐
│  ② VLM 推理(Vision LLM)                                │
│     - 解析当前界面(按钮 / 输入框 / 文本 / 图标)        │
│     - 决定下一步动作("点击右上角的『下一步』按钮")     │
│     - 输出结构化 action:{type, x, y, text, key}         │
└─────────────────────────────┬───────────────────────────┘
                              ▼
┌─────────────────────────────────────────────────────────┐
│  ③ 执行(在 sandbox VM / 远程桌面 / Chrome extension)   │
│     - mouse_move(x, y) / click / drag                    │
│     - type_text("...") / key_press("ctrl+c")             │
│     - 100-500ms 后截下一张图                             │
└─────────────────────────────┬───────────────────────────┘
                              │  循环
                              └──────────────────────────▶

The hard engineering problems:

Problem What you see What the field does about it
Pixel coordinates miss The LLM says “click (450, 320)” and the real target is at (445, 318). Five pixels, and the wrong button Anthropic strengthens the grounding loss at training time. At runtime, allow a tolerance and verify with a second screenshot
Dynamic / asynchronous UI The page is still loading after the click, so the next screenshot is an intermediate state Introduce wait_for_idle, plus the DOM / accessibility tree as a second signal (pixels alone are not enough)
CAPTCHA / anti-bot Almost every CAPTCHA stops the agent The field has given this up: either HITL, so the user solves it, or switch to an API path
Multiple windows / focus drift A notification pops up, or the app switches, and the agent loses context Capture the full screen and keep a window_id. OpenAI Operator isolates a dedicated browser
PII and privacy leakage The screenshot sends passwords, mail, and messages that are on screen to the LLM Mask sensitive regions on the client; filter with local OCR; use a dedicated computer-use VM
Latency and cost 1–3 seconds per step, and 1–2K vision tokens per screenshot. Ten minutes easily runs past $5 Screenshot on an interval, lower the resolution, cache UI-element detection, and prefer the DOM over vision

Mainstream reliability numbers (OSWorld, 2026-04):

So at the end of 2026, computer use is still research and assistance, not a production replacement. Before it sits on a critical product path, there has to be a HITL fallback.

8.4 Open-source options

Aider

Cline / Continue / Roo Code


9. Failure modes and real incidents

9.1 Loop of Death

90% of production agents die here. The agent keeps retrying the same failed action inside some loop, burning tokens and API quota until the budget alarm fires.

Real cases:

Five typical shapes of a Loop of Death (ordered by how often they fire)

Shape How it triggers Example What makes it fatal
Tool Retry Loop The tool keeps returning the same error, and the agent keeps trying the same arguments read_file('config.yaml') → FileNotFoundError, and the agent retries 50 times The LLM has no strong signal that it already tried this; the error message carries no diagnosis
Test-Fail-Fix-Break A change at A makes test B pass, and the new change breaks test C. Around it goes npm test is red → edit → a different test goes red → edit again → … There is no dashboard of the whole test state. Each step sees only a local slice
Hallucinated Tool / API Loop The agent calls a tool or API that does not exist, then nudges the name and tries again search_web → missing → web_search → do_search → … The tool list has no enforced schema, and the error does not return the list of available tools
Plan-Replan Spiral After every failure the agent rewrites the whole plan, and the record of the old failure is lost “Replan” makes the LLM redesign the same failing steps There is no episodic memory of “X was already tried and did not work”
Approval Wait Deadlock The agent waits for HITL approval, and nobody is looking at the UI request_human_approval fired, nobody responded, and the agent sat for hours There is no approval timeout and no escalation

Anatomy of a single step (the “Anthropic 90% case”)

An internal Anthropic analysis reports that about 90% of Loops of Death are the cycle “thinking → tool call → the same error → the same thinking → the same tool call.” The LLM has no explicit memory of “I just tried this,” so it keeps recommending the same action.

Four defenses. All four are required:

# 1. 硬上限:iterations / timeout / token / cost
MAX_STEPS = 25
MAX_DURATION = 300  # seconds
MAX_TOKENS = 200_000
MAX_COST_USD = 5.0

# 2. 重复检测:相同 tool + 相同参数 ≥ N 次 → 强制 break
def detect_repeat(history, tool_call, n=3):
    same = [h for h in history[-10:] if h.tool == tool_call.tool
            and h.args == tool_call.args and h.error == tool_call.error]
    return len(same) >= n

# 3. 错误信号注入:把"已失败 N 次"用强语言注入下一轮 prompt
if detect_repeat(history, tool_call, n=2):
    inject = f"⚠️ You have called {tool_call.tool}({tool_call.args}) "
             f"and got the same error '{tool_call.error}' {n} times. "
             f"Do NOT repeat. Choose a different approach OR stop and report."
    next_messages.append({"role": "system", "content": inject})

# 4. Escape hatch:明确给 agent "放弃 / 报告" 工具
tools.append({
    "name": "give_up_and_report",
    "description": "Use when stuck. Reports what you tried and asks user.",
    "parameters": {"reason": "string", "attempted": "list"}
})

Engineering tradeoffs:

9.2 Hallucination cascade

One invented fact triggers a chain of bad downstream calls.

A real case:

Countermeasures:

9.3 Tool misuse / over-privileged actions

The agent calls a highly destructive tool by mistake.

A 2026 collection of real incidents (as reported in the press; readers should check any specific accusation against a vendor against the primary source linked in the bibliography):

  1. A large cloud provider’s internal coding agent was reported, in 2026, to have operated on a production environment on its own and caused a long outage (the details are in each vendor’s postmortem)
  2. Multiple Hacker News and Reddit threads report that a Google AI coding tool, asked to clear a cache, affected more than was intended (for the specific vendor and product name, see the resources at the end of chapter 03)
  3. The Replit AI agent deleted a production database during a code freeze (the Replit CEO publicly apologized, 2025-07; covered by SaaStr and TechCrunch)
  4. A second-hand Undercode Testing blog reports an Opus 4.6 agent deleting a production database within a few seconds (a second-hand retelling; the original incident statement still needs verification)

Every one of them is the same combination failing at once: “the agent held permissions it should not have held + no deny-first default + no sandbox + no HITL gate.”

Countermeasures: see §10.

9.4 Memory corruption / specification gap / verification failure

Silent failures (failures with no alert) are the worst kind. The agent quietly abandons the task, returns an empty result, or opens a PR that looks finished and is wrong. This class has to be watched continuously in production, with observability plus eval.

9.5 Cost-explosion monitoring

Whatever the failure, it shows up as money. A production agent needs:

9.6 The four failure modes Anthropic summarizes, and the fixes that go with them

Anthropic’s Building Effective AI Agents, plus later engineering posts, collapses production-agent failures into 4 classes. They overlap §9.1–§9.5 above, from a different angle: organized by the fix.

Failure mode How it shows up Root cause The fix that goes with it
① Tool misuse The wrong tool / the right tool with illegal arguments / a highly destructive tool The tool description is vague, the parameter schema is loose, and there is no pre-check (1) A strict JSON schema, plus a second check on the server; (2) requires_confirmation: true on highly destructive tools; (3) a PreToolUse hook blocks before execution; (4) the tool description states when not to use it
② Hallucinated tool / hallucinated API Calling a tool that does not exist at all, or inventing an API The model guesses the tool list instead of reading it; the error message does not steer back to the right tool (1) Attach an available_tools list when returning an error; (2) constrained decoding, so the tool name is chosen from an allowlist; (3) deny-by-default: an unregistered tool is rejected immediately, with no retry
③ Context explosion Tool results, history, and intermediate thinking blow the context up No windowing; tool results are not trimmed; old steps are not summarized (1) Graded trimming of tool results (see context-engineering.en.md §2.6.3); (2) periodic compaction of old steps; (3) sub-agent isolation, so a long-running task uses a child context window
④ Reward Hacking / Goal Misgen The agent meets the goal in form and violates the intent (delete tests so CI passes, or write a mock and pretend it is implemented) The verifier signal is incomplete or gameable; there is no structured feedback (1) The verifier has to be multi-signal (test pass + diff size + lint + behavior diff); (2) a second look with the Evaluator-Optimizer pattern; (3) HITL spot checks + a long-running audit

What Anthropic’s engineering experience adds up to (from production):

  1. ≤ 20 tools is the sweet spot. Past that, the rate at which the LLM picks the wrong tool rises sharply. Above 20, use a routing pattern and split the work into sub-agents
  2. The error message is a prompt. Write a tool error as an instruction to the LLM (“this failed because X. To fix, try Y”). Do not return a raw traceback
  3. Adding an evaluator has a higher ROI than making the agent cleverer. The evaluator can be a cheaper model, and it can catch 80% of silent failures
  4. Never skip the sandbox. Even when the agent “looks well behaved,” a shell means a sandbox. One hallucination is one incident

10. Security and the permission model

10.1 A deny-first permission architecture (the Claude Code pattern)

Claude Code’s default security posture is deny-first plus human escalation: deny rules override ask rules, ask rules override allow rules, and an unrecognized action escalates to the user rather than being let through quietly.

The concrete “independent layers of guardrails”:

  1. Permission rules (the user’s configured allow/deny lists)
  2. PreToolUse hooks (can intercept before a tool call)
  3. Auto-mode classifier (an extra classifier when auto mode is on)
  4. Shell sandboxing (an optional layer)

Any one layer can block an action. That is real defense in depth.

10.2 HITL vs HOTL

Mode Meaning Where it fits
HITL (human in the loop) A human must confirm before the critical step High risk (medical, finance, deleting data)
HOTL (human on the loop) A human is watching and does not block the run; they step in at the critical moment Medium risk (coding, content generation)
Fully autonomous Report only when the work is finished Low risk (data lookup, reports)

10.3 Approval fatigue: HITL’s invisible ceiling

Anthropic’s auto-mode data: users click approve on ~93% of permission prompts, without distinction.

So approval by itself has been made behaviorally unreliable. People habitually click yes. The conclusion:

10.4 Sandboxes: a full set of production configs

10.4.1 Five isolation tiers, compared

Option Isolation strength Startup latency Memory overhead Compatibility Fits
MicroVM (Firecracker / AWS Fargate / Kata) Strongest (its own Linux kernel + KVM hardware virtualization) ~125 ms < 5 MiB / VM Full Linux High-security production (running a stranger’s code)
gVisor Strong (the user-space Sentry kernel + syscall interception) ~50 ms ~15 MiB Most syscalls The balance, plus GPU workloads
Hardened container Medium (a shared host kernel + several restrictions) < 10 ms Negligible Full Code you wrote yourself
Plain Docker Weak (namespaces + cgroups only) ~10 ms Negligible Full Must not run untrusted LLM-generated code
Process-level (seccomp / chroot) Very weak < 1 ms 0 Full The last-resort backstop

The industry consensus (from e2b, Daytona, Modal, Vercel Sandbox, and the other mainstream options): a container alone is not enough. Move up to a microVM or to gVisor. Nearly 30 years of Linux kernel attack surface is a sieve against LLM-generated code. One namespace-escape CVE jumps from the sandbox to the host.

10.4.2 Firecracker (the microVM from AWS)

Architecture: each sandbox is its own Linux kernel plus a full init process, running under KVM hardware virtualization. To get host root, an attacker first has to break through the kernel, the KVM hypervisor, and the Firecracker VMM — three layers.

A minimal boot config:

# 1. 准备 kernel 和 rootfs
wget https://s3.amazonaws.com/spec.ccfc.min/img/quickstart_guide/x86_64/kernels/vmlinux.bin
wget https://s3.amazonaws.com/spec.ccfc.min/img/quickstart_guide/x86_64/rootfs/bionic.rootfs.ext4

# 2. 启动 Firecracker
firecracker --api-sock /tmp/firecracker.sock &

# 3. 配置 microVM(curl REST API)
curl -X PUT --unix-socket /tmp/firecracker.sock http://localhost/boot-source \
  -H 'Content-Type: application/json' \
  -d '{"kernel_image_path":"./vmlinux.bin","boot_args":"console=ttyS0 reboot=k panic=1"}'

curl -X PUT --unix-socket /tmp/firecracker.sock http://localhost/drives/rootfs \
  -d '{"drive_id":"rootfs","path_on_host":"./bionic.rootfs.ext4",
       "is_root_device":true,"is_read_only":false}'

# 资源限制(必填)
curl -X PUT --unix-socket /tmp/firecracker.sock http://localhost/machine-config \
  -d '{"vcpu_count":1,"mem_size_mib":256}'

# 网络(强烈建议默认拒绝出网)
curl -X PUT --unix-socket /tmp/firecracker.sock http://localhost/network-interfaces/eth0 \
  -d '{"iface_id":"eth0","host_dev_name":"tap0"}'

# 启动
curl -X PUT --unix-socket /tmp/firecracker.sock http://localhost/actions \
  -d '{"action_type":"InstanceStart"}'

What it takes to run this in production:

E2B, Daytona, and Modal are all Firecracker wrappers inside, which saves you from operating the cluster yourself:

# E2B(最常用 LLM agent sandbox)
from e2b_code_interpreter import Sandbox
with Sandbox.create(timeout=30) as sbx:        # ★ 必须设 timeout
    result = sbx.run_code("print(2+2)")

10.4.3 gVisor (Google’s user-space kernel)

Architecture: a user-space process, Sentry, sits between the application and the host kernel, intercepts every syscall, and reimplements it in user space. The application looks like it is running on Linux. It can only call the subset Sentry implements.

Compared with Firecracker:

A minimal config (OCI runtime):

# 1. 安装 gVisor runsc
curl -fsSL https://gvisor.dev/archive.key | sudo gpg --dearmor -o /usr/share/keyrings/gvisor-archive-keyring.gpg
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/gvisor-archive-keyring.gpg] https://storage.googleapis.com/gvisor/releases release main" | sudo tee /etc/apt/sources.list.d/gvisor.list > /dev/null
sudo apt update && sudo apt install -y runsc

# 2. 把 runsc 注册为 Docker 的 runtime
sudo runsc install
sudo systemctl restart docker

# 3. 跑容器时指定 runtime
docker run --runtime=runsc --rm -it python:3.12 python -c "print('hello from gVisor')"

Kubernetes integration (RuntimeClass):

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: gvisor
handler: runsc
---
apiVersion: v1
kind: Pod
metadata:
  name: agent-sandbox
spec:
  runtimeClassName: gvisor   # ★ 这个 pod 跑在 gVisor 里
  containers:
  - name: code-runner
    image: python:3.12
    resources:
      limits: {memory: "256Mi", cpu: "500m"}

10.4.4 A hardened container (when Docker is all you have)

When this applies: you are running code you wrote (trusted), and you only need to stop accidental damage. Do not run untrusted LLM-generated code in a hardened container. Community consensus has already rejected that.

The minimum hardening config (every item is required):

docker run \
  --rm \
  --user 1000:1000 \                        # 非 root
  --read-only \                              # 文件系统只读
  --tmpfs /tmp:size=64m,noexec \             # 临时空间不可执行
  --cap-drop ALL \                           # 丢掉所有 capabilities
  --security-opt no-new-privileges \         # 禁止 setuid
  --security-opt seccomp=./seccomp.json \    # 自定义 syscall 白名单
  --security-opt apparmor=docker-default \   # AppArmor profile
  --network=none \                           # 默认无网
  --pids-limit 64 \                          # 进程数上限
  --memory 256m \                            # 内存上限
  --cpus 0.5 \                               # CPU 上限
  --memory-swap 256m \                       # 禁用 swap
  python:3.12 python /code/script.py

Rootless Docker / Podman also runs the Docker daemon inside a user namespace, which takes one more layer off the attack surface.

A custom seccomp allowlist (deny every syscall except those explicitly allowed):

{
  "defaultAction": "SCMP_ACT_ERRNO",
  "syscalls": [
    {"names": ["read", "write", "openat", "close", "fstat", "mmap", "munmap",
               "brk", "rt_sigaction", "rt_sigprocmask", "ioctl", "exit_group",
               "execve", "wait4", "uname", "fcntl", "lseek", "stat", "newfstatat"],
     "action": "SCMP_ACT_ALLOW"}
    /* 拒绝:socket, connect, ptrace, mount, kexec_load, init_module, ... */
  ]
}

10.4.5 How to choose, and how deep the defense goes

你跑什么代码?
│
├─ 陌生人/LLM 生成的 untrusted code
│   ├─ 需要 GPU / 兼容更好    → gVisor
│   └─ 极致隔离/合规           → Firecracker microVM
│
├─ 你自己写的代码 + 防意外
│   └─ 加固容器(rootless + seccomp + cap-drop + read-only)
│
└─ 测试/开发              → 普通 Docker(不要进生产)

Defense in depth: 5 layers (if one gives way, another is still there):

1. ┌───────────────────────────┐
   │  Network egress allowlist │ ← 默认拒绝出网,仅放行 GitHub/PyPI 等
   └───────────────────────────┘
2. ┌───────────────────────────┐
   │  Resource quota(CPU/MEM) │ ← 防 fork bomb / OOM
   └───────────────────────────┘
3. ┌───────────────────────────┐
   │  Time / step / cost cap   │ ← 防 Loop of Death (§9.1)
   └───────────────────────────┘
4. ┌───────────────────────────┐
   │  Sandbox isolation         │ ← Firecracker / gVisor
   └───────────────────────────┘
5. ┌───────────────────────────┐
   │  Audit log + alerting     │ ← 异常 syscall / 出网 / 高 cost
   └───────────────────────────┘

10.4.6 Mainstream commercial and open-source choices

Service Underneath How you attach Price
E2B Firecracker Python/TS SDK, the easiest to attach Free, plus per vCPU-minute
Modal gVisor + Firecracker A Python decorator Billed per GPU-second
Daytona Firecracker Dev-container style Open source + cloud
Vercel Sandbox Firecracker Native to the Next.js ecosystem Monthly
AWS Fargate / Lambda Firecracker AWS-native Usage-based
Together Code Sandbox gVisor API Per call
CodeSandbox Firecracker A dev IDE Free + a subscription

Practical experience: start a new project on E2B or Modal, and skip the 4–6 weeks of operating your own Firecracker cluster. Revisit self-hosting once you are at scale.

10.5 Where the industry is heading

The industry is moving toward selective autonomy, not fully unsupervised autonomy.

What that means: the same agent should have a different autonomy level on different actions. Reading a README can be fully autonomous. Running tests can be auto-approved. Editing a file needs review. Deleting a file needs a second human confirmation. Operating a production database stays deny-first.

10.6 Tool-design practice (the hidden factor in agent accuracy)

How well the tools are designed directly sets agent accuracy. Plenty of teams grind on the prompt and the framework and get nowhere; rewriting how the tools are described lifts accuracy by 20%+.

Five hard rules

1. Name it “verb + noun + object”

❌ search() / get_data() / process()
✅ search_github_issues(repo, query)
   list_pending_orders_by_user(user_id)
   send_slack_message_to_channel(channel, text)

When the LLM picks a tool, it mostly looks at the name. A vague name means low recall.

2. Write the description as “when to use it / when not to use it”

@tool
def cancel_order(order_id: str, reason: str) -> dict:
    """取消未发货的订单。

    何时用:
    - 用户明确要求取消订单
    - 订单状态为 pending / preparing
    - 用户已经登录验证

    何时不用:
    - 订单已发货(用 request_return 走退货流程)
    - 用户未登录(先走 require_login)
    - 仅是询问订单状态(用 get_order_status)

    参数:
    - order_id: 订单 ID(如 'ORD-12345')
    - reason: 取消原因(用户提供的文本)

    返回:
    - {"status": "cancelled" | "failed", "refund_amount": float, "message": str}

    错误:
    - OrderNotFound: 订单不存在 → 让用户检查 ID
    - OrderAlreadyShipped: 已发货 → 引导走 request_return
    """

3. The parameter schema is strict, and it has examples

Use Pydantic / JSON Schema, with strong types:

from pydantic import BaseModel, Field
from typing import Literal

class CancelOrderInput(BaseModel):
    order_id: str = Field(..., description="订单 ID,格式 'ORD-数字'", pattern=r"^ORD-\d+$",
                          examples=["ORD-12345"])
    reason: str = Field(..., description="取消原因", min_length=2, max_length=200,
                        examples=["用户改变主意", "找到更便宜的"])
    notify_user: bool = Field(True, description="是否通知用户")

The examples field materially helps the LLM choose arguments and format them.

4. An error return should tell the model what to do next

# ❌ 不够
return {"error": "OrderNotFound"}

# ✅ 引导式
return {
    "error": "OrderNotFound",
    "message": "订单 ORD-12345 不存在",
    "suggestions": [
        "用 list_user_orders(user_id) 列出该用户所有订单",
        "提示用户检查订单号格式",
    ],
}

When the LLM sees suggestions, it tries the next step on its own, which avoids a Loop of Death.

5. A cap on tool count: do not give a single agent more than 20 tools

The probability that an LLM picks the wrong tool rises sharply once there are more than 20 tools (research shows accuracy dropping 20%+ at 40+ tools). The production pattern:

Tool-design anti-patterns (real production incidents)

Anti-pattern What actually happened The fix
One query_database(sql) handed to the LLM The LLM writes dangerous SQL, and a table gets dropped Split it into dedicated tools such as lookup_user_by_email and get_order_status
Tool names that are synonyms (fetch_user + get_user) The LLM picks at random, and the results are inconsistent Merge them
Long results are not truncated 10K rows come back, and the context blows up Cap on the server, and add pagination
No timeout The tool hangs, so the agent hangs Force a 30s timeout
Side effects are undeclared The model calls it as if it were read-only, and something gets modified The description states “this modifies X”, and add require_confirmation
A long JSON result nested 7 levels deep The LLM cannot parse it Flatten it, and add a summary field

Tool-set design checklist


11. Where the agent sits in the four engineering layers

Put the agent back into the picture of the four engineering layers:

┌─────────────────────────────────────────────────────────────┐
│ Harness Engineering(驾驭工程,第 4 层)                     │
│   工具集成 / 沙箱 / 网关 / 推理 / 观测 / 评估 / 护栏        │
│   ─── 提供 agent 运行的"环境与约束"                          │
├─────────────────────────────────────────────────────────────┤
│ Agent Engineering(Agent 工程,第 3 层)← 本章               │
│   范式 / 框架 / 多 agent / 评估 / 失败模式 / 安全权限        │
│   ─── 让 LLM 自主完成多步任务                                 │
├─────────────────────────────────────────────────────────────┤
│ Context Engineering(上下文工程,第 2 层)                   │
│   长上下文 / RAG / 记忆 / MCP                                │
│   ─── 提供 agent "看到什么"                                  │
├─────────────────────────────────────────────────────────────┤
│ Prompt Engineering(提示词工程,第 1 层)                    │
│   Transformer / 训练栈 / 解码 / CoT / ReAct / 自动化         │
│   ─── 提供 agent "怎么思考"的模板                            │
└─────────────────────────────────────────────────────────────┘

The four layers stack. Each one is still required:


12. What to do when you ship

12.1 A three-week path into agent engineering

12.2 A six-item checkup for an agent you already run

  1. ✅ Are there caps on max iterations, max tokens, max cost, and max time?
  2. ✅ Does every write (edit a file, delete data, send email) default to deny-first or to HITL?
  3. ✅ Is there a sandbox? Least privilege? An egress allowlist?
  4. ✅ Does a trace (every tool call and every LLM call) land on an observability platform?
  5. ✅ Does an automatic eval run regression? Is there a golden set?
  6. ✅ Has there been an incident? Was there a postmortem, and were new rules added? (This is the core practice of harness engineering.)

12.3 Three things not to do


Bibliography

Agent paradigms and papers

Agent architecture and frameworks (2026)

Multi-agent collaboration

Agent benchmarks

Real agent products

Agent failure modes and security


13. A complete end-to-end agent: customer support with RAG, memory, and guardrails

The concepts above, wired together. Below is a production-grade minimal skeleton: LangGraph + tools + retrieval + memory + a max-iteration cap + a cost cap + observability.

from typing import TypedDict, Annotated, Sequence
from langgraph.graph import StateGraph, END
from langgraph.graph.message import add_messages
from langchain_anthropic import ChatAnthropic
from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, SystemMessage
from langchain_core.tools import tool
from mem0 import Memory
import langfuse_callback  # observability
import time

# ============ State ============
class AgentState(TypedDict):
    messages: Annotated[Sequence[BaseMessage], add_messages]
    user_id: str
    iterations: int
    total_cost_usd: float
    started_at: float

# ============ 工具:知识库检索 ============
@tool
def kb_search(query: str) -> str:
    """检索企业知识库回答用户问题"""
    # 调 §2.4 RAG pipeline,省略
    return rag_chain.invoke({"input": query})["answer"]

@tool
def create_ticket(user_id: str, summary: str, severity: str) -> str:
    """无法回答时创建工单。severity: low/medium/high/critical"""
    if severity == "critical":
        # critical 必须 HITL,不允许 agent 自主创建
        return "ERROR: critical 工单需人工创建"
    ticket_id = ticket_system.create(user_id, summary, severity)
    return f"工单 {ticket_id} 已创建"

# ============ 长期记忆 ============
memory = Memory.from_config({"vector_store": {"provider": "qdrant"}})

# ============ LLM + 工具绑定 + observability ============
llm = ChatAnthropic(
    model="claude-sonnet-4-6",
    callbacks=[langfuse_callback.LangfuseCallback()],
).bind_tools([kb_search, create_ticket])

# ============ Guardrail:输入侧(伪代码)============
def input_guardrail(messages):
    last_user = messages[-1].content
    if guardrail.detect_prompt_injection(last_user):
        raise ValueError("输入触发 prompt injection 防护")
    if guardrail.contains_pii(last_user):
        last_user = guardrail.redact_pii(last_user)
        messages[-1] = HumanMessage(content=last_user)
    return messages

# ============ Agent 节点 ============
def agent_node(state: AgentState):
    # 1. 输入 guardrail
    messages = input_guardrail(state["messages"])

    # 2. 注入历史记忆
    user_memories = memory.search(query=messages[-1].content, user_id=state["user_id"])
    memory_context = "\n".join([m["text"] for m in user_memories[:5]])
    sys_msg = SystemMessage(content=f"你是 ACME 公司客服。用户历史:\n{memory_context}")

    # 3. LLM 决策(思考 + 工具调用)
    response = llm.invoke([sys_msg] + list(messages))

    # 4. 更新成本(每个 provider 都返回 token usage)
    cost = response.response_metadata.get("usage", {}).get("total_cost_usd", 0)

    return {
        "messages": [response],
        "iterations": state["iterations"] + 1,
        "total_cost_usd": state["total_cost_usd"] + cost,
    }

# ============ 工具节点 ============
from langgraph.prebuilt import ToolNode
tool_node = ToolNode([kb_search, create_ticket])

# ============ 流程控制 ============
def should_continue(state: AgentState):
    # ★★★ Loop of Death 防御:四道闸门 ★★★
    if state["iterations"] >= 10:
        return END  # max iter cap
    if state["total_cost_usd"] >= 0.50:
        return END  # cost cap $0.5/会话
    if time.time() - state["started_at"] >= 60:
        return END  # 超时 60s
    last_msg = state["messages"][-1]
    if not last_msg.tool_calls:
        return END  # 没新工具调用 = 完成
    return "tools"

# ============ 构图 ============
graph = StateGraph(AgentState)
graph.add_node("agent", agent_node)
graph.add_node("tools", tool_node)
graph.set_entry_point("agent")
graph.add_conditional_edges("agent", should_continue, {"tools": "tools", END: END})
graph.add_edge("tools", "agent")

# ============ 编译(带 checkpoint 支持 HITL)============
from langgraph.checkpoint.memory import MemorySaver
app = graph.compile(checkpointer=MemorySaver())

# ============ 运行 ============
config = {"configurable": {"thread_id": "session_42"}}
result = app.invoke(
    {
        "messages": [HumanMessage(content="我的订单 #12345 还没收到,请帮查")],
        "user_id": "u_abc",
        "iterations": 0,
        "total_cost_usd": 0.0,
        "started_at": time.time(),
    },
    config=config,
)

# 把这次会话沉淀到长期记忆
memory.add(messages=result["messages"], user_id="u_abc")

This 100-line skeleton already has the core pieces of a production agent:

Piece Where it is implemented
The LLM + tool loop (ReAct) agent_node + tool_node
Long-term memory memory.search / memory.add (Mem0)
A RAG knowledge base the kb_search tool
An input guardrail input_guardrail
Four Loop of Death gates should_continue (max iterations + cost cap + timeout + a completion check)
HITL (critical tickets) a forced raise inside the create_ticket tool
Checkpoint / pause and resume MemorySaver
Observability LangfuseCallback
Cost tracking a running total in total_cost_usd

What you still add before this is production: automated eval (DeepEval / RAGAS), an A/B test, a staged rollout, a PagerDuty alert hookup, compliance logs, and an output guardrail for sensitive terms.


14. A systematic GitHub reading list (the agent track)

Resource Kind How to use it
microsoft/ai-agents-for-beginners A 12-lesson introduction A complete start for newcomers. Each lesson has runnable code samples, paired with the Microsoft Agent Framework
microsoft/agent-framework The official framework The successor to AutoGen. Python + .NET, for enterprise agent orchestration
datawhalechina/hello-agents A systematic Chinese tutorial (42K ⭐) From principles, to implementation, to agentic RL. The most systematic treatment in the Chinese-language community
anthropic/Building-Effective-Agents Anthropic’s official essay The original source of the six patterns in §3.4. Required reading
jcran/effective-agents-langchain A LangChain implementation The LangChain code version of Anthropic’s six patterns
langchain-ai/langgraph Official LangGraph The mainstream production agent framework. The documentation is very thorough
crewAIInc/crewAI Official CrewAI A role DSL. The fastest to get running
openai/openai-agents-python The OpenAI Agents SDK Official OpenAI. The handoff philosophy
huggingface/smolagents Smolagents A few hundred lines of core code. The most minimal implementation
mastra-ai/mastra Mastra TypeScript-native. The first choice for a JS/TS project
philschmid/ai-agent-benchmark-compendium A compendium of 50+ benchmarks When you are looking for a test of one specific capability
vectara/awesome-agent-failures A collection of failure modes The negative examples to read before you write a production agent

Papers to read (in time order):


Cross-references


Glossary

Concepts marked [term] in the answers jump to the matching entry in this table and expand it. The table groups 60+ high-frequency terms under 10 topics and is collapsed by default — expand a term only when you don’t know it, and read the short explanation, so you are not buried in information.

Software engineering fundamentals

lint Software engineering — a static code checker that scans source for potential bugs and style problems

Analyze source without actually running it, and flag potential bugs, unused variables, style violations, and suspicious usage. Common tools:

In agent engineering, lint is often used as a hard constraint in the harness — feeding lint errors back to the model to rewrite the code is much more reliable than merely saying “please follow the coding standards” in the prompt (Augment Code calls this a Constraint Harness).

type check / type checking Software engineering — check that the types of variables, parameters, and return values match

Make sure types are consistent across assignments and function calls:

For an agent: after the agent finishes writing code, force a run of tsc --noEmit / mypy . / cargo check, and feed type errors back to the model to keep fixing. That is much more reliable than letting the agent “claim it checked the types” — a typical practice of harness engineering.

CI/CD Software engineering — continuous integration / continuous deployment pipelines

CI (Continuous Integration): on every commit, automatically run tests, builds, lint, type check, and other checks. CD (Continuous Deployment): after the checks pass, automatically deploy to test / staging / production.

Common tools: GitHub Actions, GitLab CI, Jenkins, CircleCI, Buildkite.

In agent engineering, CI is the most important deterministic feedback source — an LLM’s self-assessment is unreliable, but CI pass/fail is a 0/1 signal and can be used directly as ground truth. Hashimoto’s harness engineering stresses that whether a problem gets solved is strongly tied to whether the agent can verify its own work.

sandbox / sandbox Software engineering — an isolated code-execution environment that limits access to external resources

Run untrusted code (user uploads, LLM-generated code) in a restricted environment so it cannot damage the host. Isolation strength, from weak to strong:

An agent that runs user- or LLM-generated code must be sandboxed, with defense in depth on top: a network-egress allowlist + a read-only filesystem + time/memory quotas + no host credentials mounted.

canary / canary release Software engineering — send a small slice of traffic to the new version first, and roll out fully only after nothing looks wrong

The name comes from using canaries in coal mines to detect poison gas. A typical deploy sequence is: shadow (dual-run, do not return the result) → 1% → 5% → 25% → 50% → 100%, and each stage advances only if the core metrics show no regression.

For LLM applications, a new prompt / new model / new agent harness must go out through a canary. If any key metric (resolution rate, CSAT, refusal rate, p99 latency, cost per request) worsens past a threshold, roll back. The non-determinism of LLM applications makes canaries more important than they are for traditional software.

A/B test Software engineering — a controlled experiment that splits traffic into two groups, one on the old version and one on the new, and compares key metrics

Hash on user_id to split traffic so a given user always lands in the same bucket (avoiding a flickering experience). What to judge:

Prompt changes, model swaps, and RAG changes in an LLM application should all go through an A/B test. Shipping on offline eval alone often fails in production (the live traffic distribution differs a lot from the gold set).

GMV / UV / CSAT / NPS / conversion rate Business metrics — the north-star metrics most often used in e-commerce / travel / customer support

The metrics the business side watches most closely when deciding whether an agent should launch:

What agent engineering watches: put model / prompt / RAG changes into an A/B test and look at these business metrics, not only offline benchmark scores. It is very common for a change to raise the benchmark while GMV / CSAT fall.

HITL / human-in-the-loop Software engineering — bring a human in to review or confirm at critical decision points

Pause an autonomous agent at a critical node and wait for a human:

Design principle: “Humans steer. Agents execute.” (OpenAI Harness Engineering). An agent does not replace a person; it amplifies a person’s judgment — the person sets the plan, sets the constraints, and reviews the result, and the agent does the execution.

SLO / SLI / SLA / Error Budget Software engineering — the SRE quartet of “objective / indicator / contract / budget” for service quality

Four terms defined by Google’s SRE practice:

How to use this for an agent application:

  1. Set 1–3 SLOs per agent scenario: for example “customer-support agent resolution-rate SLO = 85%”, “p99 end-to-end latency SLO ≤ 5s”, “average cost per task SLO ≤ $0.05”
  2. Alert: warn when the live SLI drops below 80% of the SLO, and page oncall when it drops below the SLO
  3. Freeze releases: once the error budget is burned, do not merge anything that is not an emergency fix
  4. Business SLO vs technical SLO: business SLOs (conversion rate / CSAT / GMV) are product acceptance; technical SLOs (latency / error rate / cost) are the engineering backstop. Both layers are required

Rule of thumb: a stricter SLO is not automatically better — 99.99% costs 5–10× more than 99.9%, and it is likely past the threshold users can perceive. Google recommends the level that is just high enough that users don’t complain.

TTL / Time To Live Software engineering — how long data, a cache entry, or a credential stays valid

It expires automatically. Common uses:

LLM fundamentals

token LLM basics — the smallest input/output unit of an LLM, produced by a tokenizer

A rule-of-thumb conversion: 1000 English words ≈ 1300 tokens; 1000 Chinese characters ≈ 1500–2000 tokens.

Why it matters: the context window, API billing, and inference speed are all counted in tokens. Controlling the token count = controlling cost and latency. Anthropic, OpenAI, and Google each have their own tokenizer, and a ±20% difference in token count for the same text is common.

embedding LLM basics — map text or an image to a high-dimensional dense vector; semantically similar vectors sit close together

Text → a neural network → a vector of 768 / 1024 / 1536 / 3072 floating-point numbers. Vectors for synonyms or same-topic text sit close together in that space (high cosine similarity).

Main uses:

Mainstream models in 2026: OpenAI text-embedding-3-large, Cohere v4, Voyage-3, BGE-M3 (open-source SOTA; Chinese–English bilingual, combining dense / sparse / multi-vector).

context window / context window LLM basics — the token limit a model can process in one call

It includes the system prompt, conversation history, user input, and model output; all of them count. Mainstream models in 2026:

Note: the advertised window ≠ the effective window. The RULER benchmark shows that most models’ performance drops sharply beyond 1/4 of the window (Lost in the Middle). Engineering guidance sets the threshold for “what should go into context” at 8–32k; anything longer goes through RAG or hierarchical summarization.

prefill / decode LLM basics — the two phases of LLM inference: process the input, then generate token by token

The two phases have different bottlenecks, so the tuning strategies differ too — prefill is optimized with parallelism / FlashAttention, and decode is optimized with continuous batching / speculative decoding. Because the two phases have opposite characteristics, engineering also uses two kinds of scheduling optimization: PD disaggregation (Prefill/Decode Disaggregation, handling the phases on different GPU pools, as in DistServe/Mooncake) and chunked prefill (split a long prefill into chunks and interleave them with decode). See A11 for detail.

KV cache LLM basics — a cache of the K (Key) and V (Value) matrices already computed for attention

Generating token t needs the K/V of every earlier token in the attention computation. Caching them so they are not recomputed every time is the most basic optimization in LLM inference.

Memory use: 2 × num_layers × num_heads × head_dim × seq_len × batch × bytes_per_elem. On a 70B model, the KV cache for a 128k context can reach tens of GB, far more than the model weights themselves.

Further optimizations:

autoregressive / autoregressive LLM basics — generate one token at a time; the next token depends on every token before it

How GPT-style decoder-only models generate: P(x_t | x_1, ..., x_{t-1}). Every generated token runs a full forward pass (even though the KV cache can be reused), so output length directly determines latency.

By comparison: BERT is non-autoregressive (masked LM: it predicts every masked position at once), and diffusion models are also non-autoregressive (they denoise the whole span in one shot).

The cost of autoregression produced a large family of speedups: speculative decoding, parallel decoding, Medusa, EAGLE, and others.

logit LLM basics — the model’s raw unnormalized scores, one value per vocabulary token

The last decoder layer outputs a logit vector of dimension [vocab_size]; after softmax it is the probability distribution of the next token.

Places engineering can get the logits (or top-k logprobs):

Note: commercial OpenAI / Anthropic APIs return only the sampled result by default; you have to turn the logprobs option on explicitly.

temperature LLM basics — a hyperparameter that controls sampling randomness; 0 = deterministic, >1 = highly random

P(token) ∝ exp(logit / T):

Turn it up when: Self-Consistency needs diverse paths, creative writing, brainstorming. Turn it down when: code generation, math reasoning, strict formatted output, T=0.1–0.3.

Trap: T=0 is not fully identical to deterministic — non-determinism of floating-point GPU kernels plus concurrent scheduling can still leave tiny differences for the same prompt.

attention sink LLM basics — the phenomenon where the model concentrates a large share of attention on the first few tokens of the sequence

Xiao et al. 2023 found that during long-sequence inference, later tokens often assign a disproportionate share of attention to the first few tokens of the sequence (even when those tokens are semantically unrelated). Those tokens become a “sink” and absorb the normalization mass that softmax is required to distribute.

Why it matters in engineering:

Transformer architecture

LayerNorm / RMSNorm Architecture — the mainstream normalization layers in Transformers; normalize a single sample along the feature dimension

LayerNorm: y = (x - μ) / σ * g + b, mean and variance taken along the hidden dimension. Independent of the batch, so it naturally supports variable-length sequences and single-example inference — which is why Transformers use LayerNorm rather than BatchNorm.

RMSNorm (Zhang & Sennrich 2019): y = x / sqrt(mean(x²)+ε) * g, dropping the mean subtraction and the bias. Modern LLMs such as Llama, PaLM, and Mistral have almost all switched to RMSNorm, saving 7–64% of normalization time without hurting quality.

Pre-LN vs Post-LN: doing LN before the residual (Pre-LN) trains more stably than doing it after the residual (Post-LN), and warmup can be dropped. From GPT-2 onward, Pre-LN is nearly universal.

RoPE / Rotary Position Embedding Architecture — rotary position embeddings; encode position into a rotation matrix applied to Q/K

Su et al. 2021. Represent position m as a rotation matrix R_m applied to Q/K, so that <R_m·q, R_n·k> = f(q, k, m-n) — the attention score depends only on relative distance.

Advantages: (1) no extra parameters; (2) relative position is encoded naturally; (3) compatible with linear attention. It has become the position-encoding scheme of the great majority of modern LLMs, including Llama, Qwen, and Mistral.

The extrapolation problem: naive extrapolation from 2k to 32k collapses — the rotation angles of high-frequency components fall into regions never seen in training. Mitigations:

NTK-aware scaling / YaRN Architecture — RoPE length-extrapolation schemes that let a model trained at 2k run a 32k / 128k context

Naive extrapolation of RoPE collapses — the rotation angles of high-frequency components fall into regions never seen outside the training context. Two engineering schemes:

Where they are used:

Numbers from practice: YaRN is nearly lossless at a 4× context extension (2k→8k or 32k→128k); beyond 8× there is still a performance drop. Extreme long context (1M+) usually needs retraining rather than YaRN alone.

GQA / MQA Architecture — Grouped/Multi Query Attention; several Q heads share one set of K/V heads

Standard multi-head attention: each of the H heads has its own Q/K/V.

The gain: the KV cache shrinks to 1/8 ~ 1/H, inference throughput rises substantially, and quality is almost unchanged. Llama-2 70B, Llama-3, Mistral, Qwen2, and others use GQA.

MoE / Mixture of Experts Architecture — a mixture-of-experts model; each token activates only some of the expert FFNs

Replace the traditional dense FFN with N parallel expert FFNs plus a router. Each token picks the top-k experts through the router (k is usually 1–2) and only those experts are activated for the compute.

Advantage: a large parameter count with little compute. Mixtral 8x7B has 47B total parameters and only 13B activated; DeepSeek-V3 has 671B total parameters and only 37B activated. At the same inference cost, capacity far exceeds a dense model.

Challenges: (1) load balancing during training (so one or two experts are not overused); (2) memory is counted by total parameters, not activated parameters; (3) communication cost is high (expert parallelism).

multi-head attention / multi-head attention Architecture — split d_model into h independent Q/K/V projections; each head learns relations in a different subspace

Single-head attention produces one attention distribution for each pair of tokens — one “relational viewpoint”. Multiple heads (h=8/32/64/128) let the model learn several relations at once: syntactic heads attend to short-range dependencies, and semantic heads attend to coreference and long-range entities.

Why a single head with a larger dimension does not work: multi-head is a mixture of h low-rank attentions and is strictly more expressive; a single head is one high-rank attention and has fewer degrees of freedom.

A further variant: GQA / MQA drops heads on the KV side to save memory, while the Q side stays multi-head.

Inference acceleration

FlashAttention Inference acceleration — attention computed with tiling + online softmax, without materializing the full attention matrix

Dao 2022. Standard attention uses O(N²) memory (it stores an N×N attention matrix), which bottlenecks long sequences. FlashAttention loads Q/K/V in blocks into GPU SRAM for the compute and does not write out the full attention matrix. Memory drops to O(N), and it is also faster — attention is memory-bound, so reading less HBM makes it faster.

The line of work:

PagedAttention Inference acceleration — proposed by vLLM; manage the KV cache as fixed-size blocks, the way an OS manages virtual memory

Kwon et al. 2023. It addresses three kinds of fragmentation in the traditional inference KV cache:

Mechanism: cut the KV cache into fixed-size blocks (for example 16 tokens), and each sequence keeps a block table (a logical→physical mapping). Memory utilization rises from ~20% to >96%; multiple samples of the same prompt share prefix blocks; together with continuous batching, throughput is 2–4× HuggingFace TGI and 24× FasterTransformer.

vLLM Inference acceleration — UC Berkeley’s open-source high-throughput LLM inference engine, which implements PagedAttention

The de facto standard open-source inference server since 2023. Core features:

Compared with: TGI (HuggingFace), TensorRT-LLM (NVIDIA; proprietary and faster), SGLang (more thorough prefix reuse), LMDeploy (from OpenCompass).

continuous batching Inference acceleration — dynamic scheduling at token granularity; a request leaves as soon as it finishes, and a new request can join at any time

Also called in-flight batching, proposed by Yu et al., ORCA, 2022. Compared with static batching (wait until the batch is full and then run together; when short and long requests are mixed, GPU utilization is often <30%), continuous batching:

vLLM’s numbers: throughput is 5–23× static batching. It is now the default in every modern inference engine.

speculative decoding Inference acceleration — a small draft model quickly guesses K tokens, and the large model verifies them in parallel with one forward pass

Leviathan et al. 2023. The procedure:

  1. A small draft model (1–7B) autoregressively generates K tokens (K=5 is typical)
  2. The large target model (70B+) verifies K+1 positions in parallel with one forward pass
  3. The first j are accepted and the (j+1)th is rejected → keep the first j and sample one new token

Mathematically this guarantees the output distribution matches the original model exactly (rejection sampling).

When it pays off: (1) the draft and target distributions are similar (acceptance rate >60%); (2) the large model is memory-bandwidth bound, so parallel verification does not add latency. Acceptance rate is 70–90% for code generation and 30–50% for open-ended generation. Variants: EAGLE-2/3, Medusa, Llama 3.1 self-speculative.

prefix caching Inference acceleration — cache the KV cache of a shared prefix across requests and skip recomputing the prefill

The KV cache is reuse within a single request; prefix caching is reuse across requests. When many requests share a system prompt / few-shot examples / agent history, compute that KV once, cache it, and later requests hit the cache and skip prefill.

Effect: in agent / RAG / multi-turn settings, the system prompt is usually 1–4k tokens and shared by almost every request, so TTFT can drop 10–100×.

Implementations: vLLM --enable-prefix-caching, SGLang RadixAttention (a radix tree that automatically manages every historical prefix), the Anthropic prompt caching API (5-minute TTL; the cached portion is priced at 0.1×).

TTFT / Time to First Token Inference acceleration — latency from sending the request to the first token coming back

Driven mainly by prefill (processing every input token). One of the core metrics for billing and monitoring.

Ways to lower TTFT:

Companion metric: TPOT (time per output token, the gap between tokens, also called TBT/ITL) — determined by decode.

TPOT / Time Per Output Token Inference acceleration — average latency per generated token in the decode phase (also called ITL / TBT)

The other core latency metric, paired with TTFT: TTFT measures “how long until the first character appears” (determined by prefill), and TPOT measures “how fast each following character appears” (determined by decode). Perceived speed of streaming ≈ 1/TPOT (tokens/s).

Quantization

FP16 / BF16 / FP8 Quantization — low-precision floating-point formats that save memory and compute

Mixed-precision training: weights and gradients in BF16/FP16, optimizer state still in FP32.

INT4 / INT8 / NF4 Quantization — integer quantization that compresses FP16 weights to 4/8-bit integers

At deployment, quantize weights to low-bit integers and dequantize back to floating point for inference.

INT8 / INT4 quantization usually needs a calibration set (128–512 samples); AWQ is smarter (it protects the 1% salient channels). For extreme memory budgets, use GGUF (the llama.cpp format) plus 3-bit / 2-bit quantization to run on phones.

AWQ / Activation-aware Weight Quantization Quantization — INT4 weight quantization that protects the 1% salient channels

Lin et al. 2023. The core observation: protecting only ~1% of the “important weight channels” (identified by activation magnitude) is enough to hold accuracy. Scale those channels up per channel, then quantize.

Compared with GPTQ: simpler to implement, lower perplexity on Llama-2, and now the default in vLLM / TensorRT-LLM.

GPTQ Quantization — an earlier post-training 4-bit weight quantization method

Frantar 2022. Layer-wise minimization of quantization error, inspired by OBQ, with a small calibration set (128 samples). Pros: early, and the ecosystem is complete (exllama / vllm / TGI all support it). Cons: sensitive to the activation distribution; important channels can be crushed.

Deployment choices in 2026: H100/H200 → FP8; A100/3090 → AWQ INT4; phones/edge → INT4 + GGUF.

Fine-tuning and alignment

SFT / Supervised Fine-Tuning Fine-tuning — supervised fine-tuning: train the model on (prompt, response) pairs

The most basic form of instruction tuning: treat (input, desired output) pairs as supervised samples and use cross-entropy loss to teach instruction following.

Data volumes from practice:

The LIMA paper: 1000 curated samples can bring a 65B base close to GPT-4 conversation quality — quality >> quantity.

LoRA / Low-Rank Adaptation Fine-tuning — freeze the original weights and train only low-rank adapter matrices

Hu et al. 2021. Factor the weight update into two low-rank matrices ΔW = BA (r=8/16/64) and train only those matrices, cutting trainable parameters by 100–10000×.

Memory:

Advantages: few trainable parameters / multiple adapters can be hot-swapped / mitigates catastrophic forgetting.

QLoRA Fine-tuning — 4-bit quantized frozen weights plus a LoRA adapter; fine-tune a 65B model on a single 24GB GPU

Dettmers et al. 2023. Three key pieces:

  1. 4-bit NF4 quantization of the frozen weights: a 7B model shrinks from 14GB to ~4GB
  2. Double Quantization: quantize the quantization constants too, saving ~0.4 bit/param
  3. Paged Optimizer: NVIDIA unified memory; on OOM, spill to CPU

QLoRA for a 65B model is about 33GB and fits on one A100-48G or two RTX 3090s. Cost: training is 30–40% slower (dequantization overhead).

RLHF Alignment — Reinforcement Learning from Human Feedback: RL training from human preferences

Three steps: (1) SFT trains a base policy; (2) humans label (chosen, rejected) preference pairs to train a Reward Model; (3) the RM scores policy outputs, and algorithms such as PPO/RLOO/REINFORCE update the policy.

InstructGPT and ChatGPT brought RLHF into the mainstream. Three major pain points:

This produced simplifications and improvements such as DPO, GRPO, and RLVR.

RM / Reward Model Alignment — a “scoring model” trained on human preferences that scores LLM outputs

Trained in step two of RLHF. Input: (prompt, response). Output: a scalar reward. The training loss is Bradley-Terry: make the RM score chosen higher than rejected on (chosen, rejected) pairs.

Common weaknesses:

Alternatives: DPO removes the RM entirely, and RLVR uses a programmatically judged reward.

DPO / Direct Preference Optimization Alignment — a mathematical proof that you can skip the RM and optimize preferences with a supervised loss

Rafailov et al. 2023. It proves that under a Bradley-Terry preference model plus a KL constraint, the optimal policy has a closed form, so preference pairs (chosen, rejected) can be used directly as a supervised loss:

L_DPO = -log σ(β(log π(y_w)/π_ref(y_w) - log π(y_l)/π_ref(y_l)))

Advantages: (1) no RM / no online sampling / no critic; only the policy and a reference model; (2) uses the same training stack as SFT; (3) hyperparameters are stable.

Disadvantages: depends heavily on preference-data quality; easy to overfit surface patterns of the chosen answers; high reward-hacking risk.

The main post-training path for Llama-3 and Qwen2 is DPO or a variant (IPO, KTO, SimPO).

PPO / Proximal Policy Optimization Alignment — the classic RLHF algorithm: actor-critic plus a clipped objective

Schulman 2017. The actor learns the policy, the critic learns a value function to estimate advantage, and clipping limits how far the policy can move each step so it doesn’t collapse.

RLHF must load four models at once — actor / ref / critic / reward — so memory is ≥4× a single model. Hyperparameters are sensitive (KL coefficient, clip ratio, advantage normalization), and training is unstable.

This produced simplifications such as DPO (drop RL), GRPO (drop the critic), and RLOO (use mean reward as the baseline).

GRPO / Group Relative Policy Optimization Alignment — proposed by DeepSeek; drops the critic and uses the within-group mean reward as the baseline

Proposed in DeepSeek-Math 2024 and validated by R1. The core change: drop the critic (the value network). Sample G responses for the same prompt (typically G=64), normalize advantage by the within-group mean and standard deviation of the reward: A_i = (r_i - mean(r)) / std(r), then apply a PPO-like clipped objective plus KL regularization.

Effects:

RLVR / RL with Verifiable Rewards Alignment — RL with a programmatically judged 0/1 reward; no RM required

On tasks that can be checked automatically — math, code, formal logic — use a program as the reward: answer match, unit tests passing, a theorem prover verifying.

Advantages:

DeepSeek-R1 and DAPO (ByteDance’s open-source SOTA) are both in this family. Limitation: it applies only to verifiable tasks; open-ended dialogue still needs RLHF / DPO.

catastrophic forgetting / catastrophic forgetting Fine-tuning — after fine-tuning on a new task, general capability drops sharply

Mechanism: parameters are pulled by the new task’s loss, and directions that encoded general knowledge get overwritten.

A mitigation mix (recommended in production):

Advanced: EWC (Fisher-information-weighted L2 regularization), model souping (average the fine-tuned weights with the original model), and extending MoE routing.

Prompting and reasoning patterns

CoT / Chain of Thought Prompting — have the model write reasoning steps before the answer

Wei et al. 2022. The simplest form: “Let’s think step by step” (Kojima 2022 zero-shot CoT).

Why it works: (1) more effective compute (more forward steps); (2) it turns “System 1” intuitive answers into “System 2” step-by-step reasoning; (3) it exposes faulty reasoning so self-consistency voting can correct it.

It is an emergent ability and is almost useless on models under 10B. Long CoT (trained with RL in R1 / o1, including backtracking and self-verification, thousands of tokens long) is the new paradigm of 2025.

ToT / Tree of Thoughts Prompting — model reasoning as tree search: several candidates per step, plus self-evaluation and backtracking

Yao et al. 2023. CoT is a single linear chain and cannot go back once it is wrong. ToT generates several candidate thoughts at each step, the LLM self-evaluates state value (promising / sure / impossible), and BFS/DFS expansion can backtrack and prune.

On Game of 24, GPT-4 CoT scores 4% vs ToT 74%. Cost: LLM calls rise from 1 to 50–200.

Fits: solution spaces that need explicit search (puzzles, planning, theorem proving) where intermediate states can be scored. Does not fit: chitchat, summarization, translation.

ReAct Prompting — Reasoning + Acting: a think–act–observe loop

Yao et al. 2022. The structure is a Thought → Action → Observation loop: the model first writes “Thought: I need to look up X”, then outputs “Action: search[X]”, the tool result is fed back into the prompt as “Observation: …”, and the next Thought follows.

Three effects:

It is the conceptual prototype of modern agent frameworks (Claude tool use, OpenAI function calling, LangChain, AutoGPT).

Reflexion Prompting — “verbal reinforcement learning” across episodes: store the reason for failure as a lesson

Shinn et al. 2023. After a task fails (an external verifier gives a binary reward), the agent uses an LLM to summarize the cause as a natural-language lesson, stores it in episodic memory, and adds that lesson to the prompt on the next task to change behavior.

vs Self-Refine:

On HumanEval, GPT-4 with Reflexion scores 91%, above the GPT-4 baseline of 80%.

Self-Refine Prompting — iteration inside a single task: a generate → self-feedback → refine loop

Madaan et al. 2023. Loop N rounds inside one trajectory, with no external reward and no cross-task memory. Average gain of 20% across 7 tasks.

Trap: a weak model’s self-critique is inaccurate and revisions can get worse. Production often combines Self-Refine (within an episode) with Reflexion (across episodes).

self-consistency Prompting — sample N CoT traces for the same question and majority-vote the final answer

Wang et al. 2022. With temperature>0, sample N CoT paths and vote on the final answer. On GSM8K this is about 17 percentage points above greedy CoT (PaLM 55%→74%).

Pays off when: (1) the answer space is discrete (numbers, multiple choice); (2) the model’s error rate is <50%; (3) reasoning paths are diverse (temperature 0.7–1.0). Cost: N× (typically N=5–40). It does not apply to open-ended generation.

few-shot / zero-shot Prompting — whether the prompt includes examples

When to use few-shot: (1) the task format is novel or the output structure is complex (a JSON schema, a specific markdown layout); (2) a classification task has many labels.

When to use zero-shot: modern models are already saturated on general tasks (summarization, translation, QA), and adding examples can introduce bias.

Traps: example order matters a lot (recency bias); accidental regularities get learned; too many examples run into Lost in the Middle. Keep it to ≤8.

RAG

RAG / Retrieval-Augmented Generation RAG — retrieval-augmented generation: retrieve relevant documents first, then have the LLM answer from that context

The standard pipeline = Ingestion + Retrieval + Generation:

  1. Ingestion: document loader → chunking → embedding → write to the vector store
  2. Retrieval: query rewriting → embedding → vector search → reranker → top-k
  3. Generation: build the prompt (including retrieved chunks) → LLM generation → post-processing + citation

Every stage has a bottleneck: chunk size, embedding choice, insufficient recall, context order, and the model not staying faithful to the context. Production RAG ≠ “embedding + a vector store + an LLM” — it is an engineering system.

chunking RAG — split a document into small pieces suitable for embedding / retrieval

Strategies:

BM25 RAG — the classic sparse retrieval algorithm based on term frequency plus IDF

Okapi BM25. Relevance of a document to a query is Σ IDF(qi) · f(qi,d) · (k+1) / (f + k·(1-b+b·|d|/avgdl)). Strengths: exact term hits, high weight on rare terms, proper nouns, numbers. Weakness: synonyms don’t match (“医生” vs “doctor”).

It complements dense embeddings — hybrid search fuses the two, and recall is 5–15 percentage points above dense alone.

reranker / cross-encoder RAG — rescore the recalled top-N with a more accurate (and slower) model

Bi-encoder (embedding): encode the query and the doc separately, then compare by cosine. Fast, but there is no interaction. Cross-encoder (reranker): concatenate query + doc and feed them to a transformer; self-attention at every layer lets them interact. Relevance modeling is 20–40% stronger (NDCG@10), and it is 100× slower.

The production standard: bi-encoder recalls top-100 → cross-encoder reranks to top-10 → feed the LLM.

Mainstream: Cohere Rerank v3/v4, BGE-reranker-v2-m3 (open-source SOTA for Chinese and English), Jina Reranker v2, Mixedbread.

Trap: if the relevant document is not in the recalled top-100, reranking cannot save it — a reranker improves what was already recalled and cannot stand in for recall.

Choosing a mainstream embedding model RAG — how to choose among BGE-M3 / Cohere v4 / Voyage-3 / OpenAI text-3-large / Qwen3-Embedding

A 2026 comparison of mainstream embedding models:

Selection framework:

  1. Mostly Chinese → BGE-M3 / Voyage-3 / Qwen3-Embedding
  2. Multimodal → Cohere v4
  3. English-only + API → OpenAI text-3-large
  4. Self-hosted private deployment → BGE-M3

Key traps:

vector DB / vector database RAG — stores embeddings and supports approximate nearest-neighbor (ANN) search; Pinecone / Milvus / Qdrant and others

Mainstream:

ANN algorithms: HNSW (the most common), IVF, ScaNN (Google). Index time vs retrieval accuracy vs memory is a trade-off.

GraphRAG / Self-RAG / CRAG / Agentic RAG RAG — four advanced variants of naive RAG, each addressing a different weakness

Naive RAG struggles with cross-document, cross-entity reasoning, unstable recall quality, and multi-hop queries. Four common advanced schemes:

  1. GraphRAG (Microsoft 2024): use an LLM to extract entities and relations from documents, build a knowledge graph, and write hierarchical summaries by community. At query time you can both vector-search and walk the graph. It addresses incomplete recall when naive RAG reasons across many documents and entities. Cost: ingestion gets much more expensive (one LLM extraction per chunk).
  2. Self-RAG (Asai 2023): train a single LM to emit reflection tokens that decide (a) whether to retrieve, (b) whether the retrieved text is relevant, (c) whether the answer is supported by the context, and (d) overall utility. It addresses the judgment of when to retrieve and how to use what was retrieved. Requires training.
  3. CRAG (Corrective RAG, Yan 2024): a lightweight evaluator scores retrieved chunks. High scores are used directly, middling scores trigger a fresh web search, and low scores fall back to ungrounded generation. It addresses blindly using retrieved text when recall quality is uneven.
  4. Agentic RAG: the agent decides query rewriting → multi-round retrieval → division of work among sub-agents. It addresses multi-hop questions that need iterative retrieval. DeepResearch-style products are on this path.

Practical choice:

RAGAS RAG — the de facto standard for RAG evaluation; all four core metrics are implemented with an LLM-as-judge

Es et al. 2023. The four metrics:

  1. Faithfulness: whether each claim in the answer follows from the retrieved context. <0.7 = the model is making things up
  2. Context Precision: the share of the top-K that is truly relevant. Low = the retriever recalled noise
  3. Context Recall: whether the ground-truth information was all retrieved. Low = incomplete recall
  4. Answer Relevancy: whether the answer actually addresses the original question

Production thresholds: all four ≥0.7 counts as passing; if Faithfulness < 0.7, fix that first; if Context Recall < 0.7, tune the retriever.

Agent engineering

harness / harness engineering Agent — the code skeleton and engineering system wrapped around an LLM, so the agent physically cannot repeat a mistake

Named by Mitchell Hashimoto in 2026: “anytime you find an agent makes a mistake, take the time to engineer a solution such that the agent never makes that mistake again.”

This is not model fine-tuning. It is an engineered environment that makes it physically impossible for the model to fail in the same way again.

Two laws:

  1. Strong constraints: if a deterministic constraint can do it (a hard failure from lint / type check / sandbox / CI), don’t use a prompt
  2. Self-healing loop: the agent can take ground truth from the environment, evaluate itself, and resume from a checkpoint after failure

OpenAI’s formula: Agent = Model + Harness; “Humans steer. Agents execute.”

LangChain / LangGraph / LlamaIndex / Haystack Agent — mainstream frameworks for building agents and LLM applications

A comparison of mainstream frameworks, 2024–2026:

Practice: prototype by calling the SDK directly; consider LangGraph once workflow patterns (routing / parallelization / orchestrator-workers) have settled; consider LlamaIndex for pure RAG; don’t start with the LangChain “full suite”.

MCP / Model Context Protocol Agent — an open protocol from Anthropic that lets an LLM client connect to external tools and data sources through one interface

Released in 2024-11, and moved to an independent Steering Committee in 2025-Q4 (Anthropic / Block / OpenAI / Microsoft). Three core primitives:

It solves the N×M problem of “writing a new adapter for every new tool”. The single fastest-growing skill in 2026, 97M+ monthly downloads, and already an explicit requirement on the Anthropic Applied AI Engineer JD.

tool use / function calling Agent — the LLM calls external functions through a structured schema

The model outputs {"name": "search", "arguments": {"query": "..."}} JSON; the runtime parses it, actually runs the function, and feeds the result back to the model. Anthropic’s Tool Use API and OpenAI function calling are the same idea.

Design principles (Anthropic’s measurements: “agent performance is proportional to how clear the tool descriptions are”):

Computer Use / Browser Agent Agent — let the model operate a desktop GUI or a browser

Anthropic released Computer Use in 2024-Q4. The loop: screenshot → the LLM looks at the image and reasons → it outputs mouse and keyboard actions (click X,Y / type text / scroll) → the system executes them → screenshot again.

Browser Use (an open-source framework) is similar but limited to the browser, based on Playwright plus DOM augmentation (overlay numbered labels on clickable elements in the screenshot).

Useful for: automating sites with no API, automating desktop software, end-to-end e2e tests. Limits: slow, expensive, weak on security, and poor support for canvas-rendered apps. Production advice: if an API exists, use the API.

sub-agent Agent — a subtask agent dispatched by the main agent, with its own context

The main agent hands “read 30 files and research them” to a sub-agent. The sub-agent has its own context window and returns only the final summary to the main agent — the main context is not polluted by intermediate artifacts.

Claude Code’s Task tool, OpenAI Swarm, CrewAI, and others support this. It is one of the key ways to prevent a Loop of Death and a context explosion.

AGENTS.md / CLAUDE.md Agent — a project manual written for the agent, stating protocols / constraints / the startup procedure

The agent reads it automatically when it enters the project. It usually contains:

Hashimoto’s view: each line of AGENTS.md ≈ one mistake sealed off. It is the implicit-prompt form of harness engineering.

deny-first Agent — deny every tool and command by default; only an explicit allowlist permits them

The permission model Claude Code uses. Bash commands are authorized at verb + path granularity:

The matching security principle: if any one layer fails, the others still catch it. Combine it with a sandbox, a network-egress allowlist, and a read-only filesystem for defense in depth.

progress file / progress.md Agent — persist agent task progress to a file so a later session can resume

A core design from Anthropic’s Effective Harnesses: a long-running agent will inevitably blow the context window, and LLM context alone cannot remember “which step I am on”.

The fix:

The next session runs the 5-step startup protocol and resumes from the breakpoint. Core insight: the context window is “working memory”; the filesystem is “long-term memory”.

Loop of Death Agent — the agent enters an infinite loop and burns tokens until they run out

Common patterns:

Defense in depth:

  1. A hard max iteration (5–30 steps)
  2. An execution timeout (5–30 minutes)
  3. A token budget (a per-task hard cap)
  4. Progress detection (force-stop after N consecutive steps with no diff)
  5. Repeated-failure detection (break out after the same tool call fails 3 times)
  6. Cost alerts + HITL
Memory Corruption / memory pollution Agent — a false fact enters long-term memory and then contaminates every later decision

Example: a user jokes “I’m a billionaire”, it is stored in semantic memory, and the agent reasons from that assumption from then on.

Defenses:

Evaluation and safety

Trace + eval tool stack Evaluation — observability platforms such as Langfuse / LangSmith / Phoenix / Helicone / Patronus

“Full-trace plus evaluation” tools for LLM apps and agents. Mainstream in 2026:

Capabilities to line up:

  1. Trace: prompt → tool_call → response → cost / latency strung into one complete trace
  2. Prompt versioning: each prompt change gets a hash, and the dashboard can switch and compare them
  3. Eval: run the gold set in CI and alert on regressions
  4. Cost and cache hit rate: cost per trace, and the distribution of cache hits
  5. User feedback / thumbs up-down: attach it directly to the trace and file bad cases

How to choose: prefer Langfuse if you self-host; LangSmith for heavy LangChain users; Phoenix for trace monitoring alone; Patronus for safety / real-time blocking.

Mainstream LLM eval benchmarks Evaluation — what MMLU / MT-Bench / Chatbot Arena / HumanEval / LiveBench / BFCL each measure

Grouped by the capability being measured:

In practice: from a 2026 point of view, no single benchmark is trustworthy anymore — you need three layers: cross-checking several benchmarks, your own gold set, and blind human votes on Arena. See E11 and H3.

Eval / Evaluation Evaluation — the “scoring” stage of an LLM app or agent: three layers of evaluation, offline / online / CI

Eval for an LLM or agent application is not a single action; it is a system. Common layers:

How the eval tool stack splits:

  1. General frameworks: OpenAI Evals, DeepEval, Promptfoo, Inspect AI — run evals as a CLI or a library
  2. Built into observability platforms: Langfuse / LangSmith / Phoenix all ship an eval framework tied to traces
  3. RAG-specific: RAGAS (four dimensions, including faithfulness / context relevancy)
  4. Tool-use-specific: BFCL (Berkeley Function-Calling Leaderboard)
  5. Domain-specific: each team’s own gold set plus an LLM-judge rubric

Eval types by how they score:

Rules of thumb: (1) changing a prompt with no eval is changing it blind; (2) the eval model must be ≥ the model being evaluated (the judge principle); (3) the gold set must be versioned and private; (4) every bad case must be regressed into the gold set — the harness-engineering closed loop.

LLM-as-judge Evaluation — use a strong LLM to score candidate outputs in place of human evaluation

Model “evaluation” as an LLM task: the judge model reads (prompt, response) and outputs a 0–1 score / pass/fail / which side wins pairwise. It parallelizes at large scale, is cheap, and can be automated in CI.

Three major biases:

The judge principle: the judge model’s capability should be ≥ the model being evaluated, or it cannot tell what is good about a stronger model’s answer. The production standard is three layers: your own gold set + an LLM judge + human calibration.

Lost in the Middle Evaluation — in long-context QA, accuracy drops sharply when the key information sits in the middle

The Liu et al. 2023 experiment: put the gold passage at the start or the end of the prompt and accuracy is high; put it in the middle and accuracy falls in a U-shape. With 10+ documents, the middle position can score below a no-context baseline.

Engineering mitigations:

prompt injection Safety — user input or external content hijacks the model’s behavior and bypasses the system prompt

It is #1 on the OWASP LLM Top 10. Types:

Simon Willison’s conclusion: prompt injection has no 100% solution, and the system must be designed on the assumption that “the LLM is untrusted”. The dual-LLM pattern = a Planner (sees trusted input and decides) + an Executor (sees untrusted input but has no tool permissions).

hallucination / hallucination Evaluation — the model generates content that looks plausible but is actually wrong

Sources:

Debug flow: reproduce it and quantify the trigger rate → attribute the cause (RAG recall / whether the model used the context / tool calls) → fix → add a regression → production monitoring (a faithfulness scorer blocks in real time).

Key point: most hallucinations are defects in the prompt / RAG / context engineering, not “the model is sick”.

guardrails Safety — safety rails around each stage of an LLM: input, output, tools, and dialogue

NVIDIA NeMo Guardrails defines 5 kinds:

  1. Input rails: PII redaction, prompt injection detection, topic limits
  2. Dialog rails: control the dialogue flow with the Colang DSL and hard-code critical decision points
  3. Retrieval rails: drop low-quality / sensitive / untrusted chunks
  4. Execution rails: parameter allowlists and authorization checks before a tool call
  5. Output rails: hallucination detection / filtering leaked sensitive data / toxicity filtering

Key point: more rails are not automatically better. Turn on 1–2 high-ROI rails per kind, or latency and cost explode.

jailbreak / jailbreak Safety — bypass the model’s safety training so it outputs harmful content

Common techniques:

Defense: the vendor’s RLHF safety training + application-layer input/output classifiers (Llama Guard) + a cap on max context (against many-shot) + regular red-team exercises.