Describe the problem/error/question-- Template Info
- Based on this workflow which reads in a PDF, stores text chunks in Pinecone, and allows me to query them.
- The LLM is GPT‐3.5 by default, but can be swapped out.
- The final step should display an answer plus bracketed citations referencing the chunk index.
I’m using this n8n template that lets me ask questions about a PDF document, with an AI model providing the answer. The workflow is supposed to include a citation showing which chunk of the PDF the AI used (e.g., “Bitcoinwhitepaper.pdf,lines1–35Bitcoin whitepaper.pdf, lines 1–35”).
I have everything set up with Pinecone for storing the chunks and an OpenAI LLM. The “Answer the query based on chunks” node does output both “answer” and “citations”—I can see an array like [0, 1, 2, 3]. However, by the time I reach the final node (such as “Generate response”), the citations array becomes null or doesn’t appear in the final text. I only see the “answer” string.
Problem
Despite seeing [0,1,2,3] in the “Answer the query based on chunks” node, my final output just has the AI’s text. No citations are appended. How can I ensure the final node references $json.citations properly so I get the citation text in the final output?
What is the error message (if any)?
Please share your workflow
(Select the nodes on your canvas and use the keyboard shortcuts CMD+C/CTRL+C and CMD+V/CTRL+V to copy and paste the workflow.)
````{
"nodes": [
{
"parameters": {},
"id": "764a865c-7efe-4eec-a34c-cc87c5f085b1",
"name": "Chat Trigger",
"type": "@n8n/n8n-nodes-langchain.chatTrigger",
"position": [
280,
1540
],
"webhookId": "1727c687-aed0-49cf-96af-e7796819fbb3",
"typeVersion": 1
},
{
"parameters": {
"jsCode": "let out = \"\";\nconst items = $input.all(); \n\nfor (let i = 0; i < items.length; i++) {\n const item = items[i];\n const fileName = item.json.document?.metadata?.file_name || \"unknown-file\";\n const lineStart = item.json.document?.metadata?.[\"loc.lines.from\"] || \"\";\n const lineEnd = item.json.document?.metadata?.[\"loc.lines.to\"] || \"\";\n\n out += `--- CHUNK ${i} (File: ${fileName}, Lines: ${lineStart}-${lineEnd}) ---\\n`;\n out += item.json.document.pageContent + \"\\n\\n\";\n}\n\nreturn [{ json: { context: out } }];\n"
},
"id": "36cd9a8d-7d89-49b3-8a81-baa278201a21",
"name": "Prepare chunks",
"type": "n8n-nodes-base.code",
"position": [
1100,
1540
],
"typeVersion": 2
},
{
"parameters": {
"options": {}
},
"id": "6356bce2-9aae-43ed-97ce-a27cbfb80df9",
"name": "Embeddings OpenAI2",
"type": "@n8n/n8n-nodes-langchain.embeddingsOpenAi",
"position": [
720,
1760
],
"typeVersion": 1,
"credentials": {
"openAiApi": {
"id": "kwzv4owzsugglO6v",
"name": "OpenAi account"
}
}
},
{
"parameters": {
"model": "gpt-4o-2024-05-13",
"options": {}
},
"id": "8fb697ea-f2e5-4105-b6c8-ab869c2e5ab2",
"name": "OpenAI Chat Model",
"type": "@n8n/n8n-nodes-langchain.lmChatOpenAi",
"position": [
1340,
1760
],
"typeVersion": 1,
"credentials": {
"openAiApi": {
"id": "kwzv4owzsugglO6v",
"name": "OpenAi account"
}
}
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "236047ff-75a2-47fd-b338-1e9763c4015e",
"name": "chunks",
"type": "number",
"value": 4
}
]
},
"includeOtherFields": true,
"options": {}
},
"id": "9a2b0152-d008-42cb-bc10-495135d5ef45",
"name": "Set max chunks to send to model",
"type": "n8n-nodes-base.set",
"position": [
500,
1540
],
"typeVersion": 3.3
},
{
"parameters": {
"jsonSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"answer\": {\n \"type\": \"string\"\n },\n \"citations\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"number\"\n }\n }\n }\n}"
},
"id": "f2ab813f-0f0c-4d3a-a1de-7896ad736698",
"name": "Structured Output Parser",
"type": "@n8n/n8n-nodes-langchain.outputParserStructured",
"position": [
1520,
1760
],
"typeVersion": 1
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "67ecefcf-a30c-4cc4-89ca-b9b23edd6585",
"name": "citations",
"type": "array",
"value": "={{ $json.citations }}"
}
]
},
"options": {}
},
"id": "ada2a38b-0f6e-4115-97c0-000e97a5e62e",
"name": "Compose citations",
"type": "n8n-nodes-base.set",
"position": [
1740,
1540
],
"typeVersion": 3.3
},
{
"parameters": {
"assignments": {
"assignments": [
{
"id": "d77956c4-0ff4-4c64-80c2-9da9d4c8ad34",
"name": "text",
"type": "string",
"value": "={{ $if(!$json.citations.isEmpty(), \"\\n\" + $json.citations.join(\"\"), '') }}{{ $('Answer the query based on chunks').item.json.answer }}"
},
{
"id": "894eb567-932a-46ba-93ff-29c72ce1c786",
"name": "Text",
"value": "{{ $('Get top chunks matching query').item.json.document.metadata.file_name }}",
"type": "string"
}
]
},
"options": {}
},
"id": "8e115308-532e-4afd-b766-78e54c861f33",
"name": "Generate response",
"type": "n8n-nodes-base.set",
"position": [
2020,
1540
],
"typeVersion": 3.3
},
{
"parameters": {
"promptType": "define",
"text": "=Use the following pieces of context to answer the question at the end. If you don't know the answer, just say that you don't know, don't try to make up an answer. Important: In your response, also include the the indexes of the chunks you used to generate the answer.\n\n{{ $json.context }}\n\nQuestion: {{ $(\"Chat Trigger\").first().json.chatInput }}\n\nE.g. If you used chunk #0 and chunk #2, your final JSON should look like:\n{\n \"answer\": \"...\",\n \"citations\": [0, 2]\n}\n\nHelpful Answer:",
"hasOutputParser": true
},
"id": "ef357a2b-bc8d-43f7-982f-73c3a85a60be",
"name": "Answer the query based on chunks",
"type": "@n8n/n8n-nodes-langchain.chainLlm",
"position": [
1320,
1540
],
"typeVersion": 1.4,
"onError": "continueRegularOutput"
},
{
"parameters": {
"mode": "load",
"pineconeIndex": {
"__rl": true,
"value": "2665",
"mode": "list",
"cachedResultName": "2665"
},
"prompt": "={{ $json.chatInput }}",
"topK": "={{ $json.chunks }}",
"options": {
"pineconeNamespace": "Core Docs"
}
},
"id": "1a5511b9-5a24-40d5-a5b1-830376226e4e",
"name": "Get top chunks matching query",
"type": "@n8n/n8n-nodes-langchain.vectorStorePinecone",
"position": [
720,
1540
],
"typeVersion": 1,
"credentials": {
"pineconeApi": {
"id": "wITPXPxgjmrX4XGj",
"name": "PineconeApi account"
}
}
}
],
"connections": {
"Chat Trigger": {
"main": [
[
{
"node": "Set max chunks to send to model",
"type": "main",
"index": 0
}
]
]
},
"Prepare chunks": {
"main": [
[
{
"node": "Answer the query based on chunks",
"type": "main",
"index": 0
}
]
]
},
"Embeddings OpenAI2": {
"ai_embedding": [
[
{
"node": "Get top chunks matching query",
"type": "ai_embedding",
"index": 0
}
]
]
},
"OpenAI Chat Model": {
"ai_languageModel": [
[
{
"node": "Answer the query based on chunks",
"type": "ai_languageModel",
"index": 0
}
]
]
},
"Set max chunks to send to model": {
"main": [
[
{
"node": "Get top chunks matching query",
"type": "main",
"index": 0
}
]
]
},
"Structured Output Parser": {
"ai_outputParser": [
[
{
"node": "Answer the query based on chunks",
"type": "ai_outputParser",
"index": 0
}
]
]
},
"Compose citations": {
"main": [
[
{
"node": "Generate response",
"type": "main",
"index": 0
}
]
]
},
"Answer the query based on chunks": {
"main": [
[
{
"node": "Compose citations",
"type": "main",
"index": 0
}
]
]
},
"Get top chunks matching query": {
"main": [
[
{
"node": "Prepare chunks",
"type": "main",
"index": 0
}
]
]
}
},
"pinData": {},
"meta": {
"templateId": "2165",
"templateCredsSetupCompleted": true,
"instanceId": "d3a7fdc811fe5e63e0b89bee7989d057184f56a6eebfbf2d4d179fadaa82ef40"
}
}`
## Share the output returned by the last node
<!-- If you need help with data transformations, please also share your expected output. -->
## Information on your n8n setup
- **n8n version:** 1.81.4
- **Database (default: SQLite):** Pinecone
- **n8n EXECUTIONS_PROCESS setting (default: own, main):** not sure
- **Running n8n via (Docker, npm, n8n cloud, desktop app):** n8n Cloud
- **Operating system:** windows 11