[Golang]Eino探索之旅-初窥门径

Eino官方文档入口

官方文档已经非常详细,本文记录在学习Eino框架的一些理解与思考。

传送门:Eino快速开始:https://www.cloudwego.io/zh/docs/eino/quick_start/chapter_01_chatmodel_and_message/

最小对话模型

需求

调用指定模型API,在控制台输入发送给AI的话语,并在控制台流式打印AI的响应。

实现

Eino为以上需求提供了示例代码,下面会基于源码捋一捋思路和流程。

仓库地址:github.com/cloudwego/e...

克隆命令:

shell 复制代码
git clone https://github.com/cloudwego/eino-examples.git --depth=1

修改模型配置

Eino会默认使用openai的模型,为了方便,我将其修改为智谱旗下的模型(与openai完全兼容),当然,也可以配置其他模型

首先,进入到 eino-examples/quickstart/ 目录, 当前执行目录为 eino-examples ,后续所有相对路径的根目录为 quickstart

shell 复制代码
cd ./quickstart

找到 eino_assistant 目录下的.env文件,添加如下配置, 注意,值无需引号包裹

.env 复制代码
export ZHIPU_API_KEY=<your api key>
export ZHIPU_MODEL=<the model name you used>
export ZHIPU_BASE_URL=<官方开放的访问地址,如智谱:https://open.bigmodel.cn/api/paas/v4/>

保存修改,然后在当前控制台执行

shell 复制代码
source ./quickstart/eino_assistant/.env

这是因为控制台拿到的是系统环境变量的副本,修改了原配置文件,终端私有的环境变量并不会自动更新

接下来验证配置能够正常访问

shell 复制代码
echo $ZHIPU_MODEL

控制台应该打印你配置的模型名称,如:

然后打开 ./quickstart/chatwitheino/cmd/ch01 目录下的 main.go文件

修改newChatModel函数,使用自定义模型配置

go 复制代码
func newChatModel(ctx context.Context) (model.ToolCallingChatModel, error) {
	if os.Getenv("MODEL_TYPE") == "ark" {
		return ark.NewChatModel(ctx, &ark.ChatModelConfig{
			APIKey:  os.Getenv("ARK_API_KEY"),
			Model:   os.Getenv("ARK_MODEL"),
			BaseURL: os.Getenv("ARK_BASE_URL"),
		})
	}
	return openai.NewChatModel(ctx, &openai.ChatModelConfig{
		APIKey:  os.Getenv("ZHIPU_API_KEY"),
		Model:   os.Getenv("ZHIPU_MODEL"),
		BaseURL: os.Getenv("ZHIPU_BASE_URL"),
	})
}

在学习过程中并未找到MODEL_TYPE的定义位置,直接忽略掉if块,不影响程序运行。

运行项目

最后,执行 ./chatwitheino/cmd/ch01 目录下的main.go

shell 复制代码
go run ./chatwitheino/cmd/ch01/main.go -- "用一句话解释 Eino 的 Component 设计解决了什么问题?"

应该得到如下输出:

至此,使用eino框架实现一个对话功能就完成了,接下来探究一下源码,完整代码在仓库中,各位小伙伴可以自行获取

原理与思路

宏观流程

源码实现

main
go 复制代码
var instruction string
flag.StringVar(&instruction, "instruction", "You are a helpful assistant.", "")
flag.Parse()

定义系统级指令,通过命令行参数指定,默认值为"You are a helpful assistant.", 该指令会和用户输入一并发送给模型

go 复制代码
query := strings.TrimSpace(strings.Join(flag.Args(), " "))
if query == "" {
    _, _ = fmt.Fprintln(os.Stderr, "usage: go run ./cmd/ch01 -- \"your question\"")
    os.Exit(2)
}

从命令行提取并拼接用户输入,去除首尾空格。假设执行命令为 go run ./chatwitheino/cmd/ch01/main.go -- "你" -- "好 ", 那么query的值为"你 好"

go 复制代码
ctx := context.Background()
cm, err := newChatModel(ctx)
if err != nil {
    _, _ = fmt.Fprintln(os.Stderr, err)
    os.Exit(1)
}

创建空的上下文,通过newChatModel函数构建一个chatModel对象,用于后续动作的执行

go 复制代码
messages := []*schema.Message{
    schema.SystemMessage(instruction),
    schema.UserMessage(query),
}

将系统级指令和用户的输入封装为一个统一的Message

go 复制代码
stream, err := cm.Stream(ctx, messages)

Stream方法是一个核心方法,它做了以下工作:

  • 构建符合openai/智谱 API的HTTP请求,承载Message
  • 通过网络向ZHIPU_BASE_URL指定的端点发出请求
  • 构建流式连接,等待模型响应

stream对象是一个流式读取器,类型为*schema.StreamReader[*schema.Message]

这是一个泛型结构体,定义语句是type StreamReader[T any] struct,在此处内部泛型类型被传递成schema.Message

go 复制代码
for {
    frame, err := stream.Recv()
    if errors.Is(err, io.EOF) {
            break
    }
    if err != nil {
            _, _ = fmt.Fprintln(os.Stderr, err)
            os.Exit(1)
    }
    if frame != nil {
            _, _ = fmt.Fprint(os.Stdout, frame.Content)
    }
}

调用Recv,循环读取部分流,阅读源码,是通过一个channel传输流

这意味着,如果一直没有收到模型的响应,代码会一直阻塞,直到超时。

然后将读取到的内容打印至控制台,直到产生EOF错误,退出循环

注意:EOF错误表示流的所有内容已经读取完毕

newChatModel
go 复制代码
return openai.NewChatModel(ctx, &openai.ChatModelConfig{
    APIKey:  os.Getenv("ZHIPU_API_KEY"),
    Model:   os.Getenv("ZHIPU_MODEL"),
    BaseURL: os.Getenv("ZHIPU_BASE_URL"),
})

使用用户定义的模型构造一个chatModel对象,并返回

最后

本文会不定时更新,仍在持续学习中~

如有错误,欢迎指正

相关推荐
JustHappy6 分钟前
古法编程秘籍(七):互联网到底是什么?把两台电脑怎么说话搞懂就够了
前端·后端·网络协议
Hommy8827 分钟前
【剪映小助手】添加图片接口(Add Images)
后端·github·剪映小助手·视频剪辑自动化
GetcharZp1 小时前
别再盲目用 OpenCV 读图了,这才是 CV 预处理的终极杀手锏!
后端
IT_陈寒5 小时前
Vite热更新失效?可能你在用Windows
前端·人工智能·后端
椰椰椰耶6 小时前
[SpringCloud][14]OpenFeign参数传递方法
后端·spring·spring cloud
onething3656 小时前
Spring Boot + Spring AI 从入门到实战:7天转型计划 Day 3 —— 消息表设计 + 级联删除 + 事务管理
人工智能·后端
荣江6 小时前
Hermes Agent 代码仓库打包工具使用指南(repomix-rs 高性能版)
后端
王某某人6 小时前
LangChain4j 入门:Java 程序员的第一个 AI 对话程序
人工智能·后端
码农刚子6 小时前
从零开始:在 Windows 服务器上部署 Node.js 项目(小白实战教程)
后端·node.js
Cache技术分享6 小时前
435. Java 日期时间 API - Clock 灵活获取当前时间
前端·后端