Files
crm-ai/bridge/src/trace-writer.js
T

52 lines
1.9 KiB
JavaScript

'use strict';
// 轻量 trace 明细:LLM/工具步骤写入 agent_trace_steps(瀑布图数据源)。
// TRACE_ENABLED=false 时不写,零开销。
function createTraceWriter(pool, enabled = false) {
let ready = null;
function ensureTable() {
if (!pool) return Promise.resolve();
if (!ready) {
ready = pool.query(`
CREATE TABLE IF NOT EXISTS agent_trace_steps (
id BIGSERIAL PRIMARY KEY,
trace_id TEXT,
conv_id TEXT,
step_type TEXT,
phase TEXT,
turn INTEGER,
model TEXT,
tool_name TEXT,
prompt_tokens INTEGER,
completion_tokens INTEGER,
duration_ms INTEGER,
finish_reason TEXT,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
`).catch((e) => console.error('[trace_writer] table init error:', e.message.slice(0, 120)));
}
return ready;
}
async function writeSteps(steps, traceId, convId) {
if (!enabled || !pool || !steps || !steps.length) return;
await ensureTable();
const values = [];
const params = [];
let i = 1;
for (const s of steps) {
values.push(`($${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++},$${i++})`);
params.push(traceId || null, convId || null, s.step_type || null, s.phase || null, s.turn ?? null, s.model || null, s.tool_name || null, s.prompt_tokens ?? null, s.completion_tokens ?? null, s.duration_ms ?? null, s.finish_reason || null);
}
try {
await pool.query(`INSERT INTO agent_trace_steps (trace_id,conv_id,step_type,phase,turn,model,tool_name,prompt_tokens,completion_tokens,duration_ms,finish_reason) VALUES ${values.join(',')}`, params);
} catch (err) {
console.error('[trace_writer] insert error:', err.message.slice(0, 120));
}
}
return { writeSteps, enabled };
}
module.exports = { createTraceWriter };