{"id":3901,"date":"2025-05-17T07:04:49","date_gmt":"2025-05-17T07:04:49","guid":{"rendered":"https:\/\/mailitics.com\/index.php\/2025\/05\/17\/how-to-build-an-ai-journal-to-build-your-own-principles\/"},"modified":"2025-05-17T07:04:49","modified_gmt":"2025-05-17T07:04:49","slug":"how-to-build-an-ai-journal-to-build-your-own-principles","status":"publish","type":"post","link":"https:\/\/mailitics.com\/index.php\/2025\/05\/17\/how-to-build-an-ai-journal-to-build-your-own-principles\/","title":{"rendered":"How to Build an AI Journal with LlamaIndex"},"content":{"rendered":"<p>    How to Build an AI Journal with LlamaIndex<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n    <!-- no image --><br \/>\n \t<BR><br \/>\n<BR><\/BR><\/p>\n<div>\n<p class=\"wp-block-paragraph\"><mdspan datatext=\"el1747426306756\" class=\"mdspan-comment\">This post <\/mdspan>will share how to build an AI journal with the <a href=\"https:\/\/www.llamaindex.ai\/\">LlamaIndex<\/a>. We will cover one essential function of this AI journal: asking for advice. We will start with the most basic implementation and iterate from there. We can see significant improvements for this function when we apply design patterns like <a href=\"https:\/\/towardsdatascience.com\/tag\/agentic-rag\/\" title=\"Agentic Rag\">Agentic Rag<\/a> and multi-agent workflow.<\/p>\n<p>You can find the source code of this AI Journal in my GitHub repo <a href=\"https:\/\/github.com\/PepperStudio77\/principle-master\">here<\/a>. And about <a href=\"https:\/\/www.linkedin.com\/in\/ming-gao-57509a101\/\">who I am<\/a>.<\/p>\n<h2 class=\"wp-block-heading\">Overview of AI Journal<\/h2>\n<p class=\"wp-block-paragraph\">I want to build my principles by following Ray Dalio\u2019s practice. An <a href=\"https:\/\/towardsdatascience.com\/tag\/ai\/\" title=\"AI\">AI<\/a> journal will help me to self-reflect, track my improvement, and even give me advice. The overall function of such an AI journal looks like this:<\/p>\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" height=\"1011\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/05\/ai_journal_overview-1-1024x1011.png?resize=1024%2C1011&#038;ssl=1\" alt=\"\" class=\"wp-image-604265\"><figcaption class=\"wp-element-caption\">AI Journal Overview. Image by Author.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Today, we will only cover the implementation of the seek-advise flow, which is represented by multiple purple cycles in the above diagram.  <\/p>\n<h2 class=\"wp-block-heading\">Simplest Form: LLM with Large Context<\/h2>\n<p class=\"wp-block-paragraph\">In the most straightforward implementation, we can pass all the relevant content into the context and attach the question we want to ask. We can do that in <a href=\"https:\/\/towardsdatascience.com\/tag\/llamaindex\/\" title=\"Llamaindex\">Llamaindex<\/a> with a few lines of code. <\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">import pymupdf\nfrom llama_index.llms.openai import OpenAI\n\npath_to_pdf_book = '.\/path\/to\/pdf\/book.pdf'\ndef load_book_content():\n    text = \"\"\n    with pymupdf.open(path_to_pdf_book) as pdf:\n        for page in pdf:\n            text += str(page.get_text().encode(\"utf8\", errors='ignore'))\n    return text\n\nsystem_prompt_template = \"\"\"You are an AI assistant that provides thoughtful, practical, and *deeply personalized* suggestions by combining:\n- The user's personal profile and principles\n- Insights retrieved from *Principles* by Ray Dalio\nBook Content: \n```\n{book_content}\n```\nUser profile:\n```\n{user_profile}\n```\nUser's question:\n```\n{user_question}\n```\n\"\"\"\n\ndef get_system_prompt(book_content: str, user_profile: str, user_question: str):\n    system_prompt = system_prompt_template.format(\n        book_content=book_content,\n        user_profile=user_profile,\n        user_question=user_question\n    )\n    return system_prompt\n\ndef chat():\n    llm = get_openai_llm()\n    user_profile = input(\"&gt;&gt;Tell me about yourself: \")\n    user_question = input(\"&gt;&gt;What do you want to ask: \")\n    user_profile = user_profile.strip()\n    book_content = load_book_summary()\n    response = llm.complete(prompt=get_system_prompt(book_content, user_profile, user_question))\n    return response<\/code><\/pre>\n<p class=\"wp-block-paragraph\">This approach has downsides:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Low Precision: Loading all the book context might prompt LLM to lose focus on the user\u2019s question.<\/li>\n<li class=\"wp-block-list-item\">High Cost: Sending over significant-sized content in every LLM call means high cost and poor performance.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">With this approach, if you pass the whole content of Ray Dalio\u2019s Principles book, responses to questions like \u201cHow to handle stress?\u201d become very general. Such responses without relating to my question made me feel that the AI was not listening to me. Even though it covers many important concepts like <em>embracing reality<\/em>, <em>the 5-step process to get what you want<\/em>, and <em>being radically open-minded<\/em>. I like the advice I got to be more targeted to the question I raised. Let\u2019s see how we can improve it with RAG.<\/p>\n<h2 class=\"wp-block-heading\">Enhanced Form: Agentic RAG<\/h2>\n<p class=\"wp-block-paragraph\">So, what is Agentic RAG? Agentic RAG is combining dynamic decision-making and data retrieval. In our AI journal, the Agentic RAG flow looks like this:<\/p>\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" height=\"309\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/05\/rag-stages-1024x309.png?resize=1024%2C309&#038;ssl=1\" alt=\"\" class=\"wp-image-604203\"><figcaption class=\"wp-element-caption\">Stages of Agentic Rag. Image by Author<\/figcaption><\/figure>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Question Evaluation: Poorly framed questions lead to poor query results. The agent will evaluate the user\u2019s query and clarify the questions if the Agent believes it is necessary. <\/li>\n<li class=\"wp-block-list-item\">Question Re-write: Rewrite the user enquiry to project it to the indexed content in the semantic space. I found these steps essential for improving the precision during the retrieval. Let\u2019s say if your knowledge base is Q\/A pair and you are indexing the questions part to search for answers. Rewriting the user\u2019s query statement to a proper question will help you find the most relevant content. <\/li>\n<li class=\"wp-block-list-item\">Query Vector Index: Many parameters can be tuned when building such an index, including chunk size, overlap, or a different index type. For simplicity, we are using VectorStoreIndex here, which has a default chunking strategy. <\/li>\n<li class=\"wp-block-list-item\">Filter &amp; Synthetic: Instead of a complex re-ranking process, I explicitly instruct LLM to filter and find relevant content in the prompt. I see LLM picking up the most relevant content, even though sometimes it has a lower similarity score than others. <\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">With this Agentic RAG, you can retrieve highly relevant content to the user\u2019s questions, generating more targeted advice.<\/p>\n<p class=\"wp-block-paragraph\">Let\u2019s examine the implementation. With the LlamaIndex SDK, creating and persisting an index in your local directory is straightforward. <\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from llama_index.core import Document, VectorStoreIndex, StorageContext, load_index_from_storage\n\nSettings.embed_model = OpenAIEmbedding(api_key=\"ak-xxxx\")\nPERSISTED_INDEX_PATH = \"\/path\/to\/the\/directory\/persist\/index\/locally\"\n\ndef create_index(content: str):\n    documents = [Document(text=content)]\n    vector_index = VectorStoreIndex.from_documents(documents)\n    vector_index.storage_context.persist(persist_dir=PERSISTED_INDEX_PATH)\n\ndef load_index():\n    storage_context = StorageContext.from_defaults(persist_dir=PERSISTED_INDEX_PATH)\n    index = load_index_from_storage(storage_context)\n    return index<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Once we have an index, we can create a query engine on top of that. The query engine is a powerful abstraction that allows you to adjust the parameters during the query(e.g., TOP K) and the synthesis behaviour after the content retrieval. In my implementation, I overwrite the response_mode  <code>NO_TEXT<\/code> because the agent will process the book content returned by the function call and synthesize the final result. Having the query engine to synthesize the result before passing it to the agent would be redundant. <\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">from llama_index.core.indices.vector_store import VectorIndexRetriever\nfrom llama_index.core.query_engine import RetrieverQueryEngine\nfrom llama_index.core.response_synthesizers import ResponseMode\nfrom llama_index.core import  VectorStoreIndex, get_response_synthesizer\n\ndef _create_query_engine_from_index(index: VectorStoreIndex):\n    # configure retriever\n    retriever = VectorIndexRetriever(\n        index=index,\n        similarity_top_k=TOP_K,\n    )\n    # return the original content without using LLM to synthesizer. For later evaluation.\n    response_synthesizer = get_response_synthesizer(response_mode=ResponseMode.NO_TEXT)\n    # assemble query engine\n    query_engine = RetrieverQueryEngine(\n        retriever=retriever,\n        response_synthesizer=response_synthesizer\n    )\n    return query_engine<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The prompt looks like the following:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-markup\">You are an assistant that helps reframe user questions into clear, concept-driven statements that match \nthe style and topics of Principles by Ray Dalio, and perform look up principle book for relevant content. \n\nBackground:\nPrinciples teaches structured thinking about life and work decisions.\nThe key ideas are:\n* Radical truth and radical transparency\n* Decision-making frameworks\n* Embracing mistakes as learning\n\nTask:\n- Task 1: Clarify the user's question if needed. Ask follow-up questions to ensure you understand the user's intent.\n- Task 2: Rewrite a user\u2019s question into a statement that would match how Ray Dalio frames ideas in Principles. Use formal, logical, neutral tone.\n- Task 3: Look up principle book with given re-wrote statements. You should provide at least {REWRITE_FACTOR} rewrote versions.\n- Task 4: Find the most relevant from the book content as your fina answers.<\/code><\/pre>\n<p class=\"wp-block-paragraph\">Finally, we can build the agent with those functions defined.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">def get_principle_rag_agent():\n    index = load_persisted_index()\n    query_engine = _create_query_engine_from_index(index)\n\n    def look_up_principle_book(original_question: str, rewrote_statement: List[str]) -&gt; List[str]:\n        result = []\n        for q in rewrote_statement:\n            response = query_engine.query(q)\n            content = [n.get_content() for n in response.source_nodes]\n            result.extend(content)\n        return result\n\n    def clarify_question(original_question: str, your_questions_to_user: List[str]) -&gt; str:\n        \"\"\"\n        Clarify the user's question if needed. Ask follow-up questions to ensure you understand the user's intent.\n        \"\"\"\n        response = \"\"\n        for q in your_questions_to_user:\n            print(f\"Question: {q}\")\n            r = input(\"Response:\")\n            response += f\"Question: {q}nResponse: {r}n\"\n        return response\n\n    tools = [\n        FunctionTool.from_defaults(\n            fn=look_up_principle_book,\n            name=\"look_up_principle_book\",\n            description=\"Look up principle book with re-wrote queries. Getting the suggestions from the Principle book by Ray Dalio\"),\n        FunctionTool.from_defaults(\n            fn=clarify_question,\n            name=\"clarify_question\",\n            description=\"Clarify the user's question if needed. Ask follow-up questions to ensure you understand the user's intent.\",\n        )\n    ]\n\n    agent = FunctionAgent(\n        name=\"principle_reference_loader\",\n        description=\"You are a helpful agent will based on user's question and look up the most relevant content in principle book.n\",\n        system_prompt=QUESTION_REWRITE_PROMPT,\n        tools=tools,\n    )\n    return agent\n\nrag_agent = get_principle_rag_agent()\nresponse = await agent.run(chat_history=chat_history)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">There are a few observations I had during the implementations:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">One interesting fact I found is that providing a non-used parameter, <code>original_question<\/code> , in the function signature helps. I found that when I do not have such a parameter, LLM sometimes does not follow the rewrite instruction and passes the original question in <code>rewrote_statement<\/code> the parameter. Having <code>original_question<\/code> parameters somehow emphasizes the rewriting mission to LLM. <\/li>\n<li class=\"wp-block-list-item\">Different LLMs behave quite differently given the same prompt. I found DeepSeek V3 much more reluctant to trigger function calls than other model providers. This doesn\u2019t necessarily mean it is not usable. If a functional call should be initiated 90% of the time, it should be part of the workflow instead of being registered as a function call. Also, compared to OpenAI\u2019s models, I found Gemini good at citing the source of the book when it synthesizes the results. <\/li>\n<li class=\"wp-block-list-item\">The more content you load into the context window, the more inference capability the model needs. A smaller model with less inference power is more likely to get lost in the large context provided.<\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\">However, to complete the seek-advice function,  you\u2019ll need multiple Agents working together instead of a single Agent. Let\u2019s talk about how to chain your Agents together into workflows.<\/p>\n<h2 class=\"wp-block-heading\">Final Form: Agent Workflow<\/h2>\n<p class=\"wp-block-paragraph\">Before we start, I recommend this article by Anthropic, <a href=\"https:\/\/www.anthropic.com\/engineering\/building-effective-agents\">Building Effective Agents.<\/a> The one-liner summary of the articles is that <em>you should always prioritise building a workflow instead of a dynamic agent when possible<\/em>. In LlamaIndex, you can do both. It allows you to create an agent workflow with more automatic routing or a customised workflow with more explicit control of the transition of steps. I will provide an example of both implementations. <\/p>\n<figure class=\"wp-block-image size-large\"><img data-recalc-dims=\"1\" height=\"166\" width=\"1024\" decoding=\"async\" src=\"https:\/\/i0.wp.com\/contributor.insightmediagroup.io\/wp-content\/uploads\/2025\/05\/workflow-2-1024x166.png?resize=1024%2C166&#038;ssl=1\" alt=\"\" class=\"wp-image-604262\"><figcaption class=\"wp-element-caption\">Workflow Explain. Image by Author.<\/figcaption><\/figure>\n<p class=\"wp-block-paragraph\">Let\u2019s take a look at how you can build a dynamic workflow. Here is a code example.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">interviewer = FunctionAgent(\n        name=\"interviewer\",\n        description=\"Useful agent to clarify user's questions\",\n        system_prompt=_intervierw_prompt,\n        can_handoff_to = [\"retriver\"]\n        tools=tools\n)\ninterviewer = FunctionAgent(\n        name=\"retriever\",\n        description=\"Useful agent to retrive principle book's content.\",\n        system_prompt=_retriver_prompt,\n        can_handoff_to = [\"advisor\"]\n        tools=tools\n)\nadvisor = FunctionAgent(\n        name=\"advisor\",\n        description=\"Useful agent to advise user.\",\n        system_prompt=_advisor_prompt,\n        can_handoff_to = []\n        tools=tools\n)\nworkflow = AgentWorkflow(\n        agents=[interviewer, advisor, retriever],\n        root_agent=\"interviewer\",\n    )\nhandler = await workflow.run(user_msg=\"How to handle stress?\")<\/code><\/pre>\n<p class=\"wp-block-paragraph\">It is dynamic because the Agent transition is based on the function call of the LLM model. Underlying, LlamaIndex workflow provides agent descriptions as functions for LLM models. When the LLM model triggers such \u201cAgent Function Call\u201d, LlamaIndex will route to your next corresponding agent for the subsequent step processing. Your previous agent\u2019s output has been added to the workflow internal state, and your following agent will pick up the state as part of the context in their call to the LLM model. You also leverage <code>state<\/code> and <code>memory<\/code> components to manage the workflow\u2019s internal state or load external data(reference the document <a href=\"https:\/\/docs.llamaindex.ai\/en\/stable\/module_guides\/deploying\/agents\/memory\/#memory-vs-workflow-context\">here<\/a>). <\/p>\n<p class=\"wp-block-paragraph\">However, as I have suggested, you can explicitly control the steps in your workflow to gain more control. With LlamaIndex, it can be done by extending the workflow object. For example:<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">class ReferenceRetrivalEvent(Event):\n    question: str\n\nclass Advice(Event):\n    principles: List[str]\n    profile: dict\n    question: str\n    book_content: str\n\nclass AdviceWorkFlow(Workflow):\n    def __init__(self, verbose: bool = False, session_id: str = None):\n        state = get_workflow_state(session_id)\n        self.principles = state.load_principle_from_cases()\n        self.profile = state.load_profile()\n        self.verbose = verbose\n        super().__init__(timeout=None, verbose=verbose)\n\n    @step\n    async def interview(self, ctx: Context,\n                        ev: StartEvent) -&gt; ReferenceRetrivalEvent:\n        # Step 1: Interviewer agent asks questions to the user\n        interviewer = get_interviewer_agent()\n        question = await _run_agent(interviewer, question=ev.user_msg, verbose=self.verbose)\n\n        return ReferenceRetrivalEvent(question=question)\n\n    @step\n    async def retrieve(self, ctx: Context, ev: ReferenceRetrivalEvent) -&gt; Advice:\n        # Step 2: RAG agent retrieves relevant content from the book\n        rag_agent = get_principle_rag_agent()\n        book_content = await _run_agent(rag_agent, question=ev.question, verbose=self.verbose)\n        return Advice(principles=self.principles, profile=self.profile,\n                      question=ev.question, book_content=book_content)\n\n    @step\n    async def advice(self, ctx: Context, ev: Advice) -&gt; StopEvent:\n        # Step 3: Adviser agent provides advice based on the user's profile, principles, and book content\n        advisor = get_adviser_agent(ev.profile, ev.principles, ev.book_content)\n        advise = await _run_agent(advisor, question=ev.question, verbose=self.verbose)\n        return StopEvent(result=advise)<\/code><\/pre>\n<p class=\"wp-block-paragraph\">The specific event type\u2019s return controls the workflow\u2019s step transition. For instance, <code>retrieve<\/code> step <span style=\"font-size: revert;\">returns an <\/span><code>Advice<\/code><span style=\"font-size: revert;\">  event that will trigger the execution of the <\/span><code>advice<\/code><span style=\"font-size: revert;\"> step. You can also leverage the <\/span><code>Advice<\/code><span style=\"font-size: revert;\"> event to pass the necessary information<\/span> you need.<\/p>\n<p class=\"wp-block-paragraph\">During the implementation, if you are annoyed by having to start over the workflow to debug some steps in the middle, the <em>context object<\/em> is essential when you want to failover the workflow execution. You can store your state in a serialised format and recover your workflow by unserialising it to a context object. Your workflow will continue executing based on the state instead of starting over.<\/p>\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-python\">workflow = AgentWorkflow(\n    agents=[interviewer, advisor, retriever],\n    root_agent=\"interviewer\",\n)\ntry:\n    handler = w.run()\n    result = await handler\nexcept Exception as e:\n    print(f\"Error during initial run: {e}\")\n    await fail_over()\n    # Optional, serialised and save the contexct for debugging \n    ctx_dict = ctx.to_dict(serializer=JsonSerializer())\n    json_dump_and_save(ctx_dict)\n    # Resume from the same context\n    ctx_dict = load_failed_dict()\n    restored_ctx = Context.from_dict(workflow, ctx_dict,serializer=JsonSerializer())\n    handler = w.run(ctx=handler.ctx)\n    result = await handler<\/code><\/pre>\n<h2 class=\"wp-block-heading\">Summary<\/h2>\n<p class=\"wp-block-paragraph\">In this post, we have discussed how to use LlamaIndex to implement an AI journal\u2019s core function. The key learning includes:<\/p>\n<ul class=\"wp-block-list\">\n<li class=\"wp-block-list-item\">Using Agentic RAG to leverage LLM capability to dynamically rewrite the original query and synthesis result. <\/li>\n<li class=\"wp-block-list-item\">Use a Customized Workflow to gain more explicit control over step transitions. Build dynamic agents when necessary. <\/li>\n<\/ul>\n<p class=\"wp-block-paragraph\"><span style=\"margin: 0px; padding: 0px;\">The sour<\/span>ce code of this AI journal is in my GitHub repo\u00a0<a href=\"https:\/\/github.com\/PepperStudio77\/principle-master\">here<\/a>. I hope you enjoy this article and this small app I built. Cheers!<\/p>\n<p>The post <a href=\"https:\/\/towardsdatascience.com\/how-to-build-an-ai-journal-to-build-your-own-principles\/\">How to Build an AI Journal with LlamaIndex<\/a> appeared first on <a href=\"https:\/\/towardsdatascience.com\/\">Towards Data Science<\/a>.<\/p>\n<\/div>\n<p> \t<BR><br \/>\n <BR><\/BR><br \/>\n    Ming Gao<br \/>\n \t<BR><br \/>\n<BR><\/BR><br \/>\n<a href=\"https:\/\/towardsdatascience.com\/how-to-build-an-ai-journal-to-build-your-own-principles\/\">Go to original source<\/a><br \/>\n \t<BR><br \/>\n <BR><\/BR><\/p>\n","protected":false},"excerpt":{"rendered":"<p>How to Build an AI Journal with LlamaIndex This post will share how to build an AI journal with the LlamaIndex. We will cover one essential function of this AI journal: asking for advice. We will start with the most basic implementation and iterate from there. We can see significant improvements for this function when [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1062,151,62,69,1730,447,2260],"tags":[98,2710,1773],"class_list":["post-3901","post","type-post","status-publish","format-standard","hentry","category-agentic-rag","category-ai","category-aimldsaimlds","category-artificial-intelligence","category-llamaindex","category-llm-agent","category-rag","tag-ai","tag-book","tag-user"],"_links":{"self":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/3901"}],"collection":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/comments?post=3901"}],"version-history":[{"count":0,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/posts\/3901\/revisions"}],"wp:attachment":[{"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/media?parent=3901"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/categories?post=3901"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mailitics.com\/index.php\/wp-json\/wp\/v2\/tags?post=3901"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}