A knowledge graph we genuinely wanted to build
This project was really fun because all three of us played Clash Royale. For our IF4070 Knowledge Representation and Reasoning assignment, we needed to build a RAG system backed by a knowledge graph. Once we realized we shared the same game, the domain choice felt natural.
We were not learning Clash Royale only for the assignment. We already had opinions about decks, counters, synergies, and archetypes, which meant we could notice when an answer sounded plausible but did not make sense to an actual player.
The work continued from an earlier rule-based system written in Prolog. This assignment asked us to represent the domain as a knowledge graph, so cards became Neo4j nodes connected through relationships such as counters, synergies, and archetype membership.
The difficult part was not creating nodes. It was deciding what a relationship should mean. A graph is only as useful as the abstractions behind its edges, and Clash Royale knowledge contains far more context than a simple list of card statistics.
Turning the pipeline into a usable product
Derwin created the initial knowledge-graph and RAG pipeline. I focused on integrating that pipeline into the rest of the application, building the interface, and refining rules when the answers did not reflect how we understood the game.
The interface exposed useful intermediate stages, including the generated query and retrieved results. That made the system easier to demonstrate, but it was equally valuable for debugging because we could see whether a bad answer began with the question, the Cypher query, the graph, or the final generation step.
General questions travel through the language model and Neo4j, but deck analysis follows deterministic rules. That separation began as part of the specification, then became a design choice we genuinely believed in.
The generative model did not have enough reliable Clash Royale knowledge to judge every deck on its own. Grounding it with retrieved facts reduced that uncertainty, while the rule-based path gave important deck checks a more predictable foundation.
P.E.K.K.A. was an edge case in punctuation
One surprisingly memorable failure came from P.E.K.K.A. A player naturally types “pekka,” but the graph stored the official name with periods, so an exact lookup could not find it.
I added preprocessing and fuzzy name correction so informal capitalization, spelling, and punctuation could still resolve to the correct card. It was a small feature, but it showed how quickly a technically correct knowledge base can become unusable when it does not understand the language of its users.
We also found that the language model sometimes shortened complete graph results. That may produce a cleaner sentence, but it hides information the retrieval system actually found.
I hardened the prompts and interface so users could inspect the underlying results and receive the full list when completeness mattered. For this project, a confident answer was not enough. We wanted the evidence behind it to remain visible.
Our favorite game became domain expertise
The relationship and deck rules combined our experience playing Clash Royale with knowledge gathered from YouTube and other game resources. Beatdown was my favorite archetype, so seeing the analyzer recognize its heavy pushes and warn about an unbalanced deck felt especially personal.
This was also where the hardest design problem lived. Statistics can suggest that two cards work together, but strong game knowledge often depends on timing, roles, and strategy that are difficult to compress into a single edge.
We initially ran a local language model, and it was heavy. The dependency and runtime constraints made every iteration slower, while the model still lacked much of the specialized knowledge we needed.
That experience made the architecture feel less like a fashionable combination of technologies and more like a set of tradeoffs. The LLM was useful for translating questions and explaining retrieved facts, but the graph, rules, and human knowledge carried the domain itself.
If I rebuilt this project, I would spend more time improving the abstraction of its knowledge. Better relationships and clearer rules would give every later stage a stronger foundation.
The lesson that stayed with me is simple: AI needs human knowledge and expertise to function properly. A model can phrase an answer fluently, but people still have to decide what is true, what should be connected, and when generation should give way to deterministic reasoning.
What stayed with me
- A knowledge graph is only as good as the meaning behind its edges.
- Transparency is part of correctness.
- Not every answer belongs to the LLM.
- AI still needs someone who understands the domain.
Run it locally
Clone the source repository or download the project ZIP, then run these commands from the project folder.
Explore the complete project
Download the source, assets, and included documentation as a ZIP archive.
Setup
$ cp .env.example .env
# add your GEMINI_API_KEY (or LLM_PROVIDER=openrouter with OPENROUTER_API_KEY)
$ docker compose up -d neo4j
$ uv sync
$ uv run python -m src.kg.ingestion
# ingests 178 Clash Royale cards into Neo4j
Run
$ uv run python run_web.py
# open http://localhost:8000 and ask 'What cards counter Giant?'
# or 'Analyze my deck: Hog Rider, Musketeer, Cannon, Fireball, Zap, ...'




