Skip to main content

Tool Graph Search

Tool graph search retrieves a small, evidence-backed candidate set from a large tool catalog. It is the first stage before target selection, plan synthesis, and execution.

Instead of sending hundreds or thousands of tools to an LLM, graph-tool-call uses keyword matching, semantic metadata, IO contracts, graph edges, and optional learning evidence to produce a compact ranked set.

When To Use This

Use graph search when:

  • a catalog contains more tools than you want to expose to the LLM directly
  • tool names are inconsistent or mixed across Korean and English
  • OpenAPI descriptions are long, duplicated, or noisy
  • the caller needs evidence for why a tool was selected
  • execution should be guarded by deterministic target selection

Do not use graph search as a substitute for runtime authorization, business policy checks, or API execution safety. Those belong in the adapter.

Query Flow

  1. Normalize the user query.
  2. Search indexed tool text such as operation id, summary, action, resource, module, and contract fields.
  3. Combine score signals into a ranked candidate set.
  4. Expand candidates with producer tools when contract evidence shows data flow.
  5. Return evidence and score breakdowns when requested.
  6. Hand the ranked catalog to the LLM or to select_target_candidate().

Search API

Use retrieve_graphify() when the graph has already been built or loaded from a collection artifact. This is the API product adapters normally call before LLM target selection.

from graph_tool_call.graphify import retrieve_graphify

response = retrieve_graphify(
tg,
query,
top_k=10,
depth=2,
token_budget=2000,
history=None,
include_evidence=True,
learning_suggestions=None,
)
ParameterTypeDefaultPurpose
tgToolGraphrequiredBuilt or loaded tool graph
querystrrequiredNatural-language user request
top_kint10Maximum candidate rows returned
depthint2Graph expansion depth from seed candidates
token_budgetint2000Approximate character budget for subgraph_text
historylist[str]NoneTools already used in the session; these are demoted
include_evidenceboolFalseAdd score breakdown, edge evidence, and semantic evidence
learning_suggestionslist[dict]NoneOptional promoted trace-learning suggestions

Response contract:

FieldTypeMeaning
resultslist[dict]Ranked candidate rows
subgraph_textstrCompact LLM context for the selected subgraph
intentdictRead/write/delete/neutral intent scores
statsdictSeeds, visited graph size, and optional token budget diagnostics

Candidate rows contain name, score, and tool. With include_evidence=True, they also contain score_breakdown, expanded_from, edge_evidence, semantic_evidence, and optional learning_evidence.

For one-shot local experiments, ToolGraph.retrieve_with_scores() and graph-tool-call search are shorter. For production adapters, prefer the evidence-rich retrieve_graphify() response.

Minimal Example

from graph_tool_call import ToolGraph

graph = ToolGraph.from_url("openapi.json")

results = graph.retrieve_with_scores(
"find refund-ready orders",
top_k=8,
)

for result in results:
print(result.tool.name, result.score)

Ranking Signals

Search quality depends on multiple additive signals. A single fuzzy match should not dominate the result when stronger semantic or contract evidence exists.

SignalWhat It ChecksTypical Evidence
Keyword matchOperation id, name, summary, descriptionoperationId, normalized tokens
Action matchWhether query intent matches canonical_actionsearch, read, create, update, delete
Resource matchWhether query resource matches primary_resourceorder, customer, claim, payment
Module matchWhether the query points at a path/module grouppath_module, operation_group
Shape matchWhether the query asks for a list, detail, count, or mutationresult_shape
Contract matchRequest/response field compatibilityconsumes/produces leaves
Graph expansionRelated producer or manually linked toolsdata-flow and trace edges
Learning boostValidated promoted trace evidencetarget preference or plan path

Evidence Output

Use include_evidence=True when building a product UI, debugging search quality, or writing regression tests.

from graph_tool_call import ToolGraph
from graph_tool_call.graphify import retrieve_graphify

graph = ToolGraph.load("collection.json")
response = retrieve_graphify(
graph,
"회원 상세 정보를 조회해줘",
top_k=8,
include_evidence=True,
)

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

Important fields:

FieldMeaning
score_breakdownAdditive ranking signals used for this candidate
stats.seedsInitial matches before graph expansion
expanded_fromCandidate that caused this tool to be added
edge_evidenceGraph edge evidence used during expansion
stats.token_budget_usedApproximate retrieval context budget
semantic_evidenceSelector-ready semantic and contract evidence

Target Selector Handoff

Retrieval returns candidates. Target selection chooses the final tool.

from graph_tool_call.graphify import select_target_candidate

selection = select_target_candidate(
query="회원 상세 정보를 조회해줘",
candidates=[item["name"] for item in response["results"]],
tools=tools,
retrieval_results=response["results"],
llm_target=llm_intent.target,
)

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

The selector should only override the LLM when evidence is strong and the margin is sufficient. Ambiguous cases should stay visible in diagnostics instead of being silently corrected.

Korean And Mixed-Language Queries

Enterprise OpenAPI catalogs often mix Korean summaries with English operationId values.

Good retrieval indexes both:

  • Korean summary and description text
  • English operation names
  • path segments
  • deterministic action/resource/module metadata
  • consumes and produces field names

Example:

graph.retrieve_with_scores("환불 가능한 주문 목록", top_k=8)
graph.retrieve_with_scores("refund order list", top_k=8)

Both queries should surface the same target family when the underlying catalog contains matching semantic and contract evidence.

Troubleshooting

SymptomLikely CauseWhat To Inspect
Correct tool is not in Top-KMissing semantic metadata or weak textsemantic_summary, indexed fields
Correct tool is in Top-K but not selectedLLM target mismatch or weak selector margintarget_selector.rank_signals
Too many sibling tools tieMissing result shape or resource evidenceresult_shape, primary_resource
Producer tools are missingContract fields were not extractedapi_contract.produces, api_contract.consumes
Results depend on noisy descriptionsRaw OpenAPI leaves are overrepresentedscore breakdown and indexed text policy

Quality Checks

Run fast search tests during development:

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

Run broader gates before publishing a quality claim:

make quick
make xgen-scale-snapshot

Public benchmark claims should point to committed fixtures or stored result artifacts.

  • ToolGraph.retrieve()
  • ToolGraph.retrieve_with_scores()
  • graph_tool_call.graphify.retrieve_graphify()
  • graph_tool_call.graphify.expand_candidates_with_producers()
  • graph_tool_call.graphify.select_target_candidate()