source+sorcery— supplier search that actually checks its sources.
You give it a natural language query like "Top 5 semiconductor manufacturers in Taiwan" and it goes out, finds candidates, cross-references them against real registries (GLEIF, MOEA, TWSE, OFAC, IAF), and comes back with per-field confidence scores. If it can't verify something, it says so honestly instead of making things up.
You'll need Python 3.12+, uv, and Node.js 18+.
cp .env.example .env # add your API keys, or leave blank for stub mode
uv sync --all-extras # python deps
npm ci # frontend deps (skip if you only want the CLI)Works out of the box with --provider stub (no API keys, uses hardcoded test data):
uv run sourcery "Top 5 semiconductor manufacturers in Taiwan" --out outputs/my_run --provider stubWith a real LLM (set your keys in .env first):
uv run sourcery "Top 5 semiconductor manufacturers in Taiwan" --out outputs/my_runUse the launcher script — it handles port cleanup, starts both servers, and opens the browser:
# Windows
run.bat # select [2] Start dev server
# macOS / Linux
chmod +x run.sh && ./run.sh # select [2]Or manually in two terminals:
uv run python scripts/dev_server.py # Terminal 1: API on :8000
npm run dev # Terminal 2: UI on :3000uv run pytest -qflowchart LR
Q["Natural language query"] --> P["Parser (LLM)"]
P --> C["Candidate Generation"]
C --> R["Entity Resolution"]
R --> E["Evidence Gathering"]
E --> S["Per-Field Scoring"]
S --> O["JSON + CSV"]
subgraph Candidates
C
C1["Tavily"] -.-> C
C2["DuckDuckGo"] -.-> C
C3["LLM hypothesis"] -.-> C
end
subgraph Verification
E
E1["GLEIF · MOEA · TWSE"] -.-> E
E2["OFAC · IAF"] -.-> E
E3["Brave · Company Website"] -.-> E
end
The key idea: registries first, LLM last. If GLEIF says a company exists, that's a HIGH confidence signal. If only the LLM thinks so, that's LOW. The tool is honest about what it knows and what it's guessing.
Set LLM_PROVIDER in .env, or pick one from the /providers page in the web UI.
| Provider | Key | Notes |
|---|---|---|
bedrock |
AWS credentials | Converse API with tool_use |
anthropic |
ANTHROPIC_API_KEY |
Direct API |
openai |
OPENAI_API_KEY |
Direct API |
gemini |
GEMINI_API_KEY |
Google GenAI |
groq |
GROQ_API_KEY |
Fast inference |
ollama |
OLLAMA_BASE_URL |
Local models |
stub |
None | Hardcoded fixtures, no network calls |
The hard problems and how we solved them:
- Source Strategy — why registries come first
- Verification Logic — how confidence scoring works
- Entity Resolution — matching companies across scripts and aliases
- Failure Modes — what breaks and how we handle it
- Tools & Stack — why each dependency is here
- Decision Log — tradeoffs we made along the way
vss/ # the engine
├── pipeline.py # orchestrates everything
├── parser.py # turns your query into structured criteria
├── candidates.py # finds supplier candidates (Tavily + DDG + LLM)
├── resolve.py # deduplicates via fuzzy matching
├── normalize.py # handles CJK, transliteration, legal suffixes
├── confidence.py # scores each field based on evidence quality
├── models.py # Pydantic schemas
├── cli.py # CLI entry point
├── sources/ # registry adapters (GLEIF, MOEA, TWSE, etc.)
└── llm/ # 7 provider adapters behind a common Protocol
app/ # Next.js frontend
components/ # React UI
api/ # Python API handlers (dev server)
tests/ # pytest suite
Apache 2.0