人人都会AI编程

12.4 提示词拼接与大模型调用

更新时间:2026-07-12

当检索模块拿到最相关的文档片段后,下一步就是将“用户问题”与“相关上下文”组装成一条完整的提示词,发给大语言模型生成最终回答。这一步看似简单,但细节处理不当会直接影响回答质量,甚至导致模型忽略检索材料,变回“自由发挥”的状态。

1. 提示词拼接的核心要素

一条 RAG 场景下的典型提示词通常包含以下部分:

  • 系统指令(可选但推荐):明确模型的角色、能力边界、回答风格。例如“你是一个基于内部资料回答的公司助手,只能根据下方提供的资料作答,不要使用你自己的常识。”
  • 检索到的上下文:多次召回的相关文档片段,按相关度或其它规则排序,每个片段最好附带简短的来源标记。
  • 用户问题:保持原样,或适当改写以消除歧义。
  • 回答指引(可选):指定输出格式、是否需要引用出处、遇到无答案情况应如何回复等。

将这些部分按固定模板拼接,就形成了每次调用大模型的真实输入。

2. 一个实用的拼接模板

以下是一个被广泛使用的提示词结构(以中文企业内部答疑为例):

你是一个严谨的公司知识库助手。请严格根据以下提供的【参考资料】回答问题,不要在答案中添加资料中未提及的信息。如果资料中找不到足够的信息,请明确回答“根据现有资料无法解答”。

【参考资料】
{context}

【问题】
{question}

【回答要求】
- 使用清晰的结构,可分点说明;
- 如果涉及具体条款,请注明出处,格式为“(来源:文档名)”。
- 回答尽量简洁,不重复资料中的整段原文,而是提炼要点。

实际代码中,{context} 会被替换为检索结果的拼接字符串,{question} 则替换为用户原始提问。拼接工作通常由一段极简的 Python 脚本完成,不依赖特殊库。

示例组装后的最终输入:

你是一个严谨的公司知识库助手。请严格根据以下提供的【参考资料】回答问题……

【参考资料】
[1] 《员工手册》第3章:年假天数每年15天,可跨年使用。
[2] 《2024年福利调整通知》:自2024年1月1日起,年假天数调整为18天。

【问题】
今年的年假有多少天?

【回答要求】
……

3. 处理上下文窗口限制

大语言模型有最大上下文长度(如 4k、8k、32k tokens),而检索片段拼接后的总长度可能超出这个限制。实用中需要做好以下控制:

  • 控制检索片段的个数和长度top_k 不宜过大(通常 3~8 个片段已足够),每个片段保留合理字数(如 200~500 字)。
  • 截断策略:按相关性排序后,如果总 tokens 超限,从末尾逐步去掉片段,确保最终输入不超过模型上下文窗口的 80%~90%,留出生成空间。
  • 动态调整:有些系统会先统计上下文 token 数,超过阈值时自动缩减片段数量或缩短每个片段。

伪代码示意:

def build_prompt(question, retrieved_chunks, max_tokens=3500):
    context = "\n\n".join([f"[{c.source}] {c.content}" for c in retrieved_chunks])
    # 估算token数(简易方式:字数/1.5 或 调用tokenizer)
    while estimate_tokens(context) > max_tokens:
        retrieved_chunks.pop()  # 丢弃相关性最低的片段
        context = "\n\n".join([f"[{c.source}] {c.content}" for c in retrieved_chunks])
    return PROMPT_TEMPLATE.format(context=context, question=question)

4. 多轮对话场景的处理

如果系统需要支持多轮对话(如追问“那跨年使用需要审批吗?”),拼接提示词时必须带上历史对话记录,否则模型无法理解上下文。

常见做法是维护一个messages列表,按以下结构发送给模型(以 OpenAI 兼容接口为例):

[
  {"role": "system", "content": "你是一个基于资料回答的公司助手……"},
  {"role": "user", "content": "(问题1)今年的年假有多少天?"},
  {"role": "assistant", "content": "根据最新通知,18天。"},
  {"role": "user", "content": "(问题2)那跨年使用需要审批吗?"},
  {"role": "user", "content": "【本次参考资料】:\n……(新检索结果)"}
]

注意,每次新提问都会重新检索,因此最新一轮的参考资料需要作为一个额外的 user 消息追加,或将参考资料拼接到最近一次 user 问题中,确保模型能看到当前所需的文档内容。

5. 大模型调用的工程细节

  • 接口选择:可使用 OpenAI 兼容的 API,或通过 LangChain 等框架的统一调用入口,但核心都相同:传入 messages 列表和生成参数。
  • 重要参数设置
  • temperature:建议设为相对较低的值(0~0.3),让回答更聚焦于检索资料,减少随机发散。需要严格事实性时可用 0。
  • max_tokens:限制回答最大长度,避免浪费 Token 和响应时间。
  • stop:可设置停止词,在模型开始无意义重复时终止。
  • 超时与重试:生成可能因网络或模型负载而耗时较长,需要合理设置超时(如 30~60 秒),并支持失败重试 1~2 次。

6. 提取与返回最终回答

模型返回的是一个完整的文本回答,可能需要根据约定格式提取关键信息。如果提示词中要求了来源标记,回答通常已经包含出处。实际输出可以直接返回给前端,或者进行简单后处理(如截断尾巴、格式化为 Markdown)。

示例回答:

根据《2024年福利调整通知》,今年的年假天数为 18 天。(来源:2024年福利调整通知)

这种格式既满足溯源需求,也便于后续解析和渲染。

7. 落地注意事项

  • 提示词需迭代打磨:不同业务场景、不同模型的最佳提示词差异较大,建议根据实际测试数据反复调整,甚至准备 A/B 测试。
  • 避免提示词注入:用户输入可能包含恶意指令,如“忽略之前的指令”。拼接时应将用户问题放在专用占位符内,避免直接嵌入。同时可在系统指令中加入抵抗注入的提示。
  • 记录 Prompt 日志:每次调用日志应保存当时使用的完整提示词和回答,便于调试和效果分析。

通过合理的拼接和调用策略,这一步能将前面的检索成果转换为用户真正需要的自然语言答案,是整个 RAG 流程的“临门一脚”。对提示词和调用细节的持续优化,常常比调整检索算法更能带来直接的质量提升。