NOUKAI

LangChain Patterns

Pattern catalog for auditing LangChain codebases — imports, code shapes, and deprecation status.

This page is a reference for the Audit & Design phase. It lists the LangChain patterns an AI assistant should search for when auditing a codebase, organized by era and type.

Eras of LangChain Code

LangChain code in the wild falls into three eras. Real codebases often mix them.

EraPeriodKey PatternStatus
Legacy Chains2022–2023LLMChain, SequentialChainDeprecated in v0.1.17, removed in v1.0
LCEL2023–presentprompt | llm | parser pipe compositionCurrent standard
LangGraph2024–presentStateGraph with nodes and edgesEmerging standard for stateful workflows

Imports to Search For

Core (Current)

from langchain_core.prompts import ChatPromptTemplate, PromptTemplate
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser, PydanticOutputParser
from langchain_core.runnables import RunnableSequence, RunnableParallel, RunnableBranch, RunnableLambda, RunnablePassthrough
from langchain_openai import ChatOpenAI
from langchain_anthropic import ChatAnthropic

LangGraph

from langgraph.graph import StateGraph, START, END
from langgraph.graph import add_messages
from langgraph.prebuilt import create_react_agent, ToolNode

Legacy (Deprecated)

from langchain.chains import LLMChain, SequentialChain, SimpleSequentialChain, TransformChain
from langchain.chains import ConversationalRetrievalChain  # deprecated v0.1.17, removed v0.3.0
from langchain.memory import ConversationBufferMemory, ConversationSummaryMemory
from langchain.agents import AgentExecutor, create_react_agent, create_openai_functions_agent

RAG (Current)

from langchain.chains import create_retrieval_chain
from langchain.chains.history_aware_retriever import create_history_aware_retriever
from langchain.chains.combine_documents import create_stuff_documents_chain

TypeScript/JavaScript

import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { StringOutputParser } from "@langchain/core/output_parsers";
import { RunnableSequence, RunnableParallel } from "@langchain/core/runnables";
import { StateGraph, START, END } from "@langchain/langgraph";

Code Shapes

These are the patterns to recognize during the audit step. Each maps to a Noukai flow topology.

LCEL Chain (Sequential)

The most common pattern in modern LangChain code. Maps to a sequential Noukai flow.

prompt = ChatPromptTemplate.from_template("Classify this: {text}")
model = ChatOpenAI(model="gpt-4o")
parser = StrOutputParser()
 
chain = prompt | model | parser
result = chain.invoke({"text": user_input})

What to capture: Each segment of the pipe (prompt, model, parser) becomes a block. The prompt template becomes the block's prompt text. The model becomes the block's model config.

LCEL with RunnableParallel

Maps to a parallel container in Noukai.

from langchain_core.runnables import RunnableParallel
 
chain = RunnableParallel(
    summary=prompt_summary | llm | StrOutputParser(),
    keywords=prompt_keywords | llm | StrOutputParser(),
    sentiment=prompt_sentiment | llm | StrOutputParser(),
)
result = chain.invoke({"text": user_input})

What to capture: Each named branch becomes a parallel block inside a v container. The keys (summary, keywords, sentiment) suggest block names.

RunnableBranch (Routing)

Maps to a branching flow — a router block followed by conditional blocks.

from langchain_core.runnables import RunnableBranch
 
branch = RunnableBranch(
    (lambda x: "technical" in x["category"], technical_chain),
    (lambda x: "billing" in x["category"], billing_chain),
    general_chain,  # default
)
result = branch.invoke({"category": "technical", "question": "..."})

What to capture: The routing logic becomes a router block (or can be encoded in prompt logic). Each branch becomes a downstream block. The default branch is the fallback.

LangGraph StateGraph

Maps to a complex Noukai flow with sequential and conditional blocks.

from langgraph.graph import StateGraph, START, END
from typing_extensions import TypedDict
 
class State(TypedDict):
    query: str
    category: str
    response: str
 
def classify(state: State) -> dict:
    # LLM call to classify
    return {"category": result}
 
def handle_technical(state: State) -> dict:
    # LLM call for technical queries
    return {"response": result}
 
def handle_general(state: State) -> dict:
    # LLM call for general queries
    return {"response": result}
 
builder = StateGraph(State)
builder.add_node("classify", classify)
builder.add_node("technical", handle_technical)
builder.add_node("general", handle_general)
 
builder.add_edge(START, "classify")
builder.add_conditional_edges("classify",
    lambda s: "technical" if s["category"] == "technical" else "general")
builder.add_edge("technical", END)
builder.add_edge("general", END)
 
graph = builder.compile()
result = graph.invoke({"query": "How do I reset my API key?"})

What to capture: Each node that contains an LLM call becomes a block. Edges define the flow topology. Conditional edges suggest branching. The State TypedDict suggests the flow's input/output schema.

Agent with Tool Calling

Maps to a single LLM block with tool configuration or a more complex flow depending on the tools.

from langgraph.prebuilt import create_react_agent
 
tools = [search_tool, calculator_tool, database_tool]
agent = create_react_agent(ChatOpenAI(model="gpt-4o"), tools=tools)
result = agent.invoke({"messages": [("user", "What's the weather in NYC?")]})

Agent loops are the hardest pattern to migrate because Noukai flows are DAGs (directed acyclic graphs), not loops. For agent patterns, consider: (1) converting the agent to a single powerful LLM block with tool descriptions in the prompt, (2) breaking the agent into a classification block + specialized handler blocks, or (3) keeping the agent as-is and only migrating the non-agent chains.

RAG Chain

Maps to a sequential flow where the first block handles retrieval context and the second generates the answer.

from langchain.chains import create_retrieval_chain
from langchain.chains.combine_documents import create_stuff_documents_chain
 
retriever = vector_store.as_retriever()
prompt = ChatPromptTemplate.from_template(
    "Answer based on context:\n{context}\n\nQuestion: {input}"
)
document_chain = create_stuff_documents_chain(llm, prompt)
rag_chain = create_retrieval_chain(retriever, document_chain)
result = rag_chain.invoke({"input": "What is our refund policy?"})

The retrieval step (vector search) runs outside Noukai — it's not an LLM call. In the migrated version, your code performs the retrieval locally and passes the retrieved context as input to the Noukai flow. The Noukai flow handles only the LLM generation part.

Legacy LLMChain (Deprecated)

If found, flag as deprecated. Maps to a single LLM block.

from langchain.chains import LLMChain
 
chain = LLMChain(llm=llm, prompt=prompt)
result = chain.run(text="Hello")

Legacy SequentialChain (Deprecated)

If found, flag as deprecated. Maps to a sequential Noukai flow.

from langchain.chains import SequentialChain
 
overall_chain = SequentialChain(
    chains=[chain_one, chain_two, chain_three],
    input_variables=["text"],
    output_variables=["final_output"],
)
result = overall_chain({"text": user_input})

Memory Patterns

LangChain memory classes manage conversation history. In Noukai, the calling code manages history and passes relevant context as input to the flow.

LangChain MemoryStatusMigration Approach
ConversationBufferMemoryDeprecatedPass conversation history in the flow's message or parameters input
ConversationSummaryMemoryDeprecatedCreate a separate "summarize history" flow, call it before the main flow
ChatMessageHistoryCurrentKeep as-is in calling code, pass relevant messages to the flow

Mapping Cheat Sheet

LangChain PatternNoukai Equivalent
LCEL pipe (a | b | c)Sequential blocks
RunnableParallelBlocks in a v (parallel) container
RunnableBranchRouter block + conditional blocks
StateGraph nodesIndividual blocks matching the graph topology
StateGraph conditional edgesBranching flow logic
AgentExecutor / tool loopSingle powerful block, or decompose into specialized blocks
create_retrieval_chainRetrieval in calling code → LLM blocks in Noukai flow
LLMChain (deprecated)Single LLM block
SequentialChain (deprecated)Sequential blocks
Output parsers (JsonOutputParser)Block output schema
Memory classesCalling code manages history, passes as input