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>
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user