AI 工具

Mistral API 文档问答:添加上下文长度守卫

把本地文档塞进对话前,先做字符上限守卫并包装「根据文档回答,不知道就说不知道」提示,降低幻觉与超限浪费。

BINBHO · 图文教程

把本地文档塞进对话前,先做字符上限守卫并包装「根据文档回答,不知道就说不知道」提示,降低幻觉与超限浪费。

先看清成品

  • 短文档 OK 并生成 messages;超长文档 INVALID。
  • 3 项 pytest 通过。

合规提醒:面向用户的助手原名 Le Chat,官方称已更名为 Vibe(入口与账号保留,以官网公告为准);开发调用走 Mistral API(Studio 管理密钥)。密钥勿入库;生成内容需人工审,避免违法与侵权输出。免费额度与价格以 Studio/官网为准,本文不编造。

运行说明:无正式 MISTRAL_API_KEY。A/B 用本地 mock;对官方 api.mistral.ai 无效密钥实测 HTTP 401。C 为文档粘贴体积守卫。2026-10-23(Asia/Shanghai)pytest 通过。

做完之后你会得到什么?

成果 说明
doc_prompt.py 提示包装
sample_doc.txt 样例
test_104c.py 测试

需要准备哪些环境?

项目 说明
Python 3.10+

关键事实

事实 来源
真实上限以模型上下文 token 计;本教程用字符软限制 重要
文档问答仍需引用核对 实践
勿上传无授权机密文档到第三方 API 合规

文件结构

104-mistral-le-chat-C-src/
├── doc_prompt.py
├── sample_doc.txt
└── test_104c.py

第 1 步:包装脚本

#!/usr/bin/env python3
"""Build a Mistral chat prompt from a local document with size guards."""
from __future__ import annotations
import argparse, json, sys
from pathlib import Path

# Soft tutorial limit (chars); real model limits are in tokens — check docs.
DEFAULT_MAX = 12000

def build(doc: str, question: str, max_chars: int) -> dict:
    errs = []
    if not question.strip():
        errs.append("question 为空")
    if len(doc) > max_chars:
        errs.append(f"文档 {len(doc)} 字符超过上限 {max_chars},请摘要或切片")
    if not errs:
        content = f"根据下列文档回答问题。若文档未包含答案,请明确说不知道。\n\n---\n{doc}\n---\n\n问题:{question}"
        return {"ok": True, "messages": [{"role": "user", "content": content}], "chars": len(doc)}
    return {"ok": False, "errors": errs, "chars": len(doc)}

def main(argv=None) -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument("doc")
    ap.add_argument("question")
    ap.add_argument("--max-chars", type=int, default=DEFAULT_MAX)
    ap.add_argument("-o", "--out", default="")
    args = ap.parse_args(argv)
    doc = Path(args.doc).read_text(encoding="utf-8")
    result = build(doc, args.question, args.max_chars)
    text = json.dumps(result, ensure_ascii=False, indent=2)
    if args.out:
        Path(args.out).write_text(text + "\n", encoding="utf-8")
    print(text)
    return 0 if result.get("ok") else 1

if __name__ == "__main__":
    raise SystemExit(main())

第 2 步:测试

from pathlib import Path
import subprocess, sys
from doc_prompt import build
HERE = Path(__file__).resolve().parent

def test_ok():
    r = build((HERE/"sample_doc.txt").read_text(), "开封的耳机能退吗?", 12000)
    assert r["ok"] and "messages" in r

def test_too_big():
    r = build("x" * 100, "q", 50)
    assert not r["ok"]

def test_cli():
    r = subprocess.run([sys.executable, str(HERE/"doc_prompt.py"), str(HERE/"sample_doc.txt"), "退货几天?"], capture_output=True, text=True)
    assert r.returncode == 0

第 3 步:运行

$ python doc_prompt.py
{
  "ok": true,
  "messages": [
    {
      "role": "user",
      "content": "根据下列文档回答问题。若文档未包含答案,请明确说不知道。\n\n---\nAcme 退货政策:自签收起 30 日内可退,商品需未使用且包装完整。电子产品开封后仅保修,不支持无理由退货。\n\n---\n\n问题:开封的耳机能退吗?"
    }
  ],
  "chars": 56
}

$ pytest -q
...                                                                      [100%]
3 passed in 0.04s

怎么检查结果?

  • OK 含 messages[0].content。
  • 超限返回 errors。

调试示例

整本 PDF 糊进去。 软限制会拒绝。先摘要或按章节切片,再多轮问。

常见问题

现象 原因 处理
PDF 先转文本 再喂本脚本
多文件 自行合并/检索 本篇单文件
与 Vibe 上传 产品功能不同 API 需自建

模板规则

  • 无授权文档不上传。
  • 超长先切片。
  • 答案要可追溯到原文。

项目资源

用途 地址
Quickstart(官方) https://docs.mistral.ai/getting-started/quickstart
Docs(官方) https://docs.mistral.ai/
Mistral 官网 https://mistral.ai/

文档进模型之前,先过体积与授权两道闸。