hiphopsllm.pipeline¶
The whole analysis behind one object.
AgenticReliabilityStudy runs the five steps this package exists to
connect, in order, and keeps every intermediate result addressable:
Extract the architecture from a LangGraph application.
Synthesise static fault trees for each system-level hazard, unrolling feedback loops so the trees are genuinely acyclic.
Measure each component’s failure probability from observed outcomes under an explicit operational profile, using HIP-LLM’s hierarchical imprecise posterior — which returns an interval, because a few hundred items do not identify a point.
Calibrate the trees’ basic events with those intervals, replacing engineering-judgement placeholders and recording what could not be matched.
Convert a tree to conditional probability tables and a Bayesian network, for an exact top-event probability, a posterior over causes, and a picture.
End to end:
from hiphopsllm import AgenticReliabilityStudy, load_example, load_outcomes
study = AgenticReliabilityStudy(load_example("parallel_aggregator"))
study.observe(load_outcomes(), stratum_column="stratum",
profile={"short": 0.3, "medium": 0.5, "long": 0.2})
study.run()
print(study.summary())
study.bayesnet("H2").show()
Each step can be run on its own, and nothing is done implicitly: a study that has not been given outcomes reports placeholder probabilities and says so, rather than quietly presenting judgement as measurement.
- class hiphopsllm.pipeline.AgenticReliabilityStudy[source]¶
Bases:
objectA reliability study of one agentic workflow, from graph to Bayesian network.
- Parameters:
graph (
Any) – A compiled LangGraph, the drawable fromgraph.get_graph(), mermaid text, a graph specification dict (seeload_example()), or aSystemModel.name (
str) – What the report calls this system.profile (
Union[OperationalProfile,Mapping[str,float],None]) – The operational profile. It can also be supplied later, toobserve().globals_ns (
Optional[Dict[str,Any]]) – Passglobals()in a notebook so the node functions and the real model objects can be found; that is what makes shared-snapshot detection — and therefore common-cause analysis — reliable.node_functions (
Optional[Dict[str,Callable[...,Any]]]) – Explicit{node_id: function}mapping when the functions are not inglobals_ns. Use"<node>::router"for a conditional-edge function.unroll (
int) – Iterations of each feedback loop represented explicitly.hazards (
Optional[Sequence[Hazard]]) – System-level hazards to synthesise trees for. The default set is derived from the architecture.settings (
Any) – HIP-LLM inference settings; defaults to the interactive-speed ones.exact_inference (
bool) – Run HIP-LLM’s full hierarchical inference (default).Falseuses a Jeffreys approximation — much faster, and labelled as an approximation in every evidence string it writes.
-
report:
Optional[SafetyReport] = None¶
-
evidence:
Dict[str,ComponentEvidence]¶
-
calibration:
Optional[CalibrationReport] = None¶
-
operational_failure:
Any= None¶ the system-level HIP-LLM result, when whole-system outcomes were given
- analyse(**kwargs)[source]¶
Extract the architecture and synthesise the fault trees.
Called automatically by
run()and by anything that needs a tree, so it rarely has to be called by hand. It is worth calling on its own when you want the structural result — cut sets, single points of failure, the FMEA — before any measurement exists.- Return type:
- Parameters:
kwargs (Any)
- observe(outcomes=None, strata=None, *, profile=None, component=None, stratum_column='stratum', component_columns=None, split_column='split', calibration_split='calibration', component_map=None)[source]¶
Record measured outcomes. Accepts three shapes.
A table — one row per item, a stratum column, and one
1/0correctness column per component:study.observe(load_outcomes(), profile={"short": .3, "medium": .5, "long": .2})
One component — outcomes and strata as sequences:
study.observe([1, 1, 0, 1], ["short"] * 4, component="react_agent")
The whole system — outcomes and strata with no component named. This runs HIP-LLM over the system’s end-to-end correctness and stores it as
operational_failure, the direct analogue of callingOperationalFailureProbyourself:study.observe(outcomes, strata, profile={"short": .3, "long": .7})
1means the item was answered correctly, matching HIP-LLM.When a
splitcolumn is present, only the calibration rows are used; fitting basic-event probabilities on the evaluation set would make every downstream number optimistic and untestable.- Return type:
- Parameters:
- run_and_observe(inputs, success, *, stratum=None, profile=None, invoke=None, calibration_fraction=0.75, on_error='skip', progress=True, calibrate=True)[source]¶
Run the graph over
inputs, score every node, and calibrate.This is the one-cell entry point for a notebook that already builds and runs a LangGraph application: append this and the whole reliability analysis follows from the runs it performs.
study = AgenticReliabilityStudy(graph, globals_ns=globals()) study.run_and_observe( inputs=[{"smiles": s} for s in SMILES], stratum=lambda item: "large" if len(item["smiles"]) > 40 else "small", success={ "research_agent": lambda s: s.get("browser_status") == "ready", "pixelrag_agent": lambda s: s.get("capture_status") == "captured", "safety_agent": lambda s: bool(s.get("workflow_succeeded")), }, profile={"small": 0.6, "large": 0.4}, )
- Parameters:
inputs (
Sequence[Any]) – One graph input per benchmark item. Each is passed tograph.invoke(or toinvoke).success (
Mapping[str,Callable[[Any],Any]]) –{node_id: predicate}. Each predicate receives the final state and returnsTrue(that node did its job),False(it did not), orNone.Nonemeans not exercised — a router sent the run toENDbefore this node ran — and is recorded as a missing observation rather than a failure. That distinction matters: scoring an unreached node as failed would blame it for an upstream fault.stratum (
Union[Callable[[Any],str],Sequence[str],None]) – A callable mapping an input to its stratum label, or a ready-made sequence of labels, one per input. Defaults to a single stratum, which is honest but gives up the whole point of an operational profile — pass one if the workload is not uniform.profile (
Union[OperationalProfile,Mapping[str,float],None]) – The operational profile. Defaults to the observed frequencies of the stratum labels, recorded as such.invoke (
Optional[Callable[[Any],Any]]) – Custom runner, for a graph that needs streaming or a config. Receives one input and must return the final state.calibration_fraction (
float) – Fraction of items used to fit basic-event probabilities; the rest are markedtestand left out, so a held-out set survives.on_error (
str) –What to do when a run raises.
"skip"(the default) drops the item and reports how many were dropped;"record"keeps the row with every node unscored and arun_errormessage.Neither blames a node. A crashed run leaves no state to score against, so marking its nodes as failures would penalise components that had already succeeded before the exception — the same mistake as scoring an unreached node. What is lost either way is visible: the count is printed, and
"record"keeps the message.calibrate (
bool) – Runcalibrate()when the runs finish.Falsestops after recording the outcomes.progress (bool)
- Return type:
- Returns:
pandas.DataFrame – One row per item:
item_id,stratum, one column per scored node, andsplit. Keep it — it is the measurement, and re-running the graph is the expensive part.
- calibrate(**kwargs)[source]¶
Fit each observed component and write the intervals into the trees.
Re-synthesises the trees afterwards, so cut-set quantification and the Bayesian network both see the calibrated numbers.
- Return type:
- Parameters:
kwargs (Any)
- run()[source]¶
Analyse, and calibrate if outcomes were given. Returns
self.This is the one call that makes the whole pipeline a chain:
study = AgenticReliabilityStudy(graph).observe(table).run()
- Return type:
- bayesnet(hazard='H2', **kwargs)[source]¶
The Bayesian network for one hazard, built from its fault tree.
- Return type:
- Parameters:
- imprecise_bayesnet(hazard='H2', **kwargs)[source]¶
The lower/upper network pair, when basic events carry intervals.
Only meaningful after
calibrate(): without measurement the intervals are degenerate and both networks are the same.- Return type:
- Parameters:
- cpts(hazard='H2', **kwargs)[source]¶
The conditional probability tables for one hazard’s fault tree.
- hazard_probability(hazard='H2')[source]¶
P(hazard)as an interval, exactly, by inference over the network.
- property system: SystemModel¶
- property failure_model¶
- plot_importance(hazard='H2', top_n=12)[source]¶
Fussell-Vesely contribution per basic event, ranked — what to fix first.
- plot_cutset_orders()[source]¶
Cut sets per order, per hazard — how much defence in depth exists.
A tall order-1 bar is the finding: those are single points of failure.
- operational_reliability(n_tasks=1)[source]¶
The measured claim, stated the way HIP-LLM defines it.
This is the measurement: for each component, the probability that it fails on one task drawn from the stated operational profile, and the probability of failure-free operation over
n_tasks.It is deliberately separate from the fault tree. The tree decomposes each of these numbers over a component’s internal failure modes so that it can be propagated through the architecture; that decomposition is a modelling step, not something that was observed. What was observed is here: a task either succeeded or it did not, whatever the reason.
- save(directory, prefix=None)[source]¶
Write the report, every tree export, the cut sets and the FMEA.
- __init__(graph, name='agentic workflow', profile=None, globals_ns=None, node_functions=None, role_overrides=<factory>, resource_overrides=<factory>, unroll=1, hazards=None, settings=None, exact_inference=True, credible_level=0.95, bound='credible')¶
- exception hiphopsllm.pipeline.StudyNotReady[source]¶
Bases:
RuntimeErrorA step was asked for before the step it depends on had been run.