Human-Agent Engineering

The previous lecture established the perception-reasoning-action loop and the architectural separation between the LLM and the agent's execution code. This lecture turns to the other side of the equation: the human. How a person interacts with an agent — the context they provide, the oversight they maintain, the judgment they exercise — determines whether the agent produces reliable results or unreliable ones. This applies to every kind of agent, not just coding agents.

The lecture uses agentic coding as a concrete, familiar example to explore a broader set of principles. AI coding agents like Claude Code, Cursor, and GitHub Copilot follow the same perception-reasoning-action loop defined in Lecture 1.1. When a user tells a coding agent to "add input validation to the login form," the agent perceives the codebase, reasons about what validation to add and where, acts by editing files, and then loops — checking for errors, running tests, and iterating. The mechanics are identical to the general agent loop. What varies is how effectively the human participates.


Vibe Coding and Why It Fails

Vibe coding is the practice of giving an AI agent vague instructions, accepting whatever it produces, and hoping for the best. The term, coined by Andrej Karpathy, describes a mode of interaction where the user "fully gives in to the vibes" — watching code appear without understanding it, running it, and moving on.

Vibe coding can work for throwaway prototypes and personal experiments. It fails for anything that matters, and it fails for three specific reasons.

LLMs do not know your constraints. The model has no access to your security requirements, performance targets, coding conventions, or business rules unless you provide them. It will make reasonable-sounding choices based on its training data, but those choices may be wrong for your context. A login page generated without explicit security guidance may omit CSRF protection, expose passwords in the URL, or store session tokens insecurely — not because the model is incapable of implementing these protections, but because it was never told to.

Quality compounds over time. A single poorly understood function becomes a fragile foundation. When something breaks, the user cannot debug code they never reviewed. Technical debt from unexamined AI output accumulates faster than human-written debt because the volume of generated code is higher and the comprehension lower.

The user loses the ability to evaluate. As unreviewed code accumulates, the codebase becomes intractable. The user becomes dependent on the agent to make any changes — not because the agent is the best tool for the job, but because the user has lost sight of what the code does. This is analogous to starting a new job at a company with a hundred thousand lines of code you have never seen: you may be a capable developer, but your effectiveness is near zero until you understand the system. Vibe coding creates this situation within your own project.

These failure modes are not specific to coding. A research agent that produces reports the user does not verify, a customer service agent that sends responses the user never reviews, a data analysis agent that generates graphs the user cannot interpret — all exhibit the same pattern. Delegating without understanding leads to brittle, unreliable results.


Agent as Expert vs. Agent as Tool

There are two fundamental mindsets when working with an agent.

Agent as expert. The user treats the agent as the authority. They give it a problem, hope it knows the answer, and accept what comes back. This is the vibe coding mindset generalized. It works when the agent happens to be right — but the user has no way to tell when it is not.

Agent as tool. The user is the expert. They use the agent to amplify their own knowledge and abilities. They know what they want before they ask, they understand the domain well enough to catch mistakes, and they take responsibility for evaluating the result.

The distinction matters because it predicts the trajectory of the collaboration. When the agent is the user's tool, the user stays in control: they learn from each interaction, their expertise grows, and the quality of what they produce with the agent improves over time. When the agent is the user's expert, the user is stuck: they cannot distinguish good output from bad, they do not learn anything, and they become increasingly dependent.

For agent engineers, this framing has a direct design implication. The agents you build should support the "agent as tool" model. They should keep users informed, give them enough visibility to evaluate results, and avoid creating dependence. An agent that leaves its user unable to function without it is a poorly designed agent.


The Developer as Manager

Human-agent engineering is the discipline of effectively collaborating with AI agents — providing clear context, maintaining oversight, and ensuring quality outcomes. The relationship between a human and an agent is closer to management than to tool use in the traditional sense.

A good manager, when delegating to a junior developer, does five things:

  1. Provides clear context — the codebase, the conventions, the goal.
  2. Sets expectations — edge cases to handle, tests to include, style to follow.
  3. Reviews the work — reads the output, evaluates it, does not simply accept it.
  4. Iterates — provides specific feedback and asks for revisions.
  5. Knows when to take over — recognizes when a task is too complex or too sensitive to delegate.

A bad manager says "just handle it" and never checks the result. The parallel to vibe coding is direct.

This analogy also applies in reverse. When designing an agent, the developer must think about the human side of the collaboration: what context does the human need to provide (which drives system prompt design), how does the human review output (which drives approval workflow design), when should the agent ask for help (which drives escalation logic), and what is the feedback loop (which drives conversation design). These are not afterthoughts — they are core architectural decisions that determine whether the agent is usable in practice.


Context Determines Quality

The quality of an agent's output is directly proportional to the quality of context the user provides. The LLM's raw capability is constant; what varies is what it has to work with.

Consider a progression. A vague instruction — "write a function to process user data" — gives the model almost nothing: no language, no format, no behavior, no edge cases. The model will guess, and it will guess wrong. A more specific instruction — "write a Python function that validates an email address using regex, returns True or False, and handles None input gracefully" — gives the model a language, an approach, expected behavior, and an edge case. The output will be substantially better. The best context goes further: it includes the existing codebase, shows the patterns and conventions already in use, and provides concrete examples of similar functions. The model now has style, structure, and precedent to follow.

The components of an agent's context — the system prompt, conversation history, tool results, and user instructions — are each an opportunity to improve or degrade quality. The system prompt defines the agent's identity and behavioral guidelines. Conversation history captures what has been discussed and decided. Tool results provide the data the agent has gathered from its environment. User instructions specify the current goal. Every one of these can be engineered.

This is why context engineering becomes a major topic later in the course. The agent engineer's job is to take the user's inevitably incomplete, vague input and assemble it into context that allows the LLM to produce intelligent results. Users will always tend toward vibe coding — giving incomplete instructions without sufficient context. The agent must compensate by pulling in relevant information, anticipating needs, and structuring the prompt so the LLM can do its work.

The quality of the operating environment also matters. In a coding agent, a codebase with clear naming conventions, consistent patterns, good documentation, and modular architecture produces better agent output than a messy codebase — because the LLM reasons about the code it can see. Vibe coding is self-defeating in this regard: the sloppy code it produces degrades the environment for future agent interactions, creating a negative feedback loop. In a conversational agent, maintaining a well-managed conversation history — compacting it without losing important information, retaining relevant context while discarding noise — serves the same purpose.


The Autonomy Spectrum

Not every task warrants the same level of human involvement. Effective human-agent engineering requires matching the level of autonomy to the characteristics of each task.

The spectrum has five levels. At one extreme, full human control means the agent has no involvement — the human performs the action directly. Setting production database credentials is a task that belongs here. At the other extreme, full agent autonomy means the agent handles everything independently, such as auto-formatting code on save.

Between these extremes sit three intermediate levels. Agent suggests means the agent proposes and the human decides — code review suggestions work this way. Agent acts, human approves means the agent does the work but the human reviews before it takes effect — an agent that writes code for a human to review before merging follows this pattern. Agent acts, human monitors means the agent executes autonomously while the human watches for problems — automated test generation is a reasonable example.

Three criteria guide where a given task should fall on this spectrum.

Reversibility. If the action is easy to undo — formatting code, renaming a variable — higher autonomy is appropriate. If it cannot be reversed — deleting a production database, sending an email — the human must be in control.

Consequence of error. If the agent gets it wrong and the impact is minor — an imperfect variable name — more autonomy is acceptable. If the impact is severe — a security vulnerability in authentication — human review is essential.

Agent capability. If the task falls within the LLM's reliable capabilities — generating boilerplate, following well-established patterns — more autonomy is warranted. If the task requires judgment that LLMs handle inconsistently — complex architectural decisions, novel design problems — human involvement should increase.

When building agents, these autonomy levels become explicit design decisions. Which tools can the agent invoke without asking? Which require user confirmation? When should the agent stop and request guidance? What actions should the agent never be permitted to take? These questions define the permission boundaries and approval workflows that make an agent safe and productive in practice.