KnowledgeFlow: Answer questions across documentation silos
from the links writers already maintain
Disclaimer. This is a portfolio design document. Google has not engaged, sponsored or endorsed this work. The sample content is adapted from the Cloud TPU and Cloud NAT documentation, which Google publishes under the Creative Commons Attribution 4.0 licence1. The adapted versions are modified from the originals. The sample questions, issues and pull requests are written for this document. Stakeholders are job roles, not real people. The two readers in §3 are fictional.
structure, with no model call
used only with a label
without a checked source
Product teams write Google's data center documentation. Each team keeps its own documentation set, and each set links well inside itself. Questions from employees often cross sets. In the 2024 Stack Overflow survey, 61% of professional developers spent more than 30 minutes a day searching for answers, and 30% said knowledge silos affected their productivity ten or more times a week2.
KnowledgeFlow is an agent that answers an employee's question with a cited path across documentation sets. It builds a knowledge graph from the structure that writers already maintain: DITA maps, relationship tables, keys, content references, cross-references and subject classifications. Gemini reads prose only to find mentions that have no link. Each edge it finds stays proposed until an information architect approves it.
Fixed checks decide whether an answer is grounded. Every step must cite a topic and the edge that reached it, and every value must match its source. When a step fails, KnowledgeFlow drops that step, says so, and opens a gap issue for writers. An approved edge becomes a relationship table row in the source, so the next build reads it without the model.
§1 Client Brief
Google publishes documentation for its data center products and services. Two of those products are Cloud TPU (Tensor Processing Unit) accelerators and Cloud NAT (network address translation). Different teams write the two documentation sets, and each product publishes release notes.
This MVP uses three samples from the first two projects in this series. The Cloud TPU sample is the DITA set from MANIFEST, with its maps, keys and relationship tables3. The Cloud NAT sample is the MyST Markdown set from the Autonomous Author4. The third sample is the Cloud NAT release notes10. One set is still in DITA and one is already docs as code. That is the state of a team during a migration, and KnowledgeFlow reads both.
The samples are a good test because a real question crosses them. An engineer who creates a TPU VM without an external IP address, and then needs the internet, finds half the answer in the TPU docs and half in the Cloud NAT docs (§2.1). The published pages give the reference answer for each step.
| Term | Meaning in this document | Example |
|---|---|---|
| Documentation set | The topics that one team writes and publishes for one product. | Cloud TPU docs; Cloud NAT docs |
| DITA map | A file that lists topics and their hierarchy. | tpu.ditamap |
| Relationship table | A table in a map. Each row relates the topics referenced in its cells11. | A task row joined to its concept and reference topics |
| Key and content reference | A key stores a value once. A content reference (conref) reuses an element. MANIFEST keeps both as MyST substitutions and includes3. | tpu7x-chips-per-pod = 9,2165 |
| Subject scheme | A map that defines subjects, such as products and features, and their controlled terms12. Topics are classified with subject references13. | Subject no-external-ip |
| Knowledge graph | Nodes (topics, values, subjects) joined by typed edges. | configure-networking -[about]-> no-external-ip |
| Authored and proposed edge | An authored edge comes from a line that a writer wrote. A proposed edge comes from Gemini and carries a label until a person approves it. | about (authored); mentions (proposed) |
| Grounded answer | An answer where every step cites a topic and the edge that reached it, and every value appears in that topic. | Figure 8 |
| Gap issue | A docs issue that records a step the graph could not answer, with the edge that is missing. | Issue #58 |
§2 Problem Statement
Writers link topics well inside a documentation set. A link across sets needs a writer who knows the other product. Site search covers one set at a time, and it returns pages, not the path between them. Employees fill the gap by asking colleagues, and 53% of professional developers say that waiting for answers disrupts their workflow2.
Figure 2 follows one real question through the published pages. Every step has an answer somewhere. One join between the steps is missing.
| Step | Where the answer is | Join from the step before | Status |
|---|---|---|---|
| 1. Create a TPU VM without an external IP address | TPU docs, Configure networking and access: the --no-address or --internal-ips flag67 | Start | Start |
| 2. Reach Google APIs, such as Cloud Storage | Same page: Private Google Access7 | Link on the same page | Linked |
| 3. Reach a destination on the internet, such as a public package index | Cloud NAT docs, Cloud NAT overview: Public NAT8 | No link from either TPU page | Missing |
| 4. Check the timeout when connections drop | Cloud NAT docs, Tune NAT configuration9 | Same documentation set as step 3 | Same set |
| Option | What it does | What it misses | Result |
|---|---|---|---|
| Site search for each set | Finds pages inside one documentation set. | Pages in other sets. The path between pages. | One silo |
| Ask an expert | A person who knows both products answers. | Costs expert time, and the asker waits2. The answer stays in chat. | Slow |
| Vector search over all docs | Finds chunks with similar wording. | Steps that use different words. In VaultRAG, a fuse replacement query missed the isolation procedure in the same SOP for this reason18. | Misses joins |
| Graph built by a language model | GraphRAG uses a language model to extract a graph from every document15. LazyGraphRAG avoids the upfront summarisation cost16. | Every edge is a model guess. The structure that writers already maintain is ignored. | Inferred |
| Enterprise graph platform | The original KnowledgeFlow v2.1 design: Neo4j Aura Enterprise, GKE and a SIEM audit layer17. | Its pilot tier needs about €5,800 a month in infrastructure17. | Costly |
| KnowledgeFlow | Builds the graph from DITA and MyST structure. Uses Gemini only for unlinked mentions. Answers with a checked path. | Cannot join two sets that share no subject, link or named entity. It reports the gap instead (§5.4). | Checked |
§3 User Profiles
Five roles at Google run or depend on KnowledgeFlow. Two readers ask it questions.
§4 User Stories
Each story comes from the Goal and Success fields in §3. The acceptance criteria are what the checks in §5 test.
§5 Proposed Design
KnowledgeFlow does one thing. It answers an employee's question with a path through the documentation, and it checks every step of the path. It is an agent built with Agent Development Kit (ADK), Google's open-source agent framework. ADK is licensed under Apache 2.0 and its agents can run on Cloud Run19. Gemini 3.8 Flash (gemini-3.8-flash, a stable model20) runs the agent and calls its tools through Gemini function calling21. The embedding model gemini-embedding-001 finds entry topics by meaning22.
The agent has six plain Python tools that give the same result every time, and two model steps. Gemini proposes edges from prose, and it writes the answer. The checks decide whether each step is grounded. The agent cannot change a check result, and it cannot add an edge to the graph as authored.
KnowledgeFlow has two parts. The build runs on every docs merge. It reads the structure of each documentation set and writes the graph. The answer runs on every question. It finds entry topics, walks the graph and writes a checked answer. Figure 4 adds KnowledgeFlow to the system in Figure 1.
The graph has four node types and seven edge types. Six edge types come from structure. KnowledgeFlow reads them with lxml from DITA maps and topics, and with MyST-Parser from MyST pages, where MANIFEST kept reuse as includes, substitutions and targets3. One edge type comes from the model.
| Edge | Read from | Meaning | Status |
|---|---|---|---|
contains | Map hierarchy (topicref nesting), or the MyST table of contents | The topic is part of this map or section. | Authored |
related | Relationship table row11 | A task is supported by these concept and reference topics. | Authored |
reuses | Conref, or MyST include3 | The topic shares this element. | Authored |
states | Key reference, or MyST substitution3 | The topic states this value. | Authored |
links-to | Cross-reference, or MyST link | The topic sends the reader to another topic. | Authored |
about | Subject reference in a topic or map13 | The topic is about this subject. | Authored |
mentions | Gemini, from prose that has no link | The topic names this subject but does not link to it. | Proposed |
MANIFEST has no mapping for relationship tables. KnowledgeFlow reads them from the DITA source, which MANIFEST leaves unchanged3.
A shared subject scheme joins the sets. Each team classifies its own topics against the same subjects, once. Writers do not maintain a link from every TPU topic to every networking topic. The DITA standard expects this use: tools such as search tools can use subject classifications to find related content14.
One real thing is one node. Subject nodes take their names and aliases from the subject scheme, key names and topic titles. The TPU7x page is titled TPU7x (Ironwood), so both names resolve to one subject5. A name with no match in the subject scheme never becomes a new subject on its own. It becomes a proposal for the information architect.
1 · Build the graph build_graph
Runs in GitHub Actions on every merge to a documentation set. Parses DITA maps and topics with lxml, and MyST pages with MyST-Parser. Writes one document for each node and edge it reads, with the file and line it came from. Makes no model call.
2 · Propose unlinked mentions (Gemini) propose_mentions
Gemini reads the prose of changed topics and lists subjects that a topic names but does not link. Each proposal must quote its sentence. A fixed check keeps a proposal only when the subject name or one of its aliases appears in that sentence. Proposals that pass are stored as mentions edges with the status proposed.
3 · Find entry topics find_entry
Finds the topics where an answer starts. SQLite FTS5 ranks exact terms, such as flags, commands and version strings, with BM2525. Firestore vector search finds topics by meaning with a K-nearest-neighbour query23. Aliases resolve first, so Ironwood finds TPU7x topics.
4 · Walk the graph walk_graph
Follows typed edges from the entry topics, up to three hops. It follows authored edges first, and proposed edges only when no authored path exists. It applies the audience and generation filter from the subject scheme, so a TPU7x question does not reach v5e values.
5 · Compose the answer (Gemini) compose
Gemini writes the answer as numbered steps. Each step cites one topic and the edge that reached it, from the candidate paths only. Gemini may restate text from that topic. It may not add facts from outside the paths. On a failed check, it revises only the failed steps.
6 · Check the answer check_answer
Runs four checks. Source: every step cites a topic in the candidate paths. Literals: every number, unit, flag, field and command in a step appears in its topic or in its key value. Path: each cited topic is joined to the question's entry topics by edges in the graph. Labels: every step reached through a proposed edge carries a label.
7 · Report the gap report_gap
Runs when a step still fails after two revisions. The agent drops the step and tells the employee what it could not answer. This tool opens one docs issue for each missing edge, with the question, the topics reached, the failed step and a suggested relationship table row. A repeat question adds to the same issue. Every question writes one row to the question log.
8 · Turn approved edges into structure record_review
For each proposed edge that an answer used, opens a pull request that adds the edge as a relationship table row in the DITA map, or as a link in the MyST page. Branch protection requires the information architect's approval33. After merge, the next build reads the edge as authored. A closed pull request is stored as rejected, so Gemini does not propose that edge again.
The agent runs find_entry and walk_graph, then asks Gemini to compose. check_answer tests every step. When a step fails, Gemini reads the reason and revises only that step, and the checks run again. After two failed revisions, the agent drops the step, says so in the answer, and report_gap opens an issue. No step reaches the employee without a passing check.
The build follows the same rule. Gemini proposes, a check filters, and a person approves. As approved edges become structure, fewer edges are proposed, so the model is called less at build time.
Figure 7 shows the path for Lena's question, scenario 2 in §6. Two about edges join the sets. Both come from subject references that the information architect added to the sample sets.
Microsoft's guidance is that GraphRAG suits a use case only when its benefits outweigh the upfront cost of building the graph index15. For DITA content, most of that index already exists.
| Approach | How edges are made | Model use at build time | What an edge is worth |
|---|---|---|---|
| GraphRAG | A language model extracts a graph from every document15. | Every document | Inferred |
| LazyGraphRAG | No prior summarisation of the source data. A relevance test budget sets the cost and quality at query time16. | Low at build time; model calls move to query time | Inferred |
| KnowledgeFlow | Read from maps, relationship tables, keys, conrefs, links and subject references. Gemini proposes only unlinked mentions. | Prose of changed topics only; falls as proposals are approved | Authored edges trace to a line |
The build logs the number of edges from each source and the model tokens it used. So the share of edges that cost no model call is measured on every build, not estimated (§7).
| Part | Service | Note |
|---|---|---|
| Graph build | GitHub Actions, on merge to a documentation set | Standard runners are free for public repositories28. |
| Graph store | Firestore, one document for each node and edge. The agent loads the graph into NetworkX when it starts. | Free quota: 50,000 reads and 20,000 writes a day, on one database for each project24. NetworkX uses the 3-clause BSD licence26. Limit: an in-memory graph suits the sample sets. A full documentation set needs a graph database, and Spanner Graph has a 90-day free trial, then needs the Enterprise edition27. |
| Entry search | Firestore vector search with gemini-embedding-001; SQLite FTS5 in the agent container | K-nearest-neighbour queries23. The embedding model has a free tier22. FTS5 has BM25 ranking built in25. |
| Agent | Cloud Run service, one request for each question | Free tier: 180,000 vCPU-seconds and 2 million requests a month29. |
| Question log | BigQuery | Free tier: 10 GiB storage and 1 TiB of queries a month30. |
| Ask page | Firebase Hosting | No-cost plan: 10 GB storage and 360 MB of data transfer a day31. Limit: the sample docs are public, so the MVP has no access control for each set. Private docs need it. |
| Model | Gemini API, gemini-3.8-flash | The free tier is acceptable here because the sample content is public. Free tier content is used to improve Google products, so private docs need the paid tier. The paid tier costs $0.75 per million input tokens and $3.75 per million output tokens until 31 December 202632. Each question logs its tokens, so the cost of an answer is measured, not estimated. |
§6 Answer Simulator
The simulator runs three sample questions through KnowledgeFlow. Each run shows the tools in order and the log that the agent writes. The runs are scripted to show the design. They do not call Gemini, Firestore or GitHub.
// choose a sample question and run it
§7 Success Metrics
The MVP runs on the three sample sets and an evaluation set of 30 questions. Each question has a reference path, written from the published pages, and half the questions cross documentation sets. The MVP succeeds if the numbers below are met. The first metric matters most: an answer with one unchecked step is worse than an answer that says what it could not find.
| Metric | How it is measured | MVP target |
|---|---|---|
| Unchecked steps delivered | Answer steps that reached the asker without a passing check, from a review of every answer in the evaluation set | 0 |
| Steps with a cited topic and edge | Steps with a citation ÷ steps delivered | 100% |
| Cross-set questions answered with a full path | Cross-set questions whose answer cites every topic in the reference path | Higher than a vector-search-only baseline on the same questions |
| Values that match their key | Keyed values in answers that equal the key value, for the right generation | 100% |
| Proposed edges labelled | Steps that use a proposed edge and carry the label ÷ steps that use a proposed edge | 100% |
| Dropped steps with a gap issue | Dropped steps that opened or updated a gap issue | 100% |
| Edges from structure | Authored edges ÷ all edges, from the build log | Reported on every build |
| Model tokens per build | Tokens used by propose_mentions, from the build log | Falls as proposed edges are approved |
| Time to answer | Question received to answer shown, from the question log | Under 20 seconds on the sample sets |
Question
Connections from our TPU VMs through Cloud NAT drop under load. Which timeout applies, and what is our gateway's default?
Answer
| Step | Source | Check |
|---|---|---|
| 1. Your TPU VMs have no external IP addresses, so Cloud NAT gives them shared external addresses for outbound connections. | nat/overview, reached by about | pass |
2. The default TCP TIME_WAIT timeout is 30 seconds for gateways created after 30 September 2026, and 120 seconds for older gateways. | nat/tune-nat-configuration, key nat_tcp_time_wait_default | literals 3/3 |
3. To see the value in effect, run gcloud compute routers nats describe and read effectiveTcpTimeWaitTimeoutSec. | nat/tune-nat-configuration | literals 2/2 |
| 4. Google announced the new default on 31 March 2026. | release-notes/2026-03-31, reached by a proposed edge | unreviewed link |
Path
- authored
configure-networking -[about]-> no-external-ip(subject reference, TPU map) - authored
nat/overview -[about]-> no-external-ip(subject reference, NAT page) - authored
nat/overview -[links-to]-> nat/tune-nat-configuration - authored
nat/tune-nat-configuration -[states]-> nat_tcp_time_wait_default - proposed
release-notes/2026-03-31 -[mentions]-> tcp-time-wait
Sent to people
- dropped The first draft had a step that said to restart the TPU VMs to apply the change. No topic in the paths states it. Gemini removed it in revision 1.
- edge PR #57 For the information architect: add a link from the 31 March 2026 release note to Tune NAT configuration. The quoted sentence is attached.
- logged One row in the question log, with tokens, time and the edges used.
Sources
Checked on 19 October 2026.
- Google Developers, "Site Policies." developers.google.com/site-policies
- Stack Overflow, "2024 Developer Survey: Professional developers." survey.stackoverflow.co/2024/professional-developers
- Siddharth Rao, "MANIFEST: Migrate DITA to Markdown without losing content," design document. siddharthraop.github.io/Manifest
- Siddharth Rao, "The Autonomous Author," design document. siddharthraop.github.io/The-Autonomous-Author
- Google Cloud, "TPU7x (Ironwood)." docs.cloud.google.com/tpu/docs/tpu7x
- Google Cloud, "Configure networking and access to your Cloud TPU," last updated 5 August 2026. docs.cloud.google.com/tpu/docs/configure-networking-access
- Google Cloud, "Configure networking and access to a TPU instance," last updated 9 September 2026. docs.cloud.google.com/tpu/docs/configure-networking-access-compute
- Google Cloud, "Cloud NAT overview." docs.cloud.google.com/nat/docs/overview
- Google Cloud, "Tune NAT configuration." docs.cloud.google.com/nat/docs/tune-nat-configuration
- Google Cloud, "Cloud NAT release notes." docs.cloud.google.com/nat/docs/release-notes
- DITA language reference, "reltable." dita-lang.org/dita/langref/base/reltable
- DITA language reference, "subjectdef." dita-lang.org/dita/langref/base/subjectdef
- OASIS, DITA 1.3 specification, "subjectref." docs.oasis-open.org/dita/dita/v1.3/.../subjectref.html
- DITA 1.3 language reference, "topicSubjectTable," as published in the Adobe FrameMaker documentation. help.adobe.com/.../topicSubjectTable.html
- Pure AI, "Microsoft Open Sources AI Tool for Exploring Large Document Datasets," July 2024. pureai.com/Articles/2024/07/12/Microsoft-Open-Sources-AI-Tool.aspx
- Microsoft Research, "LazyGraphRAG: Setting a new standard for quality and cost." microsoft.com/en-us/research/blog/lazygraphrag-setting-a-new-standard-for-quality-and-cost
- Siddharth Rao, "KnowledgeFlow: Enterprise Knowledge Graph Architecture v2.1" (Agentic Org Memory). github.com/raosiddharthp/Agentic-Org-Memory
- Siddharth Rao, "VaultRAG." github.com/raosiddharthp/VaultRAG
- Google, Agent Development Kit documentation README. github.com/google/adk-docs
- Google AI for Developers, "Gemini models." ai.google.dev/gemini-api/docs/models
- Google AI for Developers, "Function calling with the Gemini API." ai.google.dev/gemini-api/docs/function-calling
- Google Developers Blog, "Gemini Embedding now generally available in the Gemini API." developers.googleblog.com/en/gemini-embedding-available-gemini-api
- Google Cloud, "Search with vector embeddings" (Firestore). cloud.google.com/firestore/docs/vector-search
- Google Cloud, "Firestore pricing." cloud.google.com/firestore/pricing
- SQLite, "SQLite FTS5 Extension: The bm25() function." sqlite.org/fts5.html
- NetworkX, "License." networkx.org/documentation/networkx-2.5/license.html
- Google Codelabs, "Getting started with Spanner Graph." codelabs.developers.google.com/codelabs/spanner-graph-getting-started
- GitHub Docs, "How use of GitHub Actions is measured." docs.github.com/en/billing/concepts/product-billing/github-actions
- Google Cloud, "Cloud Run pricing." cloud.google.com/run/pricing
- Google Cloud, "BigQuery pricing." cloud.google.com/bigquery/pricing
- Firebase, "Pricing." firebase.google.com/pricing
- Google AI for Developers, "Gemini Developer API pricing." ai.google.dev/gemini-api/docs/pricing
- GitHub Docs, "About protected branches." docs.github.com/.../about-protected-branches