2026-10-19 14:29:31 +08:00
|
|
|
|
"""作业 2 验收测试:LangGraph 后端适配器。
|
|
|
|
|
|
|
|
|
|
|
|
通过标准(对应迁移计划作业 2):
|
2026-10-20 14:53:46 +08:00
|
|
|
|
- ``complete()`` 返回带 ``<state>`` 前缀的 ``ChatResult``,
|
|
|
|
|
|
API 层据此解析阶段码(首轮为 welcome 固定问候 1001);
|
2026-10-19 14:29:31 +08:00
|
|
|
|
- ``stream()`` 先产出含完整 state 前缀的 ``TextDelta``,再产出正文,
|
|
|
|
|
|
保证 ``stage_code`` 事件先于正文;
|
|
|
|
|
|
- 会话通过 ``thread_id = session_id`` 绑定(图 checkpoint 语义)。
|
|
|
|
|
|
|
2026-10-20 14:53:46 +08:00
|
|
|
|
注意:新会话首条消息返回 1001(对照工作流 is_first_message
|
|
|
|
|
|
分支);1002 是进入采集后的阶段。
|
2026-10-19 14:29:31 +08:00
|
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
|
|
import pytest
|
|
|
|
|
|
|
|
|
|
|
|
from src.backends.chat import ChatInput, TextDelta
|
|
|
|
|
|
from src.backends.langgraph import LangGraphBackend
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def make_input() -> ChatInput:
|
|
|
|
|
|
return ChatInput(
|
|
|
|
|
|
session_id="session-001",
|
|
|
|
|
|
text="发生了交通事故",
|
|
|
|
|
|
client_mode="direct",
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
|
|
async def test_complete_returns_state_prefixed_result() -> None:
|
|
|
|
|
|
backend = LangGraphBackend()
|
|
|
|
|
|
|
|
|
|
|
|
result = await backend.complete(make_input())
|
|
|
|
|
|
|
2026-10-20 14:53:46 +08:00
|
|
|
|
# 首轮为 welcome 固定问候(1001,对照工作流 is_first_message 分支)
|
|
|
|
|
|
assert result.content.startswith("<state>1001</state>")
|
2026-10-19 14:29:31 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
|
|
async def test_stream_emits_prefix_before_body() -> None:
|
|
|
|
|
|
backend = LangGraphBackend()
|
|
|
|
|
|
|
|
|
|
|
|
events = [event async for event in backend.stream(make_input())]
|
|
|
|
|
|
|
|
|
|
|
|
assert events, "stream 至少应产生一个 TextDelta"
|
|
|
|
|
|
assert all(isinstance(event, TextDelta) for event in events)
|
|
|
|
|
|
joined = "".join(event.text for event in events)
|
2026-10-20 14:53:46 +08:00
|
|
|
|
# 首轮为 welcome 固定问候(1001)
|
|
|
|
|
|
assert joined.startswith("<state>1001</state>")
|
2026-10-19 14:29:31 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
|
|
|
|
async def test_sessions_are_isolated_by_thread_id() -> None:
|
|
|
|
|
|
backend = LangGraphBackend()
|
|
|
|
|
|
|
|
|
|
|
|
first = await backend.complete(make_input())
|
|
|
|
|
|
second = await backend.complete(make_input())
|
|
|
|
|
|
other = await backend.complete(
|
|
|
|
|
|
ChatInput(session_id="session-002", text="你好", client_mode="direct")
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
assert first.content != "" and second.content != ""
|
2026-10-20 14:53:46 +08:00
|
|
|
|
# 三个会话的首轮都是 welcome 问候;checkpoint 相互隔离
|
|
|
|
|
|
assert other.content.startswith("<state>1001</state>")
|