- 新增 cloudcost-client.ts:5 个 API 函数(dashboard/metering/detail/alerts/accounts) - config.ts 添加 cloudcost.apiBase(默认 orange-wave-09002e800.7.azurestaticapps.net) - toolConfig.ts 添加 cloudcost_* 超时/重试配置 - CLAUDE.md 更新架构图和 env var 文档 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
13 KiB
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
cd langgraph
pnpm install
pnpm run agent # 启动后端 langgraphjs dev (port 2024)
pnpm run build # tsc -b && vite build(前端)
开发机一键重启:
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 使用双流模式 + 子图流式推送:
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 Blobsrc/agent/utils/checkpointer.ts— PostgresSaver,Gen-UI ui items 随 checkpoint 持久化恢复src/agent/utils/inject-thinking.ts— 将 LLM 工具调用前的 content 转为{ type: "thinking", thinking, source: "prompt"|"reasoning" }blocksrc/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— 卡片底部追问/快捷动作,dispatchsoc:prefill-inputCustomEventsrc/components/SourceBadge.tsx— 来源类型徽章(颜色+置信度图标)src/components/MessageBubble.tsx— ReactMarkdown + KaTeX + Prism + COT 思考链渲染(Brain 图标可折叠)+rehypeSanitizeLinks(防无 href 崩溃)+MarkdownErrorBoundary(fallback 到纯文本)+ >800字智能摘要块src/components/CanvasPanel.tsx— 右侧文档编辑抽屉,监听open-canvasCustomEventsrc/agent-uis/index.tsx— Gen-UI 组件注册表(ComponentMap)
Gen-UI 卡片开发规范
新增卡片需要:
- 创建
src/agent-uis/enterprise/{name}/index.tsx(参考 knowledge-result 结构) - 在
src/agent-uis/index.tsx的 ComponentMap 注册 - 后端
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 工具