6.7 KiB
RAG Agent (Postgres)
Custom RAG agent that indexes text files from a git repository into Postgres and answers queries using retrieval + LLM generation. Changes are always in the context of a Story: the unit of work is the story, not individual commits. The agent indexes all changes from all commits in the story range (base_ref..head_ref); per-commit indexing is not used.
Quick start
- (Optional) Run Postgres and the app via Docker (clone the repo first):
git clone git@git.lesha.spb.ru:alex/RagAgent.git && cd RagAgentdocker compose up -d— starts Postgres and the RAG app in one networkrag_net; app connects to DB at hostpostgres.- On first start (empty DB), scripts in
docker/postgres-init/run automatically (extension + tables). To disable, comment out the init volume indocker-compose.yml. - Default DSN inside the app:
postgresql://rag:rag_secret@postgres:5432/rag. Override withPOSTGRES_*andRAG_REPO_PATH(path to your knowledge-base repo, mounted into the app container). - Run commands:
docker compose run --rm app index --story my-branch,docker compose run --rm app ask "Question?".
- Configure environment variables:
RAG_REPO_PATH— path to git repo with text filesRAG_DB_DSN— Postgres DSN (e.g.postgresql://rag:rag_secret@localhost:5432/rag)RAG_EMBEDDINGS_DIM— embedding vector dimension (e.g.1536)
- Create DB schema (only if not using Docker, or if init was disabled):
python scripts/create_db.py(orpsql "$RAG_DB_DSN" -f scripts/schema.sql)
- Index files for a story (e.g. branch name as story slug). Use the full story range so all commits in the story are included:
rag-agent index --story my-branch --changed --base-ref main --head-ref HEAD- Or
--base-ref autoto use merge-base(default-branch, head-ref) as the start of the story.
- Ask a question (optionally scoped to a story):
rag-agent ask "What is covered?"rag-agent ask "What is covered?" --story my-branch
Webhook: index on push to remote
When the app runs as a service in Docker, it can start a webhook server so that each push to the remote repository triggers a pull and incremental indexing.
- Start the stack with the webhook server (default in Docker):
docker compose up -d— app runsrag-agent serveand listens on port 8000.- Repo is mounted at
RAG_REPO_PATH(e.g./data) writable, so the container can rungit fetch+git merge --ff-onlyto pull changes.
- Clone the knowledge-base repo into the mounted directory (once), e.g. on the host:
git clone <url> ./dataso that./datais the worktree (or setRAG_REPO_PATHto that path and mount it). - In GitHub (or GitLab) add a Webhook:
- URL:
http://<your-server>:8000/webhook(use HTTPS in production and put a reverse proxy in front). - Content type:
application/json. - Secret: set a shared secret and export
WEBHOOK_SECRETin the app environment (Docker: indocker-compose.ymlor.env). IfWEBHOOK_SECRETis empty, signature is not checked.
- URL:
- On each push to a branch, the server receives the webhook, pulls that branch into the worktree, and runs
rag-agent index --story <branch> --changed --base-ref <old_head> --head-ref <new_head>so only changed files are re-indexed.
Health check: GET http://<host>:8000/health → ok. Port is configurable via WEBHOOK_PORT (default 8000) in docker-compose.
Git hook (index on commit)
Install the post-commit hook so changed files are indexed after each commit:
cp scripts/post-commit .git/hooks/post-commit && chmod +x .git/hooks/post-commit
Story for the commit is taken from (in order): env RAG_STORY, file .rag-story in repo root (one line = slug), or current branch name.
Git hook (server-side)
Use scripts/post-receive in the bare repo on the server so that pushes trigger indexing.
- On the server, create a non-bare clone (worktree) that the hook will update and use for indexing, e.g.
git clone /path/to/repo.git /var/rag-worktree/repo. - In the bare repo, install the hook:
cp /path/to/RagAgent/scripts/post-receive /path/to/repo.git/hooks/post-receive && chmod +x .../post-receive. - Set env for the hook (e.g. in the hook or via systemd/sshd):
RAG_REPO_PATH=/var/rag-worktree/repo,RAG_DB_DSN=...,RAG_EMBEDDINGS_DIM=.... OptionallyRAG_AGENT_VENV(path to venv withrag-agent) orRAG_AGENT_SRC+RAG_AGENT_PYTHONforpython -m rag_agent.cli. - On each push the hook updates the worktree to the new commit, then runs
rag-agent index --changed --base-ref main --head-ref newrev --story <branch>so the story contains all commits on the branch (from main to newrev).
Story is taken from the ref name (e.g. refs/heads/main → main).
DB structure
- stories — story slug (e.g. branch name); documents and chunks are tied to a story. Optional:
indexed_base_ref,indexed_head_ref,indexed_atrecord the git range that was indexed (all commits in that range belong to the story). - documents — path + version per story; unique
(story_id, path). - chunks — text chunks with embeddings (pgvector), plus:
start_line,end_line— position in the source file (for requirements/use-case files).change_type—added|modified|unchanged(relative to base ref when indexing with--changed).previous_content— formodifiedchunks, the content before the change (for test-case generation).
Indexing is always per-story: base_ref..head_ref defines the set of commits that belong to the story. Use --base-ref main (or auto) and --head-ref HEAD so the story contains all commits on the branch, not a single commit. When you run index --changed, the base ref is compared to head; each chunk is marked as added, modified, or unchanged.
What changed in a story (for test cases)
To get only the chunks that were added or modified in a story (e.g. to generate test cases for the changed part):
from rag_agent.index import fetch_changed_chunks
changed = fetch_changed_chunks(conn, story_id)
for r in changed:
# r.path, r.content, r.change_type, r.start_line, r.end_line, r.previous_content
...
Scripts: scripts/create_db.py (Python, uses ensure_schema and RAG_* env), scripts/schema.sql (raw SQL).
Embeddings (GigaChat)
If GIGACHAT_CREDENTIALS is set (e.g. in .env for local runs), embeddings use GigaChat API; otherwise the stub client is used. Optional env: GIGACHAT_EMBEDDINGS_MODEL (default Embeddings), GIGACHAT_VERIFY_SSL (true/false). Ensure RAG_EMBEDDINGS_DIM matches the model output (see GigaChat docs).
Notes
- LLM client is still a stub; replace it in
src/rag_agent/agent/pipeline.pyfor real answers. - This project requires Postgres with the
pgvectorextension.