n4nAI

How to add human feedback to an AutoGen conversation

Learn how to add AutoGen human feedback loops to multi-agent workflows using UserProxyAgent, custom reply functions, and OpenAI-compatible inference endpoints.

n4n Team3 min read596 words

Audio narration

Coming soon — every post will get a voice note here.

Adding AutoGen human feedback to a multi-agent pipeline is what separates a toy demo from a deployable system. In this guide we wire a human checkpoint into a Microsoft AutoGen conversation using the built-in UserProxyAgent and a custom reply hook, so you can review or redirect agent output before it propagates.

Step 1: Install AutoGen and configure the LLM client

Pin a known-good version of the classic AutoGen package. The AgentChat rewrite changes APIs frequently; the pyautogen 0.2.x line is stable for the patterns below.

pip install pyautogen==0.2.32

AutoGen expects an OpenAI-style config_list. You can target any compliant endpoint. If you point AutoGen at an OpenAI-compatible gateway such as n4n.ai, the same config_list works and you get automatic fallback across providers when one is rate-limited, without rewriting your agent code.

from autogen import AssistantAgent, UserProxyAgent

config_list = [
    {
        "model": "gpt-4o-mini",
        "base_url": "https://api.n4n.ai/v1",
        "api_key": "YOUR_KEY",
    }
]

llm_config = {"config_list": config_list, "cache_seed": None}

Keep cache_seed None during development so prompts aren’t memoized; set it to an integer in prod if you want deterministic caching.

Step 2: Define the assistant and human proxy agents

The assistant generates proposals. The UserProxyAgent represents the human (or a system boundary). For AutoGen human feedback, this agent is where the interception happens.

assistant = AssistantAgent(
    name="planner",
    llm_config=llm_config,
    system_message="You are a concise planning agent. Propose one next step at a time.",
)

user_proxy = UserProxyAgent(
    name="human_proxy",
    human_input_mode="NEVER",       # we will gate manually via register_reply
    max_consecutive_auto_reply=0,   # never auto-reply on behalf of human
    code_execution_config=False,    # no local code exec in this example
)

human_input_mode="NEVER" stops AutoGen from blocking on stdin by default. We’ll add a controlled block only when we want it.

Step 3: Force synchronous feedback with human_input_mode

The fastest way to get AutoGen human feedback in a script is to flip human_input_mode to "ALWAYS" on the proxy. Every assistant message then triggers a stdin prompt before the conversation continues.

user_proxy.human_input_mode = "ALWAYS"

user_proxy.initiate_chat(
    assistant,
    message="Draft a launch plan for a developer API.",
)

Run this and you’ll see the assistant’s proposal, then a > prompt. Type feedback, press enter, and the text is fed back as the human’s reply. This is sufficient for interactive CLIs but too blunt for production: it asks after every single turn.

Use "TERMINATE" if you only want to confirm the final summary. Use "NEVER" plus a custom hook (next step) when feedback must be conditional.

Step 4: Register a structured feedback function for conditional gating

For real systems, you want a checkpoint only when the assistant crosses a threshold—say, proposing an external action. AutoGen’s register_reply lets you insert a function that runs before the default human prompt.

def human_review(recipient, messages, sender, config):
    # Only intercept messages from the planner
    if sender is not assistant:
        return False, None

    last = messages[-1]["content"]
    print(f"\n[PLANNER PROPOSAL]\n{last}\n")

    verdict = input("Approve (y) / Edit (e) / Reject (r): ").strip().lower()
    if verdict == "y":
        return True, "Approved. Proceed to next step."
    if verdict == "e":
        correction = input("Enter your corrected instruction: ")
        return True, correction
    if verdict == "r":
        return True, "REJECTED"  # assistant will see this and should stop
    return False, None  # fall back to default behavior

user_proxy.register_reply(assistant, human_review, position=1)
user_proxy.human_input_mode = "NEVER"  # we handle input ourselves

position=1 puts human_review ahead of AutoGen’s built-in reply logic. Returning (True, reply) consumes the turn; (False, None) defers. This pattern gives you typed, structured AutoGen human feedback instead of a raw text append.

You can extend human_review to read from a webhook, a Slack message, or a database poll instead of input(). The agent code doesn’t change.

Step 5: Run a multi-turn conversation and verify the loop

Wire the pieces together and start the chat. The human proxy initiates; the assistant replies; your hook fires.

if __name__ == "__main__":
    user_proxy.initiate_chat(
        assistant,
        message="Propose step 1 of a 3-step plan to onboard a new LLM provider.",
        clear_history=True,
    )

Verifying success

A correct implementation shows three observable behaviors:

  1. The script prints [PLANNER PROPOSAL] and pauses at Approve (y) / Edit (e) / Reject (r):.
  2. Typing e and supplying new text causes the assistant’s next message to reflect that correction (check the transcript).
  3. Typing r leads the assistant to yield or terminate within one turn, not loop indefinitely.

If you see the assistant auto-replying without a prompt, max_consecutive_auto_reply is likely non-zero or register_reply wasn’t positioned ahead of defaults. If you get a stdin error in a notebook, wrap input() in a try/except or use a GUI event loop.

Production notes

AutoGen human feedback is synchronous by default. In a service, block a worker thread, not the event loop. Persist messages to recover a half-finished review after a crash. When you route through a gateway that honors provider cache-control hints, set cache_seed consistently so repeated proposals with the same human edit hit cache and cut cost.

The UserProxyAgent is not magic—it is a plain agent that defaults to representing a person. Once you treat its reply path as a programmable boundary, you can build approval gates, red-team interrupts, or tiered sign-offs without forking the framework.

Tagsautogenhuman-in-the-loopai-agents

Written by

n4n Team

The team building n4n — a single OpenAI-compatible API in front of 240+ models, with automatic fallback, load balancing and pay-per-token metering.

More from n4n Team →

All autogen & microsoft agent framework posts →