Soften the tone of the docs and comments written today

This commit is contained in:
2026-08-11 10:12:25 +07:00
parent 97cb6d16f4
commit 6b8f7584ed
18 changed files with 921 additions and 64 deletions
+63 -13
View File
@@ -1,23 +1,73 @@
# ai-service
FastAPI service for drug resolution, guarded retrieval, printed-page citations,
and PostgreSQL retrieval traces.
FastAPI service holding the entire live RAG path: query understanding, drug
resolution, deterministic section routing, guarded retrieval, grounded
generation, claim/citation verification, printed-page citations, and
PostgreSQL conversation + retrieval traces. In production this is what
`apps/web` calls — there is no gateway in front of it.
Local infrastructure:
## Local infrastructure
```powershell
docker compose -f ..\..\infra\docker\docker-compose.yml up -d postgres qdrant
python -m migrate
uvicorn main:app --reload
python -m uvicorn main:app --port 8079
```
`GET /health` is always available. `POST /v1/rag/query` requires structured
`subject_scope` and `intent`; unknown/non-human/recommendation requests fail
closed. The default `EMBEDDING_PROVIDER=disabled` intentionally leaves the RAG
backend unavailable until the collection and matching query embedder are
configured.
> **Use a plain restart rather than `--reload` on Windows.** The reloader has
> been observed serving the previous code after an edit on this project, so a
> change can appear to have no effect (or appear to work when it has not been
> loaded). Restarting the process avoids the ambiguity.
`EMBEDDING_PROVIDER=local-smoke` is only for local plumbing checks. Its hashing
vectors are deterministic but not semantic and must not be used for retrieval
quality claims. Bedrock is not called by this service and no IAM change is
required.
`GET /health` is always available. `POST /v1/rag/query` is the live agent
endpoint. Structured `subject_scope`/`intent` requests fail closed on
unknown/non-human input.
## Bedrock is required for real answers
Since 2026-08-05 the live path calls AWS Bedrock and needs credentials with
invoke permission:
| Role | Default | Setting |
|---|---|---|
| Query embedding | `cohere.embed-v4:0` | `embedding_provider` (default `cohere-v4`) |
| Answer generation | Bedrock Converse | `generation_provider` (`bedrock-converse` / `bedrock-claude`) |
| Rerank | Cohere rerank | `rerank_enabled`**off** by default; only affects the similarity fallback, never the deterministic section route |
Credentials come from the environment (an IAM instance role in production, no
long-lived keys). With no working generator configured, a rejected generation
**abstains** — it must never degrade into dumping raw source text at a
clinician.
`EMBEDDING_PROVIDER=local-smoke` is only for local plumbing checks. Its
hashing vectors are deterministic but not semantic and must not be used for
any retrieval-quality claim.
## Corpus coupling
Startup verifies the `duocthu_v1__manifest` sidecar and **refuses to run**
against a collection whose corpus sha / model / dimensions do not match
(F-05). A machine with an empty Qdrant cannot serve answers until a snapshot
is restored or `ingestion/` is re-run — the latter costs real Bedrock spend.
## Request budget and timeouts
A turn makes several sequential Bedrock calls, bounded by
`max_wall_clock_ms` (40s) and `max_llm_calls_per_turn` (8) in `config.py`.
The budget is checked **between** calls and cannot cancel one already in
flight, which is separately bounded by `read_timeout` in
`adapters/bedrock_converse.py`. Real ceiling ≈ 40s + one in-flight call, so
any client calling this service must allow more than that — `apps/web`'s
`ChatPanel.tsx` uses 65s for exactly this reason.
## Tests
```powershell
python -m pytest -q # needs Postgres + Qdrant up
python -m pytest -q --ignore=tests/test_api.py --ignore=tests/test_live_datastores.py
```
230 pass without live datastores. Coverage is uneven and worth checking
before relying on it: `rag/agent.py`'s dosing state machine has been covered
only since 2026-08-11, and the repo has no frontend test setup, so a green
suite does not by itself confirm a user-visible change works.