Impact-Site-Verification: 578d421e-1081-463d-918b-ec5e29c5b9db
<Back

AI Agent Decision Support System

Commissioned Work

Overview

Designed and built a B2B SaaS AI agent that argues the same decision independently from the Pro and Con sides, raising the quality of executive decisions. An 11-node stateful workflow on LangGraph conditionally drives internal knowledge search (Vertex AI Search) and web search (Tavily), with memory isolated per company / user / thread for a multi-tenant deployment.

Architecture

LLM-heavy reasoning (Pro / Con inference) is cleanly separated from the deterministic pre- and post-processing (memory load, search-necessity judgment, context merge, memory save). The graph uses conditional branching, and `judge_search_need` decides up front whether search is needed at all — avoiding wasted latency and tokens on unnecessary calls.

Pro / Con dual agents are implemented as a ReAct (Reasoning + Acting) pattern in `backend/src/agent/react_agent.py`. Both agents read the same context independently and build citation-backed arguments, invoking Vertex AI Search or Gemini built-in tools as they go.

Graph state is strictly typed with `TypedDict(total=False)` — OverallState / UserMemory / CompanyInfo / Citation — so type mismatches between nodes surface under Python type checking and regression cost stays flat as the graph grows.

  1. load_user_memory: load history and profile per user, thread, and company
  2. judge_search_need: decide up front whether external search is needed
  3. rag_search / web_search / merge_context: run Vertex AI Search and Tavily in parallel only when needed and merge contexts
  4. set_prompt → route_agents: build Pro and Con prompts appropriate to the context
  5. pro_agent / con_agent (parallel): independently produce arguments via ReAct
  6. merge_responses → assign_variables → finalize_answer: merge responses, bind variables, and finalize
  7. save_user_memory: persist conversation, decision history, and updated preferences

Multi-Tenancy & Memory

Queries against Vertex AI Search attach `company_id` as a metadata filter, isolating knowledge and access per company. The system handles the N-to-N relationship where a single user belongs to multiple companies, so switching companies safely swaps both the search scope and the referenced documents.

Conversation history uses LangGraph MemorySaver and InMemoryStore scoped per user / thread, and `trimming.py` caps history at 800,000 tokens by evicting oldest messages first — long-running threads never blow the context budget.

`BANSO_` -prefixed environment variables override `backend/src/agent/config.py` at runtime, so per-tenant configuration can be injected without code changes. Citations normalize source URLs and attach them to responses so evidence is always reachable.

Development & Quality

A Dev Container (Ubuntu Noble + Zsh + uv + Node.js v24) provides a uniform development environment. pytest / pytest-asyncio / pytest-cov cover unit, async, and coverage testing, and LangSmith provides LLM tracing and monitoring, so CI can assert that graph changes propagate as intended.

Technologies

PythonLangGraphLangChainFastAPIGoogle Gemini 2.5 FlashGoogle Vertex AI SearchTavily APIReAct PatternMulti-AgentLangGraph MemorySaverInMemoryStorePydantic TypedDictLangSmithpytestDev Containeruv