抽屉优化

This commit is contained in:
pphua committed 2026-08-25 12:05:26 +08:00
1 parent 7234874797
commit d968727460
14 files changed
+669 -154

No files matched your search

+15
View File
@@ -697,6 +697,21 @@ CREATE TABLE IF NOT EXISTS skill_usage (
CREATE INDEX IF NOT EXISTS idx_skill_usage_skill ON skill_usage(skill, ts DESC);
CREATE INDEX IF NOT EXISTS idx_skill_usage_task ON skill_usage(task_id);
-- 工具调用账本(见 db/tool_usage.go)。一次实际 CoreTool.Call 一行,只记归属维度,
-- 不保存工具参数或返回内容。刻意不设外键,任务、会话或自定义工具删除后仍保留统计。
CREATE TABLE IF NOT EXISTS tool_usage (
id BIGSERIAL PRIMARY KEY,
ts TIMESTAMPTZ NOT NULL DEFAULT now(),
tool_key TEXT NOT NULL,
agent_key TEXT,
task_id BIGINT,
exploration_id BIGINT,
intent_id BIGINT,
session_id TEXT
);
CREATE INDEX IF NOT EXISTS idx_tool_usage_tool ON tool_usage(tool_key, ts DESC);
CREATE INDEX IF NOT EXISTS idx_tool_usage_task ON tool_usage(task_id);
-- =====================================================================
-- H. 内置工具目录
-- =====================================================================
+46
View File
@@ -0,0 +1,46 @@
package db
// ToolUsage is one catalog tool invocation. It stores attribution dimensions only:
// tool arguments and results are deliberately excluded from the ledger.
type ToolUsage struct {
ToolKey string `json:"tool_key"`
AgentKey string `json:"agent_key"`
TaskID int64 `json:"task_id"`
ExplorationID int64 `json:"exploration_id"`
IntentID int64 `json:"intent_id"`
SessionID string `json:"session_id"`
}
// InsertToolUsage appends one ledger row. Runtime callers treat metering as
// best-effort so a statistics failure never interrupts the tool itself.
func (d *DB) InsertToolUsage(u *ToolUsage) error {
_, err := d.Exec(`
INSERT INTO tool_usage(tool_key, agent_key, task_id, exploration_id, intent_id, session_id)
VALUES ($1, NULLIF($2,''), $3, $4, $5, NULLIF($6,''))`,
u.ToolKey, u.AgentKey, nullIfZero(u.TaskID), nullIfZero(u.ExplorationID),
nullIfZero(u.IntentID), u.SessionID)
return err
}
// ToolUsageCounts returns invocation totals keyed by catalog tool key. Entries
// without calls are absent; API callers merge the result into the tools catalog.
func (d *DB) ToolUsageCounts() (map[string]int, error) {
rows, err := d.Query(`
SELECT tool_key, COUNT(*)
FROM tool_usage
GROUP BY tool_key`)
if err != nil {
return nil, err
}
defer rows.Close()
out := map[string]int{}
for rows.Next() {
var key string
var calls int
if err := rows.Scan(&key, &calls); err != nil {
return nil, err
}
out[key] = calls
}
return out, rows.Err()
}
+44
View File
@@ -0,0 +1,44 @@
package db
import "testing"
func TestToolUsageLedger(t *testing.T) {
d, err := Open(testDSN(t))
if err != nil {
t.Skipf("postgres unavailable (%v) - skipping", err)
}
defer d.Close()
const (
toolA = "zz_test_tool_usage_a"
toolB = "zz_test_tool_usage_b"
)
cleanup := func() {
_, _ = d.Exec(`DELETE FROM tool_usage WHERE tool_key IN ($1,$2)`, toolA, toolB)
}
cleanup()
defer cleanup()
rows := []*ToolUsage{
{ToolKey: toolA, AgentKey: "worker", TaskID: 991, ExplorationID: 5, IntentID: 7},
{ToolKey: toolA, AgentKey: "planner", TaskID: 992, ExplorationID: 6},
{ToolKey: toolA, AgentKey: "chatbot", SessionID: "conv-1"},
{ToolKey: toolB, AgentKey: "worker", TaskID: 991},
}
for _, row := range rows {
if err := d.InsertToolUsage(row); err != nil {
t.Fatalf("insert %s: %v", row.ToolKey, err)
}
}
counts, err := d.ToolUsageCounts()
if err != nil {
t.Fatal(err)
}
if got := counts[toolA]; got != 3 {
t.Errorf("%s calls: want 3, got %d", toolA, got)
}
if got := counts[toolB]; got != 1 {
t.Errorf("%s calls: want 1, got %d", toolB, got)
}
}
+1
View File
@@ -19,6 +19,7 @@ type Tool struct {
Kind string `json:"kind"` // builtin | command | script | http
Exec json.RawMessage `json:"exec"` // 自定义工具执行规格(kind!=builtin)
Deferred bool `json:"deferred"` // schema 延迟(走 SearchExtraTools/ExecuteExtraTool)
Calls int `json:"calls"` // runtime ledger aggregate; not stored in tools
}
const toolCols = `key, system, description, schema, agents, enabled, kind, exec, deferred`