Day 22 / 共 80 天 · 阶段3 Agent 对话主线

AgentRun 实现:Pipe + safego.Go

每天约 30 分钟。焦点:agent_run_impl.go。 用类比把抽象钉住,用动图看请求流过,用真源码坐标对齐仓库。

📍 你在 80 天里的位置 · 阶段 3 Agent 对话主线 · Day 22/80
S1 开篇与全景·S2 API · IDL · Crossdomain·S3 Agent 对话主线·S4 Workflow 引擎深水·S5 知识库·插件·模型·S6 横切与基础设施·S7 前端 Rush 与 IDE·S8 工程收官
💡 今日兜底类比边跑边直播:Pipe(20) 缓冲 + 后台 goroutine 真正跑步。
📖 深度笔记实现关键四步:建 Pipe → 构造 AgentRuntime → safego.Go 后台 Run → 返回读端。panic 被 recover 打日志,避免拖垮进程。

💊 今日知识胶囊(30 分钟怎么吃)

  1. 0–5 分:读完本页类比与阶段定位,在脑中标出「我在哪一层」。
  2. 5–15 分:打开焦点路径 agent_run_impl.go,只看类型/接口/入口函数。
  3. 15–25 分:对照本页动图,口述「一次请求如何路过这里」。
  4. 25–30 分:跑「动手」命令,把 3 个关键词记到你的知识地图。
agent_run_impl.go — Pipe + 后台执行
func (c *runImpl) AgentRun(ctx context.Context, arm *entity.AgentRunMeta) (*schema.StreamReader[*entity.AgentRunResponse], error) {
    sr, sw := schema.Pipe[*entity.AgentRunResponse](20)
    art := &internal.AgentRuntime{ RunMeta: arm, SW: sw, /* ... */ }
    safego.Go(ctx, func() {
        defer sw.Close()
        _ = art.Run(ctx)
    })
    return sr, nil
}
怎么读这段先圈出「入口函数」和「分支条件」,再问:数据从哪来、到哪去、失败怎么办。
L01

痛点:为什么要学「AgentRun 实现」

🤔 痛点 / 提问很多小白打开仓库就慌:文件太多、名字陌生、不知道今天该盯哪一块。
💡 本质今天的靶心是 agent_run_impl.go。学完你应能用一句话说清它在整条链路里的位置。
大白话🍼 类比:边跑边直播:Pipe(20) 缓冲 + 后台 goroutine 真正跑步。
🎯 阶段定位你在「Agent 对话主线」阶段(D17-D28)。对话主线是产品体验的心脏,必须走通。
L02

先建立坐标:它挂在哪一层

🤔 痛点 / 提问读源码第一问永远是:这个东西属于门卫、经理、专家,还是水电工?
💡 本质用 DDD 尺子量:api/ 收请求,application/ 编排用例,domain/ 写规则,infra/ 对接中间件,crossdomain/ 做部门间外交。
大白话把「层」记成楼层,把「域」记成房间号。今天的主角房间是:agent_run_impl.go
Coze 后端四层(心智模型) api/ · 门卫:Handler + Middleware + Router(IDL 生成) application/ · 经理:用例编排、组装参数、调用 domain domain/ · 专家部门:Agent / Workflow / Knowledge / Plugin… infra/ · 水电工:DB / Redis / ES / Milvus / NSQ / MinIO / Checkpoint
发光点模拟一次请求从上到下穿过四层(并经 crossdomain 横向协作)
L03

真源码走读:关键入口怎么读

🤔 痛点 / 提问有了地图还不够,要练「打开文件第一眼看什么」。
💡 本质优先看:类型/接口定义 → 构造函数/New → 被谁调用 → 调用谁。Coze 里大量 interface + _impl.go 对:先读接口门牌,再进实现。
大白话接口像菜单,实现像厨房。菜单短好懂,厨房再乱也不慌。
schema.Pipe(20)创建有缓冲的双向流
safego.Go后台跑 AgentRuntime,防崩
defer sw.Close()写端关闭,读端结束
return sr调用方只拿读端去消费

对照仓库路径阅读,行号以你本地版本为准;关注调用关系多于死记行号。

L04

动态理解:一次请求/一次执行怎么经过这里

🤔 痛点 / 提问静态目录脑中要动画起来:用户点「发送」之后,数据如何流过今天的模块。
💡 本质记住主链路:浏览器 → Hertz 中间件 → Handler → Application → Domain(可能经 Crossdomain)→ Infra/Eino → 流式回写。
大白话把发光小球想象成「用户的一句话」——看它经过哪些盒子。
Handler Application AgentRun.Pipe AgentRuntime BuildAgent Eino Stream SSE 回前端
L05

设计取舍与边界坑

🤔 痛点 / 提问作者为什么这样写?哪些地方一改就炸?
💡 本质异步 Pipe:接口立即返回读端,真正跑在后台。优点是流式低延迟;代价是错误/取消要额外通道处理。
大白话好设计通常是在「解耦」和「省事」之间做交换。今天记住那个交换。
⚠️ 坑忘记 Close 写端 → 读端永久阻塞。

👶 小白问:我可以跳过吗?

👨‍🏫 不建议。昨天学的是「AgentRun 接口:Run · Cancel · List」,明天是「AgentRuntime.Run:加载 Agent 再分支」。今天是中间的承重墙。

L06

今日小结 · 动手 · 预告

🤔 痛点 / 提问学完能否用自己的话复述?动手验证了吗?
💡 本质闭环学习:概念 → 源码坐标 → 动手命令 → 能教别人。
大白话把今日关键词写在便利贴上,贴到你自己的「知识地图」对应格子。

🧠 今天你应该能回答

  • 今天主题「AgentRun 实现:Pipe + safego.Go」一句话是什么?
  • 关键路径 agent_run_impl.go 属于哪一层/哪个域?
  • 它上游谁调用、下游它调用谁?
  • 对应的类比你能讲给完全不懂代码的人听吗?

✋ 约 10 分钟动手

sed -n '50,100p' backend/domain/conversation/agentrun/service/agent_run_impl.go
明日预告:Day 23 · AgentRuntime.Run:加载 Agent 再分支。今晚把今日便利贴贴到知识地图上即可。