Qurio / backend-python /docs /structured_output_integration.md
veeiiinnnnn's picture
Add backend-python and Dockerfile
4ef118d

Agno Structured Output 集成技术文档

本文档记录了对后端生成服务(Generation Services)进行重构,集成 Agno output_schema(结构化输出)的技术细节与架构变更。

1. 为什么集成 Agno Structured Output?

在重构之前,系统面临以下挑战:

  • 模型输出不稳:不同的大模型(如 GLM, Gemini 等)可能会返回带有 Markdown 标签、Python 代码块或解释性文字的非标准内容。
  • 解析代码脆弱:原先使用正则表达式或简单的 json.loads 来提取数据,一旦模型返回格式稍有偏差(例如将字段名 space_label 改为 space),解析就会失败。
  • 缺乏类型安全:后端逻辑直接操作不确定的字典或字符串,容易引发运行时错误。

集成 Agno 结构化输出的主要优势:

  • 强类型约束:通过 Pydantic 模型(Schema)告诉 AI 需要填写的“表格”格式。
  • 内建解析:Agno 在底层自动处理格式校验和重试逻辑。
  • 架构一致性:核心生成逻辑统一走“Schema -> Object”链路。

2. 逻辑对比

2.1 重构前逻辑 (旧)

  1. 下发 Prompt:手动在提示词里写“返回 JSON,包含 a, b 字段”。
  2. 获取文本:从流式响应中累加 full_content 字符串。
  3. 手动解析:用正则表达式尝试从 full_content 提取 JSON 或特定字段。
  4. 容错处理:如果 JSON 报错,尝试一些简单的字符串截取。
  5. 返回结果:返回一个字段缺失风险较高的字典。

2.2 重构后逻辑 (新 - 防御性双轨制)

  1. 定义 Schema:在 models/generation.py 中定义 Pydantic 模型(如 TitleSpaceResponse)。
  2. 底层传递StreamChatService 将 Schema 传给 Agno 处理。
  3. 核心:防御性双轨获取结果: 我们刻意保留并增强了原有的 safe_json_parse 和正则表达式逻辑,形成了所谓的“防御性双轨制”:
    • **第一轨:Agno 结构化提取 (优先)**:直接从响应中提取 Agno 转换好的 Pydantic 对象。这是最理想的情况。
    • **第二轨:手动解析与正则兜底 (核心保险)**:
      • 为什么要保留?:大模型(尤其是 GLM 等)是非确定性的。即便有 Schema 约束,它们偶尔仍会由于各种原因(如 Context 干扰、模型微调差异)返回纯文本、错误的 JSON 键名或 Python 风格的赋值语句(如 title='...')。
      • 作用:当 Agno 的内建解析器因为格式极其混乱而报错时,手动逻辑(safe_json_parse + 增强正则)会介入。这保证了即使大模型“发疯”,应用层依然能顽强地从乱码中抠出关键数据,而不是返回一个冷冰冰的错误或空结果。
  4. 归一化处理:针对模型输出的细微偏差(如 space_label vs spaceLabel)或描述溢出进行最终清洗。

3. 做的主要变更

3.1 模型层 (src/models/generation.py)

  • 新增了 TitleResponse, TitleSpaceResponse, TitleSpaceAgentResponse, RelatedQuestionsResponse, DailyTipResponse 五大 Pydantic 模型。
  • 集成了 field_validator 来自动修复模型常见的表情符号返回格式问题。

3.2 基础服务层

  • stream_chat.py: 增加了对 output_schema 的流式接收与封装,通过 DoneEvent 将结构化对象透传给业务层。
  • llm_utils.py: 更新了 run_agent_completion 工具函数,确保它在任务完成时同时返回文本和结构化对象。

3.3 业务逻辑层 (src/services/generation.py)

  • 重构了 5 个核心生成函数,使其完全支持 Agno 的结构化输出。
  • 为每个函数增加了防御性编程逻辑:结构化解析 -> JSON 安全解析 -> 强力正则匹配 -> 归一化清洗。

4. 集成效果

功能模块 改进点
标题生成 不再受 Markdown 块干扰,标题长度和表情更精准。
空间/Agent 识别 能够准确剥离描述语,确保返回的 Label 与数据库 100% 匹配。
相关问题 解决了模型返回纯文本列表而非 JSON 导致按钮显示不出的顽疾。
每日贴士 确保只返回干货文字,杜绝开场白和结束语。

5. 结论

通过此次集成,系统将原本依赖“运气”和“正则”的解析逻辑,进化为一套由模型驱动、由 Schema 约束、由代码兜底的稳健传输体系。这不仅大幅提升了后端生成的成功率,也为未来支持更复杂的交互功能打下了坚实的基础。