Skip to content

Latest commit

 

History

1 Commit

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

agentkit

AI Agent 开发工具箱 —— 从生产项目提炼的通用组件库:代码审查平台 Argus + 智能运维多智能体平台 bianque + LLM 评测/观测平台 heimdallr。 当前版本 v0.10.31 · Go ≥ 1.26 · 43 个包。

📖 完整框架文档:docs/FRAMEWORK.md —— 设计原则、六层架构、 各包逐一详解(API/示例/边界契约)、横向能力专题(可靠性/成本/多副本/安全)、 生产实践参考、版本纪律与陷阱清单。

七种 Agent 架构:何时用 / 何时不用

逐架构代码示例与完整陷阱清单见 docs/patterns.md。 总原则:从最简单的架构开始,被现实逼着升级;不要从最复杂的开始,被复杂度困死。

1. Single Agent —— llm

  • ✅ 该用:一次调用能完成(分类/抽取/改写/摘要/单点问答);无外部事实依赖;延迟成本敏感。
  • ❌ 不该用:答案依赖模型看不到的事实(→ ReAct);输出需按硬标准迭代打磨(→ Reflection)。
  • ⚠️ 最大陷阱是"杀鸡用牛刀":把一次调用的事拆成 agent 循环,成本延迟失败面全部 ×N。80% 的 LLM 调用应止步于此。

2. ReAct —— agentrun + toolprior

  • ✅ 该用:步骤不可预知、边做边看;探索型任务(定位根因/未知代码库找证据);工具结果会改变后续方向。
  • ❌ 不该用:步骤固定可枚举(≥4 步 → 写代码/Graph);单次调用可完成;对延迟极敏感。
  • ⚠️ MaxIterations 必设;有副作用的工具必配 LimitCalls;必须有降级出口(失败落回单轮)。

3. Plan-and-Execute —— agentrun.PlanAndExecute

  • ✅ 该用:目标明确、可预规划为步骤清单,步骤多(≥4)或单步重需独立审计;计划本身有价值(可人工评审/当进度依据)。
  • ❌ 不该用:目标模糊(规划会把误解固化成计划,先 ReAct 探索);步骤 ≤3 或单轮可完成;环境每步剧变(计划频繁作废,Replan 烧钱不收敛)。
  • ⚠️ 计划质量 = Planner 模型质量(弱规划 + 强执行是常见错配);Replanner 判"完成"要可靠,MaxSteps 兜底必设。

4. Reflection —— agentkit/reflection

  • ✅ 该用:有可判定的硬标准(编译过/测试过/清单可核对);单稿质量不稳定且失败模式可枚举进 Rubric;产出重要到值得 2~3 倍调用成本。
  • ❌ 不该用:标准主观("写得好"——Critic 自评不可信,收敛 ≠ 正确);需外部事实核验(Critic 无工具,"通过"是幻觉);第一稿已稳定达标。
  • ⚠️ 全部价值在 Rubric 质量——写不进具体条目就别用;重要场景 Critic 换不同家族模型(同模型有共同盲区)。

5. Router + Skill —— agentkit/router + agentkit/skill

  • ✅ 该用(router 显式路由):入口意图可枚举(≤10)且各类别处理链差异大;想按类别配成本档;分类错误有 Fallback 兜底。
  • ✅ 该用(skill 隐式路由):类别多、持续增长、由领域文档承载;路由决策需要看了任务全文再定(渐进披露)。
  • ❌ 不该用:类别间处理链相同(路由白付一次分类调用);类别 <3 或边界模糊;skill 文档质量差(隐式路由上限 = 文档质量)。
  • ⚠️ router 的 MinConfidence + Fallback 必配;两者可组合:router 粗分到域,域内 skill 细分。门槛在 Classify 内自守:只取 Classify 决策、自行分发的编排器同样受 MinConfidence 约束(低置信/未知名返回错误,Decision 随错误返回供可观测);分类置信度钳位 [0,1]。

6. Blackboard —— agentkit/blackboard

  • ✅ 该用:多视角分析同一材料且视角间要互看(后位专家依赖前位贡献);贡献顺序不可预知、无中心指派逻辑;需要共识收敛信号(一轮无人补充 = 分析饱和)。
  • ❌ 不该用:有中心指派逻辑(→ eino adk Supervisor);专家彼此独立无需互看(→ 并行 fan-out + 合并,Argus R4 模式);强顺序依赖(→ Sequential/graph)。
  • ⚠️ 无中心调度无法保证覆盖度——专家职责要互斥且完备;话痨专家会跑满轮次(要有"写过即沉默"约束)。

7. Graph Workflow —— eino compose + adk workflow

  • ✅ 该用:流程结构稳定且复杂(条件分支/并行汇聚/循环/人工审批);需确定性保证与全链路可追溯(合规);简单架构验证过的流程固化成产品级管线。
  • ❌ 不该用:流程还在探索期经常变(改图成本 > 改 prompt,先跑通再固化——这是图的正确定位);需要 LLM 自主决策且路径空间大(图的分支是写死的 → ReAct)。
  • ⚠️ 别把需要语义判断的地方写成确定性条件边;节点粒度 = 一件事一节点;定义好节点失败时的路由(跳过/重试/终止),别让第一个错误毒化全图。

模块路径

github.com/yi-nology/agentkit

包清单

包 说明 外部依赖
acpx CLI 编码 agent 统一调用(11 家 + GenericAgent,执行纪律经 procx) eino
llm LLM 客户端(重试/限速/预算/fitInput/JSON + Resilient 降级链 + StageRouter + CostTracker + UsageHandler + 流恢复原语/空终态检测/busy 退避 v0.10.25) eino, eino-ext openai, x/time
toolprior 工具优先级决策层(提示词/排序/限流三层约束) eino
toolsched 工具并发调度器(注解驱动并行判定 + 依赖拓扑分组执行,v0.10.23) 无
mcp MCP server 工具池(lazy 建连 + 白名单 + 工具目录缓存/注解归一 + OAuth + elicitation + 调用期自愈 + UnwrapMCPText) eino, mcp-go
agentrun ReAct 样板 + Plan-and-Execute 样板(ADK 封装 + 事件流 + 重试) eino adk
reflection Reflection 架构原语(生成→批判→修订收敛循环) eino
router Router 架构原语(LLM 意图分类→选路→分发) eino
blackboard Blackboard 架构原语(共享黑板 + 专家轮转) 无
clarify 澄清/标准化词表内核(term_map 模型/加载/校验 + 序数指代解析 + 回答消解) yaml.v3
policy 操作审计门(四模式裁决矩阵 + 例外规则 + fail-safe 仲裁 + AuditGate 工具装饰器) eino, yaml.v3
dispatch 通用派发守卫(allow 矩阵 + 深度上限 + 自派发拒绝,EdgeSource 拓扑注入) 无
obsx eino callbacks 追踪(llm.call.* 结构化日志) eino, ekit
langfuse Langfuse Public API 只读客户端(trace 拉取 + 详情合并 + 官方契约类型) 无
breaker 熔断器(closed→open→half-open,探测超时兜底) 无
worker DB 即队列 worker pool(心跳/panic 隔离/优雅停机)+ LeaderElector 选主 ekit
worker/pglease LeaseStore 的 PostgreSQL 实现(原子 UPSERT + Migrate,表名可配) 无(database/sql)
knowledge/rag 双后端 RAG(Local TF-IDF + Milvus 向量) eino, milvus-sdk-go
websearch 公开资料检索抽象(Service + SearXNG + AsTool) eino
progress 泛型事件总线 Bus[T](有损广播 + 丢弃计数) ekit
skill SKILL.md 解析 + 多根 Library(热替换)+ 决策使用(渐进披露)+ 版本化契约(maturity/弃用窗口/区间求解/结构化写回) eino(decision)、yaml.v3(Library)、semver(区间)
pack 领域包 MCP 工具面契约清单(_shared 基线 / 包覆盖 / 字典序冲突) yaml.v3
lineage 装配血缘图(used_by 单源 + reload 影响面 diff + 焦点子图) skill, pack
hotplug 插拔视图 Plugboard + 泛型原子快照 Holder 无
logredact 日志/审计凭据脱敏(URL/token/Bearer 打码 + Redact 高敏感抹除 + Masker/Restore 拓扑标识令牌化) 无
jsonrepair LLM 宽容 JSON 修复(栅栏/尾逗号/全角/散文包裹 + 标量归一 + ExtractJSON/Unmarshal 解析链) 无
procx 子进程托管纪律单源(进程组执行/超时整组终止/限容采集/环境白名单) 无
httpx HTTP+JSON 调用纪律单源(限容读体 + rune 安全错误摘要) 无
reportutil 评审/评测报告后处理(严重度归一 + 采样聚簇 + Wilson/McNemar 统计) 无
audit 审计日志 ekit
textutil rune 安全截断 + 等分块 + TruncEllipsis + 近重复检测(bigram 集合 + Jaccard) 无
workcopy Git 工作副本沙箱(singleflight + 引用计数 + TTL 回收) ekit, x/sync
egress 出口围栏:LLM 可控 URL 字面量 SSRF 防护(NAT64/IPv4-mapped 还原,v0.10.23) 无
compact 会话压缩策略:auto-compact 判定(output 预留/token 双轨/熔断)+ microcompact 旧工具结果占位(v0.10.24) 无
sysprompt system prompt 分段组装:stable/dynamic 缓存边界 + env/git/date 段 + DetectEnv(v0.10.24) procx
permgate 工具许可判定链:allow/ask/deny 优先级状态机 + 会话授权 + 规则内容匹配(v0.10.25) 无
bashguard bash 静态风险解析:AST → 表驱动只读判定,权限判定不执行命令(v0.10.25) mvdan.cc/sh
hookx 外部 hook 拦截协议:7 拦截点 + 子进程 JSON 决策(v0.10.25) procx
filestate 读后写一致性:先读后改 + staleness 判定(v0.10.25) 无
steering 运行中转向队列:guide/queued 双投递(v0.10.25) 无

快速使用

ACPX —— 调用 CLI 编码 agent

import "github.com/yi-nology/agentkit/acpx"

// 缺省注册 11 家:claude/zcode/codex/opencode/minimax/kimi/gemini/qwen/mimo/pi/dsh
reg := acpx.NewRegistry()

// 直接调用
res, err := reg.Run(ctx, "codex", acpx.RunRequest{
    Prompt:  "修复 utils.go 中的空指针 bug 并补测试",
    WorkDir: "/path/to/repo",
    Sandbox: acpx.SandboxWorkspace,
})
fmt.Println(res.Text, res.Usage)

// 流式事件(回调在读取 goroutine 中执行:不得阻塞、不得 panic)
reg.Run(ctx, "claude", acpx.RunRequest{
    Prompt:  "重构 auth 模块",
    OnEvent: func(e acpx.Event) { fmt.Println(e.Type, e.Text) },
})

// 包成 eino 工具挂进 ReAct agent(LLM 自主决定调哪个 agent)
tool := reg.AsTool() // run_coding_agent(agent, prompt, work_dir)

// procx:只要进程组托管纪律、不需要 Agent 解析层时(v0.10.11 自 acpx 迁出)
import "github.com/yi-nology/agentkit/procx"

stdout, stderr, code, err := procx.Run(ctx, procx.RunRequest{
    Argv: []string{"my-cli", "run"}, Dir: workDir, Env: []string{"NEEDED_VAR"},
    Timeout: 5 * time.Minute, MaxStdout: 1 << 20,
})

各家协议由专用适配器处理(参数均经官方文档/真机核实):

Agent 非交互调用 Sandbox 支持
claude / zcode -p <prompt> --output-format stream-json ✅ permission-mode 映射
codex exec <prompt> --json --output-last-message ✅ --sandbox 原生
opencode run <prompt> --json ❌ 不支持
kimi -p <prompt> --output-format stream-json ❌ 不支持
gemini / qwen -p <prompt> --output-format json ✅ --approval-mode 映射
mimo run <prompt> --format json(专用事件流:tokens/cost/sessionID) ❌ 不支持
minimax GenericAgent 模板(CLI 协议待官方稳定) ❌ 不支持

能力契约(v0.10.8):Agent 接口含 Capabilities() 声明(Model/Session/ MaxTurns/AllowedTools/Sandbox),Registry.Run 对请求中声明不支持的非零字段 fail-fast 报错——请求了即须兑现,不存在静默忽略。安全敏感场景请选择支持 沙箱的 agent,或用 AllowedTools/MaxTurns(claude 支持)自行收敧行为。

安全防线:prompt 以 - 开头时自动前置换行(防 CLI flag 注入);子进程环境走 白名单(绝不继承密钥);进程组执行,超时/取消 TERM → 3s 宽限 → KILL; stdout 8MB 限容 + 单行 1MB 上限。超时/取消可程序化区分:errors.Is(err, procx.ErrTimeout)。

LLM 客户端

import "github.com/yi-nology/agentkit/llm"

client := llm.NewClient(chatModel, "deepseek-v4", myBudget)
client.OnUsage = func(stage string, p, c int) { /* Prometheus 记账 */ }
client.Limiter = rate.NewLimiter(10, 20)
client.ContextTokens = 1_000_000
client.MaxOutputTokens = 50_000

// 普通生成(带重试 + 限速 + fitInput;不污染调用方 msgs)
msg, err := client.Generate(ctx, "R1", messages)

// JSON 生成(解析失败回喂重试)
var spec MySpec
err := client.GenerateJSON(ctx, "R3", messages, &spec)

// 窗口派生配置
cfg := llm.BudgetConfig{ContextTokens: 1_000_000}
cfg.MaxDiffChars()     // 1,400,000
cfg.TaskTokenBudget()  // 600,000
cfg.MaxOutputTokens()  // 50,000

Resilient 多模型降级链(429 立即切换、5xx 先重试再切、401/4xx 确定性失败不重试; 每模型独立熔断;预算耗尽全链短路):

primary, _ := llm.NewOpenAIProvider(ctx, llm.OpenAIProviderConfig{
    BaseURL: "https://api.example.com/v1", APIKey: key, Model: "main-model",
    ContextTokens: 1_000_000,
})
fallback, _ := llm.NewOpenAIProvider(ctx, llm.OpenAIProviderConfig{
    BaseURL: "https://fallback.example.com/v1", APIKey: key2, Model: "backup-model",
})

r := llm.NewResilient(llm.NewFallbackChain(primary, fallback), llm.ResilientConfig{
    RetriesPerModel: 2,
    Tracker:         llm.NewCostTracker(), // 可选:内置成本记账(费率来自 Provider 配置)
})
r.OnFallback = func(from, to, stage, reason string) {
    log.Warn("模型降级", "from", from, "to", to, "stage", stage, "reason", reason)
}

msg, attempts, err := r.GenerateWithTrace(ctx, "R1", messages)

// ⚠️ RawModel() 返回裸模型——绕过重试/降级/熔断/记账。
// ReAct agent 等需要 model.BaseChatModel 的场景请自行权衡(降级链覆盖不到该流量)。

StageRouter 分阶段模型路由(v0.8.1)——不同阶段配不同模型,调用点零改动:

sr := llm.NewStageRouter(defaultGen) // 缺省 = 主链(含预算注入)
sr.Use("R1", bigWindowGen)           // 前缀路由:"R1" 命中 "R1a"
sr.Use("qa", fastGen)                // 精确路由
// 之后 sr.Generate(ctx, "R1a", msgs) 自动走 bigWindowGen;UsedTokens 聚合全部链

成本记账双口径:llm.Client.OnUsage 覆盖 Generate 直连路径;ReAct(RawModel 直用)路径的真实 usage 经 obsx.Options.OnUsage 回流(见 OBSX 节)→ 汇入 llm.CostTracker(Record(model, stage, p, c, 费率) / Summary() 按模型汇总, 1 万条封顶)。

ToolPrior —— 工具优先级决策层

import "github.com/yi-nology/agentkit/toolprior"

table := toolprior.NewTable()
table.Add(toolprior.Entry{Tool: getFileTool, Priority: toolprior.PriorityCore,
    When: "判定必需,必须最先使用", Cost: "low"})
table.Add(toolprior.Entry{Tool: mcpSearchTool, Priority: toolprior.PriorityExternal,
    When: "本地证据不足时补充", Cost: "high"})

instruction += table.StrategyPrompt(ctx)      // 软:提示词指引
tools := table.Ordered(ctx)                    // 隐式:按优先级排序
tools = append(tools, toolprior.LimitCalls(mcpTool, 5)) // 硬:限流
// 超限返回 "LIMIT_REACHED: ..." 文本(软止损,模型可见可收尾,不中止运行)

MCP —— 工具池

import "github.com/yi-nology/agentkit/mcp"

pool := mcp.NewPool(
    mcp.ServerConfig{Name: "docs", URL: "http://docs.svc/mcp",
        Headers: map[string]string{"Authorization": "Bearer " + tok}},
    mcp.ServerConfig{Name: "lint", Command: []string{"lint-mcp", "serve"},
        Env: []string{"LINT_CONFIG"}}, // 环境白名单:按名从当前进程透传
)
defer pool.Close()
pool.OnError = func(server string, err error) { log.Warn("mcp", "server", server, "err", err) }

tools, err := pool.Tools(ctx, []mcp.ToolSpec{
    {Server: "docs", Allow: []string{"search_docs"}}, // 工具白名单
})
// 安全模型:stdio 子进程环境绝不继承密钥(基础集 + Env 白名单)

AgentRun —— ReAct 运行样板

import "github.com/yi-nology/agentkit/agentrun"

out, err := agentrun.RunWithEvents(ctx, agentrun.Config{
    Name:        "reviewer",
    Instruction: instruction,
    Model:       chatModel,
    Tools:       tools, // 或 ToolsFactory: func() []tool.BaseTool { ... }(重试时重建,限流预算按尝试重置)
    MaxIterations: 12,
}, query, func(e agentrun.Event) {
    // e.Type: text | tool_call | tool_result
})

// 失败回喂重试(重试过程也可观测)
out, err = agentrun.RunWithEventsAndRetry(ctx, cfg, query, retryQuery, onEvent)

PlanAndExecute(计划先行编排,适合目标明确、步骤可预规划的长链路任务):

res, err := agentrun.PlanAndExecute(ctx, agentrun.PlanExecuteConfig{
    Planner:  plannerModel,  // 须支持 tool calling(计划结构强制产出)
    Replanner: replannerModel, // 可选:完成判定模型(空 = 复用 Planner;v0.10.13 起支持)
    Executor: executorModel,
    Tools:    tools,
    MaxSteps: 10,
}, goal)
fmt.Println(res.Text) // v0.10.11 起自 Answer 改名(产出字段词表统一 Text)

姊妹原语(v0.8.0):

// Reflection:生成→Rubric 批判→修订收敛(硬质量标准场景)
res, _ := reflection.Refine(ctx, &reflection.Config{
    Model: chatModel, Task: "实现函数", Input: 需求,
    Rubric: "1. 处理空切片 2. 无 data race", MaxIterations: 3,
})
// res.Text / res.Converged / res.Rounds(v0.10.11 起自 Output 改名)

// Router:LLM 意图分类→选路→分发(入口意图可枚举场景)
r, _ := router.New(&router.Config{Model: fastModel, Routes: []router.Route{
    {Name: "bug-fix", Description: "修代码类", Handle: fixChain},
    {Name: "explain", Description: "解释类", Handle: explainChain},
}, MinConfidence: 0.6, Fallback: fallbackFn})
d, out, _ := r.Run(ctx, userInput) // d.Route/d.Confidence/d.Reason 可观测

// Blackboard:无中心多专家互看协作(多视角分析场景)
board := blackboard.NewBoard()
board.Seed("material", 材料文本)
res, _ := blackboard.Convene(ctx, board, []blackboard.Specialist{
    {Name: "security", Act: observeAndContribute},
    {Name: "perf", Act: observeAndContribute},
}, &blackboard.ConveneOptions{MaxRounds: 3})

OBSX —— eino 调用追踪

import "github.com/yi-nology/agentkit/obsx"

// 一行启用:该 ctx 链上的 eino 组件调用自动产出 llm.call.start/end/error
// (stage/component/model/耗时/真实 token usage/慢调用告警)
ctx = obsx.InitLLMObservability(ctx, log, obsx.Options{
    SlowThreshold: 30 * time.Second,
    PreviewLen:    0, // 默认 0 = 不落内容(消息可能含用户代码/凭证)
    OnUsage: func(component, model, stage string, prompt, completion int) {
        // v0.7.2:真实 usage 回流——覆盖 ReAct RawModel 旁路(Client.OnUsage 看不到)
    },
})

熔断器

import "github.com/yi-nology/agentkit/breaker"

// 单 key:Allow==true 后必须恰好配对一次 Success/Failure
//(探测失联超过 DefaultProbeTimeout 会自动放行新探测,不会永久卡死)
b := breaker.New(3, 5*time.Minute)
if b.Allow(time.Now()) {
    if err := doSomething(); err != nil {
        b.Failure(time.Now())
    } else {
        b.Success()
    }
}

// 多 key
bs := breaker.NewBreakers(3, 5*time.Minute)
if bs.Allow("my-plugin") { /* ... */ }

Worker Pool

import "github.com/yi-nology/agentkit/worker"

// 实现 TaskQueue 接口
type MyQueue struct { /* ... */ }
func (q *MyQueue) ClaimNextPending(ctx context.Context) (string, bool, error) { /* ... */ }
func (q *MyQueue) TouchRunningHeartbeats(ctx context.Context) error { /* ... */ }
func (q *MyQueue) ResetRunningToPending(ctx context.Context, d time.Duration) (int64, error) { /* ... */ }

pool := &worker.Pool{
    Queue: &MyQueue{},
    Run:   func(ctx context.Context, taskID string) error { /* ... */ },
    N:     2,
    Log:   log,
}
pool.Start(ctx)
defer pool.Stop(60 * time.Second)
// 任务 panic 只损失该任务(worker 存活,心跳过期后复位重跑)

// LeaderElector(v0.7.3):多副本时"只能跑一份"的控制面组件(出站轮询/定时清理)
// 存储:实现 worker.LeaseStore(SQL 一条条件 UPSERT 即可)
e := worker.NewLeaderElector(store, "argus/poller", instanceID,
    30*time.Second, 10*time.Second,
    worker.WithOnGained(func() { log.Info("当选") }),
    worker.WithLeaderLogger(log))
e.Start(ctx)
if e.IsLeader() { /* 仅 leader 执行 */ }
defer e.Stop() // 主动让位,缩短换主窗口

// PG 可直接用内置租约实现(v0.9.0,免自写 LeaseStore):
// ls := pglease.NewPGLeaseStore(sqlDB).WithTable("my_lease") // 表名白名单,防拼接注入
// _ = ls.Migrate(ctx)                                       // 缺省表名 agentkit_lease

泛型事件总线

import "github.com/yi-nology/agentkit/progress"

type MyEvent struct { Type string; Data string }

bus := progress.NewBus[MyEvent]()
ch, cancel := bus.Subscribe(ctx)
defer cancel() // Background ctx 场景也必须 cancel(否则泄漏监听 goroutine)

bus.Publish(MyEvent{Type: "hello", Data: "world"})
ev := <-ch
n := bus.Dropped() // 订阅者积压导致的丢弃计数(有损是声明的设计)

知识检索

import "github.com/yi-nology/agentkit/knowledge/rag"

// 本地 RAG(目录放 markdown 文件)
knowledge, err := rag.NewLocal("/path/to/knowledge")
chunks, _ := knowledge.Retrieve(ctx, "如何配置 Nacos", 5, nil)

// 挂为 eino 工具
tool := knowledge.AsTool()

// 或向量后端(Milvus + OpenAI 兼容 Embedding;Index 幂等——重复启动重刷不累积重复行)
store, _ := rag.NewMilvusStore(ctx, rag.MilvusConfig{
    Address: "localhost:19530", Dimension: 1024,
}, rag.NewOpenAIEmbedder(baseURL, apiKey, "text-embedding-v3", 1024))

性能参考(Apple M5 实测,df 预计算后):

语料 检索延迟 分配
10 篇(~80 块) 60µs 25 allocs
100 篇(~800 块) 2.2ms 28 allocs
1000 篇(~8000 块) 47ms 36 allocs

基准:go test ./knowledge/rag/ -bench BenchmarkLocal

Milvus 集成测试(需容器环境):

docker compose -f docker-compose.milvus-test.yml up -d   # 等 healthy
MILVUS_TEST_ADDR=127.0.0.1:19530 go test ./knowledge/rag/ -run TestMilvusIntegration -v
docker compose -f docker-compose.milvus-test.yml down -v  # 用完清理

覆盖建连/自动建表/索引/Upsert 幂等/向量相似度检索/metadata 过滤/删除全链路。

安全工具

import "github.com/yi-nology/agentkit/fence"

// 中和不可信文本中的 markdown 注入(标题/列表/围栏/水平线/表格行/引用定义/HTML 注释)
safe := fence.EscapeUntrusted(llmOutput)

import "github.com/yi-nology/agentkit/reportutil"
import "github.com/yi-nology/agentkit/textutil"

// 归一化严重级别(P0/fatal 等外部审查别名一并折叠)
sev, ok := reportutil.Normalize("CRITICAL") // → "high", true

// 指纹去重(file + 规范化评论文本的 sha256 前 16 位,聚簇签名通道)
fp := reportutil.Fingerprint("main.go", "未处理错误返回值")

// glob 匹配(.gitignore 语义:web/** 匹配目录内部,不含目录自身;? 按 rune)
matched := textutil.GlobMatch("web/**/*.vue", "web/src/components/Foo.vue")

Skill —— 内容解析 + 决策使用

import "github.com/yi-nology/agentkit/skill"

provider := skill.NewFileProvider("/path/to/skills")

// 模式一:静态注入(直接解析)
s, _ := provider.Resolve(ctx, skill.Ref{Name: "ocr-grading"})
// s.Content → SKILL.md 正文,s.Checksum → sha256 前 16 位

// 模式二:决策使用(渐进披露——skill 多/大时不撑爆系统提示词)
metas, _ := provider.ListSkills(ctx)          // Meta.Name=目录名(use_skill 加载依据),
                                              // Meta.Title=frontmatter name(展示别名)
prompt := skill.ListPrompt(metas)             // 注入提示词的可用清单
useSkill, _ := skill.AsSkillTool(provider, nil) // use_skill(name) eino 工具
// 模型用展示名(frontmatter name)调用也会被归一化到目录名

TextUtil —— rune 安全文本工具

import "github.com/yi-nology/agentkit/textutil"

trunc, trimmed := textutil.TruncRunes(longText, 800) // rune 截断(多字节不腰斩)
chunks := textutil.SplitRunes(bigText, 4000)         // 等分块(大文本分批送 LLM)
ellipsis := textutil.TruncEllipsis(longText, 60)     // 截断 + 省略号(展示面统一语义,v0.9.0)

v0.9 新增组件速览

import "github.com/yi-nology/agentkit/logredact"

logredact.Redact("nats://ops:s3cret@host:4222") // nats://ops:****@host:4222
logredact.RedactValue(payload)                  // 递归脱敏 map/slice 中的凭据字符串

import "github.com/yi-nology/agentkit/jsonrepair"

var v MyStruct
err := jsonrepair.ParseLenient(llmOutput, &v, &jsonrepair.Schema{
    StringKeys: map[string]bool{"summary": true}, // 领域 schema:标量归一目标
    ListKeys:   map[string]bool{"steps": true},
    OnMap:      func(m map[string]any) { /* 每个子 map 归一完成后的领域钩子 */ },
})
// 栅栏剥离 → 散文抽对象 → 语法修复(全角/尾逗号/未闭合)→ 标量归一

var report ReviewReport
err := jsonrepair.Unmarshal(llmOutput, &report)
// ExtractJSON 快路径 → 语法修复 → 全链宽容;全败错误携带两路原因,可直接回喂重试

import "github.com/yi-nology/agentkit/websearch"

ws := websearch.NewSearxng("http://searxng.local", 10*time.Second) // 实例须开 json format
ws.Language = "zh-CN"
results, _ := ws.Search(ctx, "OOM 排查方法", 5) // 与 rag 互补:面向外网公开资料
tool := ws.AsTool()                              // web_search eino 工具

import "github.com/yi-nology/agentkit/hotplug"

pb := hotplug.NewPlugboard(allSlugs, disabled) // nil disabled = 全启用
h := hotplug.NewHolder[Snapshot]()
h.Store(newSnap) // 原子换整体;在途请求用旧快照跑完,新请求即时用新快照
cur := h.Load()

import "github.com/yi-nology/agentkit/pack"
import "github.com/yi-nology/agentkit/lineage"

manifests, warns, _ := pack.LoadToolManifests(fsys) // 包清单整文件替换 _shared 基线
                                                    // warns 非空 = 包间同名冲突(字典序第一生效)
lin := lineage.Build(experts, skills, manifests)    // expert→skill→MCP 血缘图(used_by 单源)
impacts := lineage.Diff(prev, lin)                  // reload 影响面(nil 基线=首帧无 diff)
focus, _ := lin.Focus("skill-x", 2)                 // 焦点邻接子图(depth≤2 无向)

细节与边界契约(必读)

每个包的完整契约见对应 godoc;此处集中列出最容易踩的细节(全部来自生产审查实战)。

横切契约

  • context 传播:所有 eino 工具包装(acpx.AsTool / rag.AsTool / skill.AsSkillTool / mcp 池)都透传调用方 ctx——上层取消/超时会真正终止子进程与网络调用。
  • 哨兵错误:errors.Is(err, procx.ErrTimeout / procx.ErrCanceled) 区分 CLI 超时与取消; llm 全链失败返回 *llm.AttemptError(含每次尝试的 Provider/Model/Err/Duration); 其余包错误均 %w wrap,可逐层解包。
  • 并发模型:llm/agentrun/mcp.Pool/breaker/progress/blackboard.Board/worker.Pool 并发安全;例外——toolprior.Table 与 skill.FileProvider 的注册/首扫是 build-then-read(构建后只读),skill 缓存无淘汰(假设进程内内容不变)。
  • 模型测试桩:eino v0.9 的 model.BaseChatModel 要求 Generate + Stream 两个方法都实现,只写 Generate 编译不过。
  • 测试门控:ACPX_SMOKE=1 触发 acpx 真机冒烟(真调 LLM,花钱); MILVUS_TEST_ADDR=127.0.0.1:19530 触发 Milvus 集成测试(需容器)。
  • 私有模块:go mod tidy 需 GONOSUMCHECK='git.enjoye.top/*'(或 GOPRIVATE)。

逐包细节速查

llm

  • Client 缺省:MaxRetries=3(含首次)、BaseDelay=2s、MaxDelay=30s;429 退避下限 5s。
  • GenerateJSON 解析失败只回喂重试 1 次;截断在 Generate 内部已转错误,不会流到这里。
  • MaxOutputTokens < 0 = 不下发 max_tokens 参数(推理模型兼容);0 = 走派生缺省。
  • fitInput 截断发生在最长 user 消息上并追加留痕标记;巨型 system 消息不在裁剪范围。
  • 预算注入:Client 浅拷贝 / Resilient 显式副本(共享熔断状态)——都用 BudgetInjector。
  • CostTracker 上限 1 万条(超限丢最旧);费率来自 Provider 的 CostPer1K 配置。
  • StageRouter:Use 的 stage 既可以是精确名("qa")也可以是前缀("R1" 命中 "R1a"); 预算注入在注册前完成;RawModel() 恒透传缺省链。

acpx

  • 缺省超时 10 分钟;stdout 8MB / 单行 1MB 上限;stderr 只留尾部 400 字节进错误。
  • 子进程环境 = 基础集(PATH/HOME/TMPDIR/代理/CA/XDG 等)+ Env 按名透传; 额外注入 GIT_TERMINAL_PROMPT=0、CI=1。
  • mimo 运行期错误 exit code 仍为 0,只能从 error 事件识别——错误详情在 error.data.message(顶层 error.message 为兼容回退),acpx 对 error 事件 如实上抛并全量转发(gemini error 信封、codex error 事件、claude is_error result 同纪律);transcript 消费方据此可排障。
  • mimo -m 须 xiaomi/ 全名前缀(短名被服务端拒绝);本机 CLI 缺省模型可能被 服务端下线(ultraspeed 前车之鉴)——生产装配显式配置: reg.Register(&acpx.Mimo{Bin: "mimo", DefaultModel: "xiaomi/mimo-v2.5-pro"}) (Register 重名覆盖语义)。RunRequest.Model 显式指定时优先。
  • 探活/健康判定(probe)以 Run 返回的 err != nil 为失败门槛——上述 exit=0 错误形态已如实报错,勿用"有输出即通过"判定(纯错误跑曾以 stdout 兜底成"成功"把排障带偏)。
  • codex 的 usage 是逐轮累加口径;kimi 新版 -p 直跑(无 --print,不可与 --auto 组合)。
  • OnEvent 回调在 stdout 读取 goroutine 中同步执行——不得阻塞、不得 panic。
  • Registry 构建期注册、运行期只读;AsTool 只传 Prompt/WorkDir(控制面字段 全零,不触发能力校验)——需要沙箱约束时自行构造 RunRequest 而非走 AsTool。

mcp

  • Timeout 覆盖连接 + Initialize(30s 缺省),不含子进程 spawn 阶段。
  • 列举失败自动摘除坏连接(下次调用重建);Close 后池不可复用;重名 server 保留先到。
  • Allow 白名单全部未命中时经 OnError 告警(返回 0 个工具不报错)。

toolprior

  • LimitCalls 每次调用新建包装实例(计数不跨任务共享)——跨重试需要重置 预算时配合 agentrun ToolsFactory。
  • 超限返回 LIMIT_REACHED: ... 文本(nil error):模型可见、可收尾;不要改回 返回 error——那会中止整个 agent 运行。
  • Table 构建后只读;Add nil Tool 直接 panic。

skill

  • frontmatter 只解析 name/description(--- 围栏);缓存无淘汰(进程内内容不变假设); symlink 不在路径防护范围(root 应为可信目录)。
  • Format 用 eino FString(pyfmt):正文含裸 {/} 需写成 {{/}}。
  • Meta.Name = 目录名(use_skill/allowed 唯一依据);Meta.Title = frontmatter 展示别名;模型用别名回填会被归一化。

agentrun

  • 出口判定 = assistant 消息且无 tool_calls;空内容答复报错文案区分"空答复"与"没答复"。
  • MaxIterations 默认 12(比 ADK 缺省 20 更收紧)。
  • RunWithRetry 两次尝试共用 Tools 实例——有状态包装(限流)跨尝试累计, 需要重置请用 ToolsFactory。

reflection

  • Critic 输出 {"pass":bool,"issues":[]};pass=true 仍带 issues 判不通过。
  • MaxIterations 默认 3;收敛只代表符合 Rubric,不代表正确。

blackboard

  • Board 是内存态;Convene 每轮串行调用各专家(专家内部自行并发); 游标语义 = 错过的增量不重看(每轮都是新起点)。

knowledge/rag

  • chunk 缺省:目标 600 rune / 硬上限 4000 / 块间重叠 100 / 重扫间隔 10min; topK 缺省 5;工具返回单片段截断 800 rune。
  • 过滤字段白名单:file / heading(其他 key 直接报错)。
  • Local 分词 = ASCII 词 + 中文二元组(日韩文暂不支持);Milvus 索引固定 IVF_FLAT (IndexType 字段保留但未生效);COSINE 下 Score 是相似度(越大越好)。
  • Embedder 每批 16 条串行、带维度校验;集成测试需 MILVUS_TEST_ADDR 门控。

websearch

  • 面向外网公开资料(与 knowledge/rag 私有知识库互补);SearXNG 实例须配置 formats: [html, json],否则响应非 JSON 直接报错。
  • HTTP 非 200 / 响应非 JSON 一律报错;无命中 = 空切片 + nil error;Language 空串 = 不传 language 参数。

jsonrepair / logredact / hotplug

  • jsonrepair:修复顺序 = 栅栏剥离 → 散文抽对象 → 语法修复 → 标量归一;领域 schema(StringKeys/ListKeys/OnMap)留给调用方。OnMap 在子节点归一完成后 对每个 map 触发(v0.9.1 更名自 Mutate 并改时机——旧 API 已删,领域钩子现在 看得到已规范化的嵌套结构)。
  • logredact:只打码三类——URL 内嵌账号口令 / token·secret·password·api_key 键值对 / Authorization·Bearer 头;与 fence(注入卫生)正交,一个管密钥一个管注入。
  • hotplug:NewPlugboard(all, disabled) 传 nil = 全启用;Holder.Store 原子换 整体、读无锁——在途请求继续用旧快照跑完,新请求即时用新快照。

pack / lineage

  • pack:包清单对 _shared 基线是整文件替换不是 merge——扩展清单须拷出全量 再增改;包间同名 server 冲突 = 警告 + 包名字典序第一生效(警告即治理信号, 两包真争同一 server 属治理问题);无清单目录合法。conf 是装配事实源、清单是 契约事实源,对账由调用方做。
  • lineage:只管图机制不绑定装配实现——有效技能集(覆盖感知)由装配方经中性输入 注入;Diff nil 基线不产出 impact(重启首帧把全量资产报成"新增"是噪音); 工具面 diff 取 manifest ∪ 显式授予并集(只 diff manifest 会让授予变更静默), 任一侧 Unlimited 授予则枚举不可知、跳过不产出;Focus depth≤2 无向遍历。

worker

  • 心跳 20s / 过期判定 90s(StaleRunningAfter)——任务须短于此或自行续期。
  • ClaimNextPending 实现必须原子(多副本正确性的根);Log/Queue/Run 为 nil 会在启动或消费期回退/报错。
  • 多副本要求共享 DB 为网络库;Stop(grace) 后心跳可能还有 ≤5s 尾巴。
  • pglease:TryAcquire 原子 UPSERT(空闲/过期/本人持有 → true),Release 仅 持有者生效;表名白名单 WithTable(防拼接注入),缺省 agentkit_lease, 使用前需 Migrate。

breaker / progress / audit / textutil

  • breaker:Allow==true 后必须恰好配对一次 Success/Failure;Breakers.Now 仅 启动期可注入。
  • progress:订阅缓冲 64,满了丢(Dropped() 可观测);cancel 与 ctx 双向收口。
  • audit:走 Info 级别——日志级别调到 Warn 以上会吞掉审计事件(可用独立 sink)。
  • textutil:TruncRunes(s, -1) 返回空串 + true(不 panic);SplitRunes(s, 0) 整串单块。

依赖关系

你的项目
    │
    ▼
agentkit/llm            ← LLM 调用(重试/降级/限速/预算/阶段路由/成本/用量)
agentkit/agentrun       ← ReAct / Plan-and-Execute 样板
agentkit/reflection     ← 反思循环
agentkit/router         ← 意图路由
agentkit/blackboard     ← 多专家黑板协作
agentkit/dispatch       ← 派发守卫(allow 矩阵 + 深度上限)
agentkit/policy         ← 操作审计门(四模式裁决)
agentkit/clarify        ← 澄清/标准化词表内核(回答消解)
agentkit/toolprior      ← 工具优先级决策
agentkit/skill          ← SKILL.md 渐进披露 + 多根库 + 版本化契约
agentkit/pack           ← 领域包 MCP 工具面契约清单
agentkit/lineage        ← 装配血缘图(依赖 skill + pack)
agentkit/mcp            ← MCP 工具池
agentkit/acpx           ← CLI 编码 agent
agentkit/websearch      ← 公开资料检索
agentkit/knowledge/rag  ← 双后端知识检索
agentkit/worker         ← 异步任务队列(+ pglease PG 租约 / LeaderElector 选主)
agentkit/hotplug        ← 插拔/热替换
agentkit/jsonrepair     ← 宽容 JSON 修复 + 模型输出解析链
agentkit/procx · httpx  ← 子进程/HTTP 调用纪律单源
agentkit/logredact      ← 凭据脱敏
agentkit/breaker        ← 熔断保护
agentkit/progress       ← 事件总线
agentkit/obsx           ← eino 调用追踪
agentkit/langfuse       ← Langfuse trace 读回(只读客户端)
agentkit/reportutil     ← 评审/评测报告后处理(严重度/聚簇/统计)
agentkit/fence · audit · textutil · workcopy  ← 安全/审计/文本/副本沙箱
    │
    ▼
  eino / eino-ext / mcp-go / milvus-sdk-go / ekit / x/time / x/sync / semver / yaml.v3

从生产项目迁移

Argus

Argus 内部包改为 import agentkit:

Argus 旧路径 agentkit 新路径
argus/internal/llm agentkit/llm
argus/internal/worker agentkit/worker
argus/internal/textutil agentkit/textutil
argus/internal/audit agentkit/audit
argus/internal/skill → knowledge/skill agentkit/skill
argus/internal/progress agentkit/progress
argus/internal/knowledge/rag agentkit/knowledge/rag
argus/internal/context/workcopy agentkit/workcopy
argus/internal/adapter_cli / acpx agentkit/acpx
argus/internal/mcp(如适用) agentkit/mcp
argus/internal/obs(如适用) agentkit/obsx
argus/internal/plugin.Breaker/Breakers agentkit/breaker
argus/internal/plugin.SeverityRank/Normalize... agentkit/reportutil(v0.10.11 起自 severity 并入)
argus/internal/plugin.TokenBudget agentkit/llm.TokenAccountant 接口
argus/internal/plugin.GlobMatch agentkit/textutil.GlobMatch(v0.10.9 迁入)
argus/internal/plugin.Fingerprint agentkit/reportutil.Fingerprint(v0.10.9 迁 sampling,v0.10.11 并入)
argus/internal/reportview.EscapeUntrusted agentkit/fence.EscapeUntrusted(v0.10.9 起,原 safejson)

argus(v0.9.8)

argus 旧路径 agentkit 新路径
argus/internal/llmjson agentkit/jsonrepair.Unmarshal(v0.10.11 起自 llmjson 并入)

bianque(v0.9.0)

bianque 旧路径 agentkit 新路径
bianque/internal/logredact agentkit/logredact
bianque/internal/search agentkit/websearch
bianque/internal/cluster(PGLeaseStore) agentkit/worker/pglease
bianque/internal/strutil.Truncate agentkit/textutil.TruncEllipsis
bianque/internal/agents Plugboard/SnapshotStore agentkit/hotplug
bianque/internal/skills Library/DecisionProvider agentkit/skill.Library
bianque/internal/llm/obs.go UsageHandler agentkit/llm.NewUsageHandler
bianque/internal/engine/protocol 宽容 JSON / UnwrapMCPText agentkit/jsonrepair / agentkit/mcp.UnwrapMCPText

报告 schema、专家包 schema、审批/会话等领域模型仍留在 bianque。

bianque(v0.9.2)

bianque 旧路径 agentkit 新路径
bianque/internal/skills(SkillMeta/写回/校验/弃用窗口) agentkit/skill(LibMeta/Validate/RewriteMode/RewriteBody/DeprecatedExpiredInUse)
bianque/internal/skills.VersionInRange agentkit/skill.VersionInRange
bianque/internal/agents.SkillRef agentkit/skill.Decl
bianque/internal/service.ToolManifest + loadToolManifests agentkit/pack.ToolManifest + LoadToolManifests
bianque/internal/service Lineage/DiffLineage/Focus/LineageHub agentkit/lineage(Build/Diff/Focus/Hub,中性输入)

bianque(v0.9.4)

bianque 旧路径 agentkit 新路径
bianque/internal/llm/failover.go(failoverModel) agentkit/llm.NewFailoverModel(OnFailover 回调替代全局钩子)
bianque/internal/engine/runner mutatingToolSegments agentrun.MutatingVerbs + IsMutatingTool + SideEffectTracker(重试守卫内建于 RunWithRetry)
bianque/internal/agents/routing.go 词表匹配内核 agentkit/router.KeywordHit 四件套(否定守门/词边界/排除构式)
bianque/internal/logredact(副本分叉) agentkit/logredact(凭证词 : 空格形态 + PEM 整段规则已合入)
bianque/internal/strutil.Truncate agentkit/textutil.TruncEllipsis(v0.9.0 挂账清账)

bianque(v0.9.5)

bianque 旧路径 agentkit 新路径
bianque/internal/scheduler/usage.go priceOf agentkit/llm.PriceOf(精确 → 最长前缀回落,未配价归零)
bianque/internal/engine/dispatch/guard.go agentkit/dispatch(注册表耦合改 EdgeSource 接口注入拓扑)

bianque(v0.9.6)

bianque 旧路径 agentkit 新路径
bianque/internal/engine/policy agentkit/policy(yaml 路径约定改显式入参;bianque 侧薄转发)
bianque/internal/engine/runner/audit.go agentkit/policy.AuditGate
bianque/internal/engine/scheduler/normalize.go postNegated agentkit/router.KeywordPostNegated

bianque(v0.9.7)

bianque 旧路径 agentkit 新路径
bianque/internal/agents TermEntry/TermClarify + loadTermMap agentkit/clarify.Entry/Options + LoadVocab(别名薄层)
bianque/internal/agents 词表内在校验 agentkit/clarify.Validate(域注册/路由词冲突校验留宿主)
bianque/internal/engine/scheduler ordinalIndex/resolveTermAnswer agentkit/clarify.OrdinalIndex/ResolveAnswer

heimdallr(v0.10.0)

heimdallr 旧路径 agentkit 新路径
heimdallr/internal/mine/dedup.go bigramSet/jaccard agentkit/textutil(BigramSet/Jaccard/Similarity/NearDuplicate;InstructionBigrams 留宿主)
heimdallr/internal/report WilsonCI/McNemarExact agentkit/reportutil(v0.10.11 起自 stats 并入,comb 转私有)
heimdallr/internal/observe/client.go + Trace/Observation 契约类型 agentkit/langfuse(错误前缀 langfuse:;UsageTokens/UsageCost 导出;MapTrace 留宿主)

About

agentkit mirror (canonical: git.enjoye.top/enjoydream/agentkit)

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages