Files
socaichat/CLAUDE.md
T
gongzhiyongandClaude Opus 4.6 1e735202fc fix(backend): wrap SSE astream_events in try/except/finally
Tool call failures (httpx network errors) propagated as unhandled exceptions
through LangGraph TaskGroup, killing SSE stream mid-flight. Frontend received
neither tokens nor done event, leaving it stuck.

- except: sends {"type":"error"} SSE event so frontend shows error message
- finally: persists partial AI content and always sends {"type":"done"}

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-08 20:36:39 +08:00

4.6 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 — 企业级 Gemini 风格对话系统,前后端分离。基于 LangGraph ReAct Agent 编排,支持知识库检索、工单查询、外部搜索、文档生成、沙盒执行。

Commands

Backend

cd backend
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
uvicorn app.main:app --port 8000 --reload   # Dev server

Frontend (read-only unless explicitly authorized)

cd frontend
npm install && npm run dev     # localhost:3000
npm run build

Deployment

# Manual deploy (Oryx builds dependencies on Azure)
az webapp up --name soc-backend --resource-group Operation --runtime "PYTHON:3.12"

# Or push to main branch — GitHub Actions auto-deploys via .github/workflows/deploy-backend.yml
git push origin main

Architecture

Request Flow

Frontend POST /api/chat/stream
  → api/chat.py: resolve_tools() → get_chat_graph() → astream_events()
  → graph/builder.py: create_react_agent (with tools) OR plain StateGraph (no tools)
  → tools/*.py: LangChain @tool functions call external services
  → SSE events: token / tool_start / tool_end / done

Graph Strategy (graph/builder.py)

  • With tools: create_react_agent(llm, tools, checkpointer) — ReAct pattern, LLM decides tool calls
  • Without tools: Simple StateGraph(ChatState) with single call_model node
  • Graphs cached by (model, frozenset(tool_names)) to avoid re-compilation
  • Model presets: flash (max_tokens=500, temp=0.2), pro (max_tokens=4096, temp=0.3)

Tool System (tools/__init__.py)

Frontend sends tool keys → resolve_tools() maps to LangChain @tool objects → bound to ReAct agent.

Frontend Key Tools External Service
"knowledge" kb_search KB Agent (Azure AI Search)
"tickets" ticket_list, ticket_detail Gongdan API
"search" web_search Jina Search/Reader/Rerank
"document" generate_document Doc Creator Agent
"sandbox" sandbox_run Daytona API

Data Layer

  • PostgreSQL (store/postgres.py): SQLAlchemy async ORM — Conversation and Message models, auto-creates tables on startup
  • LangGraph Checkpointer (store/memory.py): AsyncPostgresSaver via psycopg (separate connection from SQLAlchemy, uses sslmode=require not ssl=require)
  • Redis (cache/redis.py): Search result caching, key=search:{hash}:{model}, TTL=300s, graceful degradation on failure
  • Azure Blob Storage (storage/blob.py): File uploads/downloads for attachments and generated docs
  • Azure Service Bus (tasks/bus.py): Async task dispatch for long-running operations

SSE Event Protocol

{"type": "token", "content": "..."}      // Streamed text chunk
{"type": "tool_start", "tool": "kb_search"}
{"type": "tool_end", "tool": "kb_search"}
{"type": "done"}                          // End of stream

Lifespan (main.py)

Startup creates DB tables. Shutdown closes: checkpointer → Redis → Blob client → Service Bus → SQLAlchemy engine.

Configuration

All config via pydantic-settings in app/config.py, reads from .env file. Full credentials reference in EXTERNAL_SERVICES.md.

Key env vars: AZURE_OPENAI_*, DATABASE_URL, KB_AGENT_*, GONGDAN_*, JINA_API_KEY, REDIS_URL, DOC_AGENT_*, DAYTONA_*, AZURE_STORAGE_CONNECTION_STRING, AZURE_SERVICE_BUS_CONNECTION_STRING.

Deployment

  • Azure Web App: soc-backend in Operation resource group, Python 3.12, B1 Linux
  • Startup: gunicorn -w 2 -k uvicorn.workers.UvicornWorker --bind 0.0.0.0:8000 --timeout 120 app.main:app
  • Critical setting: WEBSITES_PORT=8000 (Azure defaults to 8080)
  • CI/CD: GitHub Actions with OIDC auth (azure/login@v2) → zip deploy, triggers on backend/** changes to main
  • Always On: Enabled to avoid cold starts

Constraints

  • Frontend is read-only unless explicitly authorized
  • Azure resources: Operation and AuthData resource groups only — all az commands must include --resource-group
  • Tool invocation policy: User-selected tools are passed to ReAct Agent as available. Agent decides whether to call them. If it decides not to, it must explain why.
  • Search depth: flash = quick (top 3, no Reader/Rerank), pro = deep (top 10, concurrent Reader, Rerank top 5)

Known Issues

  • GET /api/tickets/{id} returns 404 — upstream Gongdan API issue, not backend bug
  • config.py has hardcoded DB/Redis passwords as defaults — should be empty strings (security risk if repo goes public)