deer-flow/backend/docs/TITLE_GENERATION_IMPLEMENTATION.md
xiawiie 2453718acd
Some checks are pending
Backend Blocking IO / backend-blocking-io (push) Waiting to run
Unit Tests / backend-unit-tests (push) Waiting to run
E2E Tests / e2e-tests (push) Waiting to run
Frontend Unit Tests / frontend-unit-tests (push) Waiting to run
Lint Check / lint-backend (push) Waiting to run
Lint Check / lint-frontend (push) Waiting to run
Replay E2E (front-back contract) / Layer 1 — backend golden (no API key) (push) Waiting to run
Replay E2E (front-back contract) / Layer 2 — full-stack render (no API key) (push) Waiting to run
fix(title): avoid default LLM call before stream end (#3885)
* fix(title): avoid default LLM call before stream end

* fix(title): keep default fallback local

* fix(title): harden fallback and replay e2e

* docs(title): align fallback title behavior
2026-06-30 18:58:02 +08:00

6.3 KiB
Raw Blame History

自动 Title 生成功能实现总结

已完成的工作

1. 核心实现文件

packages/harness/deerflow/agents/thread_state.py

  • 添加 title: str | None = None 字段到 ThreadState

packages/harness/deerflow/config/title_config.py (新建)

  • 创建 TitleConfig 配置类
  • 支持配置enabled, max_words, max_chars, model_name, prompt_template
  • 提供 get_title_config()set_title_config() 函数
  • 提供 load_title_config_from_dict() 从配置文件加载

packages/harness/deerflow/agents/middlewares/title_middleware.py (新建)

  • 创建 TitleMiddleware
  • 实现 _should_generate_title() 检查是否需要生成
  • 默认使用本地 fallback 生成标题,避免流式回复结束前等待额外 LLM 调用;显式配置 model_name 时可使用 LLM 标题
  • 实现 after_model() / aafter_model() 钩子,在首次对话后自动触发
  • 包含 fallback 策略LLM 未配置或失败时使用用户消息前几个字符)

packages/harness/deerflow/config/app_config.py

  • 导入 load_title_config_from_dict
  • from_file() 中加载 title 配置

packages/harness/deerflow/agents/lead_agent/agent.py

  • 导入 TitleMiddleware
  • 注册到 middleware 列表:[SandboxMiddleware(), TitleMiddleware()]

2. 配置文件

config.yaml

  • 添加 title 配置段:
title:
  enabled: true
  max_words: 6
  max_chars: 60
  model_name: null  # null = 快速本地 fallback填模型名才启用 LLM 标题

3. 文档

docs/AUTO_TITLE_GENERATION.md (新建)

  • 完整的功能说明文档
  • 实现方式和架构设计
  • 配置说明
  • 客户端使用示例TypeScript
  • 工作流程图Mermaid
  • 故障排查指南
  • State vs Metadata 对比

TODO.md

  • 添加功能完成记录

4. 测试

tests/test_title_generation.py (新建)

  • 配置类测试
  • Middleware 初始化测试
  • TODO: 集成测试(需要 mock Runtime

🎯 核心设计决策

为什么使用 State 而非 Metadata

方面 State ( 采用) Metadata ( 未采用)
持久化 自动(通过 checkpointer 取决于实现,不可靠
版本控制 支持时间旅行 不支持
类型安全 TypedDict 定义 任意字典
标准化 LangGraph 核心机制 扩展功能

工作流程

用户发送首条消息
  ↓
Agent 处理并返回回复
  ↓
TitleMiddleware.after_model()/aafter_model() 触发
  ↓
检查:是否首次对话?是否已有 title
  ↓
默认从首条用户消息生成本地 fallback title
  ↓
如果显式配置 title.model_name才调用 LLM 生成更精炼的 title
  ↓
返回 {"title": "..."} 更新 state
  ↓
Checkpointer 自动持久化(如果配置了)
  ↓
客户端从 state.values.title 读取

📋 使用指南

后端配置

  1. 启用/禁用功能
# config.yaml
title:
  enabled: true  # 设为 false 禁用
  1. 自定义配置
title:
  enabled: true
  max_words: 8      # 标题最多 8 个词
  max_chars: 80     # 标题最多 80 个字符
  model_name: null  # null = 快速本地 fallback填模型名才启用 LLM 标题
  1. 配置持久化(可选)

如果需要在本地开发时持久化 title

# checkpointer.py
from langgraph.checkpoint.sqlite import SqliteSaver

checkpointer = SqliteSaver.from_conn_string("deerflow.db")
// langgraph.json
{
  "graphs": {
    "lead_agent": "deerflow.agents:lead_agent"
  },
  "checkpointer": "checkpointer:checkpointer"
}

客户端使用

// 获取 thread title
const state = await client.threads.getState(threadId);
const title = state.values.title || "New Conversation";

// 显示在对话列表
<li>{title}</li>

⚠️ 注意Title 在 state.values.title,而非 thread.metadata.title


🧪 测试

# 运行测试
pytest tests/test_title_generation.py -v

# 运行所有测试
pytest

🔍 故障排查

Title 没有生成?

  1. 检查配置:title.enabled = true
  2. 确认是首次对话1 个用户消息 + 1 个助手回复)
  3. 如果显式配置了 title.model_name,检查标题模型是否可用;未配置时会走本地 fallback

Title 生成但看不到?

  1. 确认读取位置:state.values.title(不是 thread.metadata.title
  2. 检查 API 响应是否包含 title
  3. 重新获取 state

Title 重启后丢失?

  1. 本地开发需要配置 checkpointer
  2. LangGraph Platform 会自动持久化
  3. 检查数据库确认 checkpointer 工作正常

📊 性能影响

  • 默认延迟:默认 title.model_name: null 不会发起额外 LLM 调用,仅从首条用户消息生成本地 fallback title
  • 显式 LLM 标题延迟:只有配置 title.model_name 时,首轮回复后才会等待一次标题模型调用
  • 并发安全:在 after_model() / aafter_model() 中更新 state不需要客户端额外请求
  • 资源消耗:每个 thread 只生成一次

优化建议

  1. 默认保持 model_name: null,避免流式回复结束前的额外 LLM 等待
  2. 如需更精炼标题,再显式配置较快的标题模型
  3. 减少 max_wordsmax_chars,并让 prompt 保持简洁

🚀 下一步

  • 补充 prompt template 的集成测试
  • 支持多语言 title 生成
  • 添加 title 重新生成功能
  • 监控 title 生成成功率和延迟

📚 相关资源


实现完成时间: 2026-01-14