Skip to main content

Target Selection

Target selection is the decision layer between retrieval and plan synthesis. It receives a small candidate set, compares the candidates with stable semantic and contract evidence, and returns the final tool that should be planned.

The selector does not replace the LLM. It gives the LLM a safer operating boundary. When deterministic evidence is strong and the LLM selected a weaker sibling, the selector can override. When evidence is close, it keeps the LLM target and records ambiguity.

Use this page when you need to explain why a specific tool was selected, why an LLM target was overridden, or why a Quality Lab case passed search but failed planning.

Where It Runs

The selector sits after graph retrieval and before PathSynthesizer.

StageInputOutputFailure Signal
Retrievequery, graph artifactranked candidatesexpected tool absent from Top-K
LLM intentquery, compact catalogoptional llm_targetLLM picks a sibling or external tool
Selectquery, candidates, evidencetarget_selector blockambiguous_target, no_candidates
Planselected target, entitiesexecutable Planunsatisfied_field, enum_required
Executeplan, adapter authrunner eventsauth/API/request failure

If the correct tool is absent from retrieval Top-K, fix search first. Target selection is designed to choose among visible candidates, not to recover missing index coverage.

When To Use It

Use target selection when:

  • retrieval Top-K contains the right tool but the LLM may choose a sibling
  • list, detail, count, and mutation operations have similar names
  • operation names are similar but request or response contracts differ
  • a product UI needs to explain LLM override decisions
  • Quality Lab needs a stable plan hit signal
  • promoted trace-learning evidence should influence ranking without dominating base retrieval

Do not use selector overrides to hide poor retrieval. If the expected tool is not in the candidate set, improve OpenAPI semantic build, aliases, contract extraction, or graph edges first.

Public API

select_target_candidate() is product-neutral. It reads generic tool metadata, retrieval evidence, and optional promoted learning suggestions.

from graph_tool_call.graphify import select_target_candidate

selection = select_target_candidate(
query="find refund-ready order details",
candidates=candidate_names,
tools=tools_by_name,
)

print(selection["selected_target"])
print(selection["reason_codes"])

Input Contract

ParameterTypeRequiredMeaning
querystryesOriginal user request
candidateslist[str] or list[dict]yesRetrieved candidate names or retrieval rows
toolsdict[str, Any]yesTool dictionary keyed by tool name
retrieval_resultslist[dict]noEvidence-rich retrieval rows from retrieve_graphify()
llm_targetstrnoTarget selected by the LLM intent step
learning_suggestionslist[dict]noPromoted collection-scoped trace-learning suggestions
policystrnoDefault is strong_evidence

The selector ignores candidates that are not present in tools. If llm_target is not in the candidate list but exists in tools, it is added to the comparison set so the final decision can explain the disagreement.

Output Schema

The return value is a plain dictionary so adapters can store it directly in intent metadata, plan metadata, Quality Lab results, and trace records.

{
"selected_target": "getOrderDetail",
"llm_target": "getGeneralOrderInfo",
"confidence": 0.87,
"overrode_llm": true,
"ambiguous": false,
"reason_codes": [
"llm_target_overridden"
],
"margin": 0.19,
"llm_margin": 0.19,
"policy": "strong_evidence",
"rank_signals": [],
"candidate_evidence": [],
"target_action_priority": {
"read": 3,
"search": 2
},
"result_shape_priority": {
"single": 3,
"list": 1
},
"learning_applied": false
}
FieldMeaning
selected_targetFinal selected tool name
llm_targetOriginal LLM target when supplied
confidenceSelector score of the final target
overrode_llmWhether deterministic evidence replaced the LLM target
ambiguousWhether the margin was weak or candidates were too close
reason_codesStable diagnostic reason codes
marginDifference between the top two selector scores
llm_marginDifference between the deterministic winner and the LLM target
rank_signalsPer-candidate scoring rows with selected and LLM flags
candidate_evidenceCompact evidence per candidate
target_action_priorityQuery-derived action preferences
result_shape_priorityQuery-derived result-shape preferences
learning_appliedWhether promoted learning suggestions affected scoring

The numeric score is useful for relative comparison inside one selector run. Do not treat absolute score values as a public compatibility contract.

Ranking Signals

The selector combines retrieval position with deterministic evidence from the collection artifact.

SignalSourceWhat It Helps With
retrieval rankcandidates, retrieval_resultskeeps the retrieval engine as the base ordering
operation surfacename, operation id, summary, descriptiondirect query and identifier matches
canonical_actionsemantic metadataread vs search vs mutation confusion
primary_resourcesemantic metadatabusiness object alignment
path_moduleOpenAPI metadatalarge API module scoping
result_shapesemantic metadata or surface inferencelist/detail/count/mutation siblings
contract fitmetadata.api_contractrequired/request/response field alignment
learningpromoted suggestionsvalidated local feedback as a low-weight boost

Good selector decisions usually have more than one supporting signal. A single weak text match should not override an LLM target.

Override Policy

The default strong_evidence policy is intentionally conservative.

ConditionBehavior
No candidates are validreturn no_candidates
LLM target is also the deterministic winnerkeep it
LLM target differs, winner has strong evidence, and margin is large enoughoverride
LLM target differs but margin is weakkeep LLM target and mark ambiguous_target
Top candidates are too closemark ambiguity or tie
LLM target is outside candidates and unknownreport llm_target_not_in_candidates

The library uses a fixed margin threshold for safe override. Product adapters should not lower that threshold casually. If operators want more aggressive behavior, first prove it with Quality Lab cases.

Reason Codes

ReasonMeaningTypical Next Step
selected_by_strong_evidenceDeterministic evidence selected the winnerproceed to plan synthesis
selected_by_rankRanking selected the winner without strong evidenceinspect evidence before relying on it for critical flows
llm_target_overriddenStrong evidence replaced the LLM targetstore selector block for audit
llm_target_preservedLLM target was kept even though another candidate ranked higherinspect margin and ambiguity
llm_target_not_in_candidatesLLM selected a tool outside the visible candidate setcheck catalog prompt and tool visibility
ambiguous_targetCandidate scores were too close for a confident overrideadd metadata, aliases, or contract evidence
candidate_tieTop candidates are effectively tiedadd a Quality Lab case or operator hint
no_candidatesNo selectable candidates were availablefix retrieval or source ingestion

Reason codes are stable enough to store in product logs and Quality Lab results.

Example: Detail vs List Sibling

Large enterprise OpenAPI catalogs often contain siblings such as:

ToolActionResourceShape
getMemberDeliveryListsearch or readmember_deliverylist
getMemberDeliveryDetailreadmember_deliverysingle
getMemberInforeadmembersingle

For a detail query, the selector should prefer the detail operation only when shape, resource, and contract evidence agree.

selection = select_target_candidate(
query="회원 배송지 상세 정보를 조회해줘",
candidates=[
"getMemberDeliveryList",
"getMemberDeliveryDetail",
"getMemberInfo",
],
tools=tools_by_name,
retrieval_results=retrieval_results,
llm_target="getMemberDeliveryList",
)

assert selection["selected_target"] == "getMemberDeliveryDetail"
assert selection["overrode_llm"] is True
assert "llm_target_overridden" in selection["reason_codes"]

If the selector cannot see the single shape or the response fields, it should not force an override. Fix semantic metadata or contract extraction first.

Example: Weak Margin

When two candidates are too close, ambiguity is a feature, not a bug.

selection = select_target_candidate(
query="주문 정보 조회",
candidates=["getOrderInfo", "getOrderSummary"],
tools=tools_by_name,
llm_target="getOrderSummary",
)

if selection["ambiguous"]:
show_operator_debug(selection["candidate_evidence"])

This tells the adapter to keep the result explainable and avoid pretending the engine had stronger evidence than it did.

Adapter Integration

Product adapters should run target selection in both online flows and regression suites.

Integration PointWhat To Store
intent resultllm_target, selected_target, overrode_llm
plan metadatacomplete target_selector block
Quality Lab resultselector outcome, reason codes, rank signals
trace learning recordscrubbed selector block
UI diagnosticscompact evidence comparison

Recommended flow:

from graph_tool_call import ToolGraph
from graph_tool_call.graphify import retrieve_graphify, select_target_candidate
from graph_tool_call.plan import ToolCatalogEntry, parse_intent

graph = ToolGraph.load("collection.json")
retrieval = retrieve_graphify(graph, query, top_k=8, include_evidence=True)

catalog = []
for row in retrieval["results"]:
tool = row.get("tool") or {}
metadata = tool.get("metadata") or {}
ai = metadata.get("ai_metadata") or {}
contract = metadata.get("api_contract") or {}
consumes = contract.get("consumes") or metadata.get("consumes") or []
catalog.append(
ToolCatalogEntry(
name=row["name"],
summary=ai.get("one_line_summary") or tool.get("description", "")[:180],
when_to_use=ai.get("when_to_use") or "",
canonical_action=ai.get("canonical_action") or "",
primary_resource=ai.get("primary_resource") or "",
consumes_tags=[
item.get("semantic_tag") or item.get("field_name")
for item in consumes
if isinstance(item, dict)
],
)
)

intent = parse_intent(query, catalog=catalog, llm=llm)

selection = select_target_candidate(
query=query,
candidates=retrieval["results"],
tools=graph.tools,
retrieval_results=retrieval["results"],
llm_target=intent.target,
learning_suggestions=promoted_suggestions,
)

plan = synthesizer.synthesize(
target=selection["selected_target"],
entities=intent.entities,
goal=query,
)
plan.metadata.setdefault("synthesis", {})["target_selector"] = selection

Adapters should pass a compact selector-ranked catalog to the LLM. That keeps the prompt small and makes the LLM see the same candidates the deterministic selector will audit.

UI Display Contract

Do not show the full raw tool metadata in a product UI. Show a comparison table.

UI FieldSource
final targetselected_target
LLM targetllm_target
override badgeoverrode_llm
uncertainty badgeambiguous, reason_codes
matched action/resource/shapecandidate evidence and rank signals
matched fieldscontract evidence
learning boostlearning_applied and learning signal row

For a failed run, this lets the operator see whether the problem was retrieval, LLM target selection, plan inputs, auth readiness, or downstream API execution.

Quality Checks

Add selector regression cases whenever you introduce a new semantic rule or change retrieval scoring.

CheckExpected Result
exact target matchselected target equals expected target
weak marginLLM target is preserved and ambiguous_target is recorded
strong evidence overrideselector overrides the wrong LLM sibling
list/detail siblingdetail query chooses single; list query chooses list
Korean query with English operation idmixed-language query still selects expected tool
promoted learning boostboost improves rank but does not dominate weak evidence

Useful commands:

poetry run pytest tests/test_trace_learning.py -q
poetry run pytest tests/test_graphify_contract_025.py -q
poetry run pytest tests/test_xgen_tool_graph_benchmark.py -q

For product validation, run Quality Lab plan cases and compare:

  • search hit@K
  • LLM target
  • selected target
  • override rate
  • ambiguous rate
  • plan hit rate

Operational Guidance

Treat selector output as evidence, not magic. A healthy large collection should show:

  • expected target present in Top-K
  • strong selector evidence for important plan cases
  • low ambiguity for high-frequency workflows
  • override decisions backed by semantic and contract evidence
  • Quality Lab fixtures that cover sibling operations
  • promoted learning suggestions visible as low-weight rank signals

If all candidates have unknown action, unassigned resource, or missing contracts, the selector cannot make reliable decisions. Rebuild the OpenAPI collection with semantic metadata and contract extraction enabled.