Human in the Loop

Human-in-the-loop design means that an application intentionally pauses, records, routes, or gates an automated action so a person can inspect it before the system continues. In LlamaIndex, this pattern most often appears around agents because agents combine an LLM, memory, and tools to handle user inputs. The deployment guide defines an agent as a system that uses those three pieces, and its action loop sends tool schemas to the model, receives either a direct response or tool calls, executes those calls, appends results to chat history, and invokes the agent again. That loop gives developers several natural places to add review. Sources: docs/src/content/docs/framework/module_guides/deploying/agents/index.mdx

Purpose and Scope

Use this page when you need to design an approval step for a LlamaIndex application without losing the framework’s normal agent, tool, and observability model. A human review checkpoint might protect a destructive tool, require confirmation before sending external data, collect feedback for quality control, or record a trace for audit. The repository evidence for this page centers on three primitives: tool metadata and tool outputs, callback manager APIs, and the documented agent execution loop. Together they support a practical pattern: expose actions as tools, observe the run with callbacks, and insert the approval decision at the point where tool execution or orchestration is under your control. Sources: llama-index-core/llama_index/core/tools/types.py, docs/api_reference/api_reference/callbacks/index.md, docs/src/content/docs/framework/module_guides/deploying/agents/index.mdx

A key constraint is that LlamaIndex does not need a separate conceptual universe for review workflows. The same application structures used for ordinary RAG and agentic systems can carry human decisions. Tools already have typed schemas and output objects; callbacks already exist to trace what happened; deployed agents already use memory and repeated tool-call turns. Human-in-the-loop behavior is therefore best treated as a boundary around automation: the LLM may propose an action, but your code decides whether to execute it immediately, stage it for a user, reject it, or return a safe response explaining that approval is required.

Relevant Source Files

  • llama-index-core/llama_index/core/tools/types.py - Defines the core tool metadata and output structures that make tool calls inspectable, typed, and suitable for approval wrappers.
  • docs/api_reference/api_reference/callbacks/index.md - Lists the callback reference entry points for CallbackManager, BaseCallbackHandler, CBEvent, CBEventType, and EventPayload.
  • docs/src/content/docs/framework/module_guides/deploying/agents/index.mdx - Documents the deployed-agent model, the FunctionAgent example, the tool-call loop, default memory behavior, and the streaming option.

System-to-Code Mapping

The most direct review surface is the tool boundary. ToolMetadata carries a tool description, optional name, optional Pydantic function schema, and return_direct flag. Its get_parameters_dict() method converts the schema into the JSON parameter structure expected by function-calling providers, while to_openai_tool() produces the OpenAI-style function tool payload and enforces a 1024-character description limit unless skipped. For approval systems, those fields are the human-readable contract shown to both the LLM and, often, the reviewer. A clear description and schema make it easier to answer whether a proposed action is safe. Sources: llama-index-core/llama_index/core/tools/types.py

Tool results are equally important for review. ToolOutput records structured blocks, the tool_name, the raw input dictionary, the raw output value, an is_error flag, and an optional private exception. That shape is useful even when the approval step happens outside the model call. For example, a wrapper can return a ToolOutput indicating that a requested action is pending approval, rejected, or failed validation, while preserving the raw input that the reviewer needs to inspect. This keeps the agent loop honest: tool execution has a visible result, and the next LLM turn can reason over that result through chat history. Sources: llama-index-core/llama_index/core/tools/types.py

Callbacks provide the observation layer rather than the approval decision itself. The API reference page exposes CallbackManager, BaseCallbackHandler, and callback schema types such as CBEvent, CBEventType, and EventPayload. The official callback guide explains that callbacks help debug, track, and trace the inner workings of the library, including durations, event counts, and trace maps. In a human-in-the-loop design, a callback handler can capture the evidence needed for review: which query started, what retrieval or LLM event occurred, which tool was selected, and what payload should be inspected. Sources: docs/api_reference/api_reference/callbacks/index.md

Execution Flow

A typical approval flow begins with a normal agent configuration. The deployment guide shows FunctionAgent constructed with a list of tools, an LLM such as OpenAI(model="gpt-4o-mini"), and a system prompt. Running await agent.run(...) starts the loop: the agent receives the latest message and chat history, sends tool schemas and history to the LLM provider, receives a direct response or tool calls, executes every tool call, appends tool results, and invokes the agent again. Human approval belongs between selection and execution for preventive gates, or after execution for review and feedback. Sources: docs/src/content/docs/framework/module_guides/deploying/agents/index.mdx

A preventive gate is appropriate when the tool can modify external state, expose sensitive information, create cost, or contact another user. Instead of registering the destructive function directly, register a wrapper function with a precise schema and description. The wrapper can validate the proposed arguments, create an approval record in your application, and return a message indicating that the request is waiting for review. If the user approves, a later call or workflow step performs the real action. This pattern aligns with the documented agent loop because the agent still receives a tool result and can continue with updated chat history rather than silently hanging.

A review-after-execution pattern is better for quality monitoring, evaluation, or feedback collection. Here the tool executes normally, but callbacks and tool outputs preserve enough context for a reviewer to inspect the run. Because callbacks can trace events and because ToolOutput includes raw input, raw output, and error state, the review system can display both the agent decision and the observable effect. The callback API page is intentionally generic, so the human workflow is implemented by your handler or surrounding application rather than by changing the callback contract. Sources: llama-index-core/llama_index/core/tools/types.py, docs/api_reference/api_reference/callbacks/index.md

API Components and Contracts

ComponentSource-backed roleHuman-in-the-loop use
FunctionAgentAgent workflow that uses LLM function or tool calling.Let the model propose tool calls while application code controls whether selected calls execute.
ToolMetadata.descriptionHuman-readable tool description.Explain consequences, limits, and when approval is required.
ToolMetadata.fn_schemaOptional Pydantic schema for tool arguments.Validate and display proposed inputs before a reviewer approves them.
ToolMetadata.return_directMetadata flag available on tools.Useful when a tool result should be surfaced directly, including approval status messages.
ToolMetadata.to_openai_tool()Produces OpenAI function-tool metadata and checks description length.Ensures reviewable tools remain compatible with function-calling providers.
ToolOutput.raw_inputStores the raw input dictionary.Show the exact proposed action to a reviewer or audit log.
ToolOutput.raw_outputStores the underlying result.Preserve the effect or pending-approval record returned by the wrapper.
ToolOutput.is_errorIndicates failed tool execution.Distinguish rejected, invalid, or failed actions from successful tool results.
CallbackManagerCore callback coordination entry point.Register handlers that trace review-relevant events.
BaseCallbackHandlerBase type for custom handlers.Implement logging, audit, feedback, or escalation behavior.
CBEvent, CBEventType, EventPayloadCallback event schema types.Structure the event data that a review UI or audit sink consumes.

The practical contract is simple: keep the proposed action visible, keep the decision explicit, and return a normal framework result. Tool schemas should be narrow enough that a reviewer can understand the input without reverse-engineering free text. Tool descriptions should state what the tool actually does, not just what the LLM should call it for. Callback handlers should record enough payload to reconstruct the sequence of agent decisions. For deployed agents, remember that memory is part of the system; the guide states that agents use ChatMemoryBuffer by default and can accept a custom memory object at run time, so review decisions may need to account for conversation history. Sources: docs/src/content/docs/framework/module_guides/deploying/agents/index.mdx

Implementation Patterns

For simple approvals, use a wrapper tool. The original function remains private to the application, while the wrapper is the tool registered with the agent. The wrapper receives typed arguments, stores an approval request, and returns a message such as Approval required before sending this email or Request queued for reviewer. The model sees this as a tool result and can explain the next step to the user. After approval, your application can either run the original function outside the agent loop or expose a second, restricted tool that consumes an approval identifier.

For observable approvals, pair wrapper tools with callbacks. Callback handlers are intended to debug, track, and trace library internals, and the callback reference exposes the manager, handler, event, event type, and payload classes needed to build that layer. A handler can send tool-call context to an audit log, attach timestamps, count approval events, or forward payloads to a review service. Keep the callback side effect separate from the decision whenever possible: callbacks observe and report; the wrapper or workflow step should decide whether the underlying operation is allowed. Sources: docs/api_reference/api_reference/callbacks/index.md

For interactive deployed agents, consider the user experience of waiting. The agent deployment guide notes that streaming is enabled by default for FunctionAgent, with streaming=False available when a model does not support streaming. If your approval mechanism is synchronous and quick, streaming can help surface progress. If approval is asynchronous and may take minutes or hours, return a durable pending state instead of trying to keep a model call open. The agent can then resume through a later user message, a stored memory context, or an application-level workflow that knows the approval status. Sources: docs/src/content/docs/framework/module_guides/deploying/agents/index.mdx

Next Steps

Start by classifying each tool in your agent as safe, reviewable, or prohibited. Safe tools can run directly; reviewable tools should be wrapped with explicit schemas and approval-status outputs; prohibited actions should not be registered as tools. Then add callback handlers for the evidence you need to debug or audit the run. Finally, test the full loop with realistic chat history, because the documented agent flow repeatedly appends tool results and reinvokes the model. Related pages to read next are agents-overview, agent-configuration, tools, callbacks, workflows, sessions, and streaming.