guidance
用「指导语言」DSL在token级别精确约束LLM输出结构,实现JSON/Regex/条件分支的零误
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
用「指导语言」DSL在token级别精确约束LLM输出结构,实现JSON/Regex/条件分支的零误
加载项目详情…
本应用为开源项目,仅供学习研究,请遵守其开源协议。
想象一下:你招聘了一位能力超强的员工,但这位员工每次交上来的报告格式都随心情来——今天是 JSON,明天是纯文本,后天突然给你蹦出来一段 Markdown。你不得不花大量时间帮他「返工」。传统 Prompt 工程里,LLM 就是这样一位「天才但任性」的下属。而 Guidance,就是让这位天才变得靠谱听话的秘密武器。
大语言模型在生成文本时,本质上是在做一个「概率接龙」游戏——每一步都从海量 token 中挑选最可能的下一个。这种机制带来了惊人的创造力,但也带来了一个根本性问题:模型对输出格式没有任何「自我约束」能力。即使你在 prompt 里写了「请以 JSON 格式返回」,模型仍可能在某个节点「跑偏」,生成非法 JSON、遗漏字段、或者输出你根本不需要的注释。
为此,业界发展出两条路线:一是提示工程(Prompt Engineering)——不断调整 prompt 措辞,引导模型自我修正;二是输出解析(Output Parsing)——先生成再后处理,用代码强行解析提取。这两条路线的共同缺陷是:不可靠且浪费。提示词工程依赖反复试错,输出解析浪费了本可用于更有意义生成的 token。
Microsoft Research 于 2023 年发布的 Guidance,走的是第三条路——将输出结构直接嵌入生成过程本身,让模型在每一步 token 生成时,就只能在符合约束的范围内选择。从根本上消灭「事后返工」的可能性。
Guidance 的核心技术可以概括为基于语法的受限解码(Grammar-Constrained Decoding)。它的实现逻辑精妙且工程化程度极高:
1. DSL(领域特定语言)作为核心抽象
Guidance 定义了一套轻量级 DSL,通过 @guidance 装饰器将 Python 函数转化为语法规则。例如:
from guidance import system, user, assistant, gen
@guidance
def recipe(lm):
lm += system() + "你是一位专业厨师"
lm += user() + "教我做一道番茄炒蛋"
lm += assistant()
lm += gen(max_tokens=200, stop="。") # 强制以句号结束
return lm
这里的 gen、system、user、assistant 并不是普通函数调用,而是语法节点——它们同时控制 prompt 的拼接和生成行为的约束。当代码执行到 gen(stop="。") 时,Guidance 底层的语法解析引擎会将 stop 参数转换为合法的 token 掩码,在每一步解码中只允许模型从「能最终形成句号」的 token 集合中采样。这不是事后过滤,而是主动约束。
2. 状态机解析引擎
_grammar.py 和 _parser.py 是 Guidance 的心脏。Grammar 由 GrammarNode 抽象树表示,支持多种节点类型:
LiteralNode:字面量匹配,必须精确生成指定字符串RegexNode:正则约束,限制模型只能在匹配正则的 token 集合中采样RuleNode:规则节点,封装 gen 调用的核心生成逻辑SelectNode:选择节点,从多个候选中约束模型选择SubgrammarNode:子语法节点,支持模块化复用复杂规则在生成过程中,解析引擎维护一个状态机,跟踪当前处于语法树的哪个节点。每生成一个 token,状态机根据语法规则推进。只有当整个语法树被完整解析(即所有节点都成功匹配)时,一次 Guidance 程序才算成功执行。这种设计天然支持中途失败回滚——某个分支约束失败时,引擎可以自动重试或切换到其他路径。
3. 多后端统一抽象
guidance/models/ 下维护着对各种 LLM 后端的适配层:Transformers、llama.cpp、OpenAI API、Azure AI、ONNX Runtime GenAI 等。每种后端都实现了统一的流式接口,Guidance 的解析引擎完全与后端解耦——这意味着同一套语法,在本地小模型和云端大模型上都能工作,只需切换 Model 类即可。
场景一:结构化 JSON 输出
这是 Guidance 最经典的使用场景。在 RAG(检索增强生成)系统中,模型需要从知识库中抽取实体并以 JSON 格式返回。使用 Guidance:
from guidance import gen
@guidance
def extract_entity(lm, text):
lm += f"从以下文本中提取实体:{text}\n"
lm += '{\n "name": gen(stop='\"'),\n'
lm += ' "age": gen(regex=r'\d+', stop=','),\n'
lm += ' "city": gen(stop='\"')\n'
lm += '}'
return lm
模型在生成 name 字段值时,只能输出引号内的内容,一旦到达引号就自动停止,JSON 格式完全由 Guidance 约束而不是模型「自律」。这种方法的可靠性远高于纯 prompt 工程。
图1:JSON 语法约束生成过程可视化
场景二:对话流程控制
传统的聊天机器人代码需要手写复杂的对话管理逻辑。Guidance 通过 system()、user()、assistant() 语法节点,将对话角色管理变得像写 HTML 一样直观:
with system():
lm += "你是一个严谨的技术助手"
with user():
lm += user_input
with assistant():
lm += gen(max_tokens=100)
每个角色节点自动管理消息格式和位置,开发者在结构化 prompt 时拥有了对对话流程的精确控制权。
图2:对话模板结构示意
场景三:工具调用(Function Calling)
在 library/_tools.py 中,Guidance 实现了完整的函数调用协议。开发者可以定义工具 schema,Guidance 负责让模型生成严格符合工具调用格式的输出,避免「工具名称拼写错误」或「参数格式不合法」等低级问题。这在 Agent 系统构建中尤为重要。
场景四:与 LangChain 深度集成
Guidance 被设计为 LangChain 的下位替代或增强组件。对于需要精确控制输出的 LangChain 应用,可以用 Guidance 的 GuidanceLLM 包装器替换默认的 LLM Chain,同时保持其他 RAG、Memory 组件不变。这意味着企业可以在最小化代码改动的前提下,显著提升输出可靠性。
Guidance 的代码库(约 92 个 Python 文件,代码量估计 2 万行以上)呈现出极高的工程水准:
library/ 下按功能领域(gen、json、pydantic、audio、video)拆分为独立子模块,每个模块职责单一pytest、pytest-asyncio、对资源密集型测试的标记支持需要注意的是,该项目主要语言标记为「Jupyter Notebook」,这是因为大量示例代码以 .ipynb 形式存在,但核心逻辑全部是 Python 代码。
Guidance 对普通用户非常友好,一行 pip install guidance 即可完成安装。如果需要特定后端(如本地 Llama 模型),只需额外安装对应可选依赖:
pip install guidance[transformers] # Hugging Face 模型
pip install guidance[openai] # OpenAI API
pip install guidance[llamacpp] # 本地 llama.cpp 模型
pip install guidance[onnxruntime-genai] # ONNX 加速
Python 版本要求 >= 3.10,不依赖 GPU(但如果跑本地模型则另说)。唯一需要注意的是,Jupyter 环境下的交互式 widget 需要 jupyter 相关依赖。
在生产环境部署时,由于没有官方 Dockerfile,建议通过虚拟环境或容器自行封装。不过核心依赖极简(jinja2、numpy、pydantic),自行构建镜像成本很低。
1. 对模型能力的依赖:Guidance 的约束机制只在模型「有能力」遵守约束时有效。如果约束超出模型能力范围(如让小模型生成精确的复杂 JSON),模型仍然可能失败。
2. 性能开销:状态机解析和 token 级别的约束检查会带来一定延迟。在低延迟敏感场景(如实时对话)下,需要评估是否值得付出这一成本。
3. 学习曲线:虽然 Guidance API 设计得相当优雅,但 DSL 本身需要一定时间理解,尤其是复杂的嵌套语法规则。对于习惯了传统 prompt 的开发者,转向 Guidance 有一个认知切换过程。
4. 非标准 DSL:Guidance 自创了一套语法体系,与 LangChain、PromptTemplate 等主流库不兼容,需要额外的适配工作才能与现有 AI 工程栈集成。
Guidance 代表了 LLM 应用开发从「碰概率」向「精确控制」演进的一个重要方向。截至目前已收获超过 21000 颗 GitHub Stars,被 Microsoft 作为 Phi 系列小模型的配套工具广泛使用,在 Hugging Face 社区也有大量追随者。
随着开源模型能力的持续提升(尤其是小参数模型的崛起),对输出结构精确控制的需求会越来越强烈。Guidance 这条「语法约束」路线与「模型微调」路线形成互补,为企业级 AI 应用提供了另一条可控的技术路径。可以预见,未来会有更多类似 Guidance 的结构化输出工具出现,而 Guidance 作为该领域的先驱项目,其设计理念将持续影响这个方向的发展。
图3:Jupyter 环境下的 Guidance Widget 交互界面
图4:Llama-2-7B 在 Guidance 约束下的输出效果