当前位置: 首页 > news >正文

AI大模型落地系列:一文读懂 Eino 的 ChatModel 和 Message

声明:本文数据源于官方文档与官方实现。

一文读懂 Eino 的 ChatModel 和 Message

    • 1. 初入 Eino
    • 2. ChatModel 与 Message 到底是什么
    • 3. `ChatModel` 对我们而言到底有什么价值
    • 4. `Message` 的作用是什么
    • 5. 用千问把第一轮 Eino 对话跑通
    • 6. 这段代码执行时到底发生了什么
    • 7. 一分钟复盘
    • 参考资料

很多人学 Eino,一上来就盯着AgentToolMemory这些词。

虽然它们听起来更像“真正的 AI 应用开发”。
ChatModelMessage这两个才是最基础的边界。
它的之所以重要,是因为他将与你之后的所有AI开发形影不离。

1. 初入 Eino

很多 Go 后端工程师第一次接触 Eino,路径大概都是这样的:

  • 先搜“Go 怎么写 Agent”
  • 然后看到一堆工作流、工具调用、多轮会话
  • 最后一头扎进了复杂编排

你以为自己在学“AI 应用开发”,其实常常只是在拼装更大的调用链。只要底层那次最简单的模型请求没理解,后面的抽象层级越多,人就越容易飘。

说白了, ChatModel 和 Message 在整个Eino框架中,不是拿来炫功能的。

它是在回答一个更底层的问题:

在 Eino 里,一次最基础的大模型对话,到底是怎么被表达、组织和执行的?

这个问题不解决,后面所有“高级能力”都会变成悬空建筑。

2. ChatModel 与 Message 到底是什么

你可以这样理解

用最小的 Go 代码,把一次用户输入变成一次模型调用(ChatModel),并且Message不是普通字符串,而是对话协议。

注意,这里有两个重点。

第一,ChatModel

它解决的是“怎么和模型说话”。

第二,Message

它解决的是“你说的话,怎么被组织成模型能理解的上下文”。

3.ChatModel对我们而言到底有什么价值

如果你只把ChatModel理解成“调一下模型接口”,那就低估它了。

通常来说,它真正的价值至少有三层。

第一层,统一模型调用边界。

你今天接 OpenAI,明天接 Ark,后天换千问。业务最怕的不是换模型,而是换模型就要改一大片调用代码。

ChatModel的意义,就是先把“和模型交互”这件事抽象成一个稳定接口。你上层的业务逻辑关心的是“输入一组消息,拿回模型响应”,而不是每家厂商的参数细节。

第二层,给后续编排留接口。

后面你看到的AgentRunnerGraphChain,本质上都不是凭空长出来的。它们之所以能组合,是因为底下先有一层统一的Component抽象。

如果没有ChatModel这种边界,后面的编排层就会变成一堆和供应商 SDK 强耦合的胶水代码。

第三层,让测试可以做的更自然。

接口一旦稳定,mock 就有了位置。你做单测时,不必每次真打外部模型。

所以ChatModel的价值,不只是“能调模型”,而是:

它把模型能力从“某个厂商的 HTTP 调用”提升成了“业务里可替换、可编排、可测试的一类能力”。

4.Message的作用是什么

大多人会下意识觉得:

“不就是传一段 prompt(提示词)给模型吗?”

真要这么理解,问题就来了。那系统指令放哪?用户问题放哪?模型回复怎么回灌进上下文?后面工具调用结果又怎么拼回对话链路?

这就是Message存在的原因。

在 Eino 里,一次对话不是一段字符串,而是一组有角色的消息。

  • system:系统指令
  • user:用户输入
  • assistant:模型回复
  • tool:工具返回结果

它本质上是在表达一种“对话协议”,而不是一段散装文本。

你只要把Message理解成协议,就会自然明白下面这些事:

  • 为什么系统指令通常放在最前面
  • 为什么多轮对话不是简单字符串拼接
  • 为什么后面接 Tool Calling 时,tool角色必须单独存在

所以接触 Message 的时候,真正要你建立的,不只是 API 用法,而是一个认知转换:

在 Eino 里组织上下文,操作的核心单位不是 prompt 字符串,而是schema.Message

5. 用千问把第一轮 Eino 对话跑通

注:我之所以选择用千问,而非OpenAI,是因为他送的有免费额度,适合学习的时候用

先准备依赖和环境变量:

go mod init eino-ch01-demo go get github.com/cloudwego/eino@latest go get github.com/cloudwego/eino-ext/components/model/qwen@latestexportDASHSCOPE_API_KEY="你的百炼 API Key"exportQWEN_MODEL="qwen3.5-flash"

如果你在 Windows PowerShell 下,环境变量改成$env:DASHSCOPE_API_KEY="..."$env:QWEN_MODEL="qwen-flash"就行。

然后把下面这份完整代码保存成main.go

packagemainimport("context""fmt""io""log""os""strings""github.com/cloudwego/eino-ext/components/model/qwen""github.com/cloudwego/eino/schema")funcmain(){ctx:=context.Background()query:="用一句话解释 Eino 的 Component 设计解决了什么问题?"iflen(os.Args)>1{query=strings.Join(os.Args[1:]," ")}cm,err:=qwen.NewChatModel(ctx,&qwen.ChatModelConfig{BaseURL:"https://dashscope.aliyuncs.com/compatible-mode/v1",APIKey:mustEnv("DASHSCOPE_API_KEY"),Model:envOrDefault("QWEN_MODEL","qwen3.5-flash"),})iferr!=nil{log.Fatalf("new qwen chat model failed: %v",err)}messages:=[]*schema.Message{schema.SystemMessage("你是一个简洁、专业的 Go AI 框架助手。"),schema.UserMessage(query),}stream,err:=cm.Stream(ctx,messages)iferr!=nil{log.Fatalf("stream chat failed: %v",err)}deferstream.Close()for{chunk,err:=stream.Recv()iferr==io.EOF{break}iferr!=nil{log.Fatalf("recv stream failed: %v",err)}fmt.Print(chunk.Content)}fmt.Println()}funcmustEnv(keystring)string{v:=os.Getenv(key)ifv==""{log.Fatalf("%s is empty",key)}returnv}funcenvOrDefault(key,fallbackstring)string{ifv:=os.Getenv(key);v!=""{returnv}returnfallback}

直接执行go run . -- "用一句话解释 Eino 的 Component 设计解决了什么问题?",你就能看到千问按流式把回复一段段打出来。

6. 这段代码执行时到底发生了什么

按执行顺序,它其实做了四件事。

第一,初始化ChatModel

qwen.NewChatModel(...)这一层的意义,不只是创建一个客户端对象,而是把“千问模型能力”接成 Eino 能识别的ChatModel组件。

从这一步开始,你的代码面对的就是 Eino 抽象,而不再是散落的 HTTP 参数。

第二,构造messages

这里不是简单传一个字符串,而是明确传入两条消息:

  • 一条system,告诉模型你希望它以什么方式回答
  • 一条user,表达当前用户问题

这就是第一章最关键的认知点之一。对话不是一段文本,而是一组有角色的消息。

第三,调用Stream

这一点也很重要。这个代表流式生成的意思。

第四,逐块读取并打印。

chunk.Content看起来只是一个字段,但它意味着模型回复不必等到全部生成完再展示。前端可以边收边显示,后端也可以边收边处理。后面你做可观测、会话管理、回调链路时,这种流式思维会很自然。

所以本demo的意义,不只是“打印了一行字”,而是搭建起来了一个 Eino 的最小对话闭环。

7. 一分钟复盘

如果你读完这篇,只记住一句话,我希望是这一句:

Eino 本章不只是在教你写一个最简单的聊天 Demo,而是在教你建立“模型调用抽象”和“对话消息协议”这两个最基础的认知。

再压缩一点,就是三件事:

  • ChatModel解决的是模型能力的统一接入
  • Message解决的是对话上下文的结构化表达
  • Stream让这次调用更接近真实产品里的交互方式(流式输出)

本篇是为了之后的多轮对话、Runner、AgentEvent 打下坚实的根基。

参考资料

  • Eino 第一章:ChatModel 与 Message(Console)
    https://www.cloudwego.io/zh/docs/eino/quick_start/chapter_01_chatmodel_and_message/
  • Eino ChatModel 使用说明
    https://www.cloudwego.io/zh/docs/eino/core_modules/components/chat_model_guide/
  • Eino Qwen 组件文档
    https://pkg.go.dev/github.com/cloudwego/eino-ext/components/model/qwen
  • Eino Qwen 免费额度页面
  • https://bailian.console.aliyun.com/cn-beijing/?tab=model#/model-usage/free-quota
http://www.cnnetsun.cn/news/1452202.html

相关文章:

  • BotMan缓存与存储完全指南:ArrayCache、RedisCache、FileStorage终极配置教程
  • DeepSeek-OCR-WEBUI功能体验:图像描述/查找定位实测
  • DeepSeek-OCR-2开源大模型实操:自定义微调适配行业专用术语词典
  • FlutterBoost终极路由指南:5分钟掌握混合开发核心技巧
  • 终极指南:使用Symfony Translation组件实现PHP多语言支持的10个步骤
  • Lovefield外键约束终极指南:如何通过CASCADE和RESTRICT维护数据完整性
  • 数据污染战术:00后反监控革命中的社交噪音武器化
  • PRMLT实战指南:10个真实世界机器学习问题终极解决方案 [特殊字符]
  • 闻达社区资源完全指南:如何充分利用开源生态加速AI开发
  • AI 不该等你说话才干活——OpenClaw 定时系统设计哲学
  • Swift Algorithms笛卡尔积:10个product方法在组合问题中的终极应用指南
  • 快速上手Python3.11:Miniconda镜像5分钟搭建完整开发环境
  • PHP终端代码高亮神器:快速提升开发效率的终极指南
  • 程序:滚动轴承载荷分布静力学解析解,用于与动力学模型对比验证
  • Unsloth效果实测:对比传统方法,训练时间节省50%以上
  • 用Sequencer+Control Rig玩转UE5角色动画:从动捕数据到电影级运镜全流程
  • 终极指南:如何用Just.js函数式编程工具提升代码质量
  • 10个Unison调试技巧:快速定位和解决代码问题的完整指南
  • Simple Binary Encoding与Aeron集成:构建低延迟金融交易系统的完整方案
  • 视频字幕提取工具:本地OCR技术如何高效解决硬字幕识别难题
  • xiaozhi-esp32-server:10分钟快速搭建智能硬件后端的终极指南
  • Qwen3-ASR-0.6B入门指南:无需深度学习基础,30分钟搭建个人语音工作室
  • GB28181标准下PTZ控制实战:从设备检测到命令发送的全流程指南
  • Nginx多域名管理神器:conf.d目录的include配置实战(附完整流程)
  • BadUSB实战:用Digispark开发板5分钟打造你的第一个HID攻击工具(附完整代码)
  • GPT-OSS-20B快速入门:5分钟在Ollama上部署,体验长文本智能问答
  • Pixel Mind Decoder 性能调优实战:降低GPU显存占用与提升推理速度
  • 亲测好用! 降AIGC软件 千笔·专业降AIGC智能体 VS speedai 专为毕业论文全流程设计
  • StatisticalOutlierRemoval滤波器实战:点云去噪与参数调优指南
  • 状态向量 [x, y, z, vx, vy, vz