Skip to main content

Build AI Agents with Needle and Agentic

3 min read
Agentic Logo

GitHub Repository

Use Needle as a powerful RAG tool in your AI agents through Agentic - a standard library of AI functions that works with all major TypeScript AI SDKs (LangChain, LlamaIndex, Vercel AI SDK, OpenAI SDK, etc).

Setup

Installation

install.shbash
npm install @agentic/needle openai dotenv

Environment Configuration

Create a .env file with your API keys:

.envenv
NEEDLE_API_KEY=your_needle_api_key_here
OPENAI_API_KEY=your_openai_api_key_here

Package Dependencies

Add these to your package.json:

package.jsonjson
{
  "dependencies": {
    "@agentic/core": "workspace:*",
    "@agentic/needle": "workspace:*",
    "dotenv": "^16.4.5",
    "openai": "^4.28.0"
  }
}

Building an AI Agent

Let's build an agent that can create collections, add documents, and perform semantic search. We'll break it down into steps:

1. Initial Setup

First, import the required packages and initialize the clients:

setup.tsjavascript
import 'dotenv/config'
import { NeedleClient } from '@agentic/needle'
import OpenAI from 'openai'

async function main() {
const needle = new NeedleClient()
const openai = new OpenAI()
let collectionId: string | undefined

const messages: OpenAI.ChatCompletionMessageParam[] = [
  {
    role: 'system',
    content:
      'You are a helpful assistant. Only use the information provided in the search results to answer questions. Do not make assumptions or add information from other sources.'
  },
  {
    role: 'user',
    content:
      'Create a collection for Needle documentation and add the Needle website (needle.app) to it, then search for what Needle is.'
  }
]

2. Creating a Collection

The agent will first create a new collection:

create_collection.tsjavascript
// Create collection  
const res = await openai.chat.completions.create({
  messages,
  model: "gpt-5",
  temperature: 0,
  tools: needle.collections.functions.toolSpecs,
  tool_choice: "required",
});
const message = res.choices[0]?.message!;
console.log("Create collection response");
messages.push(message);

// Handle collection creation
for (const toolCall of message.tool_calls || []) {
  if (toolCall.function.name === "create_collection") {
    const fn = needle.collections.functions.get(toolCall.function.name)!;
    const result = await fn(toolCall.function.arguments);
    console.log("Collection created");
    collectionId = result.id;
    messages.push({
      role: "tool",
      tool_call_id: toolCall.id,
      content: JSON.stringify(result),
    });
  }
}

3. Adding Content

Next, add a website to the collection:

add_file.tsjavascript
// Add file to collection
const addFileRes = await openai.chat.completions.create({
  messages,
  model: "gpt-5",
  temperature: 0,
  tools: needle.collections.functions.toolSpecs,
  tool_choice: "required",
});
const addFileMessage = addFileRes.choices[0]?.message!;
console.log("Add file");
messages.push(addFileMessage);

// Handle file addition
const addFileCall = addFileMessage.tool_calls?.find(
  (call) => call.function.name === "add_file",
);
if (addFileCall) {
  const fn = needle.collections.functions.get(addFileCall.function.name)!;
  const params = JSON.parse(addFileCall.function.arguments);
  params.collection_id = collectionId;
  params.files = [{ url: "https://needle.app", name: "Needle Website" }];
  const result = await fn(JSON.stringify(params));
  console.log("Files added");
  messages.push({
    role: "tool",
    tool_call_id: addFileCall.id,
    content: JSON.stringify(result),
  });
}

// Wait for indexing
console.log("Waiting 20 seconds for file indexing...");
await new Promise((resolve) => setTimeout(resolve, 20_000));

Now search the collection:

search.tsjavascript
// Search collection
const searchRes = await openai.chat.completions.create({
  messages,
  model: "gpt-5",
  temperature: 0,
  tools: needle.collections.functions.toolSpecs,
  tool_choice: "required",
});
const searchMessage = searchRes.choices[0]?.message!;
console.log("Search response");
messages.push(searchMessage);

// Handle search
const searchCall = searchMessage.tool_calls?.find(
  (call) => call.function.name === "search_collection",
);
if (searchCall) {
  const fn = needle.collections.functions.get(searchCall.function.name)!;
  const params = JSON.parse(searchCall.function.arguments);
  params.collection_id = collectionId;
  const result = await fn(JSON.stringify(params));
  console.log("Search results");
  messages.push({
    role: "tool",
    tool_call_id: searchCall.id,
    content: JSON.stringify(result),
  });
}

5. Generating Summary

Finally, generate a summary of the search results:

generate_summary.tsjavascript
// Generate summary
messages.push({
  role: 'user',
  content:
    'Based ONLY on the search results above, what is Needle? If there are no results yet, please say so.'
})

const summaryRes = await openai.chat.completions.create({
  messages,
  model: 'gpt-5',
  temperature: 0,
  tools: needle.collections.functions.toolSpecs
})
const summaryMessage = summaryRes.choices?.[0]?.message

console.log('\n=== AI Summary ===')
if (summaryMessage?.content) {
  console.log('\n' + summaryMessage.content + '\n')
} else {
  console.log('\nNo content in response\n')
}

await main()

Support

For questions and support: