PAYATHON 2026

如何通过 Ollama api 向模型传递正确的 context

技术老齐

结论

RAG 中的 context 无须对应 Ollama API 的同名参数。它就是检索得到的文本,可以和问题一起写入 prompt,也可以通过 /api/chat 的 messages[].content 发送给模型。

Ollama /api/generate 中已经弃用的 context 字段保存的是上一轮生成返回的 token 状态,用来延续对话,与 RAG 检索得到的参考资料含义不同。

LangChain 如何传入 context

下面代码里的 context 是提示词模板变量:

const messages = await promptTemplate.invoke({ question, context });

promptTemplate.invoke() 会把 question 和 context 渲染成普通消息。模板生成的内容可能如下:

请根据以下资料回答问题。

资料:
SQLite is a lightweight embedded database...

问题:
SQLite 适合什么场景?

随后,ChatOllama 会把渲染后的消息发送给 Ollama。模型收到的是消息文本,Ollama API 并没有接收一个专门用于 RAG 的 context 字段。

通过 /api/chat 传入 RAG 上下文

对话模型通常使用 /api/chat。可以用系统消息规定回答方式,再把检索内容和问题放进用户消息:

curl http://localhost:11434/api/chat \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama3.2:latest",
    "messages": [
      {
        "role": "system",
        "content": "请根据用户提供的参考资料回答问题。如果资料不足,请明确说明无法从资料中确定答案,不要自行补充事实。"
      },
      {
        "role": "user",
        "content": "参考资料:\n<context>\nSQLite 是一种嵌入式关系型数据库,数据库内容通常保存在单个文件中。它不需要独立的数据库服务器进程。\n</context>\n\n问题:\nSQLite 与传统客户端服务器数据库的主要区别是什么?"
      }
    ],
    "options": {
      "temperature": 0
    },
    "stream": false
  }'

非流式响应的答案通常在以下位置:

{
  "message": {
    "role": "assistant",
    "content": "..."
  }
}

<context> 并非 Ollama 规定的语法,它只是一个分隔标记,方便模型区分参考资料和问题。也可以改用 参考资料开始、Markdown 标题或其他清晰的分隔方式。

通过 /api/generate 传入上下文

如果不需要对话消息结构,可以把所有内容拼接成一个 prompt:

curl http://localhost:11434/api/generate \
  -H "Content-Type: application/json" \
  -d '{
    "model": "llama3.2:latest",
    "prompt": "请仅根据以下参考资料回答问题。如果资料不足,请回答无法确定。\n\n<context>\nSQLite 是一种嵌入式关系型数据库,数据库内容通常保存在单个文件中。它不需要独立的数据库服务器进程。\n</context>\n\n问题:SQLite 与传统客户端服务器数据库的主要区别是什么?",
    "options": {
      "temperature": 0
    },
    "stream": false
  }'

这种写法与 LangChain 渲染提示词后的效果接近,只是需要自行拼接提示词。

RAG 请求的组织方式

一个完整的 RAG 请求通常包含以下步骤:

  1. 根据用户问题生成 embedding,或执行关键词检索。
  2. 从 SQLite 或向量库中取回相关片段。
  3. 将取回的片段合并成参考资料。
  4. 把参考资料和问题写入同一条请求。
  5. 调用 /api/chat 或 /api/generate。

用 JavaScript 直接调用 /api/chat 时,可以这样组织请求:

const retrievedContext = documents
  .map((document, index) => `[${index + 1}] ${document.content}`)
  .join('\n\n');

const response = await fetch('http://localhost:11434/api/chat', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'llama3.2:latest',
    messages: [
      {
        role: 'system',
        content:
          '请仅根据用户提供的参考资料回答问题。资料不足时,请明确说明无法确定。',
      },
      {
        role: 'user',
        content: `参考资料:
<context>
${retrievedContext}
</context>

问题:
${question}`,
      },
    ],
    options: {
      temperature: 0,
    },
    stream: false,
  }),
});

if (!response.ok) {
  throw new Error(`Ollama request failed: ${response.status}`);
}

const result = await response.json();
const answer = result.message.content;

使用 JSON.stringify() 构造请求体,可以防止引号、换行符或反斜杠破坏 JSON 格式。

区分三种 context

在这个场景里,context 可能有三种含义:

  • RAG context:从 SQLite、向量数据库或其他数据源检索到的文本,需要写入提示词。
  • Conversation context:此前的对话消息。调用 /api/chat 时,可以继续把这些消息放入 messages。
  • /api/generate 的旧 context 字段:上一轮返回的 token 状态,用来延续生成,不能用于传递 RAG 文档。

变量可以命名为 context、documents 或 retrievedText。Ollama 不会根据变量名判断其用途,模型最终接收到的是请求里的文本和消息。

注意事项

建议用明确的分隔符包裹检索内容,并在提示词中要求模型“仅根据参考资料回答”。这样可以减少模型脱离资料作答的情况,但无法完全消除幻觉。

还要控制检索片段的总长度。问题、系统指令、历史消息和 RAG 文本都会占用模型的上下文窗口。超过可用长度后,部分内容可能被截断,具体行为取决于模型和 Ollama 配置。如果当前 Ollama 版本支持相关选项,可以检查 num_ctx 设置。不要盲目增大该值,否则会增加内存占用和推理成本。

外部文档中的文本还可能包含恶意指令。应用应将检索内容视为不可信数据,用清晰的边界包裹,并要求模型忽略参考资料里的操作指令。权限控制和数据隔离等安全措施不能只靠提示词实现。

备注:内容仅供参考。