fix: router coder/writer distinction + writer must use doc_create tool
- Router prompt now clearly distinguishes "写代码" (execute code → coder) from "写文档" (create document → writer) - Writer prompt strengthened to always use doc_create, never plain text Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
77e64d945e
commit
8a5d1c0ea9
@@ -6,6 +6,19 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
so-c-chat-clone — 企业级对话系统,基于 LangGraph.js Gen-UI 架构。Supervisor Agent 路由 + Enterprise Agent 工具调用,支持知识库检索、工单查询、网络搜索、代码沙盒执行,前端通过 useStream 实时渲染 Gen-UI 卡片。
|
||||
|
||||
## Development Machine
|
||||
|
||||
- **开发机**: `ssh xiaohei@192.168.30.30` (密码: xiaohei, sudo 同密码)
|
||||
- **项目路径**: `~/SOC/`
|
||||
- **Docker 部署**: `cd ~/SOC && make dev`
|
||||
- **代码同步**: 本地 `git push gitee main` → 开发机 `cd ~/SOC && git pull`
|
||||
- **Gitee 仓库**: `http://gitee.ath.cx:3000/xiaohei/socaichat.git` (用户: xiaohei, 密码: By@123456)
|
||||
- **SSH 工具**: `sshpass -p xiaohei ssh xiaohei@192.168.30.30`
|
||||
|
||||
### 开发机端口
|
||||
- 前端 (dev): `http://192.168.30.30:5173`
|
||||
- LangGraph API: `http://192.168.30.30:2024`
|
||||
|
||||
## Commands
|
||||
|
||||
### 后端(LangGraph Server)
|
||||
|
||||
@@ -35,11 +35,13 @@ ${ALL_TOOL_DESCRIPTIONS}
|
||||
You should analyze the user's input, and choose the appropriate tool to use.
|
||||
|
||||
Routing rules:
|
||||
- enterprise: questions about internal knowledge base, company documents, tickets/work orders
|
||||
- enterprise: questions about internal knowledge base (知识库), company documents, tickets/work orders (工单)
|
||||
- searcher: questions that require internet search, looking up external information, news, facts
|
||||
- coder: questions that require code execution, data analysis, calculations, chart generation
|
||||
- writer: requests to create, edit, translate documents, write reports, articles, or code files
|
||||
- generalInput: general conversation, greetings, or when no specific tool is needed`;
|
||||
- coder: requests to EXECUTE code, run programs, data analysis with code, calculations, debug code. Keywords: 运行, 执行, 计算, 分析数据, 写代码并运行, Python/JavaScript/Bash 代码
|
||||
- writer: requests to CREATE written documents (reports, articles, plans, emails) WITHOUT code execution. Keywords: 写报告, 写方案, 写周报, 写邮件, 翻译文档, 编辑文档
|
||||
- generalInput: general conversation, greetings, or when no specific tool is needed
|
||||
|
||||
IMPORTANT: "写代码" (write code to execute) → coder, NOT writer. "写文档/写报告" (write a document) → writer. The key distinction is whether the user wants code EXECUTED or a document CREATED.`;
|
||||
|
||||
const allMessagesButLast = state.messages.slice(0, -1);
|
||||
const lastMessage = state.messages.at(-1);
|
||||
|
||||
@@ -15,12 +15,13 @@ const SYSTEM_PROMPT = `你是文档编辑助手。你可以创建和编辑各种
|
||||
- 调整文档风格(专业/简洁/学术)
|
||||
|
||||
规则:
|
||||
- 创建文档时,使用 doc_create 工具,在 content 中写入完整文档内容
|
||||
- 编辑文档时,使用 doc_edit 工具,在 instructions 中描述编辑要求
|
||||
- 翻译文档时,使用 doc_translate 工具,指定目标语言
|
||||
- 文档内容会在用户的 Canvas 侧面板中展示
|
||||
- 你必须始终使用 doc_create 工具来创建文档,不要直接输出文档内容作为纯文本
|
||||
- 任何写报告、写方案、写周报、写邮件、写文章的请求,都必须调用 doc_create
|
||||
- 编辑已有文档时,使用 doc_edit 工具
|
||||
- 翻译文档时,使用 doc_translate 工具
|
||||
- 文档会在用户的 Canvas 侧面板中展示,所以必须通过工具创建
|
||||
- 始终用中文回复(除非用户要求其他语言)
|
||||
- 如果用户的请求不涉及文档操作,直接用文字回答即可`;
|
||||
- 绝对不要跳过工具直接回复文档内容`;
|
||||
|
||||
export async function writerAgentNode(
|
||||
state: WriterState,
|
||||
|
||||
@@ -1,67 +1,99 @@
|
||||
# SOC LangGraph.js 本地 Docker 部署复测报告
|
||||
# SOC LangGraph.js Phase 2 端到端验收测试报告
|
||||
|
||||
## 测试环境
|
||||
- 后端: http://localhost:8080 (容器 soc-langgraph)
|
||||
- ��端: http://localhost:3002 (容器 soc-langgraph-ui)
|
||||
- LangGraph API: http://192.168.30.30:2024
|
||||
- Frontend: http://192.168.30.30:5173
|
||||
- 测试时间: 2026-04-10
|
||||
- Docker 镜像: soc-langgraph:local
|
||||
- 测试阶段: Phase 2 (Supervisor 5 路路由 - generalInput, enterprise, searcher, coder, writer)
|
||||
|
||||
## 测试结果汇总
|
||||
|
||||
| # | 测试项 | 端点 | 结果 | 备注 |
|
||||
|---|--------|------|------|------|
|
||||
| 1 | 后端健康检查 | GET /info | PASS | 返回 `{"flags":{"assistants":true,"crons":false}}` |
|
||||
| 2 | 创建 Thread | POST /threads | PASS | 返回 thread_id, status=idle |
|
||||
| 3 | Agent 流式对话 (generalInput) | POST /threads/{id}/runs/stream | PASS | Router -> generalInput, AI 正常回复中文 |
|
||||
| 4 | Agent 非流式对话 | POST /threads/{id}/runs/wait | PASS | 返回 2 条消息, AI 回复正确 |
|
||||
| 5 | Chat Graph | POST /threads/{id}/runs/wait (chat) | PASS | 独立 chat graph 正常工作 |
|
||||
| 6 | Enterprise - KB 搜索 | POST /threads/{id}/runs/wait (agent) | PASS | Router -> enterprise, 调用 kb_search, 检索到 5 条结果, UI 组件 knowledge-result 正常 |
|
||||
| 7 | Enterprise - 工单列表 | POST /threads/{id}/runs/wait (agent) | PASS | 调用 ticket_list, 返回 3 条工单, UI 组件 ticket-summary 正常 |
|
||||
| 8 | Enterprise - 网络搜索 | POST /threads/{id}/runs/wait (agent) | PASS | 调用 web_search, 找到 5 条结果, UI 组件 search-result 正常 |
|
||||
| 9 | Thread 历史记录 | POST /threads/{id}/history | PASS | 返回 4 条历史条目 |
|
||||
| 10 | Thread 状态 | GET /threads/{id}/state | PASS | 返回消息列表及��态 |
|
||||
| 11 | 助手列表 | POST /assistants/search | PASS | 3 个 graph: agent, chat, email_agent |
|
||||
| 12 | 前端 HTML | GET http://localhost:3002/ | PASS | 返回 200, 完整 HTML |
|
||||
| 13 | 前端 API 地址 | JS bundle 检查 | PASS | 指向 http://localhost:8080 |
|
||||
| 14 | 后端日志 | docker logs | PASS | 最近运行无 error 日志 |
|
||||
| # | 测试项 | 输入 | 预期路由 | 实际路由 | 结果 | 备注 |
|
||||
|---|--------|------|---------|---------|------|------|
|
||||
| 1 | 健康检查 | GET /ok | - | - | PASS | `{"ok":true}` |
|
||||
| 2 | 服务信息 | GET /info | - | - | PASS | `{"flags":{"assistants":true,"crons":false}}` |
|
||||
| 3 | 普通对话 | "你好" | generalInput | generalInput | PASS | 纯文本回复,无工具调用 |
|
||||
| 4 | 知识库查询 | "查询知识库关于产品的信息" | enterprise | enterprise | PARTIAL | 路由正确,kb_search 超时 |
|
||||
| 5 | 工单查询 | "查询最近的工单" | enterprise | enterprise | PASS | ticket-summary UI 卡片正常 |
|
||||
| 6 | 网络搜索 | "搜索 LangGraph.js 最新版本" | searcher | searcher | PASS | search-result UI 卡片正常 |
|
||||
| 7 | 代码生成 | "帮我写一段 Python 代码计算斐波那契数列" | coder | **writer** | FAIL | 路由错误,未进入 coder/sandbox |
|
||||
| 8 | 文档撰写 | "帮我写一份项目周报" | writer | writer | PASS | 路由正确,生成周报内容 |
|
||||
| 9 | 前端页面 | GET http://localhost:5173/ | - | - | PASS | HTTP 200 |
|
||||
|
||||
## 修复的问题
|
||||
## 详细测试记录
|
||||
|
||||
### 问题 1: AZURE_OPENAI_ENDPOINT 格式错误 (已修复)
|
||||
- **原值**: `https://ai-gzy0016231ai975636166896.cognitiveservices.azure.com/openai/responses?api-version=2025-04-01-preview/`
|
||||
- **修正**: `https://ai-gzy0016231ai975636166896.cognitiveservices.azure.com`
|
||||
- **原因**: LangChain AzureChatOpenAI 会自动拼接 `/openai/deployments/{name}/chat/completions` 路径,endpoint 只需基础 URL
|
||||
- **文���**: `/Users/gongzhiyong/go/SOC/langgraph/.env` (第 2 行)
|
||||
### Test 1: GET /ok
|
||||
- 响应: `{"ok":true}`
|
||||
- 判定: **PASS**
|
||||
|
||||
### 问题 2: 多个 Agent 节点使用 ChatOpenAI 而非 AzureChatOpenAI (已修复)
|
||||
- **现象**: Router 节点成功路由后, generalInput/chat 等节点报 `OPENAI_API_KEY environment variable is missing`
|
||||
- **原因**: 这些节点使用 `new ChatOpenAI({model: "gpt-4o-mini"})`, 需要普通 OpenAI API Key, 但项目用的是 Azure OpenAI
|
||||
- **修复方案**: 创建共用工厂函数 `createLlm()`, 统一使用 AzureChatOpenAI
|
||||
- **修改的文件**:
|
||||
- `src/agent/utils/create-llm.ts` -- 新建, 共用 LLM 工厂函数
|
||||
- `src/agent/supervisor/nodes/router.ts` -- 改用 createLlm()
|
||||
- `src/agent/supervisor/nodes/general-input.ts` -- ChatOpenAI -> createLlm()
|
||||
- `src/agent/chat-agent/index.ts` -- ChatOpenAI -> createLlm()
|
||||
- `src/agent/enterprise/nodes/tools.ts` -- 内联 createLlm -> 共用 createLlm
|
||||
- `src/agent/trip-planner/nodes/classify.ts` -- ChatOpenAI -> createLlm()
|
||||
- `src/agent/trip-planner/nodes/tools.ts` -- ChatOpenAI -> createLlm()
|
||||
- `src/agent/trip-planner/nodes/extraction.ts` -- ChatOpenAI -> createLlm()
|
||||
- `src/agent/email-agent/nodes/write-email.ts` -- ChatOpenAI -> createLlm()
|
||||
- `src/agent/email-agent/nodes/rewrite-email.ts` -- ChatOpenAI -> createLlm()
|
||||
- `src/agent/stockbroker/nodes/tools.ts` -- ChatOpenAI -> createLlm()
|
||||
### Test 2: GET /info
|
||||
- 响应: `{"flags":{"assistants":true,"crons":false}}`
|
||||
- 判定: **PASS**
|
||||
|
||||
## 已知的外部依赖状态
|
||||
### Test 3: generalInput 路由 - "你好"
|
||||
- Router tool_call: `router({"route":"generalInput"})` -> `next: "generalInput"`
|
||||
- generalInput 回复: "你好!有什么我可以帮你的吗?"
|
||||
- 无工具调用,纯文本回复
|
||||
- 判定: **PASS**
|
||||
|
||||
| 外部服务 | 状态 | 备注 |
|
||||
|----------|------|------|
|
||||
| Azure OpenAI (gpt-5.4) | 正常 | 所有 LLM 调用成功 |
|
||||
| KB Agent (知识库) | 正常 | 检索到 5 条结果 |
|
||||
| Gongdan (工单) | 正常 | 返回 3 条工单 |
|
||||
| Jina (网络搜索) | 正常 | 搜索到 5 条结果 |
|
||||
| Daytona (沙盒) | 未测试 | 需要特定代码执行场景 |
|
||||
### Test 4: enterprise 路由 - 知识库查询
|
||||
- Router tool_call: `router({"route":"enterprise"})` -> `next: "enterprise"`
|
||||
- enterprise 调用: `kb_search({"query":"产品 信息"})`
|
||||
- 工具结果: `TimeoutError: The operation was aborted due to timeout`
|
||||
- AI 优雅降级,建议用户提供更精准关键词重试
|
||||
- 判定: **PARTIAL** - 路由正确,但外部 KB 服务超时,未产生 knowledge-result UI 卡片
|
||||
|
||||
### Test 5: enterprise 路由 - 工单查询
|
||||
- Router tool_call: `router({"route":"enterprise"})` -> `next: "enterprise"`
|
||||
- 调用 ticket_list 成功
|
||||
- 响应包含 `ticket-summary` UI 卡片
|
||||
- 判定: **PASS**
|
||||
|
||||
### Test 6: searcher 路由 - 网络搜索
|
||||
- Router tool_call: `router({"route":"searcher"})` -> `next: "searcher"`
|
||||
- 调用 web_search 成功
|
||||
- 响应包含 `search-result` UI 卡片
|
||||
- 判定: **PASS**
|
||||
|
||||
### Test 7: coder 路由 - 代码生成 (FAIL)
|
||||
- Router tool_call: `router({"route":"writer"})` -> `next: "writer"` (错误!)
|
||||
- writer 节点调用 `create_canvas_doc` 生成 fibonacci.py (canvas-doc, type=code)
|
||||
- 未使用 sandbox 执行代码,无 sandbox-result UI 卡片
|
||||
- 判定: **FAIL** - Router 将代码请求误路由到 writer 而非 coder
|
||||
|
||||
### Test 8: writer 路由 - 文档撰写
|
||||
- Router tool_call: `router({"route":"writer"})` -> `next: "writer"`
|
||||
- writer 直接生成纯文本周报模板(628 tokens),未调用 create_canvas_doc
|
||||
- 判定: **PASS** (路由正确,完成了文档撰写任务)
|
||||
|
||||
### Test 9: 前端页面
|
||||
- HTTP 状态码: 200
|
||||
- 判定: **PASS**
|
||||
|
||||
## 问题清单
|
||||
|
||||
### 问题 1: Router 将代码请求路由到 writer 而非 coder [严重]
|
||||
- **现象**: "帮我写一段 Python 代码计算斐波那契数列" 路由到 writer 而非 coder
|
||||
- **影响**: coder Agent (sandbox 代码执行) 无法被触发
|
||||
- **根因推测**: Router prompt 中 "写代码" 和 "写文档" 的边界不清晰,gpt-3.5-turbo 将 "帮我写..." 统一归类为 writer
|
||||
- **建议修复**: 在 Router prompt 中明确区分:包含 "代码"/"编程"/"debug"/"运行" 等关键词 -> coder;包含 "文档"/"报告"/"周报"/"方案" 等关键词 -> writer
|
||||
|
||||
### 问题 2: kb_search 工具超时 [中等]
|
||||
- **现象**: enterprise 调用 kb_search 返回 TimeoutError
|
||||
- **影响**: 知识库查询功能不可用
|
||||
- **建议修复**: 检查 KB Agent 外部服务状态,或增加 kb_search 工具的超时时间
|
||||
|
||||
### 问题 3: writer Agent 未对周报请求生成 canvas-doc UI 卡片 [轻微]
|
||||
- **现象**: "帮我写一份项目周报" 时 writer 直接返回纯文本,未调用 create_canvas_doc
|
||||
- **影响**: 前端 CanvasPanel 无法展示结构化文档
|
||||
- **建议修复**: 调整 writer Agent prompt,确保文档类请求优先调用 create_canvas_doc 工具
|
||||
|
||||
## 通过率
|
||||
|
||||
**14/14 通过 (100%)**
|
||||
**6/9 通过, 1 部分通过, 2 失败 (67%)**
|
||||
|
||||
所有后端 API 端点和前端页面均正常工作。两个核心 Bug 已修复并验证。
|
||||
| 类别 | 通过 | 总计 | 详情 |
|
||||
|------|------|------|------|
|
||||
| 基础设施 | 3/3 | 100% | health, info, frontend 全部正常 |
|
||||
| Supervisor 路由 | 5/6 | 83% | coder 路由错误 |
|
||||
| UI 卡片 | 2/4 | 50% | ticket-summary, search-result 正常; knowledge-result 超时, canvas-doc/sandbox-result 未触发 |
|
||||
|
||||
Reference in New Issue
Block a user