Files
Blizzard 45ad852806 feat(dispatcher): Eino 组件化补完 —— 检索 Retriever + 提示词 ChatTemplate
补完终态架构剩余两层(A 收尾):
- 检索:新增 ragRetriever(eino_components.go)实现 components/retriever.Retriever,
  包 mcp-go kb_search(NATS)、命中转 *schema.Document;retrieve() 改经组件,
  retriever 节点与报告分章检索统一走它。
- 提示词:buildMessages 改用 prompt.FromMessages + MessagesPlaceholder
  (FString 仅解析模板串、值原样注入 → JSON 花括号安全),产出消息序列与旧手拼等价。
- 工具:mcpTool 即 InvokableTool(Phase B),用于模型自主调用;静态 tool 节点
  确定性裸调用 by design。

测试:buildMessages 形状(含花括号)+ ragRetriever 文档解析单测;make test-go 全绿。

性能:compose 每任务编译实测 ~13µs(基准),相对 LLM 秒级可忽略 → 编译图缓存
判为 premature optimization 暂不做;并行效率已由 Phase C DAG 调度拿到。

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-23 11:20:52 +08:00

57 lines
2.0 KiB
Go

package eino
import (
"context"
"strings"
"testing"
"github.com/cloudwego/eino/schema"
"github.com/sundynix/sundynix-shared/contract"
)
// TestBuildMessagesShape 锁定 ChatTemplate 产出的消息序列与旧手拼逻辑等价:
// [system(含画像+参考资料)] + [历史...] + [user(query)],且 JSON 花括号不被误解析。
func TestBuildMessagesShape(t *testing.T) {
rc := &RunCtx{
System: "你是助手",
Query: "今天几号",
Profile: "称呼=Dexter",
History: []*schema.Message{schema.UserMessage("上一句"), schema.AssistantMessage("上一答", nil)},
ToolOut: []string{`{"k":"v"}`}, // 含花括号,验证 FString 不误解析
}
msgs, err := buildMessages(context.Background(), rc)
if err != nil {
t.Fatal(err)
}
if len(msgs) != 4 {
t.Fatalf("应为 system+2历史+user=4 条,实际 %d", len(msgs))
}
if msgs[0].Role != schema.System || !strings.Contains(msgs[0].Content, "你是助手") ||
!strings.Contains(msgs[0].Content, "称呼=Dexter") || !strings.Contains(msgs[0].Content, `{"k":"v"}`) {
t.Fatalf("system 消息不对: %q", msgs[0].Content)
}
if msgs[3].Role != schema.User || msgs[3].Content != "今天几号" {
t.Fatalf("user 消息不对: %q", msgs[3].Content)
}
}
// fakeCaller 是 ToolCaller 测试替身,固定返回 kb_search 命中。
type fakeCaller struct{ content string }
func (f *fakeCaller) CallTool(_ context.Context, _ string, _ *contract.ToolCall) (*contract.ToolResult, error) {
return &contract.ToolResult{OK: true, Content: f.content}, nil
}
// TestRagRetrieverComponent 验证 Retriever 组件把 kb_search 命中转成 *schema.Document。
func TestRagRetrieverComponent(t *testing.T) {
o := &Orchestrator{tools: &fakeCaller{content: `[{"text":"片段A","score":0.9},{"text":"片段B","score":0.8}]`}}
docs, err := o.newRetriever("u/kb").Retrieve(context.Background(), "q")
if err != nil {
t.Fatal(err)
}
if len(docs) != 2 || docs[0].Content != "片段A" || docs[1].Content != "片段B" {
t.Fatalf("文档解析不对: %+v", docs)
}
}