Eric Wang 952bffe6f0 feat(streaming): real incremental SSE - model tokens flow through graph to client (assignment 8)
Replaces the 'complete answer sliced into chunks' stopgap with token-
level streaming. Graph nodes are untouched: they still consume the
batched LLMService.complete interface and validate full replies.

- agent/llm: OpenAILLMService.stream_tokens() iterates the provider
  stream with the same message construction, temperature and extra_body
  forwarding as complete(); identical error classification (401 ->
  LLMAuthError, 429 -> LLMRateLimitError, timeout via asyncio.timeout
  around the whole iteration); deliberately no retries (tokens already
  emitted cannot be recalled)
- backends/langgraph: _TokenPassThroughLLM wraps the injected LLM for
  stream turns - dialogue calls push tokens to a queue bridge while
  accumulating the full text for node validation; calls marked with the
  【字段提取】 marker take the silent inner.complete path so extraction
  JSON never leaks into the client stream; LLMs without stream_tokens
  fall back to single-chunk push (fake/test compatibility)
- stream(): graph runs in a background task; the generator yields
  TextDelta per token and FormUpdate after the turn; graph-task errors
  re-raise with the existing ChatBackend error mapping; generator close
  (client disconnect) cancels the graph task and the in-flight LLM call
- fixed-answer turns with no LLM call (welcome) fall back to emitting
  the full response text, preserving previous behavior
- endpoint untouched: its buffering parser already handles arbitrary
  chunk boundaries (state tags split across tokens, stage-first order)

Verified: 241 unit tests (11 new streaming tests: token incrementality,
extraction bypass, FormUpdate ordering, error mapping on both paths,
disconnect cancellation, fallback chunking, SSE protocol end-to-end
with per-token text_delta events)
2026-10-23 00:20:03 +08:00
2026-06-03 12:36:18 +08:00
2025-06-20 10:03:39 +08:00

AI 事故信息采集 API(LangGraph 迁移分支)

本分支是“将对话后端从 FastGPT 工作流迁移到 LangGraph”课程的迁移准备分支。

当前状态:对外 API 契约保持不变,/chat 的供应商细节已封装到后端适配层(FastGPT 仍 为唯一实现),迁移计划见 docs/langgraph-backend-migration-plan.md。 本阶段交付说明与验证证据见 docs/assignment-baseline.md。

环境要求

  • Python 3.11(使用 Conda 环境 py3.11,见 AGENTS.md)
  • fastgpt-client SDK(当前以本地可编辑方式安装,见下文)

安装

conda activate py3.11

# 项目依赖
pip install -r requirements.txt

# FastGPT SDK(本地可编辑安装;SDK 源码在独立仓库维护)
pip install -e /path/to/fastgpt-python-sdk

配置

服务端通过环境变量读取 FastGPT 连接信息。复制示例配置并按环境填写:

cp .env.example .env

需要设置的变量:

变量 说明
ANALYSIS_SERVICE_URL FastGPT 服务地址
ANALYSIS_AUTH_TOKEN FastGPT API Key
APP_ID FastGPT 应用 ID

运行

python -m uvicorn src.main:app --host 127.0.0.1 --port 8000
  • GET / 存活检查
  • POST /chat 对话(?stream=true 为 SSE 流式)
  • POST /set_info、POST /get_info、DELETE /delete_session 业务数据接口

测试

conda run -n py3.11 python -m pytest -q

测试分三层:

  • test/api/test_public_schema_contract.py:公共请求/响应 schema 的契约冻结测试
  • test/api/test_chat_backend_boundary.py:API 层与后端适配层的边界测试(fake 后端)
  • test/backends/test_fastgpt_backend.py:FastGPT 适配器的翻译测试(fake SDK)

目录结构

src/
  api/endpoints.py        # HTTP 协议层:schema、state 前缀解析、SSE 事件
  backends/chat.py        # 后端中立契约(ChatBackend Protocol、ChatInput/ChatResult/事件)
  backends/fastgpt.py     # FastGPT 适配器:SDK 调用与响应翻译
  core/fastgpt_client.py  # 客户端生命周期与依赖注入(lifespan)
  schemas/models.py       # 公共 Pydantic 模型
docs/langgraph-backend-migration-plan.md  # 十阶段迁移作业计划
evals/                    # 调用真实服务的评测用例与 runner

当前状态与已知限制

作业 1—5 已完成(LLM 提议 + 代码校验架构,提示词与 workflow/20261020 逐字对齐,全量测试 143 通过)。逐作业进度、真实模型评测结果与开放问题 见 docs/langgraph-backend-migration-plan.md 文末“当前进度与已知差异”。

  • 真实模型黄金评测:collection_skip_known_info 12/12 通过; photo_skip_plate_confirm 0/4、no_false 2/8,统一卡在短促回答“对” 的分流语义上,待与 FastGPT 应用层配置对账(差异已留档,未叠代码守卫)。
  • set_info / get_info 仍直接依赖 FastGPT 状态与历史,迁移到共享 业务状态属于作业 6;delete_session 已按后端分流(langgraph 清 checkpoint)。
  • 服务启动(langgraph 模式)不需要 FastGPT 配置;需要 LLM provider 配置。
  • 流式为“完整答案切片”,真实增量输出属作业 8;formUpdate 差量属作业 6。
S
Description
No description provided
Readme
12 MiB
Languages
Python 82.9%
HTML 8%
JavaScript 6.2%
CSS 2.9%