Files
gongzhiyongandClaude Sonnet 4.6 9c96913b4d
Deploy LangGraph Server to Azure Web App / build-and-deploy (push) Failing after 13s
Deploy LangGraph UI to Azure Static Web Apps / build-and-deploy (push) Failing after 49s
feat: enterprise product sprint — log protocol, tool rules, UX polish
Backend:
- config.ts: unified startup env validation (throw on missing critical vars)
- tool-executor: structured logToolCall() JSON, ToolStatus enum (success/partial_success/fallback_success/error), preValidateToolCall() hardcoded guards for ticket_detail/chart_generate, durationMs/inputSummary/resultCount on all execution log entries
- agent.ts: tool selection decision tree, chart-as-default-path prompt rules, source labels [知识库][工单][网络][推断]
- tool-defs.ts: applicable/not-applicable guidance on all 4 tools
- soc-client.ts: sandbox hardening (10k char limit, 15s timeout, output truncation, error classification), config.* accessors
- router.ts: preCheckRoute() rules — TK-xxx/工单/知识库 → enterprise direct; greetings → generalInput
- supervisor/types.ts: removed dead config fields (model/temperature/maxTokens/systemPrompt)
- Remove chat-agent (legacy entry point)

Frontend:
- MessageBubble: source badge rendering [知识库][工单][网络][推断], CitationChip [1][2] → clickable chips
- ThreadSidebar: auto-title from first message, collapsible search, long title truncation
- ToolCallStatus: tool-specific loading labels, collapse-all toggle for multi-tool
- main.tsx: conclusion-first layout (AI text above artifacts), draft persistence, IME fix, auto chip, multi-tool AnalysisBlock container, sort_key ordering, retry via soc:retry-tool
- chart-result: empty guard, chart/table toggle, multi-chart format support
- ticket-summary/knowledge-result: work-card quick actions (prefill with context)
- ActionBar: structured payload {text, taskType, sourceCardId}, source label UI
- index.css: card-enter slide animation, dot-bounce loading

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 13:01:02 +08:00

13 KiB
Raw Permalink Blame History

SOC 8项优化 端到端验收测试报告

测试环境

基础端点测试

# 端点 方法 状态码 响应 状态
1 /ok GET 200 {"ok":true} PASS
2 /info GET 200 {"flags":{"assistants":true,"crons":false}} PASS
3 /threads POST 200 返回 thread_id, status: idle PASS
4 前端首页 GET 200 页面正常加载 PASS

第一轮:8项优化验收测试

# 测试项 状态 备注
1 P0 Daytona sandbox 修复 PASS code_execute 工具成功调用,exit_code=0,stdout="5050",耗时1462ms
2 KB Agent retry 验证 PASS retry.ts 实现完整(3次重试,指数退避1s基准),已在 enterprise/tool-executor 中正确包裹 kb_search;本次测试 KB 正常响应无需重试
3 ticket_detail 修复 PASS TK-xxxx 格式工单 ID 可正常查询详情,返回完整工单数据
4 sourceType 字段 PASS 所有 ui items 均包含 sourceType 和 confidence 字段:sandbox-result(code_execution/high), ticket-summary(ticket_system/high), ticket-detail(ticket_system/high), canvas-doc(generated_doc/high), knowledge-result(internal_kb), search-result(external_web)
5 自动工具路由准确性 PASS (5/5) "写报告"->writer, "网络安全新闻"->searcher, "Python排序算法"->coder, "公司网络安全规范"->enterprise(kb_search), "你好介绍自己"->generalInput
6 企业风格输出 PASS 回复包含 [工单数据] 来源标注,结论/依据/建议三层结构完整,有风险提示和下一步建议
7 会话恢复 PASS 新 thread 发送工具触发消息后,GET /threads/{id}/state 返回 values.ui 数组包含 ticket-summary 卡片(含 sourceType/confidence),UI 状态正确持久化到 checkpoint

第二轮:迭代修复验收测试

# 测试项 状态 备注
R1 ticket_detail 不同工单返回不同数据 PASS 查询 TK-2026-AE4DEA 和 TK-2026-9FA15E 分别返回正确的不同工单数据(P1-1 已修复)
R2 sandbox 失败时友好提示 PASS 执行 import nonexistent_module_xyz 时 AI 给出中文分析(模块不存在、建议替代方案),未暴露原始技术栈错误
R3 空工单列表友好提示 PASS (代码验证) ticket-summary 组件 tickets.length===0 时显示 "暂无工单" 居中提示文案
R4 Gen-UI 卡片 error 状态渲染 PASS (代码验证) 4个卡片组件均支持 errorMessage prop:有错误时边框变红(border-red-200),显示红色错误文案(text-red-700)
R5 ToolCallStatus 失败状态红色X PASS (代码验证) 使用 XCircle + text-red-500 图标,失败时显示 "失败 . {工具名}"
R6 ToolCallStatus 骨架屏过渡 PASS (代码验证) expanded && !uiItem 时渲染 animate-pulse 骨架屏(4行灰色占位条)

详细测试记录

测试1:Daytona sandbox

  • 请求: "帮我用Python计算1到100的和"
  • 路由: supervisor -> coder
  • 工具调用: code_execute, language=python, code=sum(range(1, 101))
  • 响应: exit_code=0, stdout="5050\n", duration_ms=1462
  • UI 卡片: sandbox-result, props 含 sourceType="code_execution", confidence="high"
  • 判定: PASS

测试2:KB Agent retry

  • 代码验证: src/agent/utils/retry.ts 实现 executeWithRetry,支持指数退避
  • 集成验证: enterprise/tool-executor.ts 中 kb_search 调用已包裹 executeWithRetry(() => kbSearch(query), 3, { backoffMs: 1000, exponential: true })
  • 运行时验证: 发送 "我们公司的网络安全规范是什么",路由到 enterprise,调用 kb_search 成功返回 knowledge-result 卡片
  • 日志检查: 未触发 retry 日志(KB 服务正常响应,未超时)
  • 判定: PASS(代码实现正确,运行时无异常)

测试3:ticket_detail

  • 请求: "查看最新工单的详情"
  • 工具链: ticket_list(page=1) -> ticket_detail("TK-2026-296691")
  • ticket_list 响应: 3条工单,TK-2026-296691/TK-2026-AE4DEA/TK-2026-9FA15E
  • ticket_detail 响应: 返回完整工单详情(含 customer/engineer/urges/sla 等字段)
  • UI 卡片: ticket-summary + ticket-detail,均含 sourceType="ticket_system"
  • 判定: PASS

测试4:sourceType 字段

验证所有 ui 卡片 props 中的 sourceType 和 confidence 字段:

卡片类型 sourceType confidence
sandbox-result code_execution high
ticket-summary ticket_system high
ticket-detail ticket_system high
knowledge-result internal_kb (已确认存在)
search-result external_web (已确认存在)
canvas-doc generated_doc high
  • 判定: PASS

测试5:自动工具路由

输入 预期路由 实际路由 触发工具 状态
"帮我写一个关于本季度运营情况的报告" writer writer doc_create PASS
"查一下最近的网络安全新闻" searcher searcher google_search PASS
"用Python写个排序算法" coder coder (code_execute) PASS
"我们公司的网络安全规范是什么" enterprise enterprise kb_search PASS
"你好,介绍一下自己" generalInput generalInput (无工具) PASS
  • 判定: PASS (5/5)

测试6:企业风格输出

  • 请求: "分析最近3个工单的共同问题"
  • 路由: enterprise
  • 工具调用: ticket_list + 3x ticket_detail
  • 输出结构验证:
    • [工单数据] 来源标注: 出现多处,标注在每个关键结论前
    • 结论段: 有,以"结论"开头
    • 依据段: 有,以"依据"开头,按来源分组
    • 建议段: 有,以"建议"开头,含建议行动/风险提示/下一步
  • 判定: PASS

测试7:会话恢复

  • 流程: 创建 thread -> 发送"查询最近的工单" -> 等待完成 -> GET /threads/{id}/state
  • Thread ID: 8be68055-38a5-4c22-b614-601a2eaf206e
  • 验证结果: values.ui 数组包含 1 个 ticket-summary 卡片,props 含 sourceType="ticket_system" 和 confidence="high"
  • 判定: PASS(UI 状态正确持久化到 checkpoint,切换会话可恢复)

R1:ticket_detail UUID 映射修复验证

  • 请求: "分别查看工单TK-2026-AE4DEA和TK-2026-9FA15E的详情"
  • 路由: enterprise
  • 结果: 2个 ticket-detail 卡片,id 分别为 TK-2026-AE4DEA (title="12e1") 和 TK-2026-9FA15E (title="123")
  • toolStatus: 2x ticket_detail status=ok
  • 判定: PASS(第一轮 P1-1 问题已修复,不同 TK-xxxx 正确返回不同工单)

R2:sandbox 失败友好提示

  • 请求: "帮我运行这段Python代码:import nonexistent_module_xyz; print(nonexistent_module_xyz.hello())"
  • 工具结果: exit_code=1, ModuleNotFoundError
  • AI 回复: 中文分析 -- "模块 nonexistent_module_xyz 并不存在",给出表格化失败原因,提供修复建议(替换为真实模块名/自定义示例),未暴露原始 traceback
  • UI 卡片: sandbox-result, exit_code=1
  • 判定: PASS

R3:空工单列表友好提示

  • 代码验证: ticket-summary/index.tsx 中 tickets.length === 0 分支渲染 <li className="px-4 py-6 text-center text-sm text-muted-foreground">暂无工单</li>
  • 判定: PASS(组件正确处理空状态)

R4:Gen-UI 卡片 error 状态

  • 代码验证: 4个卡片组件均实现 errorMessage prop:
    • knowledge-result: errorMessage 时 border-red-200/dark:border-red-900/40,显示红色文案
    • ticket-summary: 同上
    • search-result: 同上
    • sandbox-result: 同上 + 失败时显示 "失败 (exit {code})"
  • 后端集成: enterprise/tool-executor.ts 中 kb_search 失败时推送 sourceType: "error", confidence: "low", errorMessage: "知识库暂时无响应,已切换到网络搜索" 并触发 google_search fallback
  • 判定: PASS

R5:ToolCallStatus 失败状态

  • 代码验证: ToolCallStatus.tsx 中 isFailed 时渲染 <XCircle className="size-3.5 text-red-500 shrink-0" />,文案显示 "失败 . {工具中文名}"
  • 判定: PASS

R6:ToolCallStatus 骨架屏

  • 代码验证: ToolCallStatus.tsx 中 expanded && !uiItem 时渲染:
    <div className="mt-2 ml-7 space-y-2 animate-pulse">
      <div className="h-3 bg-muted rounded w-3/4" />
      <div className="h-3 bg-muted rounded w-1/2" />
      <div className="h-3 bg-muted rounded w-5/6" />
      <div className="h-8 bg-muted rounded w-full mt-3" />
    </div>
    
  • 判定: PASS(展开时 UI 卡片未加载前显示骨架屏过渡动画)

第三轮:新功能验收测试

# 测试项 状态 备注
R3-1 chart-result 自动出图 PASS ticket-summary 后自动附带 chart-result 卡片,含2个图表:状态分布(已关闭:2, IN_PROGRESS:1) + 优先级分布(PRIORITY:2, NORMAL:1)
R3-2 reply-draft 卡片 PASS 路由到 writer,调用 reply_draft 工具,返回 reply-draft 卡片(mode="customer",含专业客户回复内容)
R3-3 next-actions 卡片 PASS 工单查询后自动附带 next-actions 卡片,含2条推荐动作;知识库查询后含"生成知识摘要"、"导出到文档"
R3-4 citations 来源列表 PASS knowledge-result 含5条 citations(带 title/source);search-result 含8条 citations(带 title/source/url)
R3-5 卡片合并 deduplication PASS (代码验证) main.tsx 中 deduplicateUiItems() 按 card_id 去重,同 card_id 只保留最新态

R3-1:chart-result 自动出图

  • 请求: "查询最近的工单"
  • 路由: enterprise
  • UI 卡片: 3个 -- ticket-summary + chart-result + next-actions
  • chart-result 详情:
    • title: "工单分布统计"
    • charts[0]: title="状态分布", data=[{name:"已关闭", value:2}, {name:"IN_PROGRESS", value:1}]
    • charts[1]: title="优先级分布", data=[{name:"PRIORITY", value:2}, {name:"NORMAL", value:1}]
  • 判定: PASS

R3-2:reply-draft 卡片

  • 请求: "帮我生成一份客户回复草稿,关于工单TK-2026-296691中LLM请求被拒绝的问题"
  • 路由: writer
  • 工具调用: reply_draft + doc_create
  • UI 卡片: reply-draft (mode="customer") + canvas-doc
  • reply-draft 内容: 专业客户回复,包含问题确认、排查方向(参数规范/鉴权/频率限制/额度)、建议步骤
  • 判定: PASS

R3-3:next-actions 卡片

  • 工单查询场景: actions = ["生成处理建议", "生成客户回复"],每条含 prompt 和 icon
  • 知识库查询场景: actions = ["生成知识摘要", "导出到文档"]
  • 判定: PASS

R3-4:citations 来源列表

  • knowledge-result: 5条 citations,格式 {index, title, source}
    • 示例: {index:1, title:"Taiji Agent 文档中心 - Openclaw相关配置说明", source:null}
  • search-result: 8条 citations,格式 {index, title, source, url}
    • 示例: {index:1, title:"推出OpenAI 安全研究员计划", source:"openai.com", url:"https://openai.com/..."}
  • 前端渲染: knowledge-result/index.tsx 和 search-result/index.tsx 均实现 Citation 接口渲染来源列表
  • 判定: PASS

R3-5:卡片合并 deduplication

  • 代码验证: main.tsx:30 deduplicateUiItems() 函数:
    • 遍历 items 按 props.card_id 建立 Map,记录每个 card_id 最后出现的 index
    • filter 时只保留 card_id 对应最后 index 的项,无 card_id 的项全部保留
    • 在消息渲染和会话恢复两处调用(L439, L588)
  • 判定: PASS

问题清单

已修复

  • P1-1 (R2已修复): ticket_detail UUID 映射异常

遗留问题

无 P0/P1 遗留问题。

P2 建议

  • KB retry 机制在正常情况下无法触发运行时验证,建议后续添加集成测试模拟超时场景
  • 骨架屏和 error 态为代码验证(非运行时触发),建议前端 Storybook 添加对应 story
  • knowledge-result citations 中 source 字段部分为 null,建议后端 kb_search 返回时补充来源文档名
  • chart-result 中 charts 子项缺少 type 字段(pie/bar),前端需靠 fallback 推断图表类型

通过率

第一轮: 7/7 通过 | 第二轮: 6/6 通过 | 第三轮: 5/5 通过 | 总计: 18/18

整体质量评分

9.2 / 10

  • 核心功能(sandbox、工单、知识库、搜索、路由)全部正常
  • sourceType/confidence 字段在所有卡片中正确注入
  • 企业风格输出格式规范,来源标注完整
  • 会话恢复 checkpoint UI 持久化正常
  • KB retry + fallback 机制代码实现完善
  • ticket_detail UUID 映射问题已修复
  • Gen-UI error 态、ToolCallStatus 失败/骨架屏均已实现
  • chart-result 自动出图(状态分布+优先级分布)
  • reply-draft 卡片含 customer/internal 模式
  • next-actions 推荐动作按场景智能生成
  • citations 来源列表完整(知识库+搜索均有)
  • deduplicateUiItems 卡片去重逻辑正确
  • 扣分项:chart-result 缺少 type 字段(-0.3);knowledge citations source 部分为 null(-0.2);部分前端状态为代码验证(-0.3)