Skip to main content

feedback-manager logo

feedback-manager

CI Documentation PyPI Python 3.12 | 3.13 | 3.14 | 3.15 Coverage 100% Typed License: Apache 2.0

Framework-agnostic feedback management and agent learning: capture, correlate, store, route, resolve, and learn from feedback, for LangChain, LangGraph, and custom agents.

Agent applications constantly receive feedback: a reviewer approves a refund, a user corrects an answer, a tool times out, an evaluator scores a response. feedback-manager turns each of them into a validated, queryable record that knows which run, node, tool call, or interrupt it is about, groups it with related feedback, routes it to your handlers, and tracks it through an explicit lifecycle until it is resolved. Your agent framework keeps owning execution; feedback-manager owns the feedback about it. Framework integrations are adapters around a framework-neutral core, so the same package works with LangChain, LangGraph, custom Python agents, and future frameworks.

feedback-manager architecture

Why feedback-manager

A support agent drafts a refund reply. A reviewer corrects it, a tool times out on the next run, and an evaluator scores the answer low. Today that feedback usually ends up scattered:

  • Feedback lives in many places. Corrections sit in a UI database, tool errors in logs, evaluator scores in a tracing tool, and approvals inside the agent framework's interrupt state.
  • It is detached from what it is about. A score without the run, node or tool call it refers to can't be acted on or audited.
  • Nobody owns its follow-up. Feedback is recorded but never acknowledged, handled or resolved, and concurrent workers overwrite each other's updates.
  • Agents repeat the same mistakes. The lesson in a correction never reaches the next run, or it reaches it unreviewed and unscoped.

How feedback-manager addresses each one:

Problem What feedback-manager does
Feedback in many places One immutable, typed event for corrections, approvals, tool failures, evaluator scores and interruptions, captured where they happen
Detached from its subject Every event carries its target and execution context, is correlated with related feedback, and links to agxai provenance
No owner for follow-up Routing to your handlers, and an explicit lifecycle whose transitions are compare-and-set, so concurrent updates never overwrite each other
Repeated mistakes A learning engine turns scoped feedback into versioned lessons that only reach an agent after human review and explicit activation

feedback-manager doesn't run your agents or replace your tracing. Your framework keeps owning execution, LangSmith and OpenTelemetry keep showing what ran, and agxai records why it was decided; feedback-manager manages the feedback about all of it.

Highlights

  • Captured where it happens. A LangChain callback handler records tool, model, retriever and node failures once, with the thread, node and tool call they happened in. A bridge records LangGraph human-in-the-loop requests and decisions around interrupt() and Command(resume=...).
  • An explicit, race-free lifecycle. Feedback moves through a validated state machine, retried submissions are idempotent, and an optional durable change journal supports crash recovery.
  • Learning that stays reviewable. Automatic, scoped background learning builds candidate lessons with evidence and confidence. Human review and explicit activation are separate from feedback approval, and original feedback is never rewritten.
  • Hybrid retrieval. Structured, vector (LanceDB), graph (LadybugDB) and hybrid retrieval over learned artifacts. Vector and graph records are rebuildable hints: every result is revalidated against the current artifact, its review state and its scope.
  • Isolated from failures. A failing handler, subscriber, router or observability sink never loses stored feedback. Choose per stage whether a failure is logged or raised.
  • Extensible through ABCs. Subclass FrameworkAdapter for Agno, CrewAI or your own loop, and FeedbackStore, VectorStore, GraphStore or EmbeddingProvider for your infrastructure. Every agxai, LanceDB and LadybugDB component can be injected, and feedback_manager.testing checks your implementations against the contracts.
  • Small and typed. The core depends on agxai, Pydantic and structlog, ships type hints, and is tested on Python 3.12 to 3.15 with 100% statement and branch coverage.

Installation

pip install "feedback-manager[langchain]"   # with LangChain and LangGraph
pip install feedback-manager                # core only, for any other framework

Optional extras:

Extra Adds
langchain LangChain and LangGraph capture, human-in-the-loop bridge and learned-context injection
lancedb LanceDBVectorStore for vector and hybrid retrieval
ladybugdb LadybugGraphStore for graph and hybrid retrieval
otel OpenTelemetryObservabilitySink
all Every extra above

The lancedb and ladybugdb extras need Python 3.14 or earlier until those databases publish Python 3.15 wheels.

Quickstart

A person corrects a generated answer. The correction is recorded against the answer and its conversation, taken through its lifecycle and queried back:

import asyncio

from feedback_manager import (
    ExecutionContext,
    FeedbackManager,
    FeedbackQuery,
    FeedbackTarget,
    FeedbackTargetType,
)


async def main() -> None:
    manager = FeedbackManager()

    # A person corrects a generated answer in conversation "support-7".
    feedback = await manager.submit(
        source="human",
        category="correction",
        target=FeedbackTarget(type=FeedbackTargetType.GENERATION, id="gen-42"),
        payload={"corrected_text": "Canberra is the capital of Australia."},
        execution_context=ExecutionContext(thread_id="support-7"),
    )
    print(f"{feedback.status}: correlated by {feedback.correlation_id}")

    # Take it through its lifecycle once the correction is applied.
    await manager.acknowledge(feedback.feedback_id)
    await manager.mark_handled(feedback.feedback_id)
    resolved = await manager.resolve(feedback.feedback_id, resolution={"applied_to": "faq"})
    print(f"{resolved.status}: {resolved.resolution}")

    # Query it back, like any other feedback.
    for event in await manager.query(FeedbackQuery(correlation_id="support-7")):
        print(event.source, event.category, event.target.id, event.status)


asyncio.run(main())

Output:

received: correlated by support-7
resolved: {'applied_to': 'faq'}
human correction gen-42 resolved

Record every tool, model and node failure of a LangChain or LangGraph agent, without changing your error handling:

from feedback_manager.integrations.frameworks.langchain import FeedbackCallbackHandler

await graph.ainvoke(inputs, {"callbacks": [FeedbackCallbackHandler(manager)]})

The quickstart walks through it step by step.

Learn from feedback

Two corrections with the same lesson become a candidate. It reaches the agent only after a person reviews it and it is activated:

from feedback_manager.learning import ArtifactScope
from feedback_manager.learning.engine import LearningEngine
from feedback_manager.learning.signals import LearningSignalExtractor
from feedback_manager.retrieval import RetrievalRequest
from feedback_manager.storage.artifacts import InMemoryArtifactRepository

scope = ArtifactScope(tenant_id="example-tenant", agent_id="research-agent")
engine = LearningEngine(InMemoryArtifactRepository())
signals = [LearningSignalExtractor().extract(event, scope=scope).signal for event in corrections]

candidate = (await engine.process(signals)).artifacts[0]
await engine.request_review(scope, candidate.artifact_id)
await engine.review(scope, candidate.artifact_id, reviewer="example-reviewer", approved=True)
await engine.activate(scope, candidate.artifact_id)

result = await engine.retrieve(
    RetrievalRequest(scope=scope, agent_id="research-agent", task="validate results")
)
print(result.as_context())

Output:

Improvement: Search, validate results, then execute.
Search, validate results, then execute.

In production, FeedbackManager queues learning jobs for a background learner instead; see background learning and recovery and hybrid retrieval.

Your own framework

The core never imports an agent framework. LangChain and LangGraph share one adapter, a dependency-free adapter covers hand-written loops, and other frameworks implement FrameworkAdapter. Program against the ABC and the same agent-side code works for all of them:

from feedback_manager.integrations import FrameworkAdapter


def wire(adapter: FrameworkAdapter, manager, engine):
    extractor = adapter.context_extractor()
    classifier = adapter.failure_classifier()
    bridge = adapter.human_in_the_loop(manager)
    injector = adapter.context_injector(engine)
    return extractor, classifier, bridge, injector

See the custom framework guide.

Your own database

Feedback is kept in memory by default. Subclass FeedbackStore and pass it to FeedbackManager; feedback_manager.testing.FeedbackStoreContract checks your store against the contract:

from feedback_manager import FeedbackManager
from feedback_manager.contracts import FeedbackStore


class MyStore(FeedbackStore):
    async def create(self, feedback): ...
    async def get(self, feedback_id): ...
    async def transition(self, feedback_id, status, *, expected, resolution=None): ...
    async def query(self, query): ...


manager = FeedbackManager(store=MyStore())

See the SQLite store and bring your own components.

Benchmarks

Each operation timed 1,000 times with the default in-memory stores:

Scenario p50 ms p95 ms
submit, learning off 0.13 0.21
submit, learning on 0.21 0.37
lifecycle: acknowledge, handle, resolve 0.15 0.29
retrieve, structured, 50 lessons 21.0 30.5
retrieve, hybrid with LanceDB, 50 lessons 102.1 132.3

Measured on one machine; see Benchmarks for the method, memory use and how to reproduce.

Examples

Complete programs in examples/, each exercised by the test suite:

Documentation

Full documentation: feedback-manager.readthedocs.io

Three Agent Skills teach coding agents such as Claude Code, Codex, Cursor and GitHub Copilot to use feedback-manager correctly. feedback-manager integrates it into your application, feedback-manager-learning makes agents learn from feedback, and feedback-manager-extend writes adapters and stores for your infrastructure:

npx skills add smuniharish/feedback-manager

feedback-manager follows semantic versioning. Changes are listed in the changelog.

Contributing

Contributions are welcome. See CONTRIBUTING.md for the development setup and checks, CODE_OF_CONDUCT.md for community standards, and SECURITY.md to report a vulnerability.

License

Apache License 2.0. See LICENSE.

Metadata

Release files for feedback-manager 0.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for feedback-manager 0.1.2
File Size Uploaded Provenance Actions
feedback_manager-0.1.2.tar.gz 2.1 MB Without provenance Details for feedback_manager-0.1.2.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for feedback-manager 0.1.2
File Interpreter ABI Platform Actions
feedback_manager-0.1.2-py3-none-any.whl Python 3 none any Details for feedback_manager-0.1.2-py3-none-any.whl

Total release size: 2.2 MB

Release files / feedback_manager-0.1.2.tar.gz

Download URL feedback_manager-0.1.2.tar.gz
Size 2.1 MB
Tags Source
SHA-256 checksum
How to use checksums
40a8f41fe08fc6ec495bb65eed069ba93cfae000b0a3a1bcf9043eff18a9ec9f
BLAKE2b-256 checksum
How to use checksums
41341529eea4884392150748e83eb18a058ef76821e8c3ef8b9c648a6eb2d77c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / feedback_manager-0.1.2-py3-none-any.whl

Download URL feedback_manager-0.1.2-py3-none-any.whl
Size 169.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
8fffac54752491cbd3713ef595313cbd76b2e8ae80757a46560942347e16d4d9
BLAKE2b-256 checksum
How to use checksums
bef54c1f17630d15f57b334ea93c1d82d2e29bc0991ed923993adfc3072358c9
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.13.6 {"installer":{"name":"uv","version":"0.13.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for feedback-manager 0.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page