96SEO 2026-09-21 10:53 7
先说一个架构决策:ReAct 循环本身我们没自己写。交给 Eino 的 react.NewAgent 跑。Handle 只做框架解决不了的部分:Session 状态迁移、多租户 context 注入、长期记忆召回、事务落库、异步记忆提炼。

下面是去掉错误处理样板代码后的主干,大约 行:
func Handle error {
// ① 加载会话,校验状态
sess,_ := h.repo.Load
if sess.IsTerminal {
return errors.New
}
// ② context 注入
ctx = context.WithValue)
ctx = context.WithValue)
ctx = context.WithValue))
// ③ 前置 hook + 加载配置
h.invokeHook { hr.BeforeSession) })
cfg,_ := h.configs.Load,sess.AgentConfig)
// ④ 判断方法:新 turn 还是 HITL 恢复
isResume := in.UserText == ""
runInput := port.RunStreamInput{IsResume: isResume}
var capturedHistory model.Message
if isResume {
// ⑤a HITL 恢复:状态迁移 WAITING→RUNNING。先落库再跑
sess.Resume
h.persist
} else {
// ⑤b 新 turn:拉历史、写 user 消息、召回记忆、拼 system prompt
history,_ := h.repo.ListMessages)
sess.IncTurn
userMsg := model.NewUserMessage,sess.TurnCount,in.UserText)
h.repo.AppendMessage
history = append
capturedHistory = history
memCtx := h.recallMemory(ctx,sess.TenantID,sess.UserID,in.UserText,)
runInput.SystemContent = expandSystemPrompt(cfg.SystemPrompt,sess) + memCtx
runInput.History = history
}
// ⑥ 交给 Eino:ReAct 循环、工具调用、Hook callback 全在里面
tr,interrupt,err := h.runnableFac.StreamTurn(
ctx,cfg,sess.TenantID,runInput,h.hooks,h.stream,sess.ID,)
if err!= nil { return h.failSession}
// ⑦ 处理 HITL 中断
if interrupt!= nil { return h.handleEinoInterrupt}
defer tr.Close
// ⑧ 消费流:token → SSE turn.delta + 收集 finalContent
finalContent,_:=h.consumeEinoStream(
ctx,sess.ID,tr)
//⑨ 落库 +触发终态事件+异步记忆提炼
asstMsg:=model.NewAssistantMessage。sess.TurnCount,finalContent,nil)
sess.Complete
h.commitFinalAnswer(
ctx,sess,asstMsg,)
if>0){
h.scheduleMemoryExtraction(
ses,&capturedHistory,finalContent)}
return nil}
接下来逐块说每一段在做什么还有为什么这样设计。
sess,_:=h.repo.Load
if err!=nil{
return...
}
if){
return errors.New
}
终态的 Session 不可以再跑新 Turn,这是状态机的硬约束。在入口做这个检查,比在循环里做更干净。
为什么用 context.WithValue 而不是 struct 字段?不过,因为 Runnable 按 AgentConfig 维度缓存。跨 session 复用——如果 sessionID绑到 struct 字段上,缓存完第一个 session 后就错了。其实,从 context 动态读,缓存才能安全共享。
ctx=context.WithValue
ctx=context.WithValue
ctx=context.WithValue
这三个值随 context 一路传进 Eino 的 chatModelAdapter/toolBrokerAdapter,后者从 context 提取做租户隔离和工具路由。
h.invokeHook{hr.BeforeSession})
cfg,_这方面。=h.configs.Load
If you don't know how to set up tenant auth or quota checks before each turn?
isResume:=in.UserText=="" // empty => HITL resume else new Turn
history,_:=h.repo.ListMessages
sess.IncTurn
userMsg:=model.NewUserMessage
h.repo.AppendMessage
history=append
至于memCtx。=h.recallMemory
runInput.SystemContent=expandSystemPrompt+memCtx
runInput.History=history
tr,intrupt,:= h.runnableFac.StreamTurn
if err!=nil{,}
if interrupt!=nil{,}
defer tr.Close
finalContent,:=…,其实,return nil}
....
Why this boundary matters
Handle
│ ├─ Load + IsTerminal 检查
│ ├─ Context 注入
│ ├─ BeforeSession hook + Load AgentConfig
│ │ ├─── isResume=true ───────────────────────┐
│ │ │ StateWaiting 校验 │
│ │ │ ⟶sess.Resume ➜ persist │
│ │ │ ⟶ runInput: IsResume=true。History=nil │
│ │ └─── isResume=false ───────────────────────┤
├ ListMessages ➜ IncTurn ➜ AppendMessage ➜ recallMemory ➜ expandSystemPrompt ➜ runInput System/Historic
↓
runnableFac.StreamTurn
├───────────────┬───────────────┬──────────────────────┐
│ interrupt TokenReader error │
├───────────────┴───────────────┴──────────────────────┘
| | |
| | |--- pause &emit SSE “interrupt”
| |--- consume &SSE “turn.delta”
|--- failSession
↓
commitFinalAnswer --> emitTerminalEvents
scheduleMemoryExtraction
The core responsibility of Handle: orchestrate everything your business layer cares about—state migration guarantees & cross‑tenant plumbing—while delegating ReAct orchestration entirely to Eino. This separation lets you upgrade frameworks or change memory strategy without touching core domain logic.
作为专业的SEO优化服务提供商,我们致力于通过科学、系统的搜索引擎优化策略,帮助企业在百度、Google等搜索引擎中获得更高的排名和流量。我们的服务涵盖网站结构优化、内容优化、技术SEO和链接建设等多个维度。
| 服务项目 | 基础套餐 | 标准套餐 | 高级定制 |
|---|---|---|---|
| 关键词优化数量 | 10-20个核心词 | 30-50个核心词+长尾词 | 80-150个全方位覆盖 |
| 内容优化 | 基础页面优化 | 全站内容优化+每月5篇原创 | 个性化内容策略+每月15篇原创 |
| 技术SEO | 基本技术检查 | 全面技术优化+移动适配 | 深度技术重构+性能优化 |
| 外链建设 | 每月5-10条 | 每月20-30条高质量外链 | 每月50+条多渠道外链 |
| 数据报告 | 月度基础报告 | 双周详细报告+分析 | 每周深度报告+策略调整 |
| 效果保障 | 3-6个月见效 | 2-4个月见效 | 1-3个月快速见效 |
我们的SEO优化服务遵循科学严谨的流程,确保每一步都基于数据分析和行业最佳实践:
全面检测网站技术问题、内容质量、竞争对手情况,制定个性化优化方案。
基于用户搜索意图和商业目标,制定全面的关键词矩阵和布局策略。
解决网站技术问题,优化网站结构,提升页面速度和移动端体验。
创作高质量原创内容,优化现有页面,建立内容更新机制。
获取高质量外部链接,建立品牌在线影响力,提升网站权威度。
持续监控排名、流量和转化数据,根据效果调整优化策略。
基于我们服务的客户数据统计,平均优化效果如下:
我们坚信,真正的SEO优化不仅仅是追求排名,而是通过提供优质内容、优化用户体验、建立网站权威,最终实现可持续的业务增长。我们的目标是与客户建立长期合作关系,共同成长。
Demand feedback