LangChain.js

repository·main·Indexed 12 days ago

https://github.com/langchain-ai/langchainjs

An agent engineering platform and framework for building LLM-powered applications in JavaScript and TypeScript. It provides a standard interface for models, embeddings, tools, and vector stores to create complex AI workflows. The framework supports multiple runtimes including Node.js, Bun, and Cloudflare Workers, and includes tools for model profile generation and standardized integration testing.

Tokens
187.2K
Snippets
651
Records
893
Agent score
94%

What's inside LangChain.js

  1. Explore the LangChain ecosystem

    main

    LangChain is part of a larger ecosystem of tools designed for different stages of agent development:

    • Deep Agents (JS): A higher-level package built on LangChain for agents with built-in capabilities like planning, subagents, and file system usage.
    • LangGraph.js: A low-level agent orchestration framework for building agents that handle complex tasks, offering customizable architecture, long-term memory, and human-in-the-loop workflows.
    • LangSmith: A unified developer platform for building, testing, and monitoring LLM applications. It is used for debugging, evaluating agent trajectories, and gaining production visibility.
    • LangSmith Deployment: A purpose-built platform for deploying and scaling agents with long-running, stateful workflows.
    • Integrations: A vast library of chat & embedding models, tools, toolkits, and vector stores.
  2. Handle Zod schema limitations for Gemini tools

    main

    When using tools with Gemini models through Vertex AI, certain Zod schema features are unsupported and will cause errors. Follow these patterns to ensure compatibility:

    Unsupported: Discriminated Unions

    .discriminatedUnion() is not supported. Solution: Use a flat object with an enum and optional fields.

    // ❌ Unsupported
    z.discriminatedUnion("type", [
      z.object({ type: z.literal("a"), value: z.string() }),
      z.object({ type: z.literal("b"), value: z.number() }),
    ]);
    
    // ✅ Supported
    z.object({
      type: z.enum(["a", "b"]),
      stringValue: z.string().optional(),
      numberValue: z.number().optional(),
    });

    Unsupported: Union Types

    z.union() is not supported. Solution: Use separate optional fields within a single object.

    // ❌ Unsupported
    z.union([z.string(), z.number()]);
    
    // ✅ Supported
    z.object({
      stringValue: z.string().optional(),
      numberValue: z.number().optional(),
    });

    Unsupported: Positive Refinement

    .positive() is automatically converted to .min(0.01). Solution: Use .min() directly to avoid ambiguity.

    // ⚠️ Automatically converted
    z.number().positive();
    
    // ✅ Preferred
    z.number().min(0.01);
  3. Manage environment variables in tests with `env`

    main

    The @langchain/test-helpers/env module provides utilities for managing process.env during testing, specifically designed for Jest. It allows you to set, preserve, or delete environment variables while ensuring changes are isolated to individual tests and automatically cleaned up using beforeEach and afterEach hooks.

    import { env } from "@langchain/test-helpers/env";
  4. How Tool Output Mapping works in MCP Adapters

    main

    MCP tools return arrays of content blocks (text, image, audio, or embedded resources). @langchain/mcp-adapters maps these into LangChain ToolMessage objects using two primary configuration settings:

    1. useStandardContentBlocks: Determines the internal structure of the content blocks.

      • When true (recommended), outputs are converted to standardized types like StandardTextBlock, StandardImageBlock, StandardAudioBlock, and StandardFileBlock (compatible with @langchain/core 0.3.48+).
      • When false, outputs use older formats like MessageContentText or MessageContentImageUrl.
    2. outputHandling: Determines visibility to the LLM.

      • ToolMessage.content: Data sent here is included in the LLM's input context.
      • ToolMessage.artifact: Data sent here is not included in the LLM context. This is useful for large outputs (like dataframes) or multimodal data that the specific LLM provider cannot handle directly.

    Default Behavior: MCP resource blocks are routed to artifact, while all other types are routed to content.

  5. Configure searchParameters in ChatXAI

    main

    You can control Live Search behavior globally by passing searchParameters to the ChatXAI constructor, or per-request by passing them to the .invoke() method.

    Note on Naming: When using tools.xaiLiveSearch(), use camelCase field names (e.g., maxSearchResults, fromDate, allowedWebsites). These are automatically mapped to the underlying API's snake_case requirements.

    // Global configuration via constructor
    const model = new ChatXAI({
      model: "grok-3-fast",
      searchParameters: {
        mode: "auto", // "auto" | "on" | "off"
        max_search_results: 5,
        from_date: "2024-01-01", // ISO date string
        return_citations: true,
      },
    });
    
    // Per-request override
    const result = await model.invoke("Find recent news about SpaceX", {
      searchParameters: {
        mode: "on",
        max_search_results: 10,
        sources: [
          {
            type: "web",
            allowed_websites: ["spacex.com", "nasa.gov"],
          },
        ],
      },
    });
  6. Understand the role of @langchain/core

    main

    @langchain/core provides the base abstractions and schemas that power the LangChain ecosystem. It defines the interfaces for key components such as:

    • Language models
    • Chat models
    • Vectorstores
    • Retrievers
    • Runnables
    • Document loaders
    • Embedding models

    Because these abstractions are standardized, any provider-specific package (like @langchain/openai) can implement these interfaces, allowing them to be used interchangeably within LangChain chains and workflows.

  7. Relationship between LangChain.js and LangChain Python

    main

    LangChain.js is designed to integrate seamlessly with the LangChain Python package.

    Key compatibility features include:

    • Serialization: All major objects (prompts, LLMs, chains, etc.) are designed to be serialized and shared across different languages.
    • LangChainHub: You can use the LangChainHub to access serialized versions of prompts, chains, and agents that are compatible with both the JS and Python ecosystems.
  8. When to use @langchain/classic vs langchain v1.0

    main

    Use @langchain/classic if:

    • You have existing code using legacy chains (e.g., LLMChain, ConversationalRetrievalQAChain, RetrievalQAChain).
    • You use the Indexing API (RecordManager).
    • You depend on @langchain/community integrations previously re-exported from the main langchain package.
    • You are maintaining an existing application and are not yet ready to migrate to the createAgent API.

    Use langchain v1.0 for new projects because:

    • It provides the createAgent API for cleaner, more powerful agent building with middleware support.
    • It offers better performance and a more focused, less complex API surface.
    • It is the primary focus for active development and new features.
  9. Customize tool calls with Tool Hooks

    main

    Use beforeToolCall and afterToolCall hooks in MultiServerMCPClient to intercept and modify tool arguments, headers, or results.

    import { MultiServerMCPClient } from "@langchain/mcp-adapters";
    
    const client = new MultiServerMCPClient({
      mcpServers: {
        math: {
          transport: "stdio",
          command: "npx",
          args: ["-y", "@modelcontextprotocol/server-math"],
        },
      },
    
      // Modify args or headers before the tool is called
      beforeToolCall: ({ serverName, name, args }) => {
        const nextArgs = { ...(args as Record<string, unknown>), injected: true };
        return {
          args: nextArgs,
          headers: { "X-Request-ID": crypto.randomUUID() },
        };
      },
    
      // Modify the result after the tool has executed
      afterToolCall: (res) => {
        // Return a 2-tuple [content, artifact]
        if (res.name === "someTool") return { result: ["modified-output", []] };
        
        // Or return the original result
        return { result: res.result };
      },
    });
    
    const tools = await client.getTools();
    const t = tools.find((tool) => tool.name.includes("add"));
    const out = await t?.invoke({ a: 1, b: 2 });