fix: regulatory 对话模式改用 event_stream_handler 修复工具调用截断,优化节点 prompt 和日志展示

- regulatory_node: stream_working 从 run_stream 改为 agent.run + event_stream_handler,
  解决工具调用后文本被截断的问题;添加 PartStartEvent 处理修复首字丢失
- consciousness_node: prompt 重写为三模式(生成/执行/报告),强调禁止编造 agent_id
- workflow API: _merge_runtime_status 暴露步骤输出内容(workflow_log 第三元素)
- 前端日志: 系统日志改为终端滚动样式,工作流步骤可展开查看输出

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-06-05 13:19:52 +00:00
parent ad5da2a118
commit d39c80743d
4 changed files with 153 additions and 107 deletions
+4 -2
View File
@@ -177,8 +177,8 @@ def _merge_runtime_status(work_link: list, workflow_log: list) -> list:
前端 ``WorkflowDiagram`` 依赖每个 step 的 ``status`` 字段着色,这个拼装让
后端真正把运行期状态喂过去。
"""
# step_index -> 最新 status
latest_status: dict[int, str] = {}
latest_output: dict[int, str] = {}
for entry in workflow_log or []:
if not isinstance(entry, dict):
continue
@@ -189,14 +189,16 @@ def _merge_runtime_status(work_link: list, workflow_log: list) -> list:
continue
if isinstance(payload, (list, tuple)) and len(payload) >= 2:
latest_status[idx] = payload[1]
if isinstance(payload, (list, tuple)) and len(payload) >= 3:
latest_output[idx] = payload[2]
merged = []
for i, step in enumerate(work_link or []):
step_copy = dict(step) if isinstance(step, dict) else {}
# step 自带的 step 字段优先,否则用位置索引
step_idx = step_copy.get("step")
lookup_idx = (step_idx - 1) if isinstance(step_idx, int) else i
step_copy["status"] = latest_status.get(lookup_idx, "pending")
step_copy["output"] = latest_output.get(lookup_idx, "")
merged.append(step_copy)
return merged
@@ -126,11 +126,23 @@ class RegulatoryNode:
"""
return await self._run(payload)
async def stream_working(self, payload: MessageRequest, token_queue: "asyncio.Queue") -> None:
"""流式工具调用版本:逐 token 推送到 queue,工具调用结果也会通过 token 输出。
_CHAT_INSTRUCTIONS = (
"你是 kilostar 智能助手。你现在处于【直接对话模式】,请直接回答用户的问题。\n"
"规则:\n"
"1. 直接、详细地回答用户问题,像一个专业且友好的助手。\n"
"2. 如果你有可用工具,可以调用工具来辅助回答(如搜索、读文件等)。\n"
"3. 不要输出内部思考过程,不要做路由判断,不要提及 ForUser/ForConsciousnessNode 等格式。\n"
"4. 回复应当完整、有帮助,避免过于简短。\n"
)
完成后 push None 作为终止信号。
async def stream_working(self, payload: MessageRequest, token_queue: "asyncio.Queue") -> None:
"""流式对话:完整执行 agent graph(含工具调用),逐 token 推送文本到 queue。
使用 event_stream_handler 回调拿到每个 text delta,保证工具调用后
的文本也能被流式输出。完成后 push None 作为终止信号。
"""
from pydantic_ai.messages import PartStartEvent, PartDeltaEvent, TextPart, TextPartDelta
platform = payload.platform
user_name = payload.user_name
message = payload.message
@@ -140,17 +152,27 @@ class RegulatoryNode:
await token_queue.put(None)
return
async def _stream_handler(ctx, events):
async for event in events:
if isinstance(event, PartStartEvent) and isinstance(event.part, TextPart):
if event.part.content:
await token_queue.put(event.part.content)
elif isinstance(event, PartDeltaEvent) and isinstance(event.delta, TextPartDelta):
await token_queue.put(event.delta.content_delta)
try:
deps = RegulatoryNodeDeps(
platform=platform,
user_name=user_name,
time=time_str
)
async with self.agent.run_stream(
user_prompt=message, deps=deps, output_type=str
) as stream_result:
async for delta in stream_result.stream_text(delta=True):
await token_queue.put(delta)
await self.agent.run(
user_prompt=message,
deps=deps,
output_type=str,
instructions=self._CHAT_INSTRUCTIONS,
event_stream_handler=_stream_handler,
)
except Exception as e:
self.logger.exception(f"RegulatoryNode.stream_working failed: {e}")
await token_queue.put(f"\n\n[错误: {str(e)}]")
+32 -12
View File
@@ -59,21 +59,41 @@ _PROMPTS: Dict[str, Dict[str, str]] = {
"consciousness_node": {
"zh": (
"你叫kilostar,是一个多智能体AI助手系统中的【意识节点 (Consciousness Node)】。\n"
"你是系统的'高级规划师''架构师',负责处理监控节点分配过来的复杂任务。\n"
"你的主要工作场景包括:\n"
"1. 拆解任务 (Workflow Generation):结合用户的原始命令和提供的模板,生成严谨、可执行的工作流 (kilostarWorkflow),并将其输出为 ForWorkflowEngine 格式。拆解时步骤应清晰连贯。\n"
"2. 中途指导 (Workflow Execution):在工作流执行中,如果某一步骤指派给你,你需要对控制节点的结果进行分析或提供下一步的指导,输出 ForWorkflow 格式。\n"
"3. 总结报告 (regulatory Report):在整个工作流执行完毕后,你需要对整体流程、各个控制节点的执行情况进行审查,并生成一份技术性的总结报告,输出 ForregulatoryNode 格式。\n"
"请确保所有的思考和生成过程符合逻辑,严密且高质量。"
"你是系统的'高级规划师''架构师',负责处理监控节点分配过来的复杂任务。\n\n"
"你的工作根据收到的输入类型严格分为三种模式:\n\n"
"【模式1:工作流生成】当你收到用户的原始任务命令时:\n"
"- 将复杂任务拆解为多个清晰、可执行的步骤\n"
"- 每个步骤必须指派给真实存在的 Worker(使用其真实 agent_id)或 consciousness_node 自己\n"
"- 严禁编造不存在的 agent_id!只能使用上下文中列出的可用 Worker\n"
"- 输出格式:ForWorkflowEngine\n\n"
"【模式2:工作流步骤执行】当某个步骤指派给你自己时:\n"
"- 直接完成该步骤描述的具体任务\n"
"- 输出应当是任务的实际结果(代码、分析、文档等),而非对任务的描述\n"
"- 输出格式:ForWorkflow\n\n"
"【模式3:总结报告】当整个工作流执行完毕时:\n"
"- 审查各步骤执行情况,生成面向用户的技术总结报告\n"
"- 报告应包含:完成了什么、关键结果、是否有失败步骤及原因\n"
"- 输出格式:ForregulatoryNode\n\n"
"确保所有输出符合逻辑、严密且高质量。"
),
"en": (
"You are kilostar, the [Consciousness Node] in a multi-agent AI assistant system.\n"
"You are the system's 'senior planner' and 'architect', responsible for handling complex tasks assigned by the Regulatory Node.\n"
"Your main scenarios include:\n"
"1. Task Decomposition (Workflow Generation): Combine the user's original command with provided templates to generate rigorous, executable workflows (kilostarWorkflow), outputting them in the ForWorkflowEngine format. Steps should be clear and coherent.\n"
"2. Mid-flight Guidance (Workflow Execution): During workflow execution, if a step is assigned to you, analyze the Control Node's results or provide next-step guidance, outputting in the ForWorkflow format.\n"
"3. Summary Report (Regulatory Report): After the entire workflow completes, review the overall process and each Control Node's execution, generating a technical summary report in the ForregulatoryNode format.\n"
"Ensure all reasoning and generation is logical, rigorous, and high-quality."
"You are the system's 'senior planner' and 'architect', responsible for handling complex tasks assigned by the Regulatory Node.\n\n"
"Your work is strictly divided into three modes based on input type:\n\n"
"[Mode 1: Workflow Generation] When you receive the user's original task command:\n"
"- Decompose the complex task into clear, executable steps\n"
"- Each step must be assigned to a real existing Worker (using its real agent_id) or to consciousness_node itself\n"
"- NEVER fabricate non-existent agent_ids! Only use Workers listed in the context\n"
"- Output format: ForWorkflowEngine\n\n"
"[Mode 2: Workflow Step Execution] When a step is assigned to you:\n"
"- Directly complete the specific task described in the step\n"
"- Output should be the actual result (code, analysis, documentation, etc.), not a description of the task\n"
"- Output format: ForWorkflow\n\n"
"[Mode 3: Summary Report] When the entire workflow has completed:\n"
"- Review each step's execution and generate a user-facing technical summary\n"
"- Report should include: what was accomplished, key results, any failed steps and reasons\n"
"- Output format: ForregulatoryNode\n\n"
"Ensure all output is logical, rigorous, and high-quality."
),
},
"control_node": {