# 对话数据保存流程

> 适用：NewLife.ChatAI
> 最后更新：2026-04-13

---

## 1. 总览

每次对话请求的数据持久化分布在多个时间点，涉及 `ChatMessage`（用户消息 + AI 回复）和 `Conversation`（会话元数据）两张表。

```
HTTP 请求
  │
  ├─ userMsg.Insert()            《立即写入》用户消息（基础字段）
  │
  ├─ BuildContextMessagesAsync() 构建历史上下文
  ├─ pipeline.PrepareContext()   注入技能提示词，生成初始 SystemPrompt
  │
  ├─ assistantMsg.Insert()       《立即写入》AI 回复占位（仅 Id + Role）
  │
  ├─► StreamAsync()              开始流式生成
  │     │
  │     ├─ OnSystemReady 回调    《第一个 chunk 前触发》
  │     │    └─ userMsg.Update()  ThinkingContent = 完整系统提示词（含技能+记忆）
  │     │
  │     ├─ content/thinking chunk 实时推送 SSE
  │     │
  │     └─ ChatAIPipeline
  │          └─ ai:ToolSchema span  记录本轮工具 Function Schema（不落库）
  │
  └─ PersistStreamResult()       《流结束后》批量写入
       ├─ assistantMsg.Update()  Content / ThinkingContent / ToolCalls / ToolNames
       │                         ModelName / MaxTokens / Temperature / FinishReason
       │                         InputTokens / OutputTokens / TotalTokens / ElapsedMs
       ├─ userMsg.Update()       SkillNames / ToolNames
       └─ conversation.Update()  MessageCount / LastMessageTime / Token 累计
```

---

## 2. 字段写入时机详表

### 2.1 用户消息（role = user）

| 字段 | 写入时机 | 说明 |
|------|---------|------|
| `Content` | `Insert()` | 用户原始输入 |
| `Attachments` | `Insert()` | 附件 ID 数组（JSON） |
| `ThinkingMode` | `Insert()` | 本轮思考模式 |
| `SkillNames` | PersistStreamResult | 本轮激活的技能名 |
| `ThinkingContent` | **OnSystemReady 回调** | 完整系统提示词快照（含技能/记忆，调试用） |
| `ToolNames` | PersistStreamResult | 本轮可用工具名（逗号分隔） |

### 2.2 AI 回复消息（role = assistant）

| 字段 | 写入时机 | 说明 |
|------|---------|------|
| `Content` | PersistStreamResult | 正文 Markdown |
| `ThinkingContent` | PersistStreamResult | AI 推理思考过程 |
| `ToolCalls` | PersistStreamResult | `ToolCallDto[]` JSON（含入参 + 结果） |
| `ToolNames` | PersistStreamResult | 实际调用工具名 |
| `ModelName` | PersistStreamResult | 本轮模型编码 |
| `FinishReason` | PersistStreamResult | stop / length / tool_calls / error |
| `InputTokens` / `OutputTokens` / `TotalTokens` | PersistStreamResult | Token 用量 |
| `ElapsedMs` | PersistStreamResult | 整轮耗时（毫秒） |

---

## 3. 字段多义性说明

`ChatMessage` 部分字段因 `role` 不同而含义不同：

| 字段 | role = user | role = assistant |
|------|------------|-----------------|
| `ThinkingContent` | 本轮注入的系统上下文全文（调试用） | AI 推理思考过程 |
| `ToolNames` | 本轮**可用**工具名（逗号分隔） | 本轮**实际调用**工具名（逗号分隔） |
| `ToolCalls` | 不使用 | `ToolCallDto[]` 调用链路（入参 + 结果） |

---

## 4. 链路追踪埋点

| Span 名称 | 位置 | 说明 |
|---------|------|------|
| `ai:Stream:{modelCode}` | `StreamMessageAsync` | 覆盖整轮 SSE 生成 |
| `ai:ToolSchema` | `ChatAIPipeline.StreamAsync` | 本轮工具 Function Schema，供调试分析；不落库以防鉴权信息泄露 |
| `ai:ToolCall:{toolName}` | `DrainPipelineAsync` | 单次工具调用，含入参 + 返回结果 |
