Skip to content

Knowledge Retrieval

04KnowledgeCited Q&A
Context Graph tribal knowledge
indexed docs · meeting recaps · slack history · entity links
Sources
Drive · Docs
Drive · Docs
Slack
Slack
Read.ai
Read.ai
indexed
Agentcy
Agentcy
Agentcy
RAG agent + realms
cited answer
Output
Q&A
+ refs

At a glance

The agent's job: answer questions like "what did we decide about the auth migration last quarter?" by pulling from Google Workspace docs, Slack history, and Read.ai meeting transcripts — with citations to the original artifact.

Stack

  • Google Workspace Google Workspace — Drive, Docs, Sheets, Calendar, Gmail.
  • Slack Slack — channels, threads, message history.
  • Read.ai Read.ai — meeting transcripts, action items, topics.
  • RAG & Semantic Search — vector index over the ingested data.
  • Memory System — store curated facts the team has explicitly agreed on.
  • Realms — keep this knowledge in its own realm so it doesn't pollute infra/dev queries.

What you'll build

   Google Workspace, Slack, Read.ai → Ingestion pipeline → realm: knowledge

                                           fastembed (local)

                                           Neo4j HNSW vector index

   user asks in /chat ───►  Knowledge agent  ─────┘


                   answer with citations (Doc URL, Slack
                   permalink, Read.ai meeting + timestamp)

Three connectors feed an ingestion pipeline that lands content in the knowledge realm. Vector embeddings are computed locally by fastembed (no external embedding API needed). When a user asks a question, the agent uses rag.search to surface the top-K matching nodes and composes an answer with citations.

Prerequisites

  • Google Workspace OAuth — admin-installed in your org so the connector can read the docs you scope it to.
  • Slack — OAuth bot installed with channels:history, groups:history, users:read, files:read, pins:read, bookmarks:read.
  • Read.ai — OAuth flow.
  • A frontier-class LLM — recall returns up to top-K chunks; the LLM has to weave them into an answer with accurate citations.
  • Workers (recommended) — first-time ingestion of a year of Slack history is heavy. AGENTCY_FEATURES_WORKERS=true.

Step-by-step

1. Define the realm

Realms keep this knowledge from leaking into infrastructure or development queries.

text
1. Open /graph or /admin (whichever shows the Realms manager) →
   "+ New Realm".
2. Name: knowledge.
   Description: Institutional knowledge — docs, Slack history, meetings.
3. Save.
bash
curl -X POST http://localhost:8080/api/v1/realms \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"name":"knowledge","description":"Institutional knowledge: docs, Slack history, meetings"}'

2. Configure the connectors

Add Connector picker showing Google Workspace, Slack, Read.ai.

text
1. Open /connectors → click "+ Add Connector".
2. Pick Google Workspace → "Continue with OAuth". A Google sign-in
   tab opens; complete consent. Realm: knowledge.
3. Modules: tick Drive, Docs, Calendar, Gmail.
4. Repeat for Slack (use the same OAuth bot you set up for the
   Slack channel; History days = 365).
5. Repeat for Read.ai → "Continue with OAuth".
6. After each, click Test → green pill = ready.
bash
# Google Workspace (OAuth — finishes in browser)
curl -X POST http://localhost:8080/api/v1/sources \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{
    "name":"gw-main","connector":"google-workspace","realm":"knowledge",
    "config":{
      "auth":{"kind":"oauth"},
      "modules":["drive","docs","calendar","gmail"],
      "drive":{"shared_drives":["acme-eng","acme-product"]},
      "gmail":{"label_filter":["important","decisions"]}
    }
  }'

# Slack
curl -X POST http://localhost:8080/api/v1/sources \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{
    "name":"slack-history","connector":"slack","realm":"knowledge",
    "config":{
      "auth":{"kind":"bot_token","token":"xoxb-..."},
      "channels":["eng-decisions","product","architecture"],
      "history_days":365
    }
  }'

# Read.ai
curl -X POST http://localhost:8080/api/v1/sources \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{
    "name":"readai-meetings","connector":"readai","realm":"knowledge",
    "config":{
      "auth":{"kind":"oauth"},
      "modules":["meetings","transcripts","action_items"]
    }
  }'

3. First sync

text
1. Open /connectors → click each source → Sync now.
2. With Workers on, syncs run in background; you'll see a progress
   indicator that updates as nodes are ingested.
3. Slack history backfill is the slow one — for a busy workspace
   plan an hour or more. Subsequent runs are incremental and fast.
bash
curl -X POST "http://localhost:8080/api/v1/sources/$SLACK_SOURCE_ID/sync" \
  -H "authorization: Bearer $TOKEN" -d '{"mode":"full"}'

# Watch progress
curl "http://localhost:8080/api/v1/sources/$SLACK_SOURCE_ID/sync-history" \
  -H "authorization: Bearer $TOKEN" | jq

4. Wire a recurring pipeline

text
1. Open /ingest → "+ New Pipeline".
2. Name: knowledge-refresh. Realm: knowledge.
3. Schedule: 0 4 * * *  (daily at 04:00 UTC).
4. Steps: add the three sources, mode = incremental for each.
5. Save → a green pill "Next run in N hours" appears.
bash
curl -X POST http://localhost:8080/api/v1/pipelines \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{
    "name":"knowledge-refresh",
    "realm":"knowledge",
    "schedule":"0 4 * * *",
    "steps":[
      {"connector":"google-workspace","source_id":"src_gw_main","mode":"incremental"},
      {"connector":"slack","source_id":"src_slack_history","mode":"incremental"},
      {"connector":"readai","source_id":"src_readai_meetings","mode":"incremental"}
    ]
  }'

5. Verify the vector index

text
1. Open /chat → start a new conversation pinned to realm: knowledge.
2. Type: "auth migration" — the agent calls rag.search and shows
   hits with score + source URL in the right pane.
bash
curl -X POST http://localhost:8080/api/v1/rag/search \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"query":"auth migration","realms":["knowledge"],"top_k":5}'

If top_k returns 0 hits, the embedding pipeline didn't run — check GET /api/v1/rag/status.

6. Use it from chat

Chat surface where the agent answers with citations.

text
1. Open /chat → "+ New conversation". Realm: knowledge.
2. Ask: "What did we decide about migrating off Auth0 last quarter?
        Cite sources."
3. The agent returns an answer with clickable citation links.
4. To make it permanent, bind a Slack channel #ask-knowledge to the
   default agent in this realm — see the binding example below.
bash
CONV=$(curl -s http://localhost:8080/api/v1/chat/conversations \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"title":"auth migration history","realm":"knowledge"}' | jq -r .id)

curl -N -X POST "http://localhost:8080/api/v1/chat/conversations/$CONV/messages" \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{"content":"What did we decide about migrating off Auth0 last quarter? Cite sources."}'

Worked example

A "knowledge agent" that monitors #ask-knowledge in Slack and answers questions there. Bind it once and the team gets a queryable corporate memory.

bash
curl -X POST http://localhost:8080/api/v1/bindings \
  -H "authorization: Bearer $TOKEN" -H 'content-type: application/json' \
  -d '{
    "agent":"default",
    "match_rule":{"channel":"slack","slack_channel":"#ask-knowledge","preserve_thread":true}
  }'

A scoped policy that enforces realm and read-only:

rego
package agentcy.knowledge

# This agent must operate within the knowledge realm
deny[msg] {
  input.subject.channel == "slack"
  input.subject.binding_realm == "knowledge"
  input.resource.realm != "knowledge"
  msg := "knowledge agent must stay in knowledge realm"
}

# Read tools auto-allow; everything else needs approval
allow {
  input.resource.tool_effect == "read"
}

A short system note attached to the agent that nudges citation behavior:

You answer questions from the team's institutional knowledge. Always cite at
least one source per claim — a Google Doc URL, a Slack permalink, or a Read.ai
meeting URL with timestamp. If the corpus has no good answer, say so plainly;
never invent a citation.

What good looks like

In #ask-knowledge:

@alice: What did we decide about the Auth0 migration last quarter?

🤖 Agentcy:

Decision was to keep Auth0 for SSO and add an in-house token service for service-to-service — not a full migration. Driven by Q3 cost analysis showing Auth0 charges were dominated by M2M tokens.

Sources:

The transcript shows the agent called rag.search for "auth migration decision", then rag.search again for "auth0 SSO M2M cost", then composed.

Variations

  • Per-team scopes. Make a realm per team (knowledge-eng, knowledge-product, …). Each team's #ask-knowledge binding pins to the right realm.
  • Trust scoring. Add a step to the pipeline that tags each Google Doc with a confidence based on age. Prompt the agent to prefer high-confidence sources or flag low-confidence ones.
  • Email integration. Same connector, add gmail module with a label filter (label:decisions or label:important).
  • Slack message commit-back. When the team agrees on something in chat, react with :memo: and have a task pick up the message and write a Memory entry — making it permanently durable beyond Slack's history.
  • Curated facts via Memory. Use the Memory system for facts the team explicitly agrees on. Memories carry higher weight in recall than raw ingested chunks.

Troubleshooting

Recall returns 0 hits, but I know the doc exists. First check GET /api/v1/sources/$GW_SOURCE_ID/sync-history — was it ingested? If yes, inspect a sample node: GET /api/v1/graph/search?q=<doc-title>&realm=knowledge. If the node exists but recall doesn't find it, the embedding likely failed. Re-run with POST /api/v1/rag/reindex for that label.

Read.ai returns 401 after a few days. Their access tokens expire and refresh tokens are 30-day. The connector handles refresh automatically, but if no one signs into Agentcy for a while the refresh window can lapse. Re-authorize via the OAuth flow.

Citations link to private Slack messages people can't read. The bot saw them because it's in the channel; the user asking might not be. Add a check in the instruction: "only cite messages from public channels, or from channels the asking user is a member of."

The agent invents a citation that doesn't exist. Smaller models do this. Switch to a frontier model. Also strengthen the prompt: "If the corpus has no relevant source, say 'I don't see this in our records' — never invent."

Slack history backfill takes forever and dies. Slack's conversations.history API is rate-limited. The connector handles 429 gracefully but huge backfills are slow. Either narrow channels in the source config or set history_days: 90 for an initial sync; widen later.

Next

Built by AgentcyLabs. For in-house deployment or Agentcy Cloud (PaaS) access, visit agentcylabs.com.