feat: 短期多轮历史接入 Eino 图 MessagesPlaceholder (⑨)

会话历史(Redis,易失,与长期画像分开)经 MCP 工具进出 Eino 图:
recall 召回历史填 MessagesPlaceholder,写回把本轮 user/assistant 落历史。

- mcp-go: internal/history(go-redis, sundynix:history:<session>, LPUSH+LTRIM 保留近20条,
  24h TTL) + 工具 history_get(返回JSON turns)/history_append; main 开 Redis(降级)
- dispatcher Eino: 模板加 MessagesPlaceholder('history'); recall 调 history_get→转 schema.Message;
  Handle 累积 answer; memorize 异步 history_append(user+assistant)
- shared: contract.MetaSessionID; gateway: SubmitTask 注入 Meta[session_id](X-Session-ID 头,缺省 default)
- demo.sh: 同会话两轮提交,验证第2轮召回第1轮历史
- 验证: 4 模块 build✓ + 3 e2e PASS; live 跑通——轮1=0轮历史→落库, 轮2 history_get 命中→注入

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Blizzard
2026-06-10 14:18:45 +08:00
parent cbd130ecae
commit 4928ffc0f7
12 changed files with 288 additions and 47 deletions
+20 -2
View File
@@ -48,18 +48,36 @@ func (pm *poolModel) Stream(ctx context.Context, input []*schema.Message, _ ...m
// 真实模型不需要本函数。
func replyFor(msgs []*schema.Message) string {
var profile, user string
for _, m := range msgs {
priorTurns := 0
for i, m := range msgs {
switch m.Role {
case schema.System:
profile = m.Content
case schema.Assistant:
priorTurns++ // 历史里的助手消息 = 过往轮次
case schema.User:
user = m.Content
if i == len(msgs)-1 {
user = m.Content // 最后一条 user 才是本轮输入
}
}
}
return "【已注入用户画像】" + condense(profile, 80) +
"(本会话已有 " + itoa(priorTurns) + " 轮历史)" +
" | 据此为你个性化作答:已编排执行该 Agent 图(输入「" + condense(user, 30) + "」)。"
}
func itoa(n int) string {
if n == 0 {
return "0"
}
var b []byte
for n > 0 {
b = append([]byte{byte('0' + n%10)}, b...)
n /= 10
}
return string(b)
}
func condense(s string, max int) string {
s = strings.TrimSpace(strings.ReplaceAll(s, "\n", " "))
r := []rune(s)