feat: 实现 Eino Graph 构建与 Orchestrator 适配器,切换 main.go

- graph.go: 构建 Graph 拓扑 START→STT→History→ChatModel→Splitter→TTS→Done→END
  - 创建 eino-ext ChatModel 对接 DashScope OpenAI 兼容接口
  - 统一使用值类型(PipelineInput/PipelineOutput)
  - Callback 在运行时通过 Stream option 传入
- adapter.go: EinoOrchestrator 实现 orchestrator.Orchestrator 接口
  - 解码 base64 音频/图片,注入 context 值
  - 调用 Graph.Stream() 触发惰性执行并消费输出
  - 追加用户/助手消息到历史
- main.go: 移除旧 llmService + orchestrator.New()
  替换为 eino.NewPipelineGraph() + eino.NewEinoOrchestrator()
- 各节点统一使用值类型,State 传递请求元数据

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-06-19 21:58:17 +08:00
parent fd5c7712f8
commit 4b731b5ac0
9 changed files with 395 additions and 98 deletions

View File

@@ -19,11 +19,24 @@ import (
// 语音模式:调用 sttService.Recognize() 进行语音识别。
// 识别结果通过 Sender 发送 stt_result 到客户端。
func NewSTTLambda(sttService stt.Service) *compose.Lambda {
return compose.InvokableLambda(func(ctx context.Context, input *PipelineInput) (*STTOutput, error) {
return compose.InvokableLambda(func(ctx context.Context, input PipelineInput) (STTOutput, error) {
log := logger.Log
sender := senderFromCtx(ctx)
requestID := requestIDFromCtx(ctx)
// 将输入元数据写入 State供下游节点History、Done读取
if state := stateFromCtx(ctx); state != nil {
state.mu.Lock()
state.SessionID = input.SessionID
state.RequestID = input.RequestID
state.ImageData = input.ImageData
state.Scenario = input.Scenario
state.DetailLevel = "low"
state.Language = input.Language
state.TTSEnabled = input.TTSEnabled
state.mu.Unlock()
}
// 文本输入模式:跳过 STT
if input.Text != "" {
log.Infow("使用文本输入,跳过 STT",
@@ -48,7 +61,7 @@ func NewSTTLambda(sttService stt.Service) *compose.Lambda {
state.mu.Unlock()
}
return &STTOutput{
return STTOutput{
Text: input.Text,
Language: input.Language,
IsSkipped: true,
@@ -57,7 +70,7 @@ func NewSTTLambda(sttService stt.Service) *compose.Lambda {
// 语音模式:解码音频
if len(input.AudioData) == 0 {
return nil, fmt.Errorf("stt: no audio data provided")
return STTOutput{}, fmt.Errorf("stt: no audio data provided")
}
log.Infow("开始语音识别",
@@ -79,7 +92,7 @@ func NewSTTLambda(sttService stt.Service) *compose.Lambda {
Message: "语音识别失败: " + err.Error(),
})
}
return nil, fmt.Errorf("stt: recognize: %w", err)
return STTOutput{}, fmt.Errorf("stt: recognize: %w", err)
}
// STT 返回空文本
@@ -109,7 +122,7 @@ func NewSTTLambda(sttService stt.Service) *compose.Lambda {
state.mu.Unlock()
}
return &STTOutput{
return STTOutput{
Text: text,
Language: input.Language,
IsSkipped: false,