September 28, 2025

LangGraph




What is LangGraph?

LangGraph is an open-source framework for building stateful, controllable AI agent workflows as graphs. You describe your app as nodes (steps) and edges (how to move between steps), with a shared, typed state flowing through the graph. It’s designed for agents and multi-step LLM apps where you need loops, branching, tool use, memory, human-in-the-loop, and reliability. 

Core ideas:

  • StateGraph: declare the shape of the shared state. Each node outputs a partial update (a diff). LangGraph applies it to the state—no in-place mutation.

  • Nodes & Edges: register node functions and connect them with edges; use conditional edges for branching; special START and END markers define entry/exit. 

  • Persistence (checkpointers): when compiled with a checkpointer, the graph saves a checkpoint each super-step into a thread, enabling resumability, memory, time-travel, fault tolerance, and human review. 

  • Helpful built-ins & optional platform: quickstarts and message-centric state helpers in the docs to get started fast, plus an optional LangGraph Platform to deploy and operate long-running, stateful agent workflows. 

The smallest possible example (Python)

This is a literal “hello world” graph: one node that replies, wired from START → node → END.

code

# pip install --pre -U langgraph from langgraph.graph import StateGraph, MessagesState, START, END # A node: takes the current state, returns updates to it def say_hello(state: MessagesState): # Append one AI message to the conversation return {"messages": [{"role": "ai", "content": "hello world"}]} # 1) Define graph over a message-based state graph = StateGraph(MessagesState) # 2) Register the node (name inferred from the function) graph.add_node(say_hello) # 3) Wire edges: START -> say_hello -> END graph.add_edge(START, "say_hello") graph.add_edge("say_hello", END) # 4) Compile to a runnable graph app = graph.compile() # 5) Run it (you can pass an initial state; here we start empty) result = app.invoke({"messages": []}) print(result["messages"][-1]["content"]) # -> hello world

This mirrors the official quickstart, just with explicit prints. The key parts to notice are StateGraph(MessagesState), add_node, add_edge(START, ...), add_edge(..., END), and compile(). 

A Tiny Graph: NFL/NBA Score Router

This minimal example shows how LangGraph models an agent as a few small nodes connected by edges: a router node inspects the latest user message to determine the league (NFL or NBA), then branches to fetch_nfl or fetch_nba, each returning a short list of mock scores; finally, a finalize node formats a concise reply. If the league is unclear, router simply asks and loops until it has enough info. The key idea is that each node returns only partial updates (like {"league": "..."} or {"scores": [...]}), which LangGraph merges into the shared state, so you get predictable, readable control flow without in-place mutation—and you can swap in real API calls without changing the graph’s structure.

START → Router ──┬──→ FetchNFL ──→ Finalize → END └──→ FetchNBA ──→ Finalize → END (if league unknown: Router asks → user replies → Router again)


# pip install --pre -U langgraph from typing import TypedDict, Optional, List, Dict, Literal from langgraph.graph import StateGraph, MessagesState, START, END class ScoreState(MessagesState, TypedDict, total=False): league: Optional[str] # "nfl" | "nba" scores: Optional[List[Dict]] # [{"home":..., "away":..., "home_score":..., "away_score":..., "status":...}] def detect_league(text: str) -> Optional[str]: t = text.lower() if "nfl" in t or "football" in t: return "nfl" if "nba" in t or "basketball" in t: return "nba" return None def router(state: ScoreState) -> Literal["fetch_nfl", "fetch_nba", "router"]: last = state["messages"][-1]["content"] if state["messages"] else "" league = detect_league(last) or state.get("league") if not league: return {"messages": [{"role": "ai", "content": "Which league would you like: NFL or NBA?"}]} | "router" return {"league": league} | ("fetch_nfl" if league == "nfl" else "fetch_nba") def fetch_nfl(state: ScoreState): return {"scores": [{"away": "Cowboys", "away_score": 20, "home": "Chiefs", "home_score": 24, "status": "Final"}]} def fetch_nba(state: ScoreState): return {"scores": [{"away": "Warriors", "away_score": 105, "home": "Lakers", "home_score": 108, "status": "Final"}]} def finalize(state: ScoreState): league = (state.get("league") or "UNKNOWN").upper() scores = state.get("scores") or [] if not scores: return {"messages": [{"role": "ai", "content": f"No {league} scores found."}]} lines = [f"{league} scores:"] for g in scores: lines.append(f"- {g['away']} {g['away_score']} @ {g['home']} {g['home_score']} — {g['status']}") return {"messages": [{"role": "ai", "content": "\n".join(lines)}]} g = StateGraph(ScoreState) g.add_node("router", router) g.add_node("fetch_nfl", fetch_nfl) g.add_node("fetch_nba", fetch_nba) g.add_node("finalize", finalize) g.add_edge(START, "router") g.add_conditional_edges( "router", lambda s: "fetch_nfl" if s.get("league") == "nfl" else ("fetch_nba" if s.get("league") == "nba" else "router"), {"fetch_nfl": "fetch_nfl", "fetch_nba": "fetch_nba", "router": "router"} ) g.add_edge("fetch_nfl", "finalize") g.add_edge("fetch_nba", "finalize") g.add_edge("finalize", END) app = g.compile() # Example: # app.invoke({"messages": [{"role": "human", "content": "NBA"}]})

LangChain and LangGraph

LangChain is a general LLM orchestration framework that covers models, prompts, retrievers, tools, and LCEL for composing linear flows, plus LangServe and LangSmith for deployment and observability. LangGraph, created by the same team, adds a graph centric layer for stateful, multi step, and agentic workflows where nodes transition via edges, supporting loops, branching, backtracking, multi agent patterns, and checkpointed state.

Use plain LangChain and LCEL for simple, mostly acyclic pipelines such as retrieve then generate then post process. Prefer LangGraph when you need iterative tool use, richer control flow, memory, or recovery. The two interoperate seamlessly: LangGraph nodes can call LangChain runnables, tools, and retrievers, and a complete LangGraph app can be wrapped as a runnable inside larger LangChain compositions. Both integrate with LangSmith for tracing and evaluation and can be exposed through LangServe. Keep state transition logic in LangGraph, factor text and IO and post processing into small LangChain runnables for reuse and testing, begin with the simplest approach, and introduce a graph only when control flow complexity or durability via checkpointers like SQLite or Postgres justifies it.


Reference

https://langchain-ai.github.io/langgraph/reference/
https://docs.langchain.com/oss/python/langgraph/quickstart
https://github.com/langchain-ai/langgraph
https://www.langchain.com/langgraph
https://docs.langchain.com/langgraph-platform/index
https://docs.langchain.com/oss/python/langchain/overview

blog helper

 B 

code block

code start

hello word
code end

expand/collapse content

content start

click to open

inside 1

inside 2


content end

expand/collapse code block content

content start

click to open

inside 1 code start

hello word
inside 2 code end

content end

LangChain





What LangChain Is (and Why It’s Used)

LangChain is a Python/TypeScript framework for building LLM-powered applications. It gives you a cohesive set of abstractions for:

  • Prompting (templates, few-shot, chat message assembly)

  • Model I/O (chat/LLMs, embeddings) with structured post-processing via output parsers 

  • Runnables + LCEL: a declarative way to wire steps into reliable, composable pipelines that support invoke, batch, stream, async out of the box

The big idea: you describe what your LLM workflow should do by composing “runnables,” and LangChain optimizes how it runs. 


A simple example

Goal: Take a messy product review and return structured JSON: { "sentiment": "...","pros":[...], "cons":[...] }.

Code

# pip install langchain langchain-openai
# pip install -U langchain-community faiss-cpu from langchain.prompts import ChatPromptTemplate from langchain_openai import ChatOpenAI from langchain_core.output_parsers import JsonOutputParser # 1) A very explicit prompt that asks for JSON only prompt = ChatPromptTemplate.from_messages([ ("system", "You are a careful analyst. Extract sentiment, pros, and cons in strict JSON."), ("human", "Review: {review}\n\nReturn ONLY JSON with keys: sentiment, pros, cons.") ]) # 2) The model (any chat model adapter works) llm = ChatOpenAI(model="gpt-4o-mini") # 3) Parse the model’s text into a Python dict parser = JsonOutputParser() # 4) Compose the pipeline left→right with | chain = prompt | llm | parser # ---- Run it ---- example = { "review": "Loved the battery life and the screen. Setup was confusing and the fan gets loud." } print(chain.invoke(example)) # Example output (as a Python dict): # { # 'sentiment': 'positive', # 'pros': ['battery life', 'screen'], # 'cons': ['confusing setup', 'loud fan'] # }

LCEL

LCEL (LangChain Expression Language) lets you connect components like Unix pipes. Each component is a Runnable with standardized methods: .invoke(), .batch(), .stream(), and async equivalents. 

Why You See | in LangChain Code

In plain Python, | is bitwise OR. LangChain overloads | for runnables so that left | right means “pipe the output of the left into the input of the right,” returning a new runnable sequence. This makes chains readable and uniform across sync, async, batch, and streaming modes. It isn’t special to prompts—any Runnable can be piped. 

LangChain implements operator overloading via __or__ and __ror__ on its Runnable classes.


A Focused RAG Paragraph (Using LangChain)

A typical Retrieval-Augmented Generation (RAG) chain looks like this in LCEL:

  1. Retriever: turns a user question into a vector query and returns top-k documents.

  2. Prompt: weaves the question + retrieved context into an instruction.

  3. LLM: generates a grounded answer.

  4. Parser: normalizes the final text (or JSON) for downstream use.

In LCEL, that becomes:

Code

from langchain_openai import ChatOpenAI, OpenAIEmbeddings from langchain_core.output_parsers import StrOutputParser from langchain.prompts import ChatPromptTemplate from langchain_community.vectorstores.faiss import FAISS # build retriever (once, during setup) emb = OpenAIEmbeddings() vs = FAISS.from_texts( ["doc A ...", "doc B ...", "doc C ..."], embedding=emb ) retriever = vs.as_retriever(search_kwargs={"k": 4}) rag_prompt = ChatPromptTemplate.from_messages([ ("system", "Answer using ONLY the provided context. If unsure, say you don't know."), ("human", "Q: {question}\n\nContext:\n{context}") ]) llm = ChatOpenAI(model="gpt-4o-mini") to_str = StrOutputParser() # LCEL composition: retrieve -> map into prompt vars -> LLM -> parse rag_chain = ( {"context": retriever, "question": lambda x: x["question"]} | rag_prompt | llm | to_str ) print(rag_chain.invoke({"question": "What does doc B say about X?"}))

This pattern mirrors the official RAG tutorial (retriever → prompt → model → parser) and leverages LCEL’s composability and streaming/batching if needed. 


Reference

https://python.langchain.com/docs/introduction/

MCP


Model Context Protocol (MCP): what it is

MCP is an open standard that lets an AI app talk to tools, data (“resources”), and prompts through a clean client–server protocol. Very small example: you run a Weather MCP server that exposes a tool get_weather(city). Your chat app (the client) discovers that tool, the model chooses to call it, the server executes it, and the model uses the result to answer the user.

How MCP + a model work together

Your app hosts or connects to the model and embeds an MCP client. On startup the client connects to one or more MCP servers, performs an initialization handshake (initialize) to negotiate capabilities and lists tools/list, prompts/list and resources/list.

When the user asks something, you send the user messages and the discovered tool schemas to the model. If the model decides a tool is needed, it proposes a tool call; your app then runs that tool via the MCP server and feeds the tool result as a typed content array back to the model to finish the reply (repeat as needed for multiple tool calls).

Exact call flow & I/O (who calls what)

These steps run in sequence—Discovery → Planning → Execution → Finalization—during a single interaction; the client may repeat the Execution + Finalization pair as needed (e.g., multiple tool calls) until the model finishes.

Initialization. Client → MCP server: initialize (negotiate capabilities such as tools/resources/prompts and notifications).

Discovery. Client → MCP server: tools/list.
Server → Client: a tool list (each tool has a name and JSON Schema input). Similarly, clients may call prompts/list and resources/list to discover prompts and resources

Planning. Client → Model: user messages + tool schemas.
Model → Client: either text, or a tool call proposal (name + JSON args).

Execution. Client → MCP server: tools/call { name, arguments }.
Server → Client: structured content (text/json/image/resource). a typed content array (e.g., text/image/JSON and resource references) When server-side catalogs change, servers may send notifications (e.g., tools list changed) and clients can re-list as needed.

Finalization. Client → Model: send the tool result.
Model → Client: final answer for the user. (Repeat tool call loop if needed.)

Server setup you actually run

Use a ready to run MCP server or build one quickly with official SDKs. Popular reference servers include Filesystem, Fetch, and Git, which you can start with a single command (e.g., npx @modelcontextprotocol/server-filesystem … or uvx mcp-server-git).

npx: A Node.js helper that runs an npm package without you installing it globally.

If you have your own API like example.com/get_today_work/{date}, register a custom tool such as get_today_work in your MCP server. The server will automatically expose the standard methods (tools/list, tools/call) and route calls to your code or REST API.

Through tools/list, the MCP server publishes a catalog of your registered tools (e.g., get_today_work) with names, descriptions, and JSON Schema argument specs; the client forwards these schemas to the model. When the model proposes a tool call, the client invokes tools/call on the MCP server with the tool name and args; the server runs your handler (which can call https://example.com/get_today_work/{date} or other backends), returns structured content (text/JSON/resources) to the client, and the client feeds that result back to the model to finish the reply.

Naming rules & request format (FAQ)

Do I invent my own discovery method? No. Use the standard MCP methods (tools/list, tools/call). Your tool names (e.g., get_today_work) are custom, but the protocol methods are fixed.

What do I send the model? Follow your model provider’s tools/function calling request shape (e.g., “messages” + a tools array, optional tool_choice). Arbitrary top level JSON keys won’t be treated as tools unless they match the provider’s schema.

“One API” orchestration option

If you prefer a single API call that runs the whole loop (model → tools → model) for you, deploy an agent server. LangGraph Server exposes a “run” endpoint that manages the iterative tool calling loop and streaming for you. On OpenAI, the Agents/Responses stack supports tool use with provider defined request shapes and can automate parts of the loop; for custom tools you still register them per the API’s tool schema.

References

https://modelcontextprotocol.io/docs/getting-started/intro https://modelcontextprotocol.io/examples https://modelcontextprotocol.io/docs/develop/build-server

September 15, 2025

Open AI GPT-5


Reasoning Effort

* control thinking time/depth: "minimal" | "low" | "medium" (default) | "high". 
* higher effort → more careful, slower; lower → faster, cheaper.
* minimal is new in GPT-5 for super-fast replies. 

Verbosity

* control answer length/detail: "low" | "medium" (default) | "high". 
* if your prompt says “write 5 paragraphs”, that explicit instruction wins over verbosity.

Open AI examples (click to open)

Verbosity=low

Why is the sky blue?

Because of Rayleigh scattering. Air molecules are much smaller than the wavelength of visible light, so they scatter short wavelengths (blue/violet) far more than long ones (red). The scattered blue light comes to your eyes from all directions, making the sky look blue. We don’t see violet as much because the Sun emits less of it, our eyes are less sensitive to it, and some is absorbed in the upper atmosphere. At sunrise and sunset, the longer path through air removes more blue, leaving the sky reddish.

Verbosity=medium

Why is the sky blue?

Because of Rayleigh scattering. Sunlight contains all colors, but air molecules scatter shorter wavelengths (blue/violet) much more strongly than longer wavelengths (red). The scattering strength goes roughly as 1/(wavelength)^4, so blue light gets redirected across the sky and into your eyes.

We don’t see a violet sky because:

The Sun emits slightly less violet than blue.
The upper atmosphere absorbs some violet/UV.
Human eyes are less sensitive to violet.
At sunrise and sunset, sunlight passes through more atmosphere, scattering out most of the blues along the way and leaving the longer red/orange wavelengths to dominate.

Verbosity=high

Why is the sky blue?

The sky looks blue because sunlight gets scattered by the tiny molecules in Earth’s atmosphere. This process is called Rayleigh scattering.

Key points:

Sunlight is made of many colors (wavelengths). Shorter wavelengths, like violet and blue, are scattered much more strongly by air molecules than longer wavelengths like red. The scattering strength increases sharply as wavelength gets shorter.
As sunlight passes through the atmosphere, the shorter-wavelength light (especially blue) is scattered in all directions, so no matter where you look away from the Sun, you see that scattered blue light — the “blue sky.”
Why not violet?

The Sun emits less violet than blue.
Our eyes are less sensitive to violet.
Some violet/UV is absorbed higher up by ozone.
Together, that makes the scattered light we perceive look mainly blue.

Why are sunsets red/orange?

Near sunrise and sunset, sunlight travels a much longer path through the atmosphere.
Much of the blue light gets scattered out of the direct path before it reaches your eyes, leaving the remaining direct sunlight enriched in reds and oranges.
Other influences:

Haze, pollution, smoke, or dust have larger particles that scatter light less selectively (called Mie scattering), making the sky look paler or whitish.
The blue sky is partially polarized due to the scattering geometry, which is why polarized sunglasses can darken parts of it.
On worlds with different atmospheres and particle sizes (like Mars), skies can look butterscotch or reddish for similar scattering reasons.
If Earth had no atmosphere, there would be nothing to scatter sunlight, and the sky would appear black even in daytime, with the Sun as a bright disk.

Other Hyperparameters

n/a - check official documents - TODO

Code

from openai import OpenAI
client = OpenAI(
resp = client.responses.create(
    model="gpt-5"
    input="Why is the sky blue?",
    reasoning={"effort": "minimal"},
    text={"verbosity": "low"}
)
print(resp.output_text)

Chart


Coding -- https://openai.com/index/introducing-gpt-5-for-developers/ 

Others graph -> check official documents