agent_log 表设计思路(文章创作器多阶段日志落地)

agentlog 的设计核心是一条 traceid 贯穿一次生成任务,一个 stage 记录一个阶段,JSON 存出入参,token 与耗时单独计量。表结构围绕可观测性建:traceid、agentname、stage、req/resp JSON、prompttokens、completiontokens、costms、status、errormsg、createtime。索引只建 traceid 与 create_time 两个核心,其他字段靠 JSON 检索或归档后分析,避免日志表变成索引重灾区。

一、日志表要回答的三个问题

多阶段生成每次任务要调用多次大模型,出问题时最常问三件事:

  1. 这篇文章生成到哪一步失败的,失败在哪个阶段?
  2. 那次调用的入参提示词是什么,模型返回了什么?
  3. 消耗了多少 token、耗时多久,成本花在哪里?

agentlog 就是为这三个问题建的。它与 article 表的分工:article 存”产出的结果”,agentlog 存”生成的过程”。

二、字段设计

字段 类型 说明
id BIGINT 主键
trace_id VARCHAR(64) 一次生成任务的全链路 ID
task_id BIGINT 关联生成任务表
article_id BIGINT 关联文章
agent_name VARCHAR(64) 阶段名:topic/outline/draft/polish
stage TINYINT 阶段序号,与 agent_name 对应
attempt TINYINT 该阶段第几次尝试
req_params JSON 入参:提示词、模型、温度等
resp_result JSON 模型最终返回
prompt_tokens INT 输入 token 数
completion_tokens INT 输出 token 数
total_tokens INT 合计
cost_ms BIGINT 该次调用耗时毫秒
status TINYINT 0 成功 1 失败 2 超时
error_msg VARCHAR(500) 失败摘要
error_stack TEXT 完整异常堆栈
create_time DATETIME 入库时间

reqparams 和 respresult 用 MySQL JSON 类型而不是 TEXT。JSON 字段在 8.0 有原生校验和 jsonextract 能力,排查时按需提取,不用把整条日志拉出来解析。respresult 只存最后一次有效返回,完整的流式 chunk 序列不上库——那是几百条小片段,直接写日志文件或对象存储,数据库只留聚合结果。

三、trace_id 怎么贯穿链路

traceid 在创建生成任务时生成,流式回调的每个阶段都带上它。前端展示进度时按 traceid 查各阶段日志,后端定位问题时一条 SQL 拉出全链路:

SELECT stage, agent_name, status, cost_ms, total_tokens, error_msg
FROM agent_log WHERE trace_id = 'xxx' ORDER BY id;

同一任务重试会产生多条同 stage 日志,用 attempt 字段区分第几次尝试,保留每次的入参出参,方便对比失败与成功路径的差异。

四、索引与存储策略

日志表的查询模式很固定:按 traceid 拉链路、按时间段分析、按 agentname 统计成功率。索引不需要多:

  1. idx_trace_id(trace_id):全链路查询的核心入口;
  2. idx_create_time(create_time):时间范围分析;
  3. idx_agent_create(agentname, createtime):单阶段成功率、耗时统计。

不要给 status、errormsg 这类低区分度字段单独建索引。日志量大以后按月分区,agentlog 保留最近三个月热数据,更早的归档到独立库,分区裁剪让时间范围查询只扫需要的分区。

五、异步落库,不拖慢流式主链路

日志写在异步线程里。生成任务本身要等大模型返回几十秒,同步落库会把等待时间再拉长。实现上用一个独立线程池,方法内只组装 AgentLog 对象,插入动作丢给线程池:

@Component
public class AgentLogRecorder {

    private final AgentLogMapper logMapper;
    private final ExecutorService executor = Executors.newFixedThreadPool(2);

    public void record(AgentLog log) {
        log.setCreateTime(LocalDateTime.now());
        executor.execute(() -> logMapper.insert(log));
    }
}

线程池容量要控制好,日志写入失败只记 error 日志,绝不能影响生成主流程。批量写入用 saveBatch 合并,避免每个阶段一次单条 insert。

六、与 AOP 配合,日志代码不进业务

记录动作不散落在各阶段代码里。在调用 AI 的服务方法上打自定义注解,AOP 切面统一采集入参、执行耗时、异常堆栈,组装成 AgentLog 交给 recorder。业务代码里只有一行注解,日志逻辑集中在切面维护,阶段代码只管生成,不关心日志怎么落。

常见问题(FAQ)

Q1:agent_log 直接存完整流式响应吗?

不存。只存最后一次有效返回,流式 chunk 序列写日志文件。

Q2:日志量增长很快怎么处理?

按 create_time 分区或按月归档,热库只保留最近三个月。

Q3:token 统计在哪一步拿到的?

流式结束时从 ChatResponse 元数据聚合,按阶段累加入库。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 qiqicto@qq.com 举报,一经查实,本站将立刻删除。
赞 (0)
其AI的头像其AI普通用户

相关推荐

返回顶部