为啥用GoZero快速实现AI应用开发后,我们又决定用字节的Eino重构优化项目呢?
是。
大家好,我是王中阳,见字如面,感谢阅读!
最近我们团队在疯狂的研究AI。期间不仅做了几个还不错的项目,也踩坑不少。下面我就分享一下,过去用GoZero开发了怎样一个AI应用,以及为什么现在要用字节的Eino重构和优化。
我们过去基于gozero实现AI面试官智能体项目,一方面搞定了从0到1开发AI智能体应用,各种造轮子;另一方面,模拟面试,也是我粉丝股东们很迫切的需求。
之所以使用GoZero,是因为我在社区里看到了对MCP的支持,过去也用gozero开发了不少项目,本着快速跑通的原则,我们团队花了不到一个月就搞定全流程了,具体功能,大家可以看文章最后的介绍哈。
大家点击这个链接可以体验:核心功能全部搞定,细节还在持续优化中,欢迎大家提bug和建议哈。(目前服务器配置不高,token也有限,如果不可用,可以微信私信我:wangzhongyang1993,我再进行充值,哈哈)
但是,我们发现想进一步做性能和效果的优化,还是有些吃力,或者说有点摸不着头脑,不想一直自己造轮子,于是开始各种调研和对比,最终,我们把目光聚焦到了CloudWeGo开源的Eino框架。
毕竟我们团队绝大多数同学是gopher,字节在go生态中的地位我就不必多说了:
现在字节跳动旗下CloudWeGo开源的Eino框架可以说Langchain的平替,提供了一套简单易用却功能强大的解决方案,最近在看到这个框架的时候真的感觉的像是用到SpringAI框架真的很方便(我也是老Java了哈哈),我最近在优化的AI面试官智能体项目也通过这个框架变得更加简洁,功能更加强大。
我这次将结合开源文档和实际开发的Demo,给大家分享一下Eino框架的使用方法和核心优势,同时下一期内容给大家演示最重要的Agent领域的表现。
什么是Eino框架?
Eino是CloudWeGo生态下的AI应用开发框架,旨在降低大模型应用开发门槛。它提供了统一的接口抽象,支持多模型集成(如OpenAI、Anthropic等),内置流式响应、提示词模板等核心功能,让开发者可以专注于业务逻辑而非底层交互细节。
相较于传统开发方式,Eino的优势在于:
- 简化大模型API调用流程,无需重复封装HTTP请求
- 内置流式响应处理,轻松实现实时对话体验
- 强大的提示词模板系统,便于管理复杂对话逻辑
- 完善的上下文管理,轻松维护对话历史
- 兼容主流大模型,切换模型无需大幅修改代码
- 灵活强大的编排能力:覆盖从简单到复杂的全场景
实战:用Eino构建对话应用
接下来我通过一个完整的Demo,看看如何用Eino快速开发一个AI对话应用。
项目结构
我的Demo项目结构非常简洁:
ai-eino-agent/
├── chatApp/
│ ├── main.go // 程序入口
│ └── chat/
│ └── chatTemplate.go // 对话模板定义
├── go.mod // 依赖管理
└── go.sum
核心依赖配置
在go.mod中,我们主要依赖了Eino核心包和OpenAI扩展组件:
require (
github.com/cloudwego/eino v0.5.11
github.com/cloudwego/eino-ext/components/model/openai v0.1.2
// 其他依赖...
)
通过这些依赖,我们可以直接使用Eino封装好的OpenAI接口,无需自己处理API鉴权、请求构造等底层逻辑。
1. 定义对话模板
在chatTemplate.go中,我们使用Eino的prompt包创建对话模板:
func creatTemplate() prompt.ChatTemplate {
// 创建模版,使用Fstring格式
return prompt.FromMessages(schema.FString,
// 系统提示词,定义AI角色和语气
schema.SystemMessage("你是一个{role},你需要用{style}的语气回答问题,你的目标是解答程序员的面试问题"),
// 插入对话历史
schema.MessagesPlaceholder("chat_history", true),
// 用户消息模板
schema.UserMessage("问题:{question}"),
)
}
这个模板包含三个关键部分:
- 系统提示词:定义AI的角色(
{role})和回答风格({style}) - 对话历史占位符:用于插入之前的对话内容
- 用户问题占位符:接收当前用户输入
通过模板参数化,可以灵活调整AI的行为和对话内容,而无需修改模板结构,比以往更加灵活。
2. 初始化对话内容
同样在chatTemplate.go中,我们实现了MessagesTemplate()函数来初始化对话内容:
func MessagesTemplate() []*schema.Message {
template := creatTemplate()
// 填充模板参数
messages, err := template.Format(context.Background(), map[string]any{
"role": "经验丰富的大厂开发面试专家",
"style": "温和且专业",
"question": "你好,什么是go语言",
"chat_history": []*schema.Message{
schema.UserMessage("你好"),
schema.AssistantMessage("嘿!我是你的程序员面试助手...", nil),
// 更多历史消息...
},
})
if err != nil {
log.Fatalf("format template failed: %v", err)
}
return messages
}
这里我们为模板填充了具体参数,包括AI角色定义、对话历史和当前问题。Eino会自动处理模板渲染,生成符合大模型要求的消息格式。
3. 主程序逻辑
在main.go中,我们实现了完整的对话流程:
func main() {
ctx := context.Background()
// 创建消息
fmt.Printf("===create messages===\n")
message := chat.MessagesTemplate()
// 创建LLM实例
fmt.Printf("===create llm===\n")
model := chat.CreatOpenAiChatModel(ctx)
// 流式获取并输出结果
fmt.Printf("===llm stream ===\n")
streamResult := chat.Stream(ctx, model, message)
chat.ReportSteam(streamResult)
}
整个流程非常清晰:
- 初始化上下文
- 创建消息列表(基于之前定义的模板)
- 初始化OpenAI模型客户端
- 发起流式对话请求并处理响应
4. 流式响应处理
Eino的流式响应处理非常优雅,我们不需要手动处理WebSocket或长轮询,只需调用Stream()方法即可获得一个流式结果通道,然后通过ReportSteam()函数实时输出结果:
func ReportSteam(sr *schema.StreamReader[*schema.Message]) {
defer sr.Close()
for {
message, err := sr.Recv()
if err == io.EOF {
return
}
if err != nil {
log.Fatalf("recv message failed: %v", err)
}
content := message.Content
fmt.Printf(content)
}
}
func Stream(ctx context.Context, llm model.ToolCallingChatModel, in []*schema.Message) *schema.StreamReader[*schema.Message] {
result, err := llm.Stream(ctx, in)
if err != nil {
log.Fatalf("llm generate failed: %v", err)
}
return result
}
这种处理方式让我们轻松实现类似ChatGPT的打字机效果,大幅提升用户体验,我在优化Ai面试官智能体项目时原有繁琐的流失输出得到了更简洁的优化,而且输出效果更好,而且还有多种实时流选择。
Eino框架的核心优势
通过这个简单的Demo,我们可以感受到Eino框架的几个核心优势:
- 简化开发流程:封装了大模型调用的底层细节,开发者无需关注API请求格式、鉴权等问题
- 强大的模板系统:通过结构化的提示词模板,轻松管理复杂对话逻辑,提高prompt的可维护性
- 原生支持流式响应:内置流式处理机制,几行代码即可实现实时对话效果
- 灵活的上下文管理:通过
MessagesPlaceholder轻松维护对话历史,无需手动拼接消息列表 - 多模型兼容:通过统一接口抽象,切换不同大模型时只需修改模型初始化部分
不仅如此!
Eino框架为大模型应用开发提供了一套高效、简洁的解决方案。通过本文的Demo,我仅用几十行代码就实现了一个具备流式响应、上下文管理功能的AI对话应用,比我们智能体项目原有的流式响应、上下文管理功能代码优化的更简洁高效,使用起来的感觉不亚于隔壁的SpringAI。
我之前在使用GoZero去写这个项目的时候感觉真的很繁琐,而现在Eino可以显著降低开发成本,让我的精力集中在业务逻辑和用户体验上。而且eino也提供了开箱即用的多agent编排模式使用也简单,我在优化我们训练营智能体项目agent的时候也方便许多,而且工具的调用也更加灵活。
如果你也在开发大模型应用,不妨试试CloudWeGo Eino,体验GO在Ai智能体领域的新方式。 (注:Demo基于Eino v0.5.11版本开发,实际使用时请参考官方最新文档)
重构优化
也正因为如此,所以,我们决定使用Eino重构优化【AI智能面试官项目】,下面是关于这个项目的介绍:


我们的项目功能:
-
交互流程与状态管理
-
接收客户端 Post 请求(含用户输入 / 操作指令 / 文件上传)
-
通过 SSE 流式实时输出 AI 面试问题 / 反馈
-
利用 Redis 状态机(SessionID:State)管理面试流程,AI 能主动引导话题,推进面试目标
-
维持请求 - 响应链路的低延迟交互
-
-
多轮对话与知识库管理
-
基于 pgvector 扩展的
vector_store表存储对话数据及知识库内容(含 id/chat_id(or doc_id)/role/content/embedding/created_at 字段) -
支持单条消息/知识存储与历史对话/知识批量查询(通过 chat_id/doc_id 关联)
-
依托 embedding 向量实现对话上下文关联、连续性维护及知识库检索
-
-
PDF 处理与知识库构建
-
通过 MCP 服务(gRPC)接收并解析客户端上传的 PDF 文件,转换为文字内容并生成向量
-
提供独立 POST 接口,支持上传 PDF 文件至 RAG 本地知识库(存储原始文本及向量至 pgvector)
-
在 SSE 聊天交互中,自动将知识库检索结果与当前解析文本(如有)拼接至上下文,作为 AI 生成响应的参考依据
-
-
RAG 本地知识库集成
-
支持构建本地知识库(通过专用接口上传 PDF 向量化存储)
-
基于用户输入、对话历史及知识库内容,实时检索(向量相似度)知识库中相关内容辅助生成回复,提升 AI 响应的专业性与针对性
-
-
智能体调度与部署
-
基于 Redis 状态机实现 AI 智能体的目标导向行为,动态调整面试流程
-
采用 容器化部署:通过
Dockerfile构建镜像,docker-compose.yml编排服务(API, MCP-gRPC, PostgreSQL-pgvector, Redis, etcd),init.sql初始化数据库表结构及扩展 -
实现一键启动:本地安装 Docker 后,执行
docker-compose up即可启动全套服务(API、MCP、DB、Redis、etcd),无需额外环境配置
-
优化重构核心思路
- 核心框架从gozero—>字节生态的Enio
- 向量数据库从pgvector—>milvus
- 实现多Agent调用
欢迎提宝贵建议
- 更多的优化细节和建议,欢迎大家在评论区讨论,我们也想基于大家迫切的需求,以及想学的功能点知识点做优化,更好的反哺社区。
对AI应用的开发感兴趣,欢迎关注我的账号,备注AI开发,我邀你进交流群。
更多推荐


所有评论(0)