Difference Between complete(), run(), and extract() Methods in Needle
complete() performs a single-shot LLM call returning a raw JSON envelope, run() executes an iterative tool-calling loop with automatic result feeding, and extract() provides one-shot structured data extraction by treating a Pydantic schema as the sole available tool.
The cactus-compute/needle library exposes three distinct high-level Python APIs for language model interaction. Understanding the difference between complete(), run(), and extract() methods in Needle is essential for selecting the right abstraction: they differ in execution steps, return types, and how they handle tool registration.
Internal Implementation of the Three APIs
Each method serves a specific interaction pattern with the underlying native engine.
complete(): Single-Shot Completion
The complete() method acts as a thin wrapper around the compiled C library function needle_complete. Located in needle/__init__.py at lines 103–118, this method serializes your prompt, calls the native engine, and deserializes the JSON response.
It performs exactly one model invocation. Tool calls only occur if your prompt already contains a tool schema in its content. The return value is a JSON object (Python dict) containing the model's text output and, if applicable, a function_calls description.
run(): Iterative Tool Orchestration
The run() method builds upon complete() to enable multi-step agentic behavior. As implemented in needle/__init__.py at lines 19–40, it first calls complete() once, then inspects the response for "function_calls" entries.
If function calls exist, it looks up the corresponding Python implementation in self._functions, executes it, captures any exceptions, and feeds the accumulated results back to the model via another complete() call. This loop repeats until no more calls are present or the max_steps limit is reached. The return value is a JSON envelope containing the final model response plus an additional "results" field with the list of tool-call results.
extract(): Structured Data Extraction
The extract() method provides a convenience wrapper for one-shot structured extraction. According to needle/__init__.py at lines 57–68 (standalone function) and lines 141–142 (method wrapper), it creates a temporary Needle agent with your supplied Pydantic schema as the only available tool.
It executes a single complete() call, inspects the returned function_calls, and instantiates your schema class with the arguments. If the model generated a matching function call, it returns an instance of the provided Pydantic model (or a plain dict if specified); otherwise, it returns None.
Key Differences Summary
- Execution Steps:
complete()performs exactly one step;run()loops up tomax_steps;extract()performs exactly one step but adds schema instantiation. - Return Enrichment:
run()appends a"results"list containing tool execution outputs;complete()returns only the raw envelope;extract()returns the parsed Python object directly. - Tool Registration:
run()utilizes the full tool registry of the persistentNeedleinstance;extract()temporarily restricts the tool set to a single schema;complete()uses tools already bound to the instance or none. - Use Case: Use
complete()for simple chat completions,run()for autonomous agents requiring external data, andextract()for parsing unstructured text into typed data models.
Practical Code Examples
from needle import Needle
Simple Completion with complete()
agent = Needle()
resp = agent.complete("Explain quantum entanglement in one sentence.")
print(resp["text"])
Iterative Tool Execution with run()
def fetch(url: str) -> str:
import requests
return requests.get(url).text
agent = Needle(tools=[fetch])
result = agent.run(
"Fetch the first paragraph of https://example.com and summarise it.",
max_steps=5
)
print(result["results"]) # List of tool-call results
print(result["text"]) # Final summarised text
Structured Extraction with extract()
from pydantic import BaseModel
class PersonInfo(BaseModel):
name: str
email: str
text = "John Doe's email is john.doe@example.com."
extracted = Needle().extract(text, PersonInfo)
print(extracted) # PersonInfo(name='John Doe', email='john.doe@example.com')
Summary
complete()inneedle/__init__.pylines 103–118 provides single-shot LLM access via the nativeneedle_completeC function, returning raw JSON.run()inneedle/__init__.pylines 19–40 orchestrates multi-step tool calling by looping overcomplete(), executing Python functions fromself._functions, and aggregating results.extract()inneedle/__init__.pylines 57–68 creates a temporary agent for one-shot Pydantic schema instantiation from model outputs.
Frequently Asked Questions
When should I use complete() instead of run()?
Use complete() when you need a single raw model response without automatic tool execution. Choose run() when your application requires the model to iteratively call external functions (like APIs or databases) and feed results back into the conversation until completion.
Does run() support limiting the number of tool calls?
Yes. The run() method accepts a max_steps parameter that caps the number of back-and-forth iterations between the model and your Python functions. The loop terminates when no more function_calls remain in the response or when the step limit is reached.
Can extract() return a plain dictionary instead of a Pydantic model?
Yes. While extract() is designed to instantiate Pydantic models for type safety, it can return a plain Python dictionary if the schema parsing fails or if no function call is generated by the model, returning None instead.
Is extract() slower than complete() because it creates a temporary agent?
The overhead is minimal. extract() creates a short-lived Needle instance internally (as seen in needle/__init__.py lines 141–142), executes a single complete() call, and immediately tears down. For most use cases, this temporary instantiation introduces negligible latency compared to the model inference time.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →