Chapter 1: ChatModel and Message (Console)
Introduction to the Eino Framework
What is Eino?
Eino is an AI application development framework (Agent Development Kit) implemented in Go, designed to help developers quickly build extensible, maintainable AI applications.
What problems does Eino solve?
- Model abstraction: Unifies interfaces across different LLM providers (OpenAI, Ark, Claude, etc.), allowing model switching without modifying business code
- Capability composition: Implements replaceable, composable capability units (conversation, tools, retrieval, etc.) through Component interfaces
- Orchestration framework: Provides orchestration abstractions like Agent, Graph, and Chain, supporting complex multi-step AI workflows
- Runtime support: Built-in streaming output, interrupt and resume, state management, Callback observability, and more
Eino’s main repositories:
- eino (this repository): Core library, defines interfaces, orchestration abstractions, and ADK
- eino-ext: Extension library, provides concrete implementations of various Components (OpenAI, Ark, Milvus, etc.)
- eino-examples: Example code repository, containing this quickstart series
ChatWithEino: An Intelligent Assistant for Conversing with Eino Documentation
What is ChatWithEino?
ChatWithEino is an intelligent assistant built on the Eino framework that helps developers learn the Eino framework and write Eino code. It provides the most accurate and timely technical support by accessing source code, comments, and examples from the Eino repository.
Core capabilities:
- Conversational interaction: Understands user questions about Eino and provides clear answers
- Code access: Directly reads Eino source code, comments, and examples, answering questions based on real implementations
- Persistent sessions: Supports multi-turn conversations, remembers context, and can resume sessions across processes
- Tool calling: Can perform file reading, code searching, and other operations
Technical architecture:
- ChatModel: Communicates with large language models (OpenAI, Ark, Claude, etc.)
- Tool: Capability extensions like file system access and code search
- Memory: Persistent storage of conversation history
- Agent: Unified execution framework coordinating components to work together
Quickstart Documentation Series: Building ChatWithEino from Scratch
This documentation series takes you through a progressive approach, starting from the most basic ChatModel call and gradually building a fully-featured ChatWithEino Agent.
Learning path:
| Chapter | Topic | Core Content | Capability Gained |
| Chapter 1 | ChatModel and AgenticMessage | Understand Component abstraction, implement single-turn conversation | Basic conversation |
| Chapter 2 | Agent and Runner | Introduce execution abstraction, implement multi-turn conversation | Session management |
| Chapter 3 | Memory and Session | Persist conversation history, support session recovery | Persistence |
| Chapter 4 | Tool and File System | Add file access capability, read source code | Tool calling |
| Chapter 5 | Middleware | Middleware mechanism, unified handling of cross-cutting concerns | Extensibility |
| Chapter 6 | Callback | Callback mechanism, monitor Agent execution | Observability |
| Chapter 7 | Interrupt and Resume | Interrupt and resume, support long-running tasks | Reliability |
| Chapter 8 | Graph and Tool | Use Graph to orchestrate complex workflows | Complex orchestration |
| Chapter 9 | Skill | Use Skill middleware to load and reuse skill documents | Knowledge reuse |
| Final | A2UI | Agent-to-UI integration solution | Production-grade application |
Why this design?
Each chapter adds one core capability on top of the previous one, allowing you to:
- Understand the role of each component: Rather than showing all features at once, they are introduced progressively
- See the architecture evolution: From simple to complex, understanding why each abstraction is needed
- Master practical development skills: Each chapter has runnable code for hands-on practice
This chapter’s goal: Understand Eino’s Component abstraction, call a ChatModel with minimal code (with streaming output support), and learn how to organize model input and streaming output using schema.AgenticMessage.
Code Location
- Entry code: cmd/ch01/main.go
Why Component Interfaces Are Needed
Eino defines a set of Component interfaces (ChatModel, Tool, Retriever, Loader, etc.), each describing a category of replaceable capabilities:
type BaseModel[M any] interface {
Generate(ctx context.Context, input []M, opts ...Option) (M, error)
Stream(ctx context.Context, input []M, opts ...Option) (*schema.StreamReader[M], error)
}
type AgenticModel = BaseModel[*schema.AgenticMessage]
Benefits of interfaces:
- Replaceable implementations:
eino-extprovides multiple implementations including OpenAI, Ark, Claude, Ollama, etc. Business code only depends on the interface; switching models only requires changing the construction logic. - Composable orchestration: Orchestration layers like Agent, Graph, and Chain only depend on Component interfaces, not caring about specific implementations. You can swap OpenAI for Ark without changing orchestration code.
- Mockable for testing: Interfaces naturally support mocking; unit tests don’t need real model calls.
This chapter only involves ChatModel; subsequent chapters will progressively introduce Tool, Retriever, and other Components.
The example code defaults to using model.AgenticModel, which is model.BaseModel[*schema.AgenticMessage]. This allows subsequent chapters to express text, reasoning, tool calls, tool results, and more within the same message structure.
schema.AgenticMessage: The Basic Unit of Conversation
AgenticMessage is the conversation data structure used in this Quickstart:
In a single model call, the model may return multiple ordered events — for example, first outputting reasoning, then calling a server tool, followed by more reasoning, then calling a function tool. AgenticMessage stores these structured events in order using ContentBlock.
type AgenticMessage struct {
Role AgenticRoleType
ContentBlocks []*ContentBlock
ResponseMeta *AgenticResponseMeta
Extra map[string]any
}
type ContentBlock struct {
Type ContentBlockType
Reasoning *Reasoning
UserInputText *UserInputText
AssistantGenText *AssistantGenText
FunctionToolCall *FunctionToolCall
FunctionToolResult *FunctionToolResult
// ...
}
Common constructors:
schema.SystemAgenticMessage("You are a helpful assistant.")
schema.UserAgenticMessage("What is the weather today?")
&schema.AgenticMessage{
Role: schema.AgenticRoleTypeAssistant,
ContentBlocks: []*schema.ContentBlock{
schema.NewContentBlock(&schema.AssistantGenText{Text: "I don't know."}),
},
}
Role semantics:
system: System instructions, typically placed at the beginning of the message listuser: User inputassistant: Model response- Tool calls and tool results are expressed through
function_tool_call/function_tool_resultcontent blocks (covered in later chapters)
Prerequisites
Get the Code
git clone https://github.com/cloudwego/eino-examples.git
cd eino-examples/quickstart/chatwitheino
- Go version: Go 1.21+ (see
go.mod) - A callable ChatModel (defaults to OpenAI; Ark is also supported)
Option A: OpenAI (Default)
export OPENAI_API_KEY="..."
export OPENAI_MODEL="gpt-4.1-mini" # OpenAI 2025 new model, gpt-4o or gpt-4o-mini also work
# Optional:
# OPENAI_BASE_URL (proxy or compatible service)
# OPENAI_BY_AZURE=true (use Azure OpenAI)
Option B: Ark
export MODEL_TYPE="ark"
export ARK_API_KEY="..."
export ARK_MODEL="..."
# Optional: ARK_BASE_URL
Running
In the examples/quickstart/chatwitheino directory:
go run ./cmd/ch01 -- "Explain in one sentence what problem Eino's Component design solves."
Example output (streamed progressively):
[assistant] Eino's Component design solves the problem of...
What the Entry Code Does
In execution order:
- Create ChatModel: Select OpenAI or Ark’s agentic model based on the
MODEL_TYPEenvironment variable - Construct input messages: Create
AgenticMessageusingmsgops.NewSystem[M]/msgops.NewUser[M] - Call Stream: Use
model.BaseModel[M].Stream(), returning aStreamReader[M] - Print results: Iterate the
StreamReaderto print assistant replies frame by frame
Key code snippet (Note: This is a simplified code snippet that cannot run directly. For the complete code, please refer to cmd/ch01/main.go):
func runTyped[M adk.MessageType](ctx context.Context, instruction, query string) {
cm, err := chatmodel.NewModel[M](ctx)
if err != nil {
log.Fatal(err)
}
messages := []M{
msgops.NewSystem[M](instruction),
msgops.NewUser[M](query),
}
stream, err := cm.Stream(ctx, messages)
if err != nil {
log.Fatal(err)
}
defer stream.Close()
for {
frame, err := stream.Recv()
if errors.Is(err, io.EOF) {
break
}
if err != nil {
log.Fatal(err)
}
fmt.Print(msgops.AssistantDeltaText(frame))
}
}
Chapter Summary
- Component interface: Defines replaceable, composable, and testable capability boundaries
- AgenticMessage: The basic unit of conversation data, distinguishing semantics through roles and content blocks
- ChatModel: The most fundamental Component, providing two core methods:
GenerateandStream - Implementation selection: Switch between different implementations like OpenAI/Ark via environment variables or configuration, with no changes needed in business code