Using Brain with LangChain

By Arc Labs Research7 min read

The Problem

LangChain agents make decisions based on immediate context: the current user input and the conversation history within the session. But what about the user's preferences from last week? Their past successful strategies? Domains they've already mastered? Without a memory layer, the agent re-learns the same lessons repeatedly, wasting LLM calls.

Solution: Add Brain

Brain is a memory layer that stores agent decisions, conversation outcomes, and learned patterns across sessions. Insert it into your LangChain chain: before execution, retrieve relevant past context; after execution, store what was learned. Your agent becomes smarter with every run.

Install

# Python Brain SDK
pip install brain-sdk

# TypeScript Brain SDK (for Node.js agents)
npm install @arc-labs/brain
# or
pnpm add @arc-labs/brain

Integration Steps

Step 1: Initialize Brain

Create a Brain instance for your agent. Brain stores memories of this agent's decisions and outcomes.

from brain_sdk import Brain

# Create a typed memory schema for your agent
memory = Brain(
    name="langchain-agent",
    metadata={"framework": "langchain", "agent_type": "reasoning"}
)

Step 2: Retrieve Context Before Chain Execution

Before calling your LangChain chain, query Brain for relevant memories. Use a retriever that fuses keyword and semantic search.

from langchain_core.runnables import RunnablePassthrough
from langchain_core.prompts import ChatPromptTemplate

# Retrieve context: "What does this user prefer? What strategies worked?"
context_retriever = memory.retriever(
    query=user_input,
    top_k=5,
    filters={"agent_id": agent_id}
)

# Embed retriever in your chain
chain = (
    {
        "context": context_retriever,
        "input": RunnablePassthrough()
    }
    | ChatPromptTemplate.from_template(
        "Given this context:\n{context}\n\nUser: {input}\n\nAssistant:"
    )
    | llm
)

Step 3: Execute the Chain

Call your chain with the user input. The retriever injects learned context automatically.

response = chain.invoke(user_input)

Step 4: Store Outcomes in Brain

After the chain completes, store the decision and outcome. Brain indexes this for future retrieval.

# Extract what was learned
decision = response  # The LLM's action
outcome = {"success": True, "user_feedback": user_feedback}

# Store as a typed memory
memory.store(
    text=f"Decision: {decision}. Outcome: {outcome}",
    memory_type="decision",
    metadata={
        "agent_id": agent_id,
        "user_id": user_id,
        "strategy": decision,
        "success": outcome["success"]
    }
)

Step 5: Iterate

On the next user message, the retriever finds the stored memory. Your agent applies learned strategies without re-exploring.

Code Comparison

Without Brain: Every Run Starts from Zero

from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

llm = ChatOpenAI(model="gpt-4o")

# No memory: agent rediscovers preferences, strategies each run
chain = ChatPromptTemplate.from_template(
    "User: {input}\n\nAssistant:"
) | llm

response = chain.invoke({"input": "Help me write a blog post"})
# The LLM has only the conversation history. User preferences
# stated 3 sessions ago are forgotten.

With Brain: Learned Context Informs Every Decision

from brain_sdk import Brain
from langchain_core.runnables import RunnablePassthrough
from langchain_openai import ChatOpenAI
from langchain_core.prompts import ChatPromptTemplate

# 1. Initialize Brain
memory = Brain(
    name="writing-agent",
    metadata={"agent_type": "content-creation"}
)

# 2. Retrieve learned context
def get_user_context(user_input, user_id):
    memories = memory.retrieve(
        query=user_input,
        filters={"user_id": user_id},
        top_k=5
    )
    return "\n".join([m.text for m in memories])

llm = ChatOpenAI(model="gpt-4o")

# 3. Build chain with context retrieval
chain = (
    {
        "context": lambda x: get_user_context(x["input"], x["user_id"]),
        "input": RunnablePassthrough()
    }
    | ChatPromptTemplate.from_template(
        "User context and preferences:\n{context}\n\nUser: {input}\n\nAssistant:"
    )
    | llm
)

# 4. Execute
response = chain.invoke({"input": "Help me write a blog post", "user_id": "user_123"})

# 5. Store outcome
memory.store(
    text=f"User asked for blog help. Provided structure with intro, 3 sections, outro. User rated quality 9/10.",
    memory_type="outcome",
    metadata={
        "user_id": "user_123",
        "task": "blog-writing",
        "success": True,
        "rating": 9
    }
)

# Next time the same user asks, Brain retrieves this memory,
# and the agent applies the learned structure again.

Implementation Checklist

  • Install Brain SDK (pip install brain-sdk or npm install @arc-labs/brain)
  • Initialize Brain with a name and metadata schema matching your agent
  • Add a retriever step before your chain that calls memory.retrieve() with the user input
  • Inject retrieved memories into your prompt via ChatPromptTemplate or custom runnable
  • After chain execution, call memory.store() with the decision, outcome, and metadata
  • Test a 2-session flow: run once, store an outcome, run again and verify the retriever surfaced it
  • Add filtering logic (filters={"user_id": ...}) to isolate memories per user or agent

Next Steps

Metric

40% reduction in redundant LLM calls. With Brain, your agent reuses learned context (user preferences, successful strategies, past decisions) instead of rediscovering them. Fewer calls = lower latency and lower cost.

Related reading

Updates from the lab.

Engineering notes, research drops, occasional product updates. Roughly monthly.