Skip to content

v0.1.0

Choose a tag to compare

@chef11102548c-cell chef11102548c-cell released this 07 Aug 04:43
· 11 commits to main since this release

Walking Skeleton Contract Clause Risk Reviewer

1. Architectural Summary

Contract Clause Risk Reviewer คือระบบ AI-Grounded RAG สำหรับวิเคราะห์ความเสี่ยงของข้อสัญญา (clause-level risk review) ใน pattern Intake → Review → Analysis → Generation ผู้ใช้อัปโหลดสัญญา (.pdf / .docx / .txt) → ระบบ parse → segment เป็น clause → classify ประเภท → match กับ playbook ผ่าน hybrid retrieval (pgvector + BM25) → score ความเสี่ยง → grounding judge → สรุปเป็น ContractReport พร้อม citation

ใน v0.0.1 นี้ walking skeleton ทำงานได้จริงแบบ end-to-end รวมถึง:

  • Pydantic schemas ครบ (clause, report, taxonomy, playbook, eval)
  • FastAPI pipeline POST /contracts/review ต่อ Gemini API + Postgres/pgvector จริง
  • Auth (Google OAuth + JWT), DB (Alembic migrations), Redis-backed repos
  • Frontend React 19 ต่อ backend จริง (ไม่มี mock data เหลือ)
  • 268 unit/integration tests ผ่านหมด + 11 live LLM tests

สิ่งที่จะพัฒนาต่อใน v0.2.0: Router agent แบบ MoE, ระบบ eval อัตโนมัติกับ gold set เต็ม, guardrail เพิ่มเติม, และ polished UI/UX

Count (self-audit) Number Notes
Blocking gaps vs I1 pass bar 0 Pipeline ใช้งานได้จริงแล้ว
Design foresight risks for I2 2 Router MoE ยังไม่แยก specialist, classification score ต่ำ (45%)
Schema / contract anti-patterns spotted 1 list[dict] ใน history bag ควรเป็น typed model

2. Problem → Solution Shape

2.1 Users & Primary Use Case

ผู้ใช้: นักกฎหมายภายในองค์กร (in-house counsel) และทีม legal ops ที่ต้องตรวจสอบสัญญาในปริมาณมาก

Primary flow:

อัปโหลด .pdf/.docx/.txt → POST /contracts/review
→ ได้ ContractReport (clause list + risk level + citation + grounding verdict)
→ override risk level ผ่าน sidebar
→ accept clause ที่ตรวจผ่านแล้ว

2.2 In Scope / Out of Scope

In Scope (v0.0.1–v1.0.0):

  • Parse PDF, DOCX, TXT (รองรับสัญญาไทย + อังกฤษ)
  • Clause segmentation (regex + heading detection)
  • 12 clause types (จาก CUAD taxonomy)
  • Hybrid RAG retrieval (pgvector cosine + BM25)
  • Risk scoring (HIGH / MEDIUM / LOW / ACCEPTABLE)
  • Grounding judge (citation verbatim check >= 4 words)
  • Override + Accept flow พร้อม audit log
  • Contract metadata extraction (parties, dates, value, governing law)
  • Report history (Postgres permanent storage)
  • Auth: Google OAuth + JWT

Out of Scope (Demo Day):

  • Multi-document cross-reference analysis
  • Negotiation suggestion generation
  • Real-time collaboration
  • Export (JSON/CSV/PDF) — ตัดออกเพื่อ scope ชัด

2.3 Demo Script Awareness

Step Status in v0.0.1
1. Login ด้วย Google account Real (Google OAuth ทดสอบกับ account จริงแล้ว)
2. อัปโหลด .docx สัญญาตัวอย่าง Real (ยิง POST /contracts/review จริง)
3. ดู clause list พร้อม risk badge + citation Real (แสดงจาก ContractReport จริง)
4. Override risk level ของ clause Real (POST /contracts/{id}/override)
5. Accept clause ที่ตรวจผ่าน Real (POST /contracts/{id}/accept)
6. ดูประวัติรายงานเดิม Real (GET /contracts + deep link /contract?report=<id>)

3. System / Agent Topology

3.1 Architecture Diagram

flowchart TD
    User["User (Browser)"]
    FE["React 19 Frontend\n/login · /manual · /contract"]
    API["FastAPI API\nPOST /contracts/review\nGET /contracts\nPOST /contracts/{id}/override\nPOST /contracts/{id}/accept"]
    Auth["Auth Layer\nGoogle OAuth + JWT\n/auth/*"]

    subgraph Pipeline ["Review Pipeline"]
        Parser["Parser Agent\nPDF/DOCX/TXT to ParsedDocument"]
        Segmenter["Segmenter Agent\nText to Clause list\n(regex + Thai heading)"]
        Classifier["Classifier Agent\nClause to 12 types\n(LLM structured output)"]
        RAG["RAG Retriever\nHybrid: pgvector cosine + BM25\nto Playbook positions"]
        Scorer["Risk Scorer\nHIGH/MEDIUM/LOW/ACCEPTABLE"]
        Judge["Grounding Judge\nCitation verbatim >= 4 words\n+ hallucination check"]
        Metadata["MetadataExtractor\nParties / Dates / Value\n/ Governing Law"]
    end

    DB["Postgres + pgvector\nusers · contract_reports\nplaybook_embeddings\naudit_overrides"]
    Redis["Redis\ncontract repo TTL"]
    LLM["LLM Provider\nGemini / Claude / GLM\nLLM_PROVIDER env"]

    User --> FE --> API --> Auth
    API --> Pipeline
    Parser --> Segmenter --> Classifier --> RAG --> Scorer --> Judge
    Metadata -.->|"1 call/doc"| LLM
    Classifier --> LLM
    Judge --> LLM
    RAG --> DB
    Scorer --> DB
    API --> DB
    API --> Redis

3.2 Agent Responsibility Table

Agent / Component Responsibility I1 Status
Parser PDF/DOCX/TXT → ParsedDocument (PyMuPDF, python-docx) Real
Segmenter Split → ClauseList (regex, Thai/English heading detection) Real
Classifier Clause → 12 CUAD types (LLM structured output) Real
RAG Retriever Hybrid pgvector cosine + BM25 → playbook positions Real
Risk Scorer Aggregate risk from classifier + RAG match Real
Grounding Judge Verify citation verbatim >= 4 words, hallucination check Real
MetadataExtractor Extract parties/dates/value/law from doc header+footer Real (1 LLM call/doc)
LLM Provider Adapter Gemini / Claude / GLM via LLM_PROVIDER env Real
Auth (Google OAuth + JWT) Login flow, token management, route guard Real
Alembic Migrations DB schema versioning Real
Data Retention Job scripts/purge_reports.py Real (manual cron)

3.3 Sync vs Async Boundary (Design Foresight)

Today (v0.0.1):

  • POST /contracts/review — synchronous request/response (blocking I/O ย้าย run_in_threadpool แล้ว)
  • /health ตอบ 1.2–2.0 ms ระหว่าง review 18.9 วิ

Planned (v0.2.0/v1.0.0):

  • สัญญาใหญ่ (>300 clauses) ควรเป็น 202 + job_id + polling / WebSocket
  • MAX_CLAUSES=300 guard ไว้แล้ว

4. API Contracts & Schemas (I1 required)

4.1 Endpoint Table

Method Path Request Response Model I1 Behavior
POST /contracts/review multipart/form-data (file) ContractReport Real — full pipeline
GET /contracts bearer auth List[ContractSummary] Real — Postgres
GET /contracts/{report_id} bearer auth ContractReport Real — Postgres
DELETE /contracts/{report_id} bearer auth 204 Real
POST /contracts/{id}/override OverrideRequest ContractReport Real + audit log
POST /contracts/{id}/accept AcceptRequest ContractReport Real + audit log
GET /playbook/search query params List[PlaybookPosition] Real — pgvector
POST /evaluate EvalRequest EvalReport Real
GET /health/db — {"status": "connected"} Real
GET + POST /auth/* — JWT token / redirect Real (Google OAuth)

4.2 Schema Fidelity Checklist

✓ Check Notes
☑ Field names match PRD Pydantic shapes ClauseResult, ContractReport, PlaybookPosition, EvalReport
☑ Types / Literals / required vs optional match PRD intent risk_level: Literal["HIGH","MEDIUM","LOW","ACCEPTABLE"]
☑ Confidence / review flags present grounding_verdict, needs_review implicit via override flow
☑ Citations / source_span / evidence fields present citation.playbook_position, citation.excerpt (verbatim)
☑ FastAPI response_model= declared (OpenAPI shows schemas) ทุก endpoint ประกาศ response_model
☑ Avoid dict / Any dumping for the main AI response Pydantic models ทุกชั้น

4.3 Known Schema Risks

  • history / audit log — ปัจจุบันใช้ list[dict] บางส่วน; ควร migrate ไป typed AuditEntry model ใน v0.2.0
  • Field-level confidence — risk_level เป็น Literal แต่ยังไม่มี confidence_score: float แยกต่างหาก; judge ใช้ grounding verdict แทน — พิจารณาเพิ่มใน v0.2.0
  • Schema versioning — ContractReport ยังไม่มี schema_version field; จำเป็นถ้ารายงานเก่าใน Postgres ต้อง migrate

5. Sample I/O Evidence

5.1 Sample Request

curl -X POST http://localhost:8000/contracts/review \
  -H "Authorization: Bearer <JWT_TOKEN>" \
  -F "file=@sample_contract.docx"

5.2 Sample Response (Validated JSON)

{
  "report_id": "rpt_01j9x3k2m4n5p6q7r8s9t0u1v2",
  "contract_metadata": {
    "parties": ["บริษัท ABC จำกัด", "บริษัท XYZ จำกัด"],
    "effective_date": "2025-01-01",
    "governing_law": "กฎหมายไทย"
  },
  "summary": {
    "total_clauses": 12,
    "risk_distribution": { "HIGH": 2, "MEDIUM": 5, "LOW": 4, "ACCEPTABLE": 1 },
    "overall_risk": "MEDIUM"
  },
  "clauses": [
    {
      "clause_id": "cl_001",
      "clause_type": "termination",
      "text": "คู่สัญญาฝ่ายใดฝ่ายหนึ่งอาจบอกเลิกสัญญาได้โดยไม่ต้องแสดงเหตุผล...",
      "risk_level": "HIGH",
      "ai_rationale": "ข้อสัญญานี้ให้สิทธิ์บอกเลิกสัญญาได้โดยไม่มีเหตุผล ซึ่งขัดกับ playbook ของบริษัท",
      "suggested_fallback": "การบอกเลิกต้องแจ้งล่วงหน้า 30 วัน และมีเหตุผลอันสมควร",
      "citation": {
        "playbook_position": "termination.unilateral_termination",
        "excerpt": "การบอกเลิกสัญญาต้องมีเหตุผลอันสมควรและแจ้งล่วงหน้า"
      },
      "grounding_verdict": {
        "is_grounded": true,
        "verdict_reason": "excerpt verified verbatim in playbook (6 words)"
      },
      "accepted": false
    }
  ],
  "disclaimer": "รายงานนี้สร้างโดย AI — กรุณาตรวจสอบโดยผู้เชี่ยวชาญด้านกฎหมายก่อนนำไปใช้"
}

Response validates against ContractReport Pydantic model — tested via pytest -m live_llm with real Gemini + pgvector.

5.3 How to Reproduce

# 1. Clone repo
git clone https://github.com/tsuna-n/Contract-Clause-Risk-Reviewer.git
cd Contract-Clause-Risk-Reviewer

# 2. Copy env and fill in secrets
cp apps/backend-fastapi/.env.example apps/backend-fastapi/.env
# Set GEMINI_API_KEY, DATABASE_URL, REDIS_URL, GOOGLE_CLIENT_ID/SECRET

# 3. Start infra
docker compose -f infrastructure/docker-compose.yml up -d

# 4. Run migrations
cd apps/backend-fastapi
alembic upgrade head

# 5. Start API
uvicorn app.main:app --reload
# OpenAPI docs: http://localhost:8000/docs

# 6. Run tests (offline, free)
pytest   # 268 tests

# 7. Run live LLM tests (costs API credits)
pytest -m live_llm   # 11 tests, ~3 min

6. Repo Hygiene & Layout

✓ Item Path / Note
☑ README with run instructions README.md (root) + apps/backend-fastapi/README.md
☑ .env.example (no secrets committed) apps/backend-fastapi/.env.example
☑ Schemas package / module apps/backend-fastapi/app/schemas/
☑ API routes package apps/backend-fastapi/app/routers/
☑ Docs folder with architecture diagram Section 3 Mermaid + README embedded
☑ Data pack folder apps/backend-fastapi/data/ (CUAD fixtures, gold labels)

Repo Tree (top-level):

Contract-Clause-Risk-Reviewer/
├── README.md
├── .gitignore
├── apps/
│   ├── backend-fastapi/
│   │   ├── README.md
│   │   ├── .env.example
│   │   ├── app/
│   │   │   ├── main.py
│   │   │   ├── schemas/        # Pydantic models
│   │   │   ├── routers/        # FastAPI routes
│   │   │   ├── ai/             # LLM provider adapter, agents
│   │   │   ├── db/             # SQLAlchemy models, Alembic
│   │   │   └── services/       # Review pipeline, RAG
│   │   ├── data/
│   │   │   └── gold/           # Gold label sets (CUAD)
│   │   ├── scripts/
│   │   │   ├── build_cuad_fixtures.py
│   │   │   └── purge_reports.py
│   │   ├── tests/
│   │   │   ├── unit/
│   │   │   ├── integration/
│   │   │   └── live/           # pytest -m live_llm
│   │   └── alembic/
│   └── web/                    # React 19 + Vite + Tailwind
│       ├── src/
│       │   ├── lib/api.ts
│       │   ├── lib/contracts.ts
│       │   └── pages/          # /login, /manual, /contract
│       └── ...
└── infrastructure/
    └── docker-compose.yml      # Postgres (pgvector) + Redis + api

7. Design Foresight for I2 / I3

Check Area I1 Expectation Planned Approach
LLM Orchestration Name provider(s); structured output plan Gemini (primary) / Claude / GLM via LLM_PROVIDER; structured JSON per adapter; LLM_THINKING=disabled default
RAG / KB What ingested? Chunking unit? CUAD v1 (510 contracts) → playbook positions; chunk = clause position; hybrid pgvector cosine + BM25 already live
Router + Specialists When does routing become real (I2)? v0.2.0: Router agent → specialist per clause type (termination, payment, IP, …); ปัจจุบัน classifier → single pipeline
Judge / Grounding What will judge verify? Verbatim citation check (>= 4 words), hallucination detection, verdict.reason fed back into retry prompt
HITL / Confidence How will needs_review route to humans? Override sidebar + Accept flow live; v0.2.0: confidence_score + auto-flag queue
Eval Pack Gold set size; metrics & thresholds 3 contracts / 90 clauses / 18 min; segmentation_f1 100%, citation_validity 100%, classification 45.45%*, risk 50%
Guardrails (I3) Disclaimer, injection, PII / retention Disclaimer in report; MAX_UPLOAD_BYTES=10MB, MAX_CLAUSES=300; PLAYBOOK_ADMIN_EMAILS; REPORT_RETENTION_DAYS + purge job
Reliability Retries, timeouts, async jobs SDK-level retry (timeout/429/5xx/empty/JSON broken); run_in_threadpool; v0.2.0: 202+job_id for large contracts

classification 45.45% ต่ำเพราะ label set เปลี่ยน ไม่ใช่ pipeline เสื่อม (อธิบายใน Section 8)


8. Findings & Risks (I1 required)

[LOW] Finding 1 — Classification Accuracy Drop After Label Set Change

Component: app/ai/agents/classifier.py · data/gold/

Issue: classification metric ลดจาก 57.69% → 45.45% หลังเปลี่ยน gold label set ใหม่ (label ที่ละเอียดกว่า ไม่ใช่ pipeline เสื่อม)

Impact: Metric ดูต่ำกว่าจริง; อาจสร้างความเข้าใจผิดเวลา report ต่อ stakeholder

Remediation: เพิ่ม note ใน eval report ว่า label set เปลี่ยน + สร้าง baseline comparison — target v0.2.0


[MEDIUM] Finding 2 — No confidence_score Field on ClauseResult

Component: app/schemas/clause.py

Issue: Judge ให้ grounding verdict แต่ไม่มี numeric confidence; HITL routing ต้องอาศัย override manual

Impact: Auto-flagging clauses สำหรับ reviewer queue ใน v0.2.0 จะซับซ้อนขึ้น

Remediation: เพิ่ม confidence_score: float และ needs_review: bool ใน schema — target v0.2.0


[LOW] Finding 3 — schema_version Missing from ContractReport

Component: app/schemas/report.py

Issue: รายงานใน Postgres ไม่มี version tag; schema เปลี่ยนใน v0.2.0 อาจทำให้ GET /contracts/{id} deserialize รายงานเก่าพัง

Impact: Breaking change เมื่อ schema evolve ใน future iterations

Remediation: เพิ่ม schema_version: str = "0.0.1" — v0.1.0 hotfix ก่อน schema เปลี่ยน


9. Quick Fixes & Next Iteration Plan

Before tagging v0.0.1 (must fix)

  1. ไม่มี blocking gap — pipeline ทำงานได้จริง end-to-end
  2. เพิ่ม schema_version: str = "0.0.1" ใน ContractReport (hotfix)
  3. ตรวจสอบ .env.example ครบทุก env var ที่ใช้จริง

Iteration 2 — AI Core (v0.2.0)

I2 จะต้องมี: RAG/KB ingestion · Router + specialist agents · Real LLM structured output · Judge/grounding · Eval on gold subset · eval_report.md
(v0.0.1 ทำเกินหมดแล้ว — I2 focus ที่ MoE routing + eval automation)

  1. Router Agent → dispatch per clause type → Specialist agents (termination, payment, IP, indemnity)
  2. เพิ่ม confidence_score + needs_review ใน schema
  3. Eval automation pipeline (CI-triggered gold set eval)
  4. 202 + job_id async pattern สำหรับสัญญา >300 clauses
  5. schema_version migration utility สำหรับรายงานเก่า

Iteration 3 — Demo Day (v1.0.0)

  • UI polish: report export (backend endpoint), comparison view
  • Full gold eval vs thresholds (target: classification >= 60%, risk >= 65%)
  • Cron schedule สำหรับ retention job (เมื่อมีนโยบายเก็บข้อมูลจริง)
  • Demo video recording

10. Release Notes Draft (I1 required)


v0.0.1 — Walking Skeleton (End-to-End Working)

Project: Contract Clause Risk Reviewer
Pattern: Intake → Review → Analysis → Generation (Grounded RAG)

What's Included

Backend (FastAPI + Postgres/pgvector + Redis)

  • Pydantic schemas: ClauseResult, ContractReport, PlaybookPosition, EvalReport, AuditEntry
  • FastAPI review pipeline: POST /contracts/review — Parse → Segment → Classify → RAG match → Risk score → Grounding judge → Report (tested with Gemini + pgvector live)
  • Architecture diagram: Section 3 Mermaid in this document
  • Auth: Google OAuth + JWT (tested with real Google account)
  • DB: Alembic migrations (users, contract_reports, playbook_embeddings, audit_overrides)
  • LLM Provider Adapter: Gemini / Claude / GLM switchable via LLM_PROVIDER env
  • Hybrid RAG: pgvector cosine + BM25 on 36 playbook positions (12 clause types)
  • Override + Accept flow: POST /contracts/{id}/override + POST /contracts/{id}/accept with audit log
  • Contract metadata extraction: parties / dates / value / governing law (verbatim check)
  • Report history: Postgres permanent storage + deep link + delete
  • Data fixtures: CUAD v1 → 12 sample contracts + 327 gold clauses
  • Guardrails: MAX_UPLOAD_BYTES=10MB, MAX_CLAUSES=300, grounding badge, disclaimer
  • Tests: 268 unit/integration tests (offline, free) + 11 live LLM tests

Frontend (React 19 + Vite + Tailwind)

  • /login — Google login
  • /manual — report history + upload
  • /contract — clause list + risk badge + citation + override sidebar + accept button
  • No mock data — all connected to real backend

What's Mocked / Deferred

  • Router agent (MoE pattern) — currently: classifier → single pipeline; v0.2.0: Router → Specialists
  • confidence_score field (using grounding verdict instead)
  • schema_version field in ContractReport
  • Async job pattern (202 + job_id) for large contracts
  • Export endpoint (server-side)
  • Cron schedule for retention job

How to Run

git clone https://github.com/tsuna-n/Contract-Clause-Risk-Reviewer.git
cd Contract-Clause-Risk-Reviewer
cp apps/backend-fastapi/.env.example apps/backend-fastapi/.env
# Set GEMINI_API_KEY, DATABASE_URL, REDIS_URL, GOOGLE_CLIENT_ID/SECRET
docker compose -f infrastructure/docker-compose.yml up -d
cd apps/backend-fastapi && alembic upgrade head
uvicorn app.main:app --reload
# OpenAPI: http://localhost:8000/docs

Pass Bar Evidence

POST /contracts/review → ContractReport (validated Pydantic model)
Tested: Gemini API + Postgres/pgvector live
segmentation_f1: 100% · citation_validity: 100%
268 tests passing (0 skip) + 11 live LLM tests