Exa
Back to demo

Enterprise Copilot with External Knowledge

Build a copilot that answers questions internal data cannot answer, with grounded answers and relevance-ranked external sources via Exa.

Why Exa for external knowledge?

An enterprise copilot is great at questions about a company's own data — orders, invoices, HR records. But many user questions require knowledge that lives outside the enterprise: general news, people data, company data, and finance. Calling Exa for those questions yields:

  1. Grounded answers: every claim traces back to a retrieved source the user can inspect
  2. Relevance-ranked retrieval: Exa's neural search returns results ranked by semantic relevance, not keyword overlap
  3. Always current: real-time information instead of stale training data
  4. Low latency: a single call returns ranked sources with content highlights — no separate scraping step
  5. Model agnostic: works with any LLM — the copilot's existing model stays in place

Get Started

1

Install dependencies

bash
npm install exa-js openai

Get your Exa API key from the Exa Dashboard.

You'll also need an API key from your model provider (OpenAI, OpenRouter, etc.).

2

Initialize clients

javascript
import Exa from "exa-js";
import OpenAI from "openai";

const exa = new Exa(process.env.EXA_API_KEY);
const client = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });
3

Define the external-knowledge tool

Give the copilot's model a tool it can call when a question falls outside internal data. The tool accepts 1-3 parallel searches:

javascript
const searchTool = {
  type: "function",
  function: {
    name: "web_search",
    description: `Search the external web via Exa for knowledge not available
in internal enterprise data: general news, people data, company data, finance.
Write queries as natural language.`,
    parameters: {
      type: "object",
      properties: {
        searches: {
          type: "array",
          items: {
            type: "object",
            properties: {
              query: { type: "string" },
              numResults: { type: "number", default: 5 },
              category: {
                type: "string",
                enum: ["company", "people", "research_paper"],
              }
            },
            required: ["query"]
          },
          description: "1-3 searches to run in parallel.",
          maxItems: 3,
        },
      },
      required: ["searches"],
    },
  },
};

Exa has dedicated company and people search categories that map directly onto the company-data and people-data question types an enterprise copilot sees.

4

Run the search and keep the ranking

When the model calls the tool, execute an Exa search. The order of results is the relevance ranking — preserve it so the UI can show ranked sources:

javascript
async function searchExa(query, category, numResults = 5) {
  const start = Date.now();
  const response = await exa.searchAndContents(query, {
    numResults,
    highlights: { maxCharacters: 4000 },
    type: "auto",
    ...(category ? { category } : {}),
  });
  return {
    latencyMs: Date.now() - start,
    results: response.results.map((r, rank) => ({
      rank: rank + 1,
      title: r.title,
      url: r.url,
      publishedDate: r.publishedDate,
      author: r.author,
      text: (r.highlights || []).join("\n"),
    })),
  };
}

highlights returns the most relevant page snippets alongside each result — no separate scraping step needed.

5

Ground the answer

Feed the ranked results back to the model and stream the final answer. The system prompt instructs the model to answer only from the retrieved sources:

javascript
const followup = await client.chat.completions.create({
  model: "gpt-5.6-luna",
  messages: [
    ...messages,
    {
      role: "user",
      content: `Here are ranked web search results:\n\n${resultsText}\n\nUsing ONLY these results, answer my original question.`,
    },
  ],
  stream: true,
});
6

Show the sources, not just the answer

Each Exa result includes title, url, publishedDate, and author. Render them as a ranked source panel under the answer, with the retrieval latency.

This gives users the two things an external-knowledge copilot must provide: a grounded answer and the underlying ranked evidence.


Query types this pattern covers

Conclusion

The copilot's model decides when a question needs external knowledge, Exa retrieves relevance-ranked sources with content in a single call, and the UI returns a grounded answer with the ranked evidence and latency attached.

Get started with Exa for free at dashboard.exa.ai.