Models and Structured OutputChat models and messages
No narration yet
Module 1, Lesson 120 min

Chat models and messages

Chronicler already classifies Discord messages with an LLM, through hand-rolled plumbing in @lumiere/openai-json: a four-attempt retry loop, markdown-fence stripping, a manual zod safeParse. This module gives you a grounded verdict on whether LangChain's structured-output primitives can replace that dance, and along the way you learn to read any LangChain code fluently.

A chat model is a function from messages to a message. In LangChain the model is an object you construct once and call many times.

Constructing a chat model, two ways
import { ChatAnthropic } from "@langchain/anthropic";
import { initChatModel } from "langchain";

const model = new ChatAnthropic({ model: "claude-sonnet-4-6" });

// or provider-agnostic, resolved from a string:
const model2 = await initChatModel("anthropic:claude-opus-4-8");

initChatModel is the indirection layer: you pass "provider:model" and it constructs the right class. This earns its keep when the provider is config, not code.

Messages are the input. A conversation is an array of message objects: HumanMessage, AIMessage, SystemMessage, ToolMessage. You call await model.invoke(messages) and get back an AIMessage. That is the whole contract at this level.

Practice

Try it yourself

Recall

The invoke contract

Without looking back, state the input and output types of model.invoke(...).

What goes into `model.invoke(...)` and what comes back?

Quiz

Why initChatModel

You have a codebase that needs to swap model providers based on a config file, not a code change. Which construction do you reach for?