Framework Integrations

LangChain

The LangChain callback handler is the primary integration. One handler, zero changes to your chain, full coverage of retrievals and (optionally) generations.

Recommended over wrap() because callbacks fire correctly for ensemble retrievers, MultiVectorRetriever, ParentDocumentRetriever, MMR rerankers, cached retrievers, and LCEL-composed chains — all places where a naive wrap either misses traces or generates noise.

Install

npm
npm install buzo-sdk @langchain/core

Basic usage

Attach the handler to any retriever invocation. The handler is safe to reuse across requests.

Retriever
import { Buzo } from 'buzo-sdk'
import { createBuzoCallbackHandler } from 'buzo-sdk/langchain'

export const buzo = new Buzo({ apiKey: process.env.BUZO_API_KEY! })

const handler = await createBuzoCallbackHandler(buzo, {
  collectionId: 'prod-support-kb',
  agentId: 'support-v3',
})

const docs = await retriever.invoke('how do I reset my password?', {
  callbacks: [handler],
})

Full chain coverage (retrieval + generation)

Enable outputCapture on the Buzo client and the same handler also fires on the LLM step of the chain — Buzo correlates retrieval and generation server-side via LangChain runId.

LCEL chain
import { Buzo } from 'buzo-sdk'
import { createBuzoCallbackHandler } from 'buzo-sdk/langchain'
import { ChatPromptTemplate } from '@langchain/core/prompts'
import { ChatOpenAI } from '@langchain/openai'
import { RunnablePassthrough } from '@langchain/core/runnables'

const buzo = new Buzo({
  apiKey: process.env.BUZO_API_KEY!,
  outputCapture: 'redacted',
  outputRedactPatterns: [
    { pattern: /[\w.-]+@[\w.-]+\.\w+/g, replacement: '<EMAIL>' },
  ],
})

const handler = await createBuzoCallbackHandler(buzo, {
  collectionId: 'prod-support-kb',
  agentId: 'support-v3',
})

const prompt = ChatPromptTemplate.fromTemplate(`
Answer based on context:
{context}

Question: {question}`)

const chain = RunnablePassthrough
  .assign({ context: async (i) => retriever.invoke(i.question) })
  .pipe(prompt)
  .pipe(new ChatOpenAI({ modelName: 'gpt-4o' }))

const answer = await chain.invoke(
  { question: 'how do I reset my password?' },
  { callbacks: [handler] },
)

What gets captured

EventWhen it firesSent to
handleRetrieverEndEvery retriever invocation in the chainPOST /v1/retrieval-traces
handleLLMEndEvery LLM/ChatModel call — only when outputCapture !== 'off'POST /v1/generation-traces
handleRetrieverError / handleLLMErrorFailure paths; trace recorded with error field, original error re-thrownSame endpoints as above

Multiple collections in one chain

If your chain uses retrievers against different Buzo collections — for example an ensemble retriever that combines a product KB with a support KB — pass mapRunToContext to derive the collectionId per invocation from LangChain run metadata.

ts
const handler = await createBuzoCallbackHandler(buzo, {
  collectionId: 'default-kb',
  mapRunToContext: ({ tags }) => {
    if (tags?.includes('product')) return { collectionId: 'product-kb' }
    if (tags?.includes('support')) return { collectionId: 'support-kb' }
    return undefined
  },
})

Compatibility

  • LangChain.js v0.1.x, v0.2.x, v0.3.x.
  • @langchain/core is declared as an optional peer dependency. The SDK imports it lazily — you can install buzo-sdk in a project that does not use LangChain without cost.
  • Ensemble retrievers, MultiVectorRetriever, ParentDocumentRetriever, cached retrievers, and MMR rerankers all emit the expected handleRetrieverEnd callbacks and are fully supported.
Not using LangChain? See Vanilla retrievers for the wrap() and wrapPineconeIndex() helpers, or call recordRetrieval directly.