You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

GrammarTest.cs 5.2 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. using LLama.Common;
  2. using LLama.Grammars;
  3. using LLama.Native;
  4. namespace LLama.Unittest
  5. {
  6. public sealed class GrammarTest
  7. : IDisposable
  8. {
  9. private readonly ModelParams _params;
  10. private readonly LLamaWeights _model;
  11. public GrammarTest()
  12. {
  13. _params = new ModelParams(Constants.ModelPath)
  14. {
  15. ContextSize = 2048,
  16. Seed = 92,
  17. };
  18. _model = LLamaWeights.LoadFromFile(_params);
  19. }
  20. public void Dispose()
  21. {
  22. _model.Dispose();
  23. }
  24. [Fact]
  25. public void CreateBasicGrammar()
  26. {
  27. var rules = new List<GrammarRule>
  28. {
  29. new GrammarRule("alpha", new[]
  30. {
  31. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 'a'),
  32. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_RNG_UPPER, 'z'),
  33. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  34. }),
  35. };
  36. using var handle = SafeLLamaGrammarHandle.Create(rules, 0);
  37. }
  38. [Fact]
  39. public void CreateGrammar_StartIndexOutOfRange()
  40. {
  41. var rules = new List<GrammarRule>
  42. {
  43. new GrammarRule("alpha", new[]
  44. {
  45. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 'a'),
  46. new LLamaGrammarElement(LLamaGrammarElementType.CHAR_RNG_UPPER, 'z'),
  47. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  48. }),
  49. };
  50. Assert.Throws<ArgumentOutOfRangeException>(() => new Grammar(rules, 3));
  51. }
  52. [Fact]
  53. public async Task SampleWithTrivialGrammar()
  54. {
  55. // Create a grammar that constrains the output to be "cat" and nothing else. This is a nonsense answer, so
  56. // we can be confident it's not what the LLM would say if not constrained by the grammar!
  57. var rules = new List<GrammarRule>
  58. {
  59. new GrammarRule("feline", new []
  60. {
  61. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 'c'),
  62. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 'a'),
  63. new LLamaGrammarElement(LLamaGrammarElementType.CHAR, 't'),
  64. new LLamaGrammarElement(LLamaGrammarElementType.END, 0),
  65. }),
  66. };
  67. var grammar = new Grammar(rules, 0);
  68. using var grammarInstance = grammar.CreateInstance();
  69. using var grammarInstance2 = grammarInstance.Clone();
  70. var executor = new StatelessExecutor(_model, _params);
  71. var inferenceParams = new InferenceParams
  72. {
  73. MaxTokens = 3,
  74. AntiPrompts = new [] { ".", "Input:", "\n" },
  75. Grammar = grammarInstance2,
  76. };
  77. var result = await executor.InferAsync("Q. 7 + 12\nA. ", inferenceParams).ToListAsync();
  78. Assert.Equal("cat", result[0]);
  79. }
  80. //this test is flakey - it reproduces an error which appears to be a bug in llama.cpp
  81. //[Fact]
  82. //public async Task SampleTwiceWithGrammar()
  83. // {
  84. // var executor = new StatelessExecutor(_model, _params);
  85. // var grammar = Grammar.Parse("""
  86. //root ::= (object | array) endline?
  87. //endline ::= "<|im_end|>" ws
  88. //value ::= object | array | string | number | ("true" | "false" | "null") ws
  89. //object ::=
  90. //"{" ws (
  91. // string ":" ws value
  92. // ("," ws string ":" ws value)*
  93. //)? "}" ws
  94. //array ::=
  95. //"[" ws (
  96. // value
  97. // ("," ws value)*
  98. //)? "]" ws
  99. //string ::=
  100. //"\"" (
  101. // [^"\\] |
  102. // "\\" (["\\/bfnrt] | "u" [0-9a-fA-F] [0-9a-fA-F] [0-9a-fA-F]) # escapes
  103. //)* "\"" ws
  104. //number ::= ("-"? ([0-9] | [1-9] [0-9]*)) ("." [0-9]+)? ([eE] [-+]? [0-9]+)? ws
  105. //# Optional space: by convention, applied in this grammar after literal chars when allowed
  106. //ws ::= ([ \t\n] ws)?
  107. //""",
  108. // "root");
  109. // using (var grammarInstance = grammar.CreateInstance())
  110. // {
  111. // var inferenceParams = new InferenceParams
  112. // {
  113. // MaxTokens = 20,
  114. // AntiPrompts = new[] { ".", "Input:", "\n", "<|im_end|>" },
  115. // Grammar = grammarInstance,
  116. // };
  117. // var result = await executor.InferAsync("Write a JSON array with the first 6 positive numbers", inferenceParams).ToListAsync();
  118. // }
  119. // using (var grammarInstance2 = grammar.CreateInstance())
  120. // {
  121. // var inferenceParams2 = new InferenceParams
  122. // {
  123. // MaxTokens = 20,
  124. // AntiPrompts = new[] { ".", "Input:", "\n" },
  125. // Grammar = grammarInstance2,
  126. // };
  127. // var result2 = await executor.InferAsync("Write a JSON array with the first 6 positive numbers", inferenceParams2).ToListAsync();
  128. // }
  129. // }
  130. }
  131. }