This commit is contained in:
liubiren 2026-07-05 13:06:20 +08:00
parent c499b16c3b
commit cc8efb7143
2 changed files with 144 additions and 143 deletions

View File

@ -98,12 +98,12 @@ class Run(BaseModel):
) )
is_reasoning: bool = Field( is_reasoning: bool = Field(
default=False, default=False,
description="正在推理状态True 表示正在推理False 表示非正在推理", description="推理状态True 表示正在推理False 表示非正在推理",
) )
assistant_content: str = Field(default="", description="回复正文") assistant_content: str = Field(default="", description="回复正文")
is_streaming: bool = Field( is_running: bool = Field(
default=False, default=False,
description="流式输出状态True 表示正在流式输出False 表示非正在流式输出", description="运行状态True 表示正在运行False 表示非正在运行",
) )

View File

@ -155,10 +155,10 @@ class ConversationState(rx.State):
return conversation.runs if conversation else {} return conversation.runs if conversation else {}
@rx.var @rx.var
def get_run_streaming_status(self) -> bool: def get_run_running_status(self) -> bool:
""" """
获取当前运行流式输出状态 获取当前运行运行状态
:return: 当前运行流式输出状态True 表示正在流式输出False 表示非正在流式输出 :return: 当前运行状态True 表示正在运行False 表示非正在运行
""" """
# 当前对话 # 当前对话
conversation = self.conversations.get(self.conversation_id) conversation = self.conversations.get(self.conversation_id)
@ -167,7 +167,7 @@ class ConversationState(rx.State):
# 末位运行 # 末位运行
run = next(reversed(conversation.runs.values())) run = next(reversed(conversation.runs.values()))
return run.is_streaming return run.is_running
@rx.event @rx.event
async def run(self, form_data: dict[str, Any]) -> AsyncGenerator[None]: async def run(self, form_data: dict[str, Any]) -> AsyncGenerator[None]:
@ -200,159 +200,160 @@ class ConversationState(rx.State):
conversation.runs[str(uuid7())] = Run(user_prompt=user_prompt) conversation.runs[str(uuid7())] = Run(user_prompt=user_prompt)
# 将末位运行唯一标识、运行设置为当前运行唯一标识、运行 # 将末位运行唯一标识、运行设置为当前运行唯一标识、运行
run_id, run = next(reversed(conversation.runs.items())) run_id, run = next(reversed(conversation.runs.items()))
# 将流式输出状态设置为正在流式输出 # 将运行状态设置为正在运行
run.is_streaming = True run.is_running = True
yield # 通知前端渲染流式输出状态 yield # 通知前端渲染运行状态
async for event in self.agent.run_stream_events( async with self.agent.run_stream_events(
conversation_id=self.conversation_id, conversation_id=self.conversation_id,
user_prompt=user_prompt, user_prompt=user_prompt,
message_history=message_history, message_history=message_history,
): ) as events:
match event: async for event in events:
# ========== 分片开始事件 ========== match event:
case PartStartEvent( # ========== 分片开始事件 ==========
index=index, case PartStartEvent(
part=part, index=index,
previous_part_kind=previous_part_kind, part=part,
): previous_part_kind=previous_part_kind,
match part: ):
# 思考分片开始事件 match part:
case ThinkingPart( # 思考分片开始事件
part_kind=part_kind, content=content case ThinkingPart(
): content=content
# 若上一分片种类为空则将正在推理状态设置为正在推理 ):
if not previous_part_kind: # 若上一分片种类为空则将推理状态设置为正在推理
run.is_reasoning = True if not previous_part_kind:
run.is_reasoning = True
# 初始化推理 # 初始化推理
run.reasonings[index] = Reasoning(kind=Kind.THINKING, content=content) run.reasonings[index] = Reasoning(kind=Kind.THINKING, content=content)
yield # 通知前端渲染推理 yield # 通知前端渲染推理
case ToolSearchCallPart( case ToolSearchCallPart(
tool_call_id=tool_call_id tool_call_id=tool_call_id
): ):
# 创建工具调用唯一标识与片段索引映射 # 创建工具调用唯一标识与片段索引映射
tool_call_ids[index] = tool_call_id tool_call_ids[index] = tool_call_id
# 初始化推理 # 初始化推理
run.reasonings[index] = Reasoning(kind=Kind.TOOL_SEARCH, content="正在检索") run.reasonings[index] = Reasoning(kind=Kind.TOOL_SEARCH, content="正在检索")
yield # 通知前端渲染推理 yield # 通知前端渲染推理
# 文本分片开始事件 # 文本分片开始事件
case TextPart( case TextPart(
part_kind=part_kind, content=content content=content
): ):
# 初始化回复正文 # 初始化回复正文
run.assistant_content = content run.assistant_content = content
yield # 通知前端渲染回复正文 yield # 通知前端渲染回复正文
case _: case _:
continue continue
# ========== 分片增量事件(前端仅就文本片段实现打字机效果) ========== # ========== 分片增量事件(前端仅就文本片段实现打字机效果) ==========
case PartDeltaEvent( case PartDeltaEvent(
index=index, delta=delta index=index, delta=delta
): ):
match delta: match delta:
# 思考分片增量事件 # 思考分片增量事件
case ThinkingPartDelta( case ThinkingPartDelta(
content_delta=content_delta, content_delta=content_delta,
): ):
run.reasonings[index].content += content_delta or "" run.reasonings[index].content += content_delta or ""
yield # 通知前端渲染推理 yield # 通知前端渲染推理
# 文本分片增量事件 # 文本分片增量事件
case TextPartDelta( case TextPartDelta(
content_delta=content_delta, content_delta=content_delta,
): ):
run.assistant_content += content_delta run.assistant_content += content_delta
yield # 通知前端渲染回复正文 yield # 通知前端渲染回复正文
case _: case _:
continue continue
# ========== 分片结束事件 ========== # ========== 分片结束事件 ==========
case PartEndEvent( case PartEndEvent(
event_kind=event_kind, event_kind=event_kind,
index=index, index=index,
part=part, part=part,
next_part_kind=next_part_kind, next_part_kind=next_part_kind,
): ):
match part: match part:
# 思考分片结束事件 # 思考分片结束事件
case ThinkingPart( case ThinkingPart(
part_kind=part_kind, content=content part_kind=part_kind, content=content
): ):
# 若下一分片种类为文本则将正在推理状态设置为非正在推理 # 若下一分片种类为文本则将推理状态设置为非正在推理
if next_part_kind == Kind.TEXT: if next_part_kind == Kind.TEXT:
run.is_reasoning = False run.is_reasoning = False
# 检索工具分片结束事件 # 检索工具分片结束事件
case ToolSearchCallPart( case ToolSearchCallPart(
tool_call_id=tool_call_id tool_call_id=tool_call_id
): ):
# 创建工具调用唯一标识与片段索引映射 # 创建工具调用唯一标识与片段索引映射
tool_call_ids[index] = tool_call_id tool_call_ids[index] = tool_call_id
# 加载能力分片结束事件 # 加载能力分片结束事件
case LoadCapabilityCallPart( case LoadCapabilityCallPart(
tool_kind=tool_kind, tool_name=tool_name tool_kind=tool_kind, tool_name=tool_name
): ):
yield Event( yield Event(
event_kind=EventKind(event_kind), event_kind=EventKind(event_kind),
part_index=index, part_index=index,
part_kind=PartKind(tool_kind), part_kind=PartKind(tool_kind),
next_part_kind=PartKind(next_part_kind), next_part_kind=PartKind(next_part_kind),
tool_name=tool_name, tool_name=tool_name,
run_id=current_run_id, run_id=current_run_id,
) )
# 调用工具分片结束事件 # 调用工具分片结束事件
case ToolCallPart( case ToolCallPart(
part_kind=part_kind, tool_name=tool_name part_kind=part_kind, tool_name=tool_name
): ):
yield Event( yield Event(
event_kind=EventKind(event_kind), event_kind=EventKind(event_kind),
part_index=index, part_index=index,
part_kind=PartKind(part_kind), part_kind=PartKind(part_kind),
next_part_kind=PartKind(next_part_kind), next_part_kind=PartKind(next_part_kind),
tool_name=tool_name, tool_name=tool_name,
run_id=current_run_id, run_id=current_run_id,
) )
# ========== 函数工具调用事件 ========== # ========== 函数工具调用事件 ==========
case FunctionToolCallEvent( case FunctionToolCallEvent(
event_kind=event_kind, event_kind=event_kind,
part=part, part=part,
): ):
yield Event( yield Event(
event_kind=EventKind(event_kind), event_kind=EventKind(event_kind),
part_index=self.tool_call_ids.get( part_index=self.tool_call_ids.get(
part.tool_call_id part.tool_call_id
), ),
part_kind=PartKind(part.part_kind), part_kind=PartKind(part.part_kind),
tool_name=part.tool_name, tool_name=part.tool_name,
run_id=current_run_id, run_id=current_run_id,
) )
# ========== 函数工具回调事件 ========== # ========== 函数工具回调事件 ==========
case FunctionToolResultEvent( case FunctionToolResultEvent(
event_kind=event_kind, event_kind=event_kind,
content=content, content=content,
part=part, part=part,
): ):
yield Event( yield Event(
event_kind=EventKind(event_kind), event_kind=EventKind(event_kind),
event_content=( event_content=(
content if isinstance(content, str) else "" content if isinstance(content, str) else ""
), # 暂仅处理文本类型,后续处理多模态和缓存 ), # 暂仅处理文本类型,后续处理多模态和缓存
part_index=self.tool_call_ids.get( part_index=self.tool_call_ids.get(
part.tool_call_id part.tool_call_id
), ),
part_kind=PartKind(part.part_kind), part_kind=PartKind(part.part_kind),
tool_name=part.tool_name, tool_name=part.tool_name,
run_id=current_run_id, run_id=current_run_id,
) )
yield Event( yield Event(
event_kind=EventKind.RUN_END, event_kind=EventKind.RUN_END,