# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Overview so-c-chat-clone — 企业级对话系统,基于 LangGraph.js Gen-UI 架构。Supervisor Agent 意图路由到 5 个专用 Sub-Agent,每个 Agent 调用外部 API 并通过 `ui.push()` 推送 Gen-UI 卡片,前端 useStream 实时渲染。 ## Development Machine - **开发机**: `sshpass -p xiaohei ssh xiaohei@192.168.30.30`(sudo 密码同) - **项目路径**: `~/SOC/` - **Docker 部署**: `cd ~/SOC && docker compose --profile dev up -d --build` - **代码同步**: 本地 `git push gitee main` → 开发机 `cd ~/SOC && git pull origin main` - **Gitee 仓库**: `http://gitee.ath.cx:3000/xiaohei/socaichat.git`(用户: xiaohei, 密码: By@123456) ### 开发机端口 - 前端 (dev): `http://192.168.30.30:5173` - LangGraph API: `http://192.168.30.30:2024` ## Commands ```bash cd langgraph pnpm install pnpm run agent # 启动后端 langgraphjs dev (port 2024) pnpm run build # tsc -b && vite build(前端) ``` 开发机一键重启: ```bash sshpass -p xiaohei ssh xiaohei@192.168.30.30 "cd ~/SOC && docker compose --profile dev up -d --build" ``` ## Architecture ### System Overview ``` 用户浏览器 ↓ [Azure Static Web App] soc-langgraph-ui (eastasia) agreeable-smoke-0364d4000.7.azurestaticapps.net Vite SPA + @langchain/langgraph-sdk@1.8.8/react useStream ↓ SSE [Azure Container App] soc-langgraph (southeastasia) soc-langgraph.victorioussand-69befc84.southeastasia.azurecontainerapps.io Node.js 20 LTS + langgraphjs dev (port 8080), min 1 replica ↓ HTTP [外部服务] ├── Azure OpenAI (gpt-5.4) ← 所有 Agent LLM(含 Supervisor 路由) ├── KB Agent (Azure AI Search) ├── Gongdan 工单 API ├── Jina Search/Reader/Rerank ├── Serper Google Search ├── Daytona Sandbox (process/execute endpoint) └── CloudCost 云管系统 (orange-wave-09002e800.7.azurestaticapps.net) ``` ### Agent Graph ``` Supervisor (Gemini 2.0 Flash) → intent router ├── enterprise → KB检索 + 工单查询(ReAct,MAX_ITERATIONS=6) ├── searcher → Google搜索 + Jina深度搜索 ├── coder → 代码执行(Daytona sandbox) ├── writer → Canvas文档 + 报告生成 + 回复草稿 └── generalInput → 通用对话 ``` 路由基于**意图**而非关键词:writer=文档/报告/话术,coder=代码/计算,searcher=最新信息/新闻,enterprise=内部知识/工单,generalInput=其他。 ### Agent 文件模式 每个 Sub-Agent 的目录结构一致: ``` src/agent/{name}/ index.ts ← StateGraph 定义(START → agent → route → tool-executor → agent) types.ts ← State annotation nodes/ agent.ts ← LLM bindTools + system prompt tool-executor.ts ← 执行工具调用,ui.push() Gen-UI 卡片 tool-defs.ts ← Zod schema + ALL_TOOLS 定义(writer/enterprise) ``` ### Tool → Gen-UI 卡片映射 | Agent | Tool | Gen-UI 卡片 | 说明 | |-------|------|------------|------| | enterprise | `kb_search` | `knowledge-result` | 含 citations,KB失败自动fallback到google_search | | enterprise | `ticket_list` | `ticket-summary` + `chart-result` | 同时推状态/优先级分布图 | | enterprise | `ticket_detail` | `ticket-detail` | TK-xxxx格式自动解析为UUID | | searcher | `google_search` | `search-result` | 结果<3条自动补Jina搜索,含citations | | searcher | `web_search_deep` | `search-result` | Jina Search+Reader+Rerank,含citations | | coder | `code_execute` | `sandbox-result` | Daytona /sandbox + /toolbox/{id}/process/execute | | writer | `doc_create/edit/translate` | `canvas-doc` | CanvasPanel右侧抽屉 | | writer | `report_generate` | `canvas-doc` | 结构化报告模板 | | writer | `reply_draft` | `reply-draft` | customer/internal双模式 | | enterprise | `cloudcost_dashboard` | `cost-result` (dashboard) | 月度总览:总费用/环比/趋势/按厂商服务拆分 | | enterprise | `cloudcost_metering` | `cost-result` (metering) | 用量费用汇总,按服务 Top N | | enterprise | `cloudcost_detail` | `cost-result` (detail) | 费用明细分页,最细粒度 | | enterprise | `cloudcost_alerts` | `cost-result` (alerts) | 告警规则状态,triggered 红色高亮 | | enterprise | `cloudcost_accounts` | `cost-result` (accounts) | 云服务账号列表,状态徽章 | | enterprise (自动) | — | `next-actions` | 工具成功后自动附带2-3条推荐动作 | 所有卡片 props 包含 `sourceType`(internal_kb/ticket_system/external_web/code_execution/generated_doc)和 `confidence`(high/medium/low)。 ### Streaming 配置 前端 useStream 使用双流模式 + 子图流式推送: ```typescript streamMode: ["values", "messages"], // values=节点完成推送, messages=LLM token 实时流 streamSubgraphs: true, // 子图内部节点完成时立即推送(消除 18s 空白) ``` SDK: `@langchain/langgraph-sdk@1.8.8`(从 0.0.73 升级,支持 streamSubgraphs) ### 关键工具函数 - `src/agent/utils/retry.ts` — `executeWithRetry(fn, retries, {backoffMs, exponential})`,`formatToolError(name, e)` - `src/agent/utils/truncate-messages.ts` — 上下文压缩 - `src/agent/utils/file-service.ts` — PDF/图片/Excel/文本解析 + Azure Blob - `src/agent/utils/checkpointer.ts` — PostgresSaver,Gen-UI ui items 随 checkpoint 持久化恢复 - `src/agent/utils/inject-thinking.ts` — 将 LLM 工具调用前的 content 转为 `{ type: "thinking", thinking, source: "prompt"|"reasoning" }` block - `src/agent/utils/clean-polluted-tool-calls.ts` — 清洗 checkpoint 中残留的未响应 tool_call_id,防止 400 崩溃 - `src/agent/utils/config.ts` — 统一配置管理,GOOGLE_API_KEY 已降级为可选 - `src/agent/utils/toolConfig.ts` — 每工具 timeout/retry 配置 - `src/agent/utils/create-llm.ts` — LLM 实例化(含 Azure OpenAI Responses API Pro 模式 COT) - `src/agent/utils/redis-client.ts` — Redis 工具结果缓存(30min) - `src/agent/utils/service-bus-client.ts` — Service Bus 异步告警 - `src/agent/utils/doc-creator-client.ts` — doc-creator agent 客户端 ### Frontend 关键文件 - `src/main.tsx` — Chat UI 主入口,useStream(streamSubgraphs+双流模式),`deduplicateUiItems()`,isLoading 守卫防并发 - `src/components/ToolCallStatus.tsx` — 工具调用状态(5 种视觉状态:loading/success/error/fallback_success/partial_success),UI_NAME_MAP 工具名映射 - `src/components/ActionBar.tsx` — 卡片底部追问/快捷动作,dispatch `soc:prefill-input` CustomEvent - `src/components/SourceBadge.tsx` — 来源类型徽章(颜色+置信度图标) - `src/components/MessageBubble.tsx` — ReactMarkdown + KaTeX + Prism + COT 思考链渲染(Brain 图标可折叠)+ `rehypeSanitizeLinks`(防无 href 崩溃)+ `MarkdownErrorBoundary`(fallback 到纯文本)+ >800字智能摘要块 - `src/components/CanvasPanel.tsx` — 右侧文档编辑抽屉,监听 `open-canvas` CustomEvent - `src/agent-uis/index.tsx` — Gen-UI 组件注册表(ComponentMap) ## Gen-UI 卡片开发规范 新增卡片需要: 1. 创建 `src/agent-uis/enterprise/{name}/index.tsx`(参考 knowledge-result 结构) 2. 在 `src/agent-uis/index.tsx` 的 ComponentMap 注册 3. 后端 `tool-executor.ts` 中 `ui.push({ name: "{name}", props: {...} })`(注意:子图内不绑定 `{ message: lastAiMessage }`,前端通过 card_id 中的 tool_call_id 匹配 orphan 卡片) props 必须包含 `sourceType` 和 `confidence`(来自 retry.ts 的工具执行结果),可选 `errorMessage`(触发红色 error 态)。 ### COT 思考链 - 后端 `inject-thinking.ts` 在 LLM 工具调用前将 text content 转为 thinking block(`source: "prompt"`) - Agent 节点 `result.reasoning` 转为 thinking block(`source: "reasoning"`,区分原生推理 vs 思考文本) - 前端 MessageBubble 解析 thinking blocks 渲染为可折叠区块(Brain 图标) - `source: "reasoning"` 用 ReactMarkdown 格式化,`source: "prompt"` 渲染为纯文本 ### Checkpoint 污染防御 - **Prevention**: 4 个 tool-executor 返回前校验每个 tool_call_id 都有对应 ToolMessage,缺失则补占位 error message - **Healing**: `clean-polluted-tool-calls.ts` 在 agent 节点调 LLM 前清洗脏 messages - **前端应急**: error 态显示"重置此对话"按钮 ## Daytona Sandbox 注意事项 Daytona API 正确端点: - 创建: `POST {DAYTONA_API_URL}/sandbox`,body: `{ autoStopInterval: 5, autoDeleteInterval: 0 }` - 执行: `POST https://proxy.app.daytona.io/toolbox/{sandboxId}/process/execute`,body: `{ command: "python3 -c '...'" }` - 删除: `DELETE {DAYTONA_API_URL}/sandbox/{sandboxId}` ## Repository Structure ``` so-c-chat-clone/ ├── langgraph/ ← 唯一代码目录 │ ├── src/agent/ │ │ ├── supervisor/ ← 路由 + generalInput │ │ ├── enterprise/ ← KB + 工单(ReAct) │ │ ├── searcher/ ← Google + Jina │ │ ├── coder/ ← Daytona 沙盒 │ │ ├── writer/ ← Canvas + 报告 + 草稿 │ │ └── utils/ ← retry, checkpointer, file-service, truncate, inject-thinking, clean-polluted-tool-calls, config, toolConfig, create-llm, redis, service-bus, doc-creator │ ├── src/agent-uis/enterprise/ ← 9 个 Gen-UI 卡片组件 │ ├── src/components/ ← 通用 UI 组件 │ ├── src/main.tsx ← Chat UI 入口 │ ├── langgraph.json ← LangGraph 配置 │ ├── Dockerfile ← 后端容器(生产) │ ├── Dockerfile.dev ← 后端容器(开发,tsx watch 热重载) │ ├── Dockerfile.frontend.dev ← 前端容器(Vite dev server) │ └── startup.sh ← Azure Web App 启动脚本 ├── .github/workflows/ │ ├── deploy-langgraph.yml ← ACR build → Web App │ └── deploy-langgraph-ui.yml ← Vite build → Static Web App └── CLAUDE.md ``` ## Configuration 环境变量通过 Azure Web App 应用设置配置,本地通过 `langgraph/.env`: ``` # Azure OpenAI (Sub-Agent LLM) AZURE_OPENAI_API_KEY, AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_API_VERSION, AZURE_OPENAI_DEPLOYMENT # Google Gemini (Supervisor router) — 开发环境可选 GOOGLE_API_KEY # KB Agent KB_AGENT_URL, KB_AGENT_API_KEY, KB_AGENT_SEARCH_PATH # Gongdan 工单 GONGDAN_API_BASE, GONGDAN_API_KEY # Jina JINA_API_KEY # Serper SERPER_API_KEY # Daytona DAYTONA_API_KEY, DAYTONA_API_URL # Frontend (Vite build-time) VITE_LANGGRAPH_URL=https://soc-langgraph.victorioussand-69befc84.southeastasia.azurecontainerapps.io # Redis (缓存) REDIS_CONNECTION_STRING # Service Bus (告警) SERVICEBUS_CONNECTION_STRING # Azure Blob (文件上传) AZURE_STORAGE_CONNECTION_STRING # Doc Creator DOC_CREATOR_API_KEY # PostgreSQL (checkpoint + 持久化) DATABASE_URL # CloudCost 云管系统(可选,有默认值) CLOUDCOST_API_BASE=https://orange-wave-09002e800.7.azurestaticapps.net ``` ## Deployment ### 后端 (soc-langgraph) - **Azure Container App**: Southeast Asia, Operation 资源组 - **Environment**: soc-cae (victorioussand-69befc84.southeastasia.azurecontainerapps.io) - **URL**: https://soc-langgraph.victorioussand-69befc84.southeastasia.azurecontainerapps.io - **容器**: socsocacr.azurecr.io/soc-langgraph:latest, port 8080 - **Scale**: min 1 replica, max 3 replicas, CPU 1.0, Memory 2Gi - **CI/CD**: ACR cloud build → Container App update (az containerapp update --image) ### 前端 (soc-langgraph-ui) - **Azure Static Web App**: East Asia - **URL**: agreeable-smoke-0364d4000.7.azurestaticapps.net - **CI/CD**: pnpm vite build → SWA upload ### CI/CD 认证 - OIDC: azure/login@v2 + Federated Identity (oidc-msi-8ac6) - SWA Token: secrets.SWA_LANGGRAPH_TOKEN ## Constraints - **Azure 资源组**: 仅允许操作 `Operation` 和 `AuthData`,所有 `az` 命令必须带 `--resource-group` - **禁止删除已存在的 Azure 资源** - **GitHub**: Fasthei/so-c-chat-clone,main 分支 - **已废弃**: backend/ (Python), frontend/ (Next.js), soc-backend/soc-frontend Web Apps, 旧 soc-langgraph Web App + App Service Plan, 旧 Log Analytics/Application Insights ## Skills ### agent-browser 所有 Agent 均已集成 `agent-browser` skill(`~/.claude/skills/agent-browser`),用于浏览器自动化: - **用途**: 网页导航、表单填写、截图、数据抓取、Web 应用测试、QA dogfooding - **触发**: 需要打开网页、截图、填表、点击按钮、测试前端页面等场景 - **使用前必须先加载技能**: `agent-browser skills get agent-browser` - **优先级**: 优先使用 agent-browser 而非内置 Playwright MCP 工具