mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 17:38:10 +00:00
- docs/zh/架构迁移评估.md: C ABI→子进程+共享内存完整迁移论证(1621行) - docs/zh/experiments/: 18项可复跑可行性实验(架构评估的所有数字来源) - plan.md §11: 11.1~11.9 插件架构缺陷修复清单(唯一权威编号) - main 保持干净,本批次为 update 特性分支的整改起点
102 lines
2.8 KiB
Go
102 lines
2.8 KiB
Go
//go:build ignore
|
||
|
||
package main
|
||
|
||
// 精确复刻现网 AfterToolcall 上 sanitizer(Global,改写) + weather(OwnTools,只读) 的并发
|
||
import (
|
||
"encoding/json"
|
||
"fmt"
|
||
"strings"
|
||
"sync"
|
||
)
|
||
|
||
type ToolResult struct {
|
||
Name string `json:"name"`
|
||
Plugin string `json:"plugin"`
|
||
Result interface{} `json:"result"`
|
||
}
|
||
type Ctx struct {
|
||
mu sync.RWMutex
|
||
ToolRes []ToolResult
|
||
}
|
||
func (c *Ctx) Lock(){c.mu.Lock()}; func (c *Ctx) Unlock(){c.mu.Unlock()}
|
||
func (c *Ctx) RLock(){c.mu.RLock()}; func (c *Ctx) RUnlock(){c.mu.RUnlock()}
|
||
|
||
func cleanText(s string) string {
|
||
// 模拟 sanitizer:去掉 ANSI/坏字节
|
||
return strings.ReplaceAll(s, "\x1b[31m", "")
|
||
}
|
||
|
||
// 内核 case 2 handler(外部插件通用路径)
|
||
func kernelExternal(sc *Ctx, pluginFn func(*Ctx)) {
|
||
// 1. 快照
|
||
sc.RLock()
|
||
snap, _ := json.Marshal(map[string]interface{}{"tool_results": sc.ToolRes})
|
||
sc.RUnlock()
|
||
|
||
// 2. go_invoke_stage: 插件进程内全新对象
|
||
local := &Ctx{}
|
||
var m map[string]interface{}
|
||
json.Unmarshal(snap, &m)
|
||
if v, ok := m["tool_results"]; ok {
|
||
b, _ := json.Marshal(v)
|
||
json.Unmarshal(b, &local.ToolRes)
|
||
}
|
||
|
||
// 3. 插件 handler 跑在副本上
|
||
pluginFn(local)
|
||
|
||
// 4. stageContextWritable: 无条件回传 tool_results
|
||
out := map[string]interface{}{}
|
||
if len(local.ToolRes) > 0 { out["tool_results"] = local.ToolRes }
|
||
rb, _ := json.Marshal(out)
|
||
|
||
// 5. applyStageResult 写回内核
|
||
var rm map[string]interface{}
|
||
json.Unmarshal(rb, &rm)
|
||
sc.Lock()
|
||
if v, ok := rm["tool_results"]; ok {
|
||
b, _ := json.Marshal(v)
|
||
var trs []ToolResult
|
||
if json.Unmarshal(b, &trs) == nil { sc.ToolRes = trs }
|
||
}
|
||
sc.Unlock()
|
||
}
|
||
|
||
func sanitizerStage(ctx *Ctx) {
|
||
ctx.Lock(); defer ctx.Unlock()
|
||
for i, tr := range ctx.ToolRes {
|
||
if s, ok := tr.Result.(string); ok {
|
||
ctx.ToolRes[i].Result = cleanText(s)
|
||
}
|
||
}
|
||
}
|
||
func weatherStage(ctx *Ctx) {
|
||
ctx.Lock(); defer ctx.Unlock()
|
||
// 只读打印,不改(own_tools scope 已匹配)
|
||
_ = len(ctx.ToolRes)
|
||
}
|
||
|
||
func main() {
|
||
const rounds = 3000
|
||
dirty := "\x1b[31m晴 25°C"
|
||
polluted := 0
|
||
for r := 0; r < rounds; r++ {
|
||
sc := &Ctx{ToolRes: []ToolResult{{Name:"weather_query", Plugin:"weather", Result: dirty}}}
|
||
var wg sync.WaitGroup
|
||
wg.Add(2)
|
||
go func(){ defer wg.Done(); kernelExternal(sc, sanitizerStage) }()
|
||
go func(){ defer wg.Done(); kernelExternal(sc, weatherStage) }()
|
||
wg.Wait()
|
||
if s, ok := sc.ToolRes[0].Result.(string); ok && strings.Contains(s, "\x1b[31m") {
|
||
polluted++
|
||
}
|
||
}
|
||
fmt.Printf("现网场景复刻:模型调用 weather_query,sanitizer+weather 并发跑 AfterToolcall\n")
|
||
fmt.Printf(" %d 轮中 %d 轮清洗结果被覆盖 (%.1f%%)\n", rounds, polluted, float64(polluted)/rounds*100)
|
||
if polluted > 0 {
|
||
fmt.Printf("\n ⚠️ 确认:weather 回传的未清洗快照覆盖了 sanitizer 的清洗结果\n")
|
||
fmt.Printf(" → 脏数据(ANSI 转义)进入 LLM 上下文\n")
|
||
}
|
||
}
|