How to approach refined grammar rules #1062
Replies: 1 comment
|
Short version: what you're hitting isn't a bug, it's a property of how guidance builds grammars. A stateless=True function is called once, at grammar-construction time, to build a static context-free grammar (CFG) tree. There is no "previous token" to inspect at that point — nothing has been generated yet, so lm["op"] can't exist, and mixing in a stateful function breaks the "build once, reuse everywhere" assumption that makes select() work (this is basically the same root cause as the error in #814, "Confusing error message when using capture on stateful function"). So "the previous operator was /" cannot be answered by reading runtime state inside the grammar — it has to be encoded structurally in the CFG itself. That's actually fine here because your rule only depends on the immediate parent production (the operator that dominates the right-hand operand), not on unbounded history, so it's still expressible as a context-free grammar — you just need two flavors of "expression"/"number": a normal one and a "no-leading-zero" one, and only use the restricted one on the right side of /. Example: python @guidance(stateless=True) @guidance(stateless=True) @guidance(stateless=True) @guidance(stateless=True) @guidance(stateless=True) Notes on this approach:
If your real constraint is more global (e.g. "no division by an expression that evaluates to zero" rather than "no literal 0 right after /"), that's a semantic/runtime check, not a grammar one — you'd need to generate candidate output and validate/retry afterward, since guidance's constrained decoding operates on syntax (CFG), not on evaluated semantics. References:
I haven't executed this example against a live model — I only verified it against the documented API (select, one_or_more, zero_or_more, @guidance(stateless=True)) shown in the README. Please test it locally before relying on it, and if you need the "no zero-valued division" (semantic) version rather than "no literal-zero right after /" (syntactic), say so — that needs a different (retry-based) approach. |
Uh oh!
There was an error while loading. Please reload this page.
I'm trying to define a cfg and add some refinement rule on top of that. For example using the cfg expression defined in the github readme:
I'd like to add a rule to stop a zero from being chosen if the previous operator was a '/'. I though about accessing the state of the lm like
lm["op"], but stateless functions can't access state. If I set it to stateful, I run into error that I can't select between stateful functions. I thought about using a table to store state, liketable["op"] = select(['+' , '*', '**', '/', '-'], name="op"), but it stores a intermediary representation like{{G|137482486511456|G}}.I'm still new to guidance, so I would appreciate some pointers in the right direction.
All reactions