Skip to main content

Evidence Output

Evidence output is the difference between a debuggable retrieval engine and a black-box prompt. It records the compact signals that made a tool visible, ranked, expanded, selected, or rejected.

Use evidence output when a product needs to answer:

  • why this tool was retrieved
  • why a producer or neighbor tool was expanded
  • why the selector accepted, rejected, or overrode an LLM target
  • whether the failure came from search, selection, planning, auth, or execution
  • which artifact changed between two benchmark or Quality Lab runs

Minimal Example

from graph_tool_call import ToolGraph
from graph_tool_call.graphify import retrieve_graphify

graph = ToolGraph.load("collection.json")
response = retrieve_graphify(
graph,
query="find refund-ready orders",
top_k=8,
include_evidence=True,
)

first = response["results"][0]
print(first["name"])
print(first["score_breakdown"])
print(first["semantic_evidence"])

include_evidence=True is intended for product diagnostics, regression cases, and Quality Lab-style validation. Tiny local demos can use simpler retrieval APIs.

Response Shape

The top-level response should be treated as an additive object. Adapters should preserve unknown keys so newer engine versions can add evidence without breaking older product code.

FieldMeaning
resultsRanked candidate rows
subgraph_textLLM-ready node/edge rendering for the selected subgraph
intentDominant read/write/delete/neutral intent scores
statsSeeds, visited node/edge counts, and optional budget diagnostics

Candidate Row

FieldMeaning
nameCandidate tool name
scoreFinal retrieval score
toolSerialized ToolSchema for the candidate
score_breakdownNamed additive signals used for ranking
expanded_fromCandidate that caused this tool to be added
edge_evidenceGraph edge evidence used during expansion
semantic_evidenceSelector-ready action/resource/module/shape/contract evidence
learning_evidencePromoted trace-learning signal, when one was applied

The stable contract is the presence of named evidence fields, not a fixed absolute score scale.

Example Result

{
"name": "getRefundableOrderList",
"score": 0.0371,
"score_breakdown": {
"seed": 0.0314,
"graph": 0.0057,
"learning": 0.0,
"history_demoted": false,
"action_match": 1.0,
"resource_match": 1.0,
"module_match": 0.0,
"shape_match": 1.0,
"contract_match": 1.0,
"graph_expansion": 0.0
},
"semantic_evidence": {
"canonical_action": "search",
"primary_resource": "order",
"result_shape": "list",
"path_module": "/orders",
"action_match": true,
"resource_match": true,
"module_match": false,
"shape_match": true,
"contract_match": true,
"matched_terms": ["order", "refund"]
},
"edge_evidence": []
}

Read this as a ranked explanation, not as a promise that every future version will use the same numeric weights.

Diagnostic Workflow

Use the evidence object in this order:

  1. Confirm the expected target is present in results.
  2. Check whether its rank is acceptable for the caller's Top-K.
  3. Compare score_breakdown against the wrong higher-ranked tools.
  4. Inspect semantic_evidence for missing action, resource, shape, or contract fields.
  5. Inspect expanded_from and edge_evidence when producer tools appear or disappear.
  6. Hand the same result rows to select_target_candidate() before blaming the LLM.

Product UI Contract

For each candidate, show compact evidence rather than raw metadata dumps.

UI FieldSource
rank and tool namelist position, name
score chipsscore_breakdown
action/resource/shape badgessemantic_evidence.action_match, resource_match, shape_match
matched termssemantic_evidence.matched_terms
why it entered Top-Kstats.seeds, expanded_from
graph reasonedge_evidence.kind, edge_evidence.evidence

For a selected target, add:

UI FieldSource
LLM targettarget_selector.llm_target
final selected targettarget_selector.selected_target
override statetarget_selector.overrode_llm
uncertaintytarget_selector.ambiguous, reason_codes
policytarget_selector.policy

This is enough for operators to distinguish search failure, selector ambiguity, missing input, auth readiness, and downstream API failure.

Persistence Policy

Persist compact, scrubbed evidence that helps reproduce the decision. Do not store raw request bodies, response bodies, tokens, cookies, or user identifiers.

Store:

  • query fingerprint or test case id
  • candidate list and rank
  • score breakdown
  • selector reason codes
  • graph/tool version
  • scrubbed trace metadata
  • learning suggestion id, if applied

Do not store:

  • full API response body
  • authorization headers
  • cookies
  • raw user ids
  • phone, email, address, or account-like payload values
  • raw prompt traces containing secrets

Failure Modes

SymptomLikely CauseWhat To Inspect
High score but wrong targetnoisy text or sibling tiescore_breakdown, semantic_evidence.shape_match
Correct target missingweak metadata or missing aliasesindexed action/resource/module fields
Producer missing from catalogcontract extraction gapapi_contract.consumes, api_contract.produces
Too many producersbroad data-flow edge or context field explosionedge_evidence, contract field kind
Selector refused to overrideinsufficient margintarget_selector.rank_signals
Evidence is emptycaller used a simple retrieval pathswitch to retrieve_graphify(..., include_evidence=True)
Evidence changed after rebuildartifact or semantic metadata changedcompare graph_tool_call_version, semantic_summary

Regression Fixture

Store evidence for failing and fixed runs so reviews can compare artifacts instead of relying on memory.

{
"case_id": "member-delivery-detail-001",
"query": "show member delivery detail",
"expected_target": "getMemberDeliveryDetail",
"actual_top_3": [
{
"name": "getMemberDeliveryDetail",
"rank": 1,
"score_breakdown": {
"resource_match": 0.18,
"shape_match": 0.08,
"contract_match": 0.07
}
}
],
"target_selector": {
"selected_target": "getMemberDeliveryDetail",
"reason_codes": ["selected_by_strong_evidence"]
}
}

Validation

Evidence output should be captured in regression fixtures when tuning ranking. For a failing query, keep the evidence from both the old and new run.

Useful checks:

poetry run pytest tests/test_graphify_contract_025.py -q
poetry run pytest tests/test_graphify_collection_artifact.py -q